Files
Deshab-OS/CODE/UTSM/vmm/xj380_loader.c
T
2026-08-09 22:20:01 +08:00

713 lines
26 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/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");
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");
return -2;
}
if (eh->e_ident[4] != 2) { /* ELFCLASS64 */
log_error("[XJ380] not a 64-bit ELF");
return -3;
}
if (eh->e_type != ELF_ET_EXEC) {
log_error("[XJ380] kernel.krl not ET_EXEC");
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");
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);
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)");
return -7;
}
if (ph[i].p_offset + ph[i].p_filesz > size) {
log_error("[XJ380] PT_LOAD filesz beyond image");
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");
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");
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");
return -2;
}
if (entry < XJ380_KERNEL_VADDR || entry >= XJ380_KERNEL_VADDR + span) {
log_error("[XJ380] entry outside kernel window");
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"); return -4; }
if (dma_alloc_pages(1, 4096, 0, &gdt_buf) != 0) { log_error("[XJ380] alloc gdt failed"); return -5; }
if (dma_alloc_pages(1, 4096, 0, &madt_buf) != 0) { log_error("[XJ380] alloc madt failed"); return -6; }
if (dma_alloc_pages(1, 4096, 0, &fadt_buf) != 0) { log_error("[XJ380] alloc fadt failed"); return -7; }
if (dma_alloc_pages(1, 4096, 0, &mcfg_buf) != 0) { log_error("[XJ380] alloc mcfg failed"); return -8; }
if (dma_alloc_pages(1, 4096, 0, &hpet_buf) != 0) { log_error("[XJ380] alloc hpet failed"); return -9; }
if (dma_alloc_pages(1, 4096, 0, &memmap_buf) != 0) { log_error("[XJ380] alloc memmap failed"); return -10; }
if (dma_alloc_pages(1, 4096, 0, &bootcfg_buf) != 0) { log_error("[XJ380] alloc bootcfg failed"); return -11; }
if (dma_alloc_pages(1, 4096, 0, &mtrr_buf) != 0) { log_error("[XJ380] alloc mtrr failed"); return -12; }
if (dma_alloc_pages(2, 4096, 0, &stack_buf) != 0) { log_error("[XJ380] alloc stack failed"); return -13; }
if (dma_alloc_pages(1, 4096, 0, &fakeefi_buf) != 0) { log_error("[XJ380] alloc fake efi failed"); return -14; }
if (dma_alloc_pages(1, 4096, 0, &fbc_buf) != 0) { log_error("[XJ380] alloc fbc failed"); 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");
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");
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)");
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");
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");
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");
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");
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");
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");
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");
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");
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");
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");
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");
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");
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");
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");
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");
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;
}