Files
Deshab-OS/CODE/UTSM/vmm/xj380_loader.c
T
Linehu 174af71b39 feat: exhaustive STUB instrumentation - 241 panic sites across VMM/kernel + whitelist alignment
- VMM cluster: XJ3-E/LIN-E/VMM-E/VMX-E/EPT-E/IPC-E/VVB-E (124 sites)

- kernel cluster: TST-E/MM-E/UTRW-E/LAPIC-E/IDT-E/SAS-E/PRB-E/NETST-E/DKM-E (117 sites)

- whitelist fixes: vmm_init env probes E10-E14 fallback, disk_log read-only block path, DSL-E05 non-FAT32 device 0 probe

- QEMU smoke: wizard -> USER.CONF -> login -> desktop ready, zero spurious panic
2026-10-03 21:26:04 +08:00

744 lines
31 KiB
C
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/* 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 <utsm/xj380_loader.h>
#include <utsm/panic.h>
#include <utsm/vmx.h>
#include <utsm/ept.h>
#include <utsm/log.h>
#include <utsm/types.h>
#include <utsm/dma.h>
#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;
}