#ifndef UTSM_LINUX_LOADER_H #define UTSM_LINUX_LOADER_H #include /* ===== Linux boot protocol structures (Documentation/x86/boot.rst) ===== */ /* bzImage setup_header — lives at offset 0x1f1 inside bzImage and boot_params. * Only the fields we actually use are listed; gaps are reserved/padding. */ struct linux_setup_header { u8 setup_sects; /* 0x1f1: number of setup sectors */ u16 root_flags; /* 0x1f2 */ u32 syssize; /* 0x1f4: protected-mode code size / 16 */ u16 ram_size; /* 0x1f8 */ u16 vid_mode; /* 0x1fa */ u16 boot_flag; /* 0x1fe: 0xAA55 */ u16 jump; /* 0x200: jump insn */ u32 header; /* 0x202: "HdrS" magic */ u16 version; /* 0x206: boot protocol version */ u32 realmode_swtch; /* 0x208 */ u16 start_sys_seg; /* 0x20c */ u16 kernel_version; /* 0x20e: offset to version string */ u8 type_of_loader; /* 0x210 */ u8 loadflags; /* 0x211 */ u16 setup_move_size; /* 0x212 */ u32 code32_start; /* 0x214: 32-bit entry (also 64-bit entry base) */ u32 ramdisk_image; /* 0x218 */ u32 ramdisk_size; /* 0x21c */ u32 bootsect_kludge; /* 0x220 */ u16 heap_end_ptr; /* 0x224 */ u8 ext_loader_ver; /* 0x226 */ u8 ext_loader_type; /* 0x227 */ u32 cmd_line_ptr; /* 0x228: command line physical address */ u32 init_size; /* 0x22c: total init memory needed */ u32 acpi_rsdp_addr; /* 0x230 */ u8 _pad0[4]; /* 0x234: relocatable_kernel + min_alignment */ u16 xloadflags; /* 0x236: bit0=XLF_KERNEL_64 */ u32 cmdline_size; /* 0x238 */ u32 _pad1; /* 0x23c */ u64 setup_data; /* 0x240: linked list of setup_data */ u64 pref_address; /* 0x248 → wait, this is payload_offset */ /* NOTE: The real layout continues with payload_offset at 0x248. * However, pref_address is at 0x258 and init_size at 0x260. * The struct above is intentionally simplified — we read fields * by offset rather than relying on this struct for the full layout. */ } __attribute__((packed)); /* boot_params is 4096 bytes. The setup_header is at offset 0x1f1. */ #define BOOT_PARAMS_SIZE 4096 #define SETUP_HEADER_OFFSET 0x1f1 #define BOOT_PARAMS_ACPI_RSDP_ADDR_OFF 0x070 #define BOOT_PARAMS_RSDP_COPY_OFF 0x800 #define BOOT_PARAMS_RSDP_COPY_SIZE 36 /* Key field offsets within bzImage / boot_params */ #define BZ_BOOT_FLAG_OFF 0x1fe #define BZ_HEADER_MAGIC 0x53726448 /* "HdrS" */ #define BZ_HEADER_OFF 0x202 #define BZ_VERSION_OFF 0x206 #define BZ_TYPE_OF_LOADER_OFF 0x210 #define BZ_LOADFLAGS_OFF 0x211 #define BZ_CODE32_START_OFF 0x214 #define BZ_RAMDISK_IMAGE_OFF 0x218 #define BZ_RAMDISK_SIZE_OFF 0x21c #define BZ_CMD_LINE_PTR_OFF 0x228 #define BZ_INIT_SIZE_OFF 0x22c /* wait — actually init_size is at 0x260 */ #define BZ_XLOADFLAGS_OFF 0x236 #define BZ_CMDLINE_SIZE_OFF 0x238 #define BZ_PAYLOAD_OFFSET_OFF 0x248 #define BZ_PAYLOAD_LENGTH_OFF 0x24c #define BZ_PREF_ADDRESS_OFF 0x258 #define BZ_INIT_SIZE_ACTUAL_OFF 0x260 /* xloadflags bits */ #define XLF_KERNEL_64 0x0001 #define XLF_CAN_BE_LOADED_ABOVE 0x0002 #define XLF_EFI_HANDOVER 0x0010 #define XLF_EFI_KEXEC 0x0020 /* loadflags bits */ #define LOADFLAG_LOADED_HIGH 0x01 #define LOADFLAG_KEEP_ROOT 0x02 #define LOADFLAG_CAN_USE_HEAP 0x80 /* e820 entry types */ #define E820_TYPE_RAM 1 #define E820_TYPE_RESERVED 2 #define E820_TYPE_ACPI 3 #define E820_TYPE_NVS 4 #define E820_TYPE_UNUSABLE 5 #define E820_TYPE_PMEM 7 /* e820_table is at 0x2d0 in Linux 6.6 boot_params (arch/x86/include/uapi/asm/bootparam.h). * e820_entries count is at 0x1e8. Each entry is 20 bytes: u64 addr, u64 size, u32 type. */ #define E820_ENTRIES_OFFSET 0x1e8 #define E820_TABLE_OFFSET 0x2d0 #define E820_MAX_ENTRIES 128 #define E820_ENTRY_SIZE 20 /* ===== Guest memory layout (GPA) ===== * Based on utsm-linux-dual-kernel-architecture.md. * 0x00000000-0x003FFFFF : UTSM reserved (denied to Linux) * 0x00400000-0x004FFFFF : boot_params / cmdline / GDT / page tables / stack * 0x01000000-0x02FFFFFF : Linux kernel image * 0x03000000-0x03FFFFFF : Linux initrd * 0x04000000-0x040FFFFF : IPC shared memory (1MB, both kernels RW) * 0x04100000-0x04FFFFFF : Graphics surface pool (16MB, VSCode integration Phase 1) * 0x05000000-0x5FFFFFFF : Linux general RAM (~1.4GB, expanded Phase 1 for VSCode) * 0xF4000000-0xF4007000 : virtio-mmio devices (8 slots, expanded Phase 1) */ #define LINUX_GUEST_KERNEL_GPA 0x01000000ULL /* 16 MB, 2MB-aligned */ #define LINUX_GUEST_BOOTPARAMS_GPA 0x00400000ULL /* 4 MB */ #define LINUX_GUEST_CMDLINE_GPA 0x00500000ULL /* 5 MB */ #define LINUX_GUEST_INITRD_GPA 0x03000000ULL /* 48 MB (within kernel+initrd region) */ #define LINUX_GUEST_STACK_GPA 0x00800000ULL /* 8 MB (stack grows down) */ #define LINUX_GUEST_GDT_GPA 0x00600000ULL /* 6 MB (guest GDT) */ #define LINUX_GUEST_PGT_GPA 0x00700000ULL /* 7 MB (guest page tables) */ #define LINUX_GUEST_CMDLINE_MAX 4096 /* IPC shared memory GPA (must match CODE/utsm-ipc/ipc_proto.h) */ #define LINUX_GUEST_IPC_SHM_GPA 0x04000000ULL /* 64 MB */ #define LINUX_GUEST_IPC_SHM_SIZE (1024 * 1024) /* 1MB */ /* VSCode integration Phase 1: Graphics surface pool. * Separate DMA region EPT-mapped into the Linux guest. Linux user-space mmaps * /dev/utsm at this GPA to obtain a writable scanout buffer that UTSM reads * for blitting to the Deshab framebuffer (Phase 3 virtio-gpu shadow buffer). * 16MB accommodates a 1920×1080×4 framebuffer (~8MB) with headroom for * cursor plane and dirty rect tracking metadata. */ #define LINUX_GUEST_SURFACE_GPA 0x04100000ULL /* 65 MB (immediately after IPC shm) */ #define LINUX_GUEST_SURFACE_SIZE (16 * 1024 * 1024) /* 16MB */ /* General RAM starts after IPC + surface regions. * Phase 1 expansion: 1.4GB to fit VSCode + Electron + GUI stack. */ #define LINUX_GUEST_RAM_GPA 0x05000000ULL /* 80 MB */ #define LINUX_GUEST_RAM_SIZE 0x5B000000ULL /* 1.4GB (0x05000000..0x5FFFFFFF) */ /* ===== virtio-mmio device GPA layout ===== * virtio-mmio 设备放在 GPA 高位 MMIO 区(guest RAM 之上,不占用 e820 RAM)。 * guest 通过 cmdline 参数 virtio_mmio.device= 发现这些设备。 * 每个设备占 0x200 字节寄存器空间(virtio-mmio 规范要求 4KB 对齐)。 * * 这些 GPA 在 EPT 中【故意不映射】,访问时触发 EPT violation, * 由 vmexit handler 路由到 virtio_mmio 后端模拟寄存器读写。 * * GPA 选择 0xF4000000 起始(接近 4GB,远离 guest RAM 0x05000000-0x5FFFFFFF)。 * * VSCode integration Phase 1 expansion: 槽位从 3 扩到 8,为后续阶段预留: * slot 0: blk (Phase 1-) IRQ5 * slot 1: net (Phase 1-) IRQ6 * slot 2: rootfs (Phase 1-) IRQ7 * slot 3: keyboard (Phase 2) IRQ8 — virtio-input, evdev /dev/input/event0 * slot 4: mouse (Phase 2) IRQ9 — virtio-input, evdev /dev/input/event1 * slot 5: gpu (Phase 3) IRQ10 — virtio-gpu 2D, /dev/dri/card0 * slot 6: extra-rootfs (Phase 4) IRQ11 — persistent rw volume (/dev/vdc) * slot 7: reserved — future use */ #define VIRTIO_MMIO_GPA_BASE 0xF4000000ULL #define VIRTIO_MMIO_GPA_STRIDE 0x1000ULL /* 每个设备 4KB */ #define VIRTIO_MMIO_MAX_SLOTS 8 /* Phase 1: 3→8 */ #define VIRTIO_MMIO_BLK_GPA (VIRTIO_MMIO_GPA_BASE + 0 * VIRTIO_MMIO_GPA_STRIDE) /* 0xF4000000 */ #define VIRTIO_MMIO_NET_GPA (VIRTIO_MMIO_GPA_BASE + 1 * VIRTIO_MMIO_GPA_STRIDE) /* 0xF4001000 */ #define VIRTIO_MMIO_ROOTFS_GPA (VIRTIO_MMIO_GPA_BASE + 2 * VIRTIO_MMIO_GPA_STRIDE) /* 0xF4002000 */ /* VSCode integration: Phase 2/3/4 device slots (currently unused, reserved) */ #define VIRTIO_MMIO_KBD_GPA (VIRTIO_MMIO_GPA_BASE + 3 * VIRTIO_MMIO_GPA_STRIDE) /* 0xF4003000 */ #define VIRTIO_MMIO_MOUSE_GPA (VIRTIO_MMIO_GPA_BASE + 4 * VIRTIO_MMIO_GPA_STRIDE) /* 0xF4004000 */ #define VIRTIO_MMIO_GPU_GPA (VIRTIO_MMIO_GPA_BASE + 5 * VIRTIO_MMIO_GPA_STRIDE) /* 0xF4005000 */ #define VIRTIO_MMIO_EXTRA_ROOTFS_GPA (VIRTIO_MMIO_GPA_BASE + 6 * VIRTIO_MMIO_GPA_STRIDE) /* 0xF4006000 */ /* 判断 GPA 是否落在 virtio-mmio 设备区(含两端) */ #define VIRTIO_MMIO_GPA_END (VIRTIO_MMIO_GPA_BASE + VIRTIO_MMIO_MAX_SLOTS * VIRTIO_MMIO_GPA_STRIDE) #define IS_VIRTIO_MMIO_GPA(gpa) ((gpa) >= VIRTIO_MMIO_GPA_BASE && (gpa) < VIRTIO_MMIO_GPA_END) /* ===== Linux loader API ===== */ /* Loaded Linux guest state */ struct linux_guest_info { u64 kernel_gpa; /* GPA where kernel was loaded */ u64 kernel_entry; /* 64-bit entry point GPA */ u64 kernel_size; /* Size of loaded kernel image */ u64 bootparams_gpa; /* GPA of boot_params */ u64 cmdline_gpa; /* GPA of command line */ u64 cmdline_size; /* Command line length (with NUL) */ u64 initrd_gpa; /* GPA of initrd (0 = none) */ u64 initrd_size; /* Size of initrd */ u64 pgt_gpa; /* GPA of guest page tables */ u64 gdt_gpa; /* GPA of guest GDT */ int loaded; /* 1 = successfully loaded */ /* VSCode integration Phase 1: graphics surface pool. * Allocated as a separate DMA buffer and EPT-mapped into the guest at * surface_gpa. Exposed to Linux user-space via UTSM_HCALL_SURFACE_INFO * and /dev/utsm mmap (see CODE/linux/patches/utsm_hcall.c). */ u64 surface_hpa; /* Host physical address of surface pool (0 = none) */ u64 surface_gpa; /* GPA visible inside Linux guest */ u64 surface_size; /* Surface pool size in bytes */ }; /* Find the Linux bzImage boot module among Limine modules. * Returns pointer to the module data, or NULL if not found. * Sets *size_out to the module size. */ void *linux_find_bzimage_module(u64 *size_out); /* Find the Arch rootfs image boot module (path contains "rootfs"). * Exposed to Linux guest via memory-backed virtio-blk as /dev/vdb. */ void *linux_find_rootfs_module(u64 *size_out); /* VSCode Phase 4: find the extra rootfs image boot module (path contains * "extra"). Exposed via writable virtio-blk slot6 as /dev/vdc (overlayfs * upper / VSCode data volume). Returns NULL when the module is absent. */ void *linux_find_extra_rootfs_module(u64 *size_out); /* VSCode Phase 5: find the VSCode tarball boot module (path contains * "vscode", e.g. linux-vscode.tar.gz). The tarball is streamed into the * guest and extracted to /opt/vscode by lxc_vscode_install(). * Returns NULL when the module is absent (install skipped, non-fatal). */ void *linux_find_vscode_module(u64 *size_out); /* Parse bzImage header and return the protected-mode image's file offset, * load length, decompression allocation size, and startup_64 entry offset. * The protected-mode image starts after setup sectors; setup_header's * payload_offset instead locates compressed data inside that image. * Returns 0 on success, negative on error. */ int linux_parse_bzimage(const void *bzimage, u64 size, u64 *kernel_offset_out, u64 *kernel_length_out, u64 *init_size_out, u64 *entry_offset_out); /* Initialize the Linux guest: parse bzImage, allocate guest memory, * set up boot_params, page tables, GDT, and EPT mappings. * Returns 0 on success, negative on error. */ int linux_loader_init(void); /* Get the loaded Linux guest info (NULL if not loaded). */ const struct linux_guest_info *linux_get_guest_info(void); /* VSCode integration Phase 1: query graphics surface pool. * Returns 0 and fills outputs if the surface pool was allocated and EPT-mapped * into the Linux guest; returns -1 if not initialized (e.g. Linux guest not * loaded). hpa_out receives the host physical address (for UTSM-side blit), * gpa_out receives the GPA visible inside Linux (for the guest mmap path), * size_out receives the pool size in bytes. Any output pointer may be NULL. */ int linux_get_surface_info(u64 *hpa_out, u64 *gpa_out, u64 *size_out); /* VSCode Phase 3: return host virtual address of the graphics surface pool. * The virtio-gpu 2D backend composites the scanout into this buffer; the * desktop reads it to blit guest graphics onto the IDE host area. * Returns NULL if the pool was not allocated (Linux guest not loaded / alloc failed). */ void *linux_get_surface_vaddr(void); /* Configure VMCS for Linux guest and perform vmlaunch. * Must be called after vmm_init() + linux_loader_init(). * Returns 0 on successful guest termination, negative on error. */ int linux_launch(void); /* Default Linux command line (can be overridden). * Daemon PARK is a VMCALL. Guest idle may HLT; that stays in the * guest (wait-for-IRQ). Do not use nohlt/idle=poll — poll idle * NULL-derefs current after the first real sleep. * noapic/nolapic/nosmp: UTSM VMM 只模拟 legacy PIC(8259) + PIT(8254), * 不提供 LAPIC/IOAPIC;guest 走 XT-PIC 模式,IRQ vector = 0x30+irq。 * virtio_mmio.device=: 向 guest 声明 virtio-mmio 设备(blk@0xF4000000 IRQ5, * net@0xF4001000 IRQ6),需 CONFIG_VIRTIO_MMIO_CMDLINE_DEVICES=y。 * VSCode Phase 2: kbd@0xF4003000 IRQ8, mouse@0xF4004000 IRQ9 (virtio-input)。 * VSCode Phase 3: gpu@0xF4005000 IRQ10 (virtio-gpu 2D, /dev/dri/card0)。 * VSCode Phase 4: xrootfs@0xF4006000 IRQ11 (可写 virtio-blk, /dev/vdc)。 * 注:无 extra-rootfs boot module 时,后端改映射 ESP 上的 * boot/linux-extra-rootfs.img(AHCI+FAT32),避免 Limine 把 4GiB * 打进 RAM。文件也没有则不注册,guest 探测超时跳过。 */ #define LINUX_DEFAULT_CMDLINE \ "earlyprintk=serial,ttyS0,115200 console=ttyS0,115200 " \ "nokaslr debug loglevel=8 noinvpcid nopcid nopti pti=off nogbpages " \ "tsc_early_khz=2000000 lpj=4000000 i8042.nokbd i8042.noaux " \ "no_timer_check " \ "noapic nolapic nosmp ibt=off user_shstk=off " \ "virtio_mmio.device=4K@0xF4000000:5 " \ "virtio_mmio.device=4K@0xF4001000:6 " \ "virtio_mmio.device=4K@0xF4002000:7 " \ "virtio_mmio.device=4K@0xF4003000:8 " \ "virtio_mmio.device=4K@0xF4004000:9 " \ "virtio_mmio.device=4K@0xF4005000:10 " \ "virtio_mmio.device=4K@0xF4006000:11" #endif