/* xj380_loader.c — OpenXJ380 kernel.krl loader for UTSM VMX non-root guest. * * 参照 linux_loader.c 的既有模式实现 XJ380 第二 guest: * 1. 在 Limine boot module 中查找 kernel.krl(路径含 "xj380") * 2. 解析 ELF64 PT_LOAD 段(固定链接 0xFFFFFFFF80000000) * 3. 分配 host 物理内存:boot area / framebuffer / kernel / RAM * 4. 构造 guest 初始页表(恒等 0-4GB + HHDM + 内核区三区布局) * 5. 构造 guest GDT(64 位 code/data/TSS) * 6. 构造 ACPI 桩表 MADT/FADT/MCFG/HPET(幽灵设备地址,EPT 按需分配) * 7. 构造 EFI 格式内存图(单一 Conventional 区 = guest RAM) * 8. 构造 BOOT_CONFIG / FrameBufferConfig / 伪 EFI_SYSTEM_TABLE * 9. EPT 映射所有 guest 区域 * * VMCS 配置与 vmlaunch 见 xj380_boot.c。 */ #include #include #include #include #include #include #include #include "../arch/x86_64/limine.h" extern volatile struct limine_module_request g_module_request; extern volatile struct limine_hhdm_request g_hhdm_request; /* ===== 运行期辅助 ===== */ static void mem_copy(void *dst, const void *src, u64 n) { u8 *d = (u8 *)dst; const u8 *s = (const u8 *)src; for (u64 i = 0; i < n; i++) d[i] = s[i]; } static void mem_zero(void *dst, u64 n) { u8 *d = (u8 *)dst; for (u64 i = 0; i < n; i++) d[i] = 0; } static u64 hhdm(void) { return g_hhdm_request.response ? g_hhdm_request.response->offset : 0; } static void *to_virt(u64 hpa) { return (void *)(hpa + hhdm()); } /* ===== ELF64 解析(kernel.krl 为 ET_EXEC) ===== */ #define ELF_MAGIC 0x464C457FULL /* "\x7fELF" */ #define ELF_ET_EXEC 2 #define ELF_PT_LOAD 1 typedef struct __attribute__((packed)) { u8 e_ident[16]; u16 e_type; u16 e_machine; u32 e_version; u64 e_entry; u64 e_phoff; u64 e_shoff; u32 e_flags; u16 e_ehsize; u16 e_phentsize; u16 e_phnum; u16 e_shentsize; u16 e_shnum; u16 e_shstrndx; } xj_elf64_ehdr; typedef struct __attribute__((packed)) { u32 p_type; u32 p_flags; u64 p_offset; u64 p_vaddr; u64 p_paddr; u64 p_filesz; u64 p_memsz; u64 p_align; } xj_elf64_phdr; /* 解析 ELF:校验头、遍历 PT_LOAD 计算内核跨度,记录入口。 * 返回 0 成功;负值失败。 */ static int xj380_parse_elf(const void *img, u64 size, u64 *entry_out, u64 *span_out) { if (size < sizeof(xj_elf64_ehdr)) { log_error("[XJ380] kernel.krl too small"); panic_full("XJ3-E01 KRL IMAGE TOO SMALL", "kernel.krl image smaller than an elf64 header", 0); return -1; } const xj_elf64_ehdr *eh = (const xj_elf64_ehdr *)img; if (*(u32 *)eh->e_ident != (u32)ELF_MAGIC) { log_error("[XJ380] bad ELF magic"); panic_full("XJ3-E02 BAD ELF MAGIC", "kernel.krl elf magic mismatch", 0); return -2; } if (eh->e_ident[4] != 2) { /* ELFCLASS64 */ log_error("[XJ380] not a 64-bit ELF"); panic_full("XJ3-E03 NOT A 64-BIT ELF", "kernel.krl is not a 64-bit elf image", 0); return -3; } if (eh->e_type != ELF_ET_EXEC) { log_error("[XJ380] kernel.krl not ET_EXEC"); panic_full("XJ3-E04 KRL NOT ET_EXEC", "kernel.krl is not an ET_EXEC elf image", 0); return -4; } if (eh->e_phnum == 0 || eh->e_phentsize != sizeof(xj_elf64_phdr) || eh->e_phoff + (u64)eh->e_phnum * sizeof(xj_elf64_phdr) > size) { log_error("[XJ380] bad program header table"); panic_full("XJ3-E05 BAD PROGRAM HEADER TABLE", "kernel.krl program header table is invalid", 0); return -5; } u64 span = 0; const xj_elf64_phdr *ph = (const xj_elf64_phdr *)((const u8 *)img + eh->e_phoff); for (u16 i = 0; i < eh->e_phnum; i++) { if (ph[i].p_type != ELF_PT_LOAD) continue; if (ph[i].p_vaddr < XJ380_KERNEL_VADDR) { log_error("[XJ380] PT_LOAD below kernel base"); log_hex64("[XJ380] vaddr=", ph[i].p_vaddr); panic_full("XJ3-E06 PT_LOAD BELOW KERNEL BASE", "pt_load segment mapped below the xj380 kernel base", 0); return -6; } u64 off = ph[i].p_vaddr - XJ380_KERNEL_VADDR; if (off + ph[i].p_memsz > XJ380_GUEST_KERNEL_MAX) { log_error("[XJ380] kernel exceeds reserved window (32MB)"); panic_full("XJ3-E07 KERNEL EXCEEDS RESERVED WINDOW", "kernel span exceeds the 32mb reserved window", 0); return -7; } if (ph[i].p_offset + ph[i].p_filesz > size) { log_error("[XJ380] PT_LOAD filesz beyond image"); panic_full("XJ3-E08 PT_LOAD FILESZ BEYOND IMAGE", "pt_load file size extends beyond the kernel.krl image", 0); return -8; } if (off + ph[i].p_memsz > span) span = off + ph[i].p_memsz; } if (span == 0) { log_error("[XJ380] no PT_LOAD segments"); panic_full("XJ3-E09 NO PT_LOAD SEGMENTS", "kernel.krl contains no pt_load segments", 0); return -9; } if (entry_out) *entry_out = eh->e_entry; if (span_out) *span_out = span; log_hex64("[XJ380] ELF entry=", eh->e_entry); log_hex64("[XJ380] kernel span=", span); return 0; } /* ===== Guest 状态 ===== */ static struct xj380_guest_info g_guest; /* ===== Guest 页表(三区布局,同 XJ380 引导器契约) ===== * * PML4 @ pgt_gpa + 0x0000 * [0] → PDPT0 恒等映射 0-4GB(早期直读 MADT 等,内核自清低半) * [256] → PDPT0 HHDM 映射 0xFFFF800000000000 + [0,4GB) * [511] → PDPT_K 内核区 0xFFFFFF8000000000+ * PDPT0 @ pgt_gpa + 0x1000,[0..3] → PD0..PD3(每页覆盖 1GB,2MB 大页) * PD0-3 @ pgt_gpa + 0x2000..0x5000 * PDPT_K@ pgt_gpa + 0x6000,[480] → PD_K(0xFFFFFFFF80000000 区间) * PD_K @ pgt_gpa + 0x7000,[0..n] 2MB 大页映射内核 GPA */ #define XJ_PGT_PDPT0_OFF 0x1000 #define XJ_PGT_PD0_OFF 0x2000 #define XJ_PGT_PDPTK_OFF 0x6000 #define XJ_PGT_PDK_OFF 0x7000 /* x86-64 页表项位 */ #define XJ_PTE_P (1ULL << 0) #define XJ_PTE_RW (1ULL << 1) #define XJ_PTE_PS (1ULL << 7) static int xj380_build_page_tables(u64 pgt_hpa, u64 kernel_gpa, u64 kernel_span) { u64 *pml4 = (u64 *)to_virt(pgt_hpa); mem_zero(pml4, XJ380_PGT_SIZE); u64 pdpt0_gpa = g_guest.pgt_gpa + XJ_PGT_PDPT0_OFF; u64 pdptk_gpa = g_guest.pgt_gpa + XJ_PGT_PDPTK_OFF; /* PML4[0] 恒等 + PML4[256] HHDM 指向同一个 PDPT0 */ pml4[0] = pdpt0_gpa | XJ_PTE_P | XJ_PTE_RW; pml4[256] = pdpt0_gpa | XJ_PTE_P | XJ_PTE_RW; /* PML4[511] → PDPT_K */ pml4[511] = pdptk_gpa | XJ_PTE_P | XJ_PTE_RW; /* PDPT0[0..3] → PD0..PD3(覆盖 0-4GB) */ u64 *pdpt0 = (u64 *)((u8 *)pml4 + XJ_PGT_PDPT0_OFF); for (int i = 0; i < 4; i++) { u64 pd_gpa = g_guest.pgt_gpa + XJ_PGT_PD0_OFF + (u64)i * 4096; pdpt0[i] = pd_gpa | XJ_PTE_P | XJ_PTE_RW; } /* 每个 PD 512 项,每项 2MB 大页:GPA = i*1GB + j*2MB */ for (int i = 0; i < 4; i++) { u64 *pd = (u64 *)((u8 *)pml4 + XJ_PGT_PD0_OFF + (u64)i * 4096); for (int j = 0; j < 512; j++) { u64 page_gpa = (u64)i * (1ULL << 30) + (u64)j * (2ULL << 20); pd[j] = page_gpa | XJ_PTE_P | XJ_PTE_RW | XJ_PTE_PS; } } /* PDPT_K[480] → PD_K(虚拟 0xFFFFFFFF80000000 落在 PML4[511] 第 480 个 1GB) */ u64 *pdptk = (u64 *)((u8 *)pml4 + XJ_PGT_PDPTK_OFF); u64 pdk_gpa = g_guest.pgt_gpa + XJ_PGT_PDK_OFF; pdptk[480] = pdk_gpa | XJ_PTE_P | XJ_PTE_RW; /* PD_K[i]:虚拟 0xFFFFFFFF80000000 + i*2MB → GPA kernel_gpa + i*2MB */ u64 *pdk = (u64 *)((u8 *)pml4 + XJ_PGT_PDK_OFF); u64 pages = (kernel_span + (2ULL << 20) - 1) >> 21; for (u64 i = 0; i < pages; i++) { u64 gpa = kernel_gpa + (i << 21); pdk[i] = gpa | XJ_PTE_P | XJ_PTE_RW | XJ_PTE_PS; } return 0; } /* ===== Guest GDT(与 linux_loader 相同的 64 位布局) ===== */ typedef struct __attribute__((packed)) { u16 limit_low; u16 base_low; u8 base_mid; u8 access; u8 flags_limit_high; u8 base_high; } xj_gdt_entry64; typedef struct __attribute__((packed)) { u32 limit_low_base_low; u8 base_mid; u8 access; u8 flags_limit_high; u8 base_high; u32 base_upper; u32 reserved; } xj_tss_desc64; static int xj380_build_gdt(u64 gdt_hpa) { u8 *gdt_page = (u8 *)to_virt(gdt_hpa); mem_zero(gdt_page, 4096); xj_gdt_entry64 *gdt = (xj_gdt_entry64 *)gdt_page; gdt[1].limit_low = 0xFFFF; gdt[1].access = 0x9B; gdt[1].flags_limit_high = 0xAF; /* G=1, L=1(64 位代码) */ gdt[2].limit_low = 0xFFFF; gdt[2].access = 0x93; gdt[2].flags_limit_high = 0xCF; /* [0x18] 64 位 TSS 描述符,TSS 本体在同页 +0x100 */ xj_tss_desc64 *tss_d = (xj_tss_desc64 *)&gdt_page[0x18]; u64 tss_base = g_guest.gdt_gpa + 0x100; u32 tss_limit = 0x67; tss_d->limit_low_base_low = (tss_limit & 0xFFFF) | ((u32)(tss_base & 0xFFFFFF) << 16); tss_d->base_mid = (u8)((tss_base >> 24) & 0xFF); tss_d->access = 0x89; tss_d->flags_limit_high = (u8)((tss_limit >> 16) & 0x0F); tss_d->base_high = 0; tss_d->base_upper = 0; tss_d->reserved = 0; return 0; } /* ===== ACPI 桩表 ===== * * XJ380 初始化需要 MADT(APIC/LAPIC/IOAPIC)、FADT(未使用)、MCFG(PCIe)、 * HPET(时钟)。所有设备地址均为"幽灵地址":EPT 未映射该区域时由 * handle_ept_violation 按需分配真实页,guest 读写不崩溃。 * LAPIC/IOAPIC/HPET/MMCONF 均落在低 4GB,恒等 + HHDM 双路可见。 */ typedef struct __attribute__((packed)) { char signature[4]; u32 length; u8 revision; u8 checksum; char oemid[6]; char oemtableid[8]; u32 oemrev; u32 creatorid; u32 creatorrev; } xj_acpi_header; /* 36 字节 */ static void acpi_set_header(xj_acpi_header *h, const char sig[4], u32 len) { mem_zero(h, len); h->signature[0] = sig[0]; h->signature[1] = sig[1]; h->signature[2] = sig[2]; h->signature[3] = sig[3]; h->length = len; h->revision = 1; mem_copy(h->oemid, "DESHAB", 6); mem_copy(h->oemtableid, "UTSMVMM", 8); h->oemrev = 1; mem_copy((char *)&h->creatorid, "UTSM", 4); h->creatorrev = 1; /* 校验和 = -sum(校验和字节置 0 后求和) */ u32 sum = 0; u8 *p = (u8 *)h; for (u32 i = 0; i < len; i++) sum += p[i]; h->checksum = (u8)(0 - (u8)sum); } /* MADT:36 头 + LAPIC 地址(4) + 标志(4) + LAPIC 项(8) + IOAPIC 项(12) = 64 字节。 * LAPIC 项:type=0, len=8, uid=0, id=0, flags=1(仅 enabled,不触发 AP 启动) * IOAPIC 项:type=1, len=12, id=0, addr=0xFEC00000(幽灵), gsib=0 */ static int xj380_build_madt(u64 hpa) { u8 *t = (u8 *)to_virt(hpa); acpi_set_header((xj_acpi_header *)t, "APIC", 64); u8 *p = t + 36; p[0] = 0x00; p[1] = 0x00; p[2] = 0x00; p[3] = 0xF0; /* lapic addr = 0xFEE00000 */ p[4] = 0x01; p[5] = 0x00; p[6] = 0x00; p[7] = 0x00; /* flags = PCAT_COMPAT */ p += 8; p[0] = 0x00; /* type = LAPIC */ p[1] = 0x08; /* len */ p[2] = 0x00; /* ACPI processor uid */ p[3] = 0x00; /* lapic id */ p[4] = 0x01; p[5] = 0x00; p[6] = 0x00; p[7] = 0x00; /* flags = enabled only */ p += 8; p[0] = 0x01; /* type = IOAPIC */ p[1] = 0x0C; /* len */ p[2] = 0x00; /* ioapic id */ p[3] = 0x00; /* reserved */ p[4] = 0x00; p[5] = 0x00; p[6] = 0xC0; p[7] = 0xFE; /* ioapic addr = 0xFEC00000 */ p[8] = 0x00; p[9] = 0x00; p[10] = 0x00; p[11] = 0x00; /* gsib */ return 0; } /* FADT:最小桩表(XJ380 仅在未接线的 power_shutdown 路径使用,启动不读) */ static int xj380_build_fadt(u64 hpa) { u8 *t = (u8 *)to_virt(hpa); acpi_set_header((xj_acpi_header *)t, "FACP", 96); return 0; } /* MCFG:36 头 + reserved(8) + 1 项(16) = 60 字节。 * base=0xF0000000(幽灵 MMCONF),1 个 segment、1 条总线(扫描结果为无设备) */ static int xj380_build_mcfg(u64 hpa) { u8 *t = (u8 *)to_virt(hpa); acpi_set_header((xj_acpi_header *)t, "MCFG", 60); u8 *p = t + 36 + 8; p[0] = 0x00; p[1] = 0x00; p[2] = 0x00; p[3] = 0x00; p[4] = 0x00; p[5] = 0x00; p[6] = 0xF0; p[7] = 0x0F; /* base = 0xF0000000 */ p[8] = 0x00; p[9] = 0x00; /* segment group 0 */ p[10] = 0x00; /* start bus 0 */ p[11] = 0x00; /* end bus 0 */ p[12] = 0x00; p[13] = 0x00; p[14] = 0x00; p[15] = 0x00; /* reserved */ return 0; } /* HPET:36 头 + event_block_id(4) + GAS(12) + tick_unit(2) + 属性(1) = 55 → 56。 * base=0xFED00000(幽灵),generalCapabilities 读 0 → hpetPeriod=0,不挂起 */ static int xj380_build_hpet(u64 hpa) { u8 *t = (u8 *)to_virt(hpa); acpi_set_header((xj_acpi_header *)t, "HPET", 56); u8 *p = t + 36; p[0] = 0x00; p[1] = 0x00; p[2] = 0x00; p[3] = 0x00; /* event_block_id */ p[4] = 0x00; /* address_space = 系统内存 */ p[5] = 0x20; /* bit_width = 64 */ p[6] = 0x00; /* bit_offset */ p[7] = 0x00; /* access_size */ p[8] = 0x00; p[9] = 0x00; p[10] = 0x00; p[11] = 0x00; p[12] = 0x00; p[13] = 0xD0; p[14] = 0xFE; p[15] = 0x0F; /* base = 0xFED00000 */ p[16] = 0x00; p[17] = 0x00; /* clock_tick_unit */ p[18] = 0x00; /* page_oem_flags */ return 0; } /* ===== EFI 格式内存图 ===== * * 仅一个 Conventional 区(guest RAM),其余区域隐式保留。 * EfiMemoryDesc:Type(4)+pad(4)+PhysicalStart(8)+VirtualStart(8)+ * NumberOfPages(8)+Attribute(8),16 字节对齐 → 48 字节。 */ typedef struct __attribute__((aligned(16))) { u32 type; u32 pad; u64 physical_start; u64 virtual_start; u64 number_of_pages; u64 attribute; } xj_efi_memdesc; #define XJ_EFI_CONVENTIONAL 7 #define XJ_EFI_DESC_SIZE (u64)sizeof(xj_efi_memdesc) #define XJ_EFI_MEM_ATTR 0xFULL static int xj380_build_memmap(u64 hpa) { xj_efi_memdesc *d = (xj_efi_memdesc *)to_virt(hpa); mem_zero(d, sizeof(*d)); d->type = XJ_EFI_CONVENTIONAL; d->physical_start = g_guest.ram_gpa; d->virtual_start = 0; d->number_of_pages = g_guest.ram_size / 4096; d->attribute = XJ_EFI_MEM_ATTR; return 0; } /* ===== BOOT_CONFIG(布局必须与 OpenXJ380 boot/include/boot.h 一致) ===== * * MEMORY_MAP 在 memory.h 中 #pragma pack(1):36 字节;BOOT_CONFIG 默认对齐。 * 关键:MemoryMap.Buffer / saved_mtrrs 是【物理地址】(内核自行 +HHDM); * temp_stack[] 是【HHDM 虚拟地址】数组(仅拷贝,1 CPU 不 deref)。 */ typedef struct __attribute__((packed)) { u64 map_size; u64 buffer; /* 物理 GPA */ u64 map_key; u64 descriptor_size; u32 descriptor_version; } xj_memory_map; /* 36 字节 */ typedef struct { xj_memory_map memory_map; u64 fadt; u64 madt; u64 hpet; u64 mcfg; u64 *saved_mtrrs; /* 物理 GPA,内核 +HHDM */ u64 *temp_stack[256]; /* HHDM 虚拟地址 */ int is_qemu; u64 boot_flags; u64 installer_root_pak; u64 installer_root_pak_size; u64 system_payload_pak; u64 system_payload_pak_size; } xj_boot_config; _Static_assert(sizeof(xj_memory_map) == 36, "xj_memory_map layout mismatch"); _Static_assert(sizeof(xj_boot_config) == 2176, "xj_boot_config layout mismatch"); /* FrameBufferConfig(boot/include/fbc.h,默认对齐,24 字节) */ typedef struct { u8 *frame_buffer; /* HHDM 虚拟地址 */ u32 pixels_per_scan_line; u32 horizontal_resolution; u32 vertical_resolution; u32 pixel_format; /* 0=kRGBR, 1=kBGRR */ } xj_framebuffer_config; _Static_assert(sizeof(xj_framebuffer_config) == 24, "fbc layout mismatch"); static int xj380_build_boot_config(u64 hpa, u64 mtrr_hpa, u64 stack_gpa, u64 fbc_gpa) { xj_boot_config *bc = (xj_boot_config *)to_virt(hpa); mem_zero(bc, sizeof(*bc)); bc->memory_map.map_size = XJ_EFI_DESC_SIZE; /* 单描述符 */ bc->memory_map.buffer = XJ380_MEMMAP_GPA; /* 物理 GPA */ bc->memory_map.map_key = 0; bc->memory_map.descriptor_size = XJ_EFI_DESC_SIZE; bc->memory_map.descriptor_version = 1; bc->fadt = XJ380_FADT_GPA; bc->madt = XJ380_MADT_GPA; bc->hpet = XJ380_HPET_GPA; bc->mcfg = XJ380_MCFG_GPA; bc->saved_mtrrs = (u64 *)mtrr_hpa; /* 物理 GPA */ u64 stack_hhdm = stack_gpa + XJ380_HHDM_OFFSET; for (int i = 0; i < 256; i++) bc->temp_stack[i] = (u64 *)stack_hhdm; bc->is_qemu = 1; bc->boot_flags = XJ380_BOOT_FLAG_DISABLE_KMOD | XJ380_BOOT_FLAG_SAFE_STORAGE_IO; /* installer paks 均为 0(安装器模式关闭) */ /* FrameBufferConfig:frame_buffer 传 HHDM 虚拟地址,pixel_format=1(kBGRR) */ xj_framebuffer_config *fbc = (xj_framebuffer_config *)to_virt(fbc_gpa); mem_zero(fbc, sizeof(*fbc)); fbc->frame_buffer = (u8 *)(XJ380_GUEST_FB_GPA + XJ380_HHDM_OFFSET); fbc->pixels_per_scan_line = XJ380_FB_WIDTH; fbc->horizontal_resolution = XJ380_FB_WIDTH; fbc->vertical_resolution = XJ380_FB_HEIGHT; fbc->pixel_format = 1; /* kBGRR */ return 0; } /* ===== Module finder ===== */ void *xj380_find_kernel_module(u64 *size_out) { if (!g_module_request.response) { log_error("[XJ380] no Limine module response"); panic_full("XJ3-E10 NO LIMINE MODULE RESPONSE", "limine did not return a boot module response", 0); return (void *)0; } struct limine_module_response *resp = g_module_request.response; for (u64 i = 0; i < resp->module_count; i++) { struct limine_file *file = resp->modules[i]; if (!file || !file->path) continue; /* 路径含 "xj380"(大小写不敏感) */ const char *p = file->path; int match = 0; for (const char *s = p; *s; s++) { if ((s[0] == 'x' || s[0] == 'X') && (s[1] == 'j' || s[1] == 'J') && (s[2] == '3' || s[2] == '3') && (s[3] == '8' || s[3] == '8') && (s[4] == '0' || s[4] == '0')) { match = 1; break; } } if (!match) continue; if (size_out) *size_out = file->size; log_info("[XJ380] found kernel module:"); log_info(file->path); log_hex64("[XJ380] module size=", file->size); return file->address; } log_warn("[XJ380] no kernel.krl module found"); return (void *)0; } /* ===== 主加载入口 ===== */ int xj380_loader_init(void) { log_info("[XJ380] loader init begin"); /* 1. 查找 kernel.krl 模块 */ u64 krl_size = 0; void *krl = xj380_find_kernel_module(&krl_size); if (!krl) { log_warn("[XJ380] no kernel.krl found, skipping XJ380 guest"); return -1; } /* 2. 解析 ELF */ u64 entry, span; if (xj380_parse_elf(krl, krl_size, &entry, &span) != 0) { log_error("[XJ380] kernel.krl parse failed"); panic_full("XJ3-E11 KRL PARSE FAILED", "xj380_parse_elf rejected the kernel.krl image", 0); return -2; } if (entry < XJ380_KERNEL_VADDR || entry >= XJ380_KERNEL_VADDR + span) { log_error("[XJ380] entry outside kernel window"); panic_full("XJ3-E12 ENTRY OUTSIDE KERNEL WINDOW", "kernel entry point lies outside the reserved kernel window", 0); return -3; } /* 3. 分配 boot area 缓冲(按页) */ dkm_dma_buffer pgt_buf, gdt_buf, madt_buf, fadt_buf, mcfg_buf, hpet_buf; dkm_dma_buffer memmap_buf, bootcfg_buf, mtrr_buf, stack_buf, fakeefi_buf, fbc_buf; if (dma_alloc_pages(8, 4096, 0, &pgt_buf) != 0) { log_error("[XJ380] alloc pgt failed"); panic_full("XJ3-E13 ALLOC PGT FAILED", "dma_alloc_pages failed for guest page tables", 0); return -4; } if (dma_alloc_pages(1, 4096, 0, &gdt_buf) != 0) { log_error("[XJ380] alloc gdt failed"); panic_full("XJ3-E14 ALLOC GDT FAILED", "dma_alloc_pages failed for the guest gdt page", 0); return -5; } if (dma_alloc_pages(1, 4096, 0, &madt_buf) != 0) { log_error("[XJ380] alloc madt failed"); panic_full("XJ3-E15 ALLOC MADT FAILED", "dma_alloc_pages failed for the madt stub", 0); return -6; } if (dma_alloc_pages(1, 4096, 0, &fadt_buf) != 0) { log_error("[XJ380] alloc fadt failed"); panic_full("XJ3-E16 ALLOC FADT FAILED", "dma_alloc_pages failed for the fadt stub", 0); return -7; } if (dma_alloc_pages(1, 4096, 0, &mcfg_buf) != 0) { log_error("[XJ380] alloc mcfg failed"); panic_full("XJ3-E17 ALLOC MCFG FAILED", "dma_alloc_pages failed for the mcfg stub", 0); return -8; } if (dma_alloc_pages(1, 4096, 0, &hpet_buf) != 0) { log_error("[XJ380] alloc hpet failed"); panic_full("XJ3-E18 ALLOC HPET FAILED", "dma_alloc_pages failed for the hpet stub", 0); return -9; } if (dma_alloc_pages(1, 4096, 0, &memmap_buf) != 0) { log_error("[XJ380] alloc memmap failed"); panic_full("XJ3-E19 ALLOC MEMMAP FAILED", "dma_alloc_pages failed for the efi memmap page", 0); return -10; } if (dma_alloc_pages(1, 4096, 0, &bootcfg_buf) != 0) { log_error("[XJ380] alloc bootcfg failed"); panic_full("XJ3-E20 ALLOC BOOTCFG FAILED", "dma_alloc_pages failed for the boot_config page", 0); return -11; } if (dma_alloc_pages(1, 4096, 0, &mtrr_buf) != 0) { log_error("[XJ380] alloc mtrr failed"); panic_full("XJ3-E21 ALLOC MTRR FAILED", "dma_alloc_pages failed for the mtrr buffer", 0); return -12; } if (dma_alloc_pages(2, 4096, 0, &stack_buf) != 0) { log_error("[XJ380] alloc stack failed"); panic_full("XJ3-E22 ALLOC STACK FAILED", "dma_alloc_pages failed for the guest boot stack", 0); return -13; } if (dma_alloc_pages(1, 4096, 0, &fakeefi_buf) != 0) { log_error("[XJ380] alloc fake efi failed"); panic_full("XJ3-E23 ALLOC FAKE EFI FAILED", "dma_alloc_pages failed for the fake efi table", 0); return -14; } if (dma_alloc_pages(1, 4096, 0, &fbc_buf) != 0) { log_error("[XJ380] alloc fbc failed"); panic_full("XJ3-E24 ALLOC FBC FAILED", "dma_alloc_pages failed for the framebuffer config page", 0); return -15; } /* 4. 分配内核缓冲并装入 PT_LOAD 段 */ u64 kernel_alloc = (span + 4095) & ~4095ULL; dkm_dma_buffer kernel_buf; if (dma_alloc_pages(kernel_alloc / 4096, 2 * 1024 * 1024, 0, &kernel_buf) != 0) { log_error("[XJ380] failed to alloc kernel memory"); panic_full("XJ3-E25 ALLOC KERNEL MEMORY FAILED", "dma_alloc_pages failed for the loaded kernel image", 0); return -16; } { const xj_elf64_ehdr *eh = (const xj_elf64_ehdr *)krl; const xj_elf64_phdr *ph = (const xj_elf64_phdr *)((const u8 *)krl + eh->e_phoff); u8 *dst = (u8 *)kernel_buf.virt; for (u16 i = 0; i < eh->e_phnum; i++) { if (ph[i].p_type != ELF_PT_LOAD) continue; u64 off = ph[i].p_vaddr - XJ380_KERNEL_VADDR; mem_copy(dst + off, (const u8 *)krl + ph[i].p_offset, ph[i].p_filesz); if (ph[i].p_memsz > ph[i].p_filesz) mem_zero(dst + off + ph[i].p_filesz, ph[i].p_memsz - ph[i].p_filesz); } log_hex64("[XJ380] kernel loaded HPA=", kernel_buf.phys); } /* 5. 分配 framebuffer 并清零 */ dkm_dma_buffer fb_buf; if (dma_alloc_pages((XJ380_FB_SIZE + 4095) / 4096, 4096, 0, &fb_buf) != 0) { log_error("[XJ380] failed to alloc framebuffer"); panic_full("XJ3-E26 ALLOC FRAMEBUFFER FAILED", "dma_alloc_pages failed for the guest framebuffer", 0); return -17; } { u8 *fb = (u8 *)fb_buf.virt; for (u64 i = 0; i < XJ380_FB_SIZE; i++) fb[i] = 0; } /* 6. 分配 guest RAM(1GB,降级 512MB/256MB) */ u64 ram_size = XJ380_GUEST_RAM_SIZE; dkm_dma_buffer ram_buf; if (dma_alloc_pages(ram_size / 4096, 2 * 1024 * 1024, 0, &ram_buf) != 0) { log_warn("[XJ380] failed to alloc guest RAM (1GB), trying 512MB"); ram_size = 512 * 1024 * 1024; if (dma_alloc_pages(ram_size / 4096, 2 * 1024 * 1024, 0, &ram_buf) != 0) { log_warn("[XJ380] failed to alloc guest RAM (512MB), trying 256MB"); ram_size = XJ380_GUEST_RAM_MIN; if (dma_alloc_pages(ram_size / 4096, 2 * 1024 * 1024, 0, &ram_buf) != 0) { log_error("[XJ380] failed to alloc guest RAM (256MB minimum)"); panic_full("XJ3-E27 ALLOC GUEST RAM MINIMUM FAILED", "dma_alloc_pages failed even for the 256mb guest ram floor", 0); return -18; } } } log_hex64("[XJ380] guest RAM HPA=", ram_buf.phys); log_hex64("[XJ380] guest RAM size=", ram_size); /* 7. 记录 guest 信息 */ g_guest.pgt_gpa = XJ380_PGT_GPA; g_guest.gdt_gpa = XJ380_GDT_GPA; g_guest.kernel_gpa = XJ380_GUEST_KERNEL_GPA; g_guest.kernel_entry = entry; g_guest.kernel_size = span; g_guest.ram_gpa = XJ380_GUEST_RAM_GPA; g_guest.ram_size = ram_size; g_guest.fb_gpa = XJ380_GUEST_FB_GPA; /* 8. 构造 guest 页表 / GDT */ xj380_build_page_tables(pgt_buf.phys, g_guest.kernel_gpa, span); xj380_build_gdt(gdt_buf.phys); log_hex64("[XJ380] page tables HPA=", pgt_buf.phys); log_hex64("[XJ380] GDT HPA=", gdt_buf.phys); /* 9. 构造 ACPI 桩表 */ xj380_build_madt(madt_buf.phys); xj380_build_fadt(fadt_buf.phys); xj380_build_mcfg(mcfg_buf.phys); xj380_build_hpet(hpet_buf.phys); /* 10. 构造内存图 + BOOT_CONFIG(含 MTRR 缓冲清零、伪 EFI 表清零) */ xj380_build_memmap(memmap_buf.phys); mem_zero(mtrr_buf.virt, 4096); mem_zero(fakeefi_buf.virt, 4096); xj380_build_boot_config(bootcfg_buf.phys, mtrr_buf.phys, XJ380_STACK_GPA, fbc_buf.phys); /* 11. EPT 映射所有 guest 区域。 * boot area 各缓冲独立分配,逐个按自身 GPA 映射。 */ if (ept_map_range(XJ380_PGT_GPA, pgt_buf.phys, XJ380_PGT_SIZE, EPT_READ | EPT_WRITE) != 0) { log_error("[XJ380] EPT map page tables failed"); panic_full("XJ3-E28 EPT MAP PAGE TABLES FAILED", "ept_map_range failed for guest page tables", 0); return -19; } if (ept_map_range(XJ380_GDT_GPA, gdt_buf.phys, 4096, EPT_READ | EPT_WRITE) != 0) { log_error("[XJ380] EPT map GDT failed"); panic_full("XJ3-E29 EPT MAP GDT FAILED", "ept_map_range failed for the guest gdt", 0); return -20; } if (ept_map_range(XJ380_MADT_GPA, madt_buf.phys, 4096, EPT_READ | EPT_WRITE) != 0) { log_error("[XJ380] EPT map MADT failed"); panic_full("XJ3-E30 EPT MAP MADT FAILED", "ept_map_range failed for the madt stub", 0); return -21; } if (ept_map_range(XJ380_FADT_GPA, fadt_buf.phys, 4096, EPT_READ | EPT_WRITE) != 0) { log_error("[XJ380] EPT map FADT failed"); panic_full("XJ3-E31 EPT MAP FADT FAILED", "ept_map_range failed for the fadt stub", 0); return -22; } if (ept_map_range(XJ380_MCFG_GPA, mcfg_buf.phys, 4096, EPT_READ | EPT_WRITE) != 0) { log_error("[XJ380] EPT map MCFG failed"); panic_full("XJ3-E32 EPT MAP MCFG FAILED", "ept_map_range failed for the mcfg stub", 0); return -23; } if (ept_map_range(XJ380_HPET_GPA, hpet_buf.phys, 4096, EPT_READ | EPT_WRITE) != 0) { log_error("[XJ380] EPT map HPET failed"); panic_full("XJ3-E33 EPT MAP HPET FAILED", "ept_map_range failed for the hpet stub", 0); return -24; } if (ept_map_range(XJ380_MEMMAP_GPA, memmap_buf.phys, 4096, EPT_READ | EPT_WRITE) != 0) { log_error("[XJ380] EPT map memory map failed"); panic_full("XJ3-E34 EPT MAP MEMMAP FAILED", "ept_map_range failed for the efi memmap", 0); return -25; } if (ept_map_range(XJ380_BOOTCFG_GPA, bootcfg_buf.phys, 4096, EPT_READ | EPT_WRITE) != 0) { log_error("[XJ380] EPT map BOOT_CONFIG failed"); panic_full("XJ3-E35 EPT MAP BOOT CONFIG FAILED", "ept_map_range failed for the boot_config page", 0); return -26; } if (ept_map_range(XJ380_MTRR_GPA, mtrr_buf.phys, 4096, EPT_READ | EPT_WRITE) != 0) { log_error("[XJ380] EPT map MTRR buffer failed"); panic_full("XJ3-E36 EPT MAP MTRR BUFFER FAILED", "ept_map_range failed for the mtrr buffer", 0); return -27; } if (ept_map_range(XJ380_STACK_GPA, stack_buf.phys, 8192, EPT_READ | EPT_WRITE) != 0) { log_error("[XJ380] EPT map stack failed"); panic_full("XJ3-E37 EPT MAP STACK FAILED", "ept_map_range failed for the guest boot stack", 0); return -28; } if (ept_map_range(XJ380_FAKEEFI_GPA, fakeefi_buf.phys, 4096, EPT_READ | EPT_WRITE) != 0) { log_error("[XJ380] EPT map fake EFI table failed"); panic_full("XJ3-E38 EPT MAP FAKE EFI FAILED", "ept_map_range failed for the fake efi table", 0); return -29; } if (ept_map_range(XJ380_FBC_GPA, fbc_buf.phys, 4096, EPT_READ | EPT_WRITE) != 0) { log_error("[XJ380] EPT map FrameBufferConfig failed"); panic_full("XJ3-E39 EPT MAP FRAMEBUFFER CONFIG FAILED", "ept_map_range failed for the framebuffer config page", 0); return -30; } if (ept_map_range(g_guest.fb_gpa, fb_buf.phys, XJ380_FB_SIZE, EPT_READ | EPT_WRITE) != 0) { log_error("[XJ380] EPT map framebuffer failed"); panic_full("XJ3-E40 EPT MAP FRAMEBUFFER FAILED", "ept_map_range failed for the guest framebuffer", 0); return -31; } if (ept_map_range(g_guest.kernel_gpa, kernel_buf.phys, kernel_alloc, EPT_RWX) != 0) { log_error("[XJ380] EPT map kernel failed"); panic_full("XJ3-E41 EPT MAP KERNEL FAILED", "ept_map_range failed for the loaded kernel image", 0); return -32; } if (ept_map_range(g_guest.ram_gpa, ram_buf.phys, ram_size, EPT_RWX) != 0) { log_error("[XJ380] EPT map guest RAM failed"); panic_full("XJ3-E42 EPT MAP GUEST RAM FAILED", "ept_map_range failed for guest ram", 0); return -33; } /* 低 1MB 恒等映射(BIOS 区,与 linux_loader 一致;<1MB 无需按需分配) */ if (ept_identity_map(0, 0x100000, EPT_RWX) != 0) { log_warn("[XJ380] EPT identity map first 1MB failed (non-critical)"); } /* 12. 完成 */ g_guest.loaded = 1; log_hex64("[XJ380] kernel GPA=", g_guest.kernel_gpa); log_hex64("[XJ380] kernel entry=", g_guest.kernel_entry); log_hex64("[XJ380] kernel size=", g_guest.kernel_size); log_hex64("[XJ380] RAM GPA=", g_guest.ram_gpa); log_hex64("[XJ380] RAM size=", g_guest.ram_size); log_info("[XJ380] loader init ok"); return 0; } const struct xj380_guest_info *xj380_get_guest_info(void) { return g_guest.loaded ? &g_guest : (struct xj380_guest_info *)0; }