Construct the memory source from a file descriptor

vmie_mem could only be built from a path. Add a second input: an
already-open file descriptor, dup()'d internally (borrowed - the
caller's fd stays valid, core owns and closes its copy).

  - vmie_mem_from_fd / vmie_mem_from_fd_segs   (read-write, as the path
    constructors: PROT_RW, MAP_SHARED)
  - vmie_mem_from_ro_fd / vmie_mem_from_ro_fd_segs   (read-only: map
    PROT_READ, mark the source ro; gpa_write/gva_write return -1, every
    read path is unchanged; accepts an O_RDONLY fd)
  - vmie_win32_open_fd   (the win32 context over an fd backing file)

Factor the mmap/validate tail and the single-low segment map out of the
path constructors into shared helpers, so the path and fd inputs go
through one mmap site and one map builder each.
This commit is contained in:
2026-06-20 11:20:33 +03:00
parent f401738702
commit 5ea9a3785f
5 changed files with 227 additions and 19 deletions
+41 -1
View File
@@ -62,7 +62,47 @@ vmie_mem* vmie_mem_open(const char* path, uint64_t low);
* Returns a heap-owned handle, or NULL on failure. Release with vmie_mem_close(). */
vmie_mem* vmie_mem_open_segs(const char* path, const gpa_seg* segs, int nseg);
/* Unmap, close, and free a handle from vmie_mem_open*. Safe on NULL. */
/* Build a source from an already-open file descriptor `fd` instead of a path,
* with the single-`low` map (as vmie_mem_open). `fd` is BORROWED: it is dup()'d
* internally, so the source owns its own copy and the caller's `fd` stays open
* and valid both after this call AND after vmie_mem_close(). `fd` must reference
* an mmap-able, read-write object (a regular file, memfd_create, or POSIX shm) -
* a pipe/socket/tty is not mmap-able and yields NULL. The fd's file position is
* not read or changed (the mapping starts at offset 0). Returns a heap-owned
* handle, or NULL on dup/fstat/mmap failure. Release with vmie_mem_close(). */
vmie_mem* vmie_mem_from_fd(int fd, uint64_t low);
/* As vmie_mem_from_fd, but with an explicit segment map (`nseg` entries; see
* gpa_seg), well-formed against the file size. Same dup-borrow semantics: the
* caller's `fd` stays valid after this call and after vmie_mem_close(); `fd`
* must be an mmap-able RW object and its position is untouched. Returns a
* heap-owned handle, or NULL on failure. Release with vmie_mem_close(). */
vmie_mem* vmie_mem_from_fd_segs(int fd, const gpa_seg* segs, int nseg);
/* Read-only twin of vmie_mem_from_fd: build a source from `fd` with the
* single-`low` map, but map it PROT_READ and mark it read-only. On the returned
* handle gpa_write/gva_write (and any write through the engine) return -1; all
* reads - gpa_read/gva_read, gpa_ptr/gva_ptr, gva_regions, sig_scan_mem - behave
* exactly as on an RW source. Because only read access is needed, `fd` may be
* opened O_RDONLY (an O_RDWR fd is also accepted). Same dup-borrow semantics: the
* fd is dup()'d internally, so the caller's `fd` stays valid after this call AND
* after vmie_mem_close(); its file position is not read or changed. NOTE: writing
* THROUGH a pointer returned by gpa_ptr/gva_ptr on a read-only source is a
* contract violation (the pages are read-only and the store will fault) - use
* such pointers for reading only. Returns a heap-owned handle, or NULL on
* dup/fstat/mmap failure. Release with vmie_mem_close(). */
vmie_mem* vmie_mem_from_ro_fd(int fd, uint64_t low);
/* As vmie_mem_from_ro_fd, but with an explicit segment map (`nseg` entries; see
* gpa_seg), well-formed against the file size. Same read-only contract
* (writes -> -1; no writes through gpa_ptr/gva_ptr) and dup-borrow semantics
* (caller's `fd` stays valid after this call and after vmie_mem_close(); accepts
* an O_RDONLY or O_RDWR fd; position untouched). Returns a heap-owned handle, or
* NULL on failure. Release with vmie_mem_close(). */
vmie_mem* vmie_mem_from_ro_fd_segs(int fd, const gpa_seg* segs, int nseg);
/* Unmap, close, and free a handle from vmie_mem_open*, vmie_mem_from_fd*, or
* vmie_mem_from_ro_fd*. Safe on NULL. */
void vmie_mem_close(vmie_mem* m);
/* ---- flat memory view (single owner) ------------------------------------- *
+9
View File
@@ -83,6 +83,15 @@ typedef struct {
* failure. Free with vmie_win32_close(). */
vmie_win32* vmie_win32_open(const char* ram_path, uint64_t low);
/* As vmie_win32_open, but over an already-open file descriptor `fd` for the RAM
* backing file instead of a path. `fd` is BORROWED: it is dup()'d internally, so
* the context owns its own copy and the caller's `fd` stays open and valid after
* this call AND after vmie_win32_close(). `fd` must reference an mmap-able,
* read-write object (regular file / memfd_create / POSIX shm); its file position
* is not read or changed. Returns a new context (call host_bootstrap() next), or
* NULL on dup/fstat/mmap failure. Free with vmie_win32_close(). */
vmie_win32* vmie_win32_open_fd(int fd, uint64_t low);
/* Unmap, close, and free a context. Safe on NULL. After this, every pointer
* into guest memory obtained through this context is invalid. */
void vmie_win32_close(vmie_win32* v);