load linux kernel from UEFI
This commit is contained in:
@ -6,12 +6,14 @@ cd ../nel_os_kernel
|
||||
cargo build --release -q
|
||||
cd ../nel_os_bootloader
|
||||
|
||||
dd if=/dev/zero of=fat.img bs=1k count=1440
|
||||
mformat -i fat.img -f 1440 ::
|
||||
dd if=/dev/zero of=fat.img bs=1k count=32768
|
||||
mformat -i fat.img -C -h 16 -t 128 -s 32 ::
|
||||
mmd -i fat.img ::/EFI
|
||||
mmd -i fat.img ::/EFI/BOOT
|
||||
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 bzImage ::/bzImage
|
||||
mcopy -i fat.img rootfs-n.cpio.gz ::/rootfs-n.cpio.gz
|
||||
|
||||
mkdir iso
|
||||
cp fat.img iso
|
||||
|
@ -42,25 +42,53 @@ fn get_fs() -> Directory {
|
||||
fs.open_volume().unwrap()
|
||||
}
|
||||
|
||||
fn read_kernel(name: &CStr16) -> Box<[u8]> {
|
||||
fn read_file(name: &CStr16) -> Box<[u8]> {
|
||||
let mut root = get_fs();
|
||||
let kernel_file_info = root
|
||||
let file_info = root
|
||||
.open(name, FileMode::Read, FileAttribute::empty())
|
||||
.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
|
||||
.get_boxed_info::<FileInfo>()
|
||||
.unwrap()
|
||||
.file_size();
|
||||
let file_size = file.get_boxed_info::<FileInfo>().unwrap().file_size();
|
||||
let mut buf = vec![0; file_size as usize];
|
||||
|
||||
let read_size = kernel_file.read(&mut buf).unwrap();
|
||||
println!("kernel size: {}", read_size);
|
||||
let read_size = file.read(&mut buf).unwrap();
|
||||
println!("file {} size: {}", name, read_size);
|
||||
|
||||
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 {
|
||||
let elf = elf::Elf::parse(&bin).expect("Failed to parse elf");
|
||||
let mut dest_start = u64::MAX;
|
||||
@ -143,7 +171,10 @@ fn main() -> Status {
|
||||
|
||||
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);
|
||||
|
||||
@ -195,6 +226,10 @@ fn main() -> Status {
|
||||
usable_memory,
|
||||
frame_buffer,
|
||||
rsdp,
|
||||
bzimage_addr,
|
||||
bzimage_size,
|
||||
rootfs_addr,
|
||||
rootfs_size,
|
||||
});
|
||||
|
||||
hlt_loop();
|
||||
|
@ -9,4 +9,8 @@ pub struct BootInfo {
|
||||
pub usable_memory: UsableMemory,
|
||||
pub frame_buffer: FrameBuffer,
|
||||
pub rsdp: u64,
|
||||
pub bzimage_addr: u64,
|
||||
pub bzimage_size: u64,
|
||||
pub rootfs_addr: u64,
|
||||
pub rootfs_size: u64,
|
||||
}
|
||||
|
@ -22,6 +22,7 @@ use core::panic::PanicInfo;
|
||||
use core::ptr::addr_of;
|
||||
|
||||
use ::acpi::AcpiTables;
|
||||
use spin::Once;
|
||||
use x86_64::{registers::control::Cr3, structures::paging::OffsetPageTable, VirtAddr};
|
||||
|
||||
use crate::{
|
||||
@ -32,6 +33,11 @@ use crate::{
|
||||
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))]
|
||||
struct AlignedStack {
|
||||
stack: [u8; KERNEL_STACK_SIZE],
|
||||
@ -159,7 +165,14 @@ pub extern "sysv64" fn main(boot_info: &nel_os_common::BootInfo) {
|
||||
|
||||
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();
|
||||
|
||||
info!("Running guest VM...");
|
||||
loop {
|
||||
let result = vcpu.run(&mut bitmap_table);
|
||||
if let Err(e) = result {
|
||||
|
@ -1,12 +1,16 @@
|
||||
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> {
|
||||
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 mut bp = BootParams::from_bytes(kernel).unwrap();
|
||||
let mut bp = BootParams::from_bytes(kernel)?;
|
||||
bp.e820_entries = 0;
|
||||
|
||||
bp.hdr.type_of_loader = 0xFF;
|
||||
@ -68,9 +72,6 @@ fn load_image(vcpu: &mut dyn VCpu, image: &[u8], addr: usize) -> Result<(), &'st
|
||||
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_CMDLINE: u64 = 0x0002_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> {
|
||||
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 {
|
||||
@ -335,7 +336,7 @@ impl E820Entry {
|
||||
3 => Ok(E820Type::Acpi),
|
||||
4 => Ok(E820Type::Nvs),
|
||||
5 => Ok(E820Type::Unusable),
|
||||
_ => Err("不明なE820タイプ"),
|
||||
_ => Err("Invalid E820 type"),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -124,10 +124,12 @@ impl IntelVCpu {
|
||||
controls::setup_entry_controls()?;
|
||||
controls::setup_exit_controls()?;
|
||||
Self::setup_host_state()?;
|
||||
Self::setup_guest_state()?;
|
||||
self.setup_guest_state()?;
|
||||
|
||||
self.init_guest_memory(frame_allocator)?;
|
||||
|
||||
common::linux::load_kernel(self)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@ -135,7 +137,7 @@ impl IntelVCpu {
|
||||
&mut self,
|
||||
frame_allocator: &mut dyn FrameAllocator<Size4KiB>,
|
||||
) -> Result<(), &'static str> {
|
||||
let mut pages = 1000;
|
||||
let mut pages = self.guest_memory_size / 0x1000;
|
||||
let mut gpa = 0;
|
||||
|
||||
while pages > 0 {
|
||||
@ -147,22 +149,9 @@ impl IntelVCpu {
|
||||
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);
|
||||
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(())
|
||||
}
|
||||
|
||||
@ -213,7 +202,7 @@ impl IntelVCpu {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn setup_guest_state() -> Result<(), &'static str> {
|
||||
fn setup_guest_state(&mut self) -> Result<(), &'static str> {
|
||||
use x86::{controlregs::*, vmx::vmcs};
|
||||
let cr0 = Cr0::empty()
|
||||
| Cr0::CR0_PROTECTED_MODE
|
||||
@ -316,8 +305,8 @@ impl IntelVCpu {
|
||||
vmwrite(vmcs::guest::RFLAGS, 0x2)?;
|
||||
vmwrite(vmcs::guest::LINK_PTR_FULL, u64::MAX)?;
|
||||
|
||||
vmwrite(vmcs::guest::RIP, 0)?; // TODO: Set linux kernel base
|
||||
// TODO: RSI
|
||||
vmwrite(vmcs::guest::RIP, common::linux::LAYOUT_KERNEL_BASE as u64)?;
|
||||
self.guest_registers.rsi = common::linux::LAYOUT_BOOTPARAM as u64;
|
||||
|
||||
//vmwrite(vmcs::control::CR0_READ_SHADOW, vmread(vmcs::guest::CR0)?)?;
|
||||
//vmwrite(vmcs::control::CR4_READ_SHADOW, vmread(vmcs::guest::CR4)?)?;
|
||||
|
Reference in New Issue
Block a user