load linux kernel from UEFI

This commit is contained in:
Masato Imai
2025-08-10 13:23:50 +00:00
parent c1e555304c
commit 46e5da346d
8 changed files with 82 additions and 38 deletions

View File

@ -6,12 +6,14 @@ cd ../nel_os_kernel
cargo build --release -q cargo build --release -q
cd ../nel_os_bootloader cd ../nel_os_bootloader
dd if=/dev/zero of=fat.img bs=1k count=1440 dd if=/dev/zero of=fat.img bs=1k count=32768
mformat -i fat.img -f 1440 :: mformat -i fat.img -C -h 16 -t 128 -s 32 ::
mmd -i fat.img ::/EFI mmd -i fat.img ::/EFI
mmd -i fat.img ::/EFI/BOOT mmd -i fat.img ::/EFI/BOOT
mcopy -i fat.img "$EFI_BINARY" ::/EFI/BOOT/BOOTX64.EFI mcopy -i fat.img "$EFI_BINARY" ::/EFI/BOOT/BOOTX64.EFI
mcopy -i fat.img ../nel_os_kernel/target/x86_64-nel_os/release/nel_os_kernel.elf ::/nel_os_kernel.elf mcopy -i fat.img ../nel_os_kernel/target/x86_64-nel_os/release/nel_os_kernel.elf ::/nel_os_kernel.elf
mcopy -i fat.img bzImage ::/bzImage
mcopy -i fat.img rootfs-n.cpio.gz ::/rootfs-n.cpio.gz
mkdir iso mkdir iso
cp fat.img iso cp fat.img iso

View File

@ -42,25 +42,53 @@ fn get_fs() -> Directory {
fs.open_volume().unwrap() fs.open_volume().unwrap()
} }
fn read_kernel(name: &CStr16) -> Box<[u8]> { fn read_file(name: &CStr16) -> Box<[u8]> {
let mut root = get_fs(); let mut root = get_fs();
let kernel_file_info = root let file_info = root
.open(name, FileMode::Read, FileAttribute::empty()) .open(name, FileMode::Read, FileAttribute::empty())
.unwrap(); .unwrap();
let mut kernel_file = kernel_file_info.into_regular_file().unwrap(); let mut file = file_info.into_regular_file().unwrap();
let file_size = kernel_file let file_size = file.get_boxed_info::<FileInfo>().unwrap().file_size();
.get_boxed_info::<FileInfo>()
.unwrap()
.file_size();
let mut buf = vec![0; file_size as usize]; let mut buf = vec![0; file_size as usize];
let read_size = kernel_file.read(&mut buf).unwrap(); let read_size = file.read(&mut buf).unwrap();
println!("kernel size: {}", read_size); println!("file {} size: {}", name, read_size);
buf.into_boxed_slice() buf.into_boxed_slice()
} }
fn load_file_to_laoder_data(name: &CStr16) -> (u64, u64) {
let mut root = get_fs();
let file_info = root
.open(name, FileMode::Read, FileAttribute::empty())
.expect("Failed to open file");
let mut file = file_info
.into_regular_file()
.expect("Failed to convert to regular file");
let file_size = file
.get_boxed_info::<FileInfo>()
.expect("Failed to get file info")
.file_size();
let page_ptr = unsafe {
uefi::boot::allocate_pages(
AllocateType::AnyPages,
MemoryType::LOADER_DATA,
file_size.div_ceil(4096) as usize,
)
.expect("Failed to allocate pages")
.as_mut()
};
let buf = unsafe { slice::from_raw_parts_mut(page_ptr, file_size as usize) };
let read_size = file.read(buf).expect("Failed to read file");
println!("file {} size: {}", name, read_size);
(page_ptr as *mut u8 as u64, file_size)
}
fn load_elf(bin: Box<[u8]>) -> u64 { fn load_elf(bin: Box<[u8]>) -> u64 {
let elf = elf::Elf::parse(&bin).expect("Failed to parse elf"); let elf = elf::Elf::parse(&bin).expect("Failed to parse elf");
let mut dest_start = u64::MAX; let mut dest_start = u64::MAX;
@ -143,7 +171,10 @@ fn main() -> Status {
println!("{} v{}", env!("CARGO_PKG_NAME"), env!("CARGO_PKG_VERSION")); println!("{} v{}", env!("CARGO_PKG_NAME"), env!("CARGO_PKG_VERSION"));
let kernel = read_kernel(cstr16!("nel_os_kernel.elf")); let kernel = read_file(cstr16!("nel_os_kernel.elf"));
let (bzimage_addr, bzimage_size) = load_file_to_laoder_data(cstr16!("bzImage"));
let (rootfs_addr, rootfs_size) = load_file_to_laoder_data(cstr16!("rootfs-n.cpio.gz"));
let entry_point = load_elf(kernel); let entry_point = load_elf(kernel);
@ -195,6 +226,10 @@ fn main() -> Status {
usable_memory, usable_memory,
frame_buffer, frame_buffer,
rsdp, rsdp,
bzimage_addr,
bzimage_size,
rootfs_addr,
rootfs_size,
}); });
hlt_loop(); hlt_loop();

View File

@ -9,4 +9,8 @@ pub struct BootInfo {
pub usable_memory: UsableMemory, pub usable_memory: UsableMemory,
pub frame_buffer: FrameBuffer, pub frame_buffer: FrameBuffer,
pub rsdp: u64, pub rsdp: u64,
pub bzimage_addr: u64,
pub bzimage_size: u64,
pub rootfs_addr: u64,
pub rootfs_size: u64,
} }

View File

@ -22,6 +22,7 @@ use core::panic::PanicInfo;
use core::ptr::addr_of; use core::ptr::addr_of;
use ::acpi::AcpiTables; use ::acpi::AcpiTables;
use spin::Once;
use x86_64::{registers::control::Cr3, structures::paging::OffsetPageTable, VirtAddr}; use x86_64::{registers::control::Cr3, structures::paging::OffsetPageTable, VirtAddr};
use crate::{ use crate::{
@ -32,6 +33,11 @@ use crate::{
memory::{allocator, memory::BitmapMemoryTable, paging}, memory::{allocator, memory::BitmapMemoryTable, paging},
}; };
pub static BZIMAGE_ADDR: Once<u64> = Once::new();
pub static BZIMAGE_SIZE: Once<u64> = Once::new();
pub static ROOTFS_ADDR: Once<u64> = Once::new();
pub static ROOTFS_SIZE: Once<u64> = Once::new();
#[repr(C, align(16))] #[repr(C, align(16))]
struct AlignedStack { struct AlignedStack {
stack: [u8; KERNEL_STACK_SIZE], stack: [u8; KERNEL_STACK_SIZE],
@ -159,7 +165,14 @@ pub extern "sysv64" fn main(boot_info: &nel_os_common::BootInfo) {
serial::disable_screen_output(); serial::disable_screen_output();
BZIMAGE_ADDR.call_once(|| boot_info.bzimage_addr);
BZIMAGE_SIZE.call_once(|| boot_info.bzimage_size);
ROOTFS_ADDR.call_once(|| boot_info.rootfs_addr);
ROOTFS_SIZE.call_once(|| boot_info.rootfs_size);
let mut vcpu = vmm::get_vcpu(&mut bitmap_table).unwrap(); let mut vcpu = vmm::get_vcpu(&mut bitmap_table).unwrap();
info!("Running guest VM...");
loop { loop {
let result = vcpu.run(&mut bitmap_table); let result = vcpu.run(&mut bitmap_table);
if let Err(e) = result { if let Err(e) = result {

View File

@ -1,12 +1,16 @@
use core::ptr::read_unaligned; use core::ptr::read_unaligned;
use crate::vmm::VCpu; use crate::{vmm::VCpu, BZIMAGE_ADDR, BZIMAGE_SIZE};
pub fn load_kernel(vcpu: &mut dyn VCpu) -> Result<(), &'static str> { pub fn load_kernel(vcpu: &mut dyn VCpu) -> Result<(), &'static str> {
let kernel = BZIMAGE; let kernel_addr = BZIMAGE_ADDR.get().unwrap();
let kernel_size = BZIMAGE_SIZE.get().unwrap();
let kernel =
unsafe { core::slice::from_raw_parts(*kernel_addr as *const u8, *kernel_size as usize) };
let guest_mem_size = vcpu.get_guest_memory_size(); let guest_mem_size = vcpu.get_guest_memory_size();
let mut bp = BootParams::from_bytes(kernel).unwrap(); let mut bp = BootParams::from_bytes(kernel)?;
bp.e820_entries = 0; bp.e820_entries = 0;
bp.hdr.type_of_loader = 0xFF; bp.hdr.type_of_loader = 0xFF;
@ -68,9 +72,6 @@ fn load_image(vcpu: &mut dyn VCpu, image: &[u8], addr: usize) -> Result<(), &'st
Ok(()) Ok(())
} }
pub const BZIMAGE: &[u8] = include_bytes!("../../../../bzImage");
pub const INITRD: &[u8] = include_bytes!("../../../../rootfs-n.cpio.gz");
pub const LAYOUT_BOOTPARAM: u64 = 0x0001_0000; pub const LAYOUT_BOOTPARAM: u64 = 0x0001_0000;
pub const LAYOUT_CMDLINE: u64 = 0x0002_0000; pub const LAYOUT_CMDLINE: u64 = 0x0002_0000;
pub const LAYOUT_KERNEL_BASE: u64 = 0x0010_0000; pub const LAYOUT_KERNEL_BASE: u64 = 0x0010_0000;
@ -209,7 +210,7 @@ impl SetupHeader {
pub fn from_bytes(bytes: &[u8]) -> Result<Self, &'static str> { pub fn from_bytes(bytes: &[u8]) -> Result<Self, &'static str> {
if bytes.len() < Self::HEADER_OFFSET + size_of::<Self>() { if bytes.len() < Self::HEADER_OFFSET + size_of::<Self>() {
return Err("バイト配列が小さすぎます"); return Err("Binary data is too short to contain a valid SetupHeader");
} }
let mut hdr = unsafe { let mut hdr = unsafe {
@ -335,7 +336,7 @@ impl E820Entry {
3 => Ok(E820Type::Acpi), 3 => Ok(E820Type::Acpi),
4 => Ok(E820Type::Nvs), 4 => Ok(E820Type::Nvs),
5 => Ok(E820Type::Unusable), 5 => Ok(E820Type::Unusable),
_ => Err("不明なE820タイプ"), _ => Err("Invalid E820 type"),
} }
} }

View File

@ -124,10 +124,12 @@ impl IntelVCpu {
controls::setup_entry_controls()?; controls::setup_entry_controls()?;
controls::setup_exit_controls()?; controls::setup_exit_controls()?;
Self::setup_host_state()?; Self::setup_host_state()?;
Self::setup_guest_state()?; self.setup_guest_state()?;
self.init_guest_memory(frame_allocator)?; self.init_guest_memory(frame_allocator)?;
common::linux::load_kernel(self)?;
Ok(()) Ok(())
} }
@ -135,7 +137,7 @@ impl IntelVCpu {
&mut self, &mut self,
frame_allocator: &mut dyn FrameAllocator<Size4KiB>, frame_allocator: &mut dyn FrameAllocator<Size4KiB>,
) -> Result<(), &'static str> { ) -> Result<(), &'static str> {
let mut pages = 1000; let mut pages = self.guest_memory_size / 0x1000;
let mut gpa = 0; let mut gpa = 0;
while pages > 0 { while pages > 0 {
@ -147,22 +149,9 @@ impl IntelVCpu {
pages -= 1; pages -= 1;
} }
let guest_ptr = Self::test_guest_code as u64;
let guest_addr = self.ept.get_phys_addr(0).unwrap();
unsafe {
core::ptr::copy_nonoverlapping(guest_ptr as *const u8, guest_addr as *mut u8, 200);
}
let eptp = ept::EPTP::init(&self.ept.root_table); let eptp = ept::EPTP::init(&self.ept.root_table);
vmwrite(x86::vmx::vmcs::control::EPTP_FULL, u64::from(eptp))?; vmwrite(x86::vmx::vmcs::control::EPTP_FULL, u64::from(eptp))?;
info!(
"GPA 0x0 -> HPA {:#x}",
self.ept
.get_phys_addr(0)
.ok_or("Failed to get physical address")?
);
Ok(()) Ok(())
} }
@ -213,7 +202,7 @@ impl IntelVCpu {
Ok(()) Ok(())
} }
fn setup_guest_state() -> Result<(), &'static str> { fn setup_guest_state(&mut self) -> Result<(), &'static str> {
use x86::{controlregs::*, vmx::vmcs}; use x86::{controlregs::*, vmx::vmcs};
let cr0 = Cr0::empty() let cr0 = Cr0::empty()
| Cr0::CR0_PROTECTED_MODE | Cr0::CR0_PROTECTED_MODE
@ -316,8 +305,8 @@ impl IntelVCpu {
vmwrite(vmcs::guest::RFLAGS, 0x2)?; vmwrite(vmcs::guest::RFLAGS, 0x2)?;
vmwrite(vmcs::guest::LINK_PTR_FULL, u64::MAX)?; vmwrite(vmcs::guest::LINK_PTR_FULL, u64::MAX)?;
vmwrite(vmcs::guest::RIP, 0)?; // TODO: Set linux kernel base vmwrite(vmcs::guest::RIP, common::linux::LAYOUT_KERNEL_BASE as u64)?;
// TODO: RSI self.guest_registers.rsi = common::linux::LAYOUT_BOOTPARAM as u64;
//vmwrite(vmcs::control::CR0_READ_SHADOW, vmread(vmcs::guest::CR0)?)?; //vmwrite(vmcs::control::CR0_READ_SHADOW, vmread(vmcs::guest::CR0)?)?;
//vmwrite(vmcs::control::CR4_READ_SHADOW, vmread(vmcs::guest::CR4)?)?; //vmwrite(vmcs::control::CR4_READ_SHADOW, vmread(vmcs::guest::CR4)?)?;