1 //! x86/HVM启动 2 //! 3 //! 初始化代码可参考:https://code.dragonos.org.cn/xref/linux-6.6.21/arch/x86/platform/pvh/enlighten.c#45 4 use alloc::string::{String, ToString}; 5 use core::{ffi::CStr, hint::spin_loop}; 6 use param::{E820Type, HvmMemmapTableEntry, HvmStartInfo}; 7 use system_error::SystemError; 8 9 use crate::{ 10 arch::MMArch, 11 driver::{ 12 serial::serial8250::send_to_default_serial8250_port, video::fbdev::base::BootTimeScreenInfo, 13 }, 14 init::{ 15 boot::{register_boot_callbacks, BootCallbacks, BootloaderAcpiArg}, 16 boot_params, 17 }, 18 libs::lazy_init::Lazy, 19 mm::{memblock::mem_block_manager, MemoryManagementArch, PhysAddr}, 20 }; 21 22 mod param; 23 24 static START_INFO: Lazy<HvmStartInfo> = Lazy::new(); 25 26 struct PvhBootCallback; 27 28 impl BootCallbacks for PvhBootCallback { 29 fn init_bootloader_name(&self) -> Result<Option<String>, SystemError> { 30 return Ok(Some("x86 PVH".to_string())); 31 } 32 33 fn init_acpi_args(&self) -> Result<BootloaderAcpiArg, SystemError> { 34 let rsdp_paddr = PhysAddr::new(START_INFO.get().rsdp_paddr as usize); 35 if rsdp_paddr.data() != 0 { 36 Ok(BootloaderAcpiArg::Rsdp(rsdp_paddr)) 37 } else { 38 Ok(BootloaderAcpiArg::NotProvided) 39 } 40 } 41 42 fn init_kernel_cmdline(&self) -> Result<(), SystemError> { 43 let cmdline_c_str: &CStr = unsafe { 44 CStr::from_ptr( 45 MMArch::phys_2_virt(PhysAddr::new(START_INFO.get().cmdline_paddr as usize)) 46 .unwrap() 47 .data() as *const i8, 48 ) 49 }; 50 let cmdline = cmdline_c_str.to_str().unwrap(); 51 boot_params() 52 .write_irqsave() 53 .boot_cmdline_append(cmdline.as_bytes()); 54 log::info!("pvh boot cmdline: {:?}", cmdline_c_str); 55 Ok(()) 56 } 57 58 fn early_init_framebuffer_info( 59 &self, 60 _scinfo: &mut BootTimeScreenInfo, 61 ) -> Result<(), SystemError> { 62 return Err(SystemError::ENODEV); 63 } 64 65 fn early_init_memory_blocks(&self) -> Result<(), SystemError> { 66 let start_info = START_INFO.get(); 67 let mut total_mem_size = 0usize; 68 let mut usable_mem_size = 0usize; 69 send_to_default_serial8250_port("init_memory_area by pvh boot\n\0".as_bytes()); 70 71 if (start_info.version > 0) && start_info.memmap_entries > 0 { 72 let mut ep = unsafe { 73 MMArch::phys_2_virt(PhysAddr::new(start_info.memmap_paddr as usize)).unwrap() 74 } 75 .data() as *const HvmMemmapTableEntry; 76 77 for _ in 0..start_info.memmap_entries { 78 let entry = unsafe { *ep }; 79 let start = PhysAddr::new(entry.addr as usize); 80 let size = entry.size as usize; 81 let typ = E820Type::from(entry.type_); 82 83 total_mem_size += size; 84 match typ { 85 param::E820Type::Ram => { 86 usable_mem_size += size; 87 mem_block_manager() 88 .add_block(start, size) 89 .unwrap_or_else(|e| { 90 log::warn!( 91 "Failed to add memory block: base={:?}, size={:#x}, error={:?}", 92 start, 93 size, 94 e 95 ); 96 }); 97 } 98 _ => { 99 mem_block_manager() 100 .reserve_block(start, size) 101 .unwrap_or_else(|e| { 102 log::warn!( 103 "Failed to reserve memory block: base={:?}, size={:#x}, error={:?}", 104 start, 105 size, 106 e 107 ); 108 }); 109 } 110 } 111 ep = unsafe { ep.add(1) }; 112 } 113 } 114 send_to_default_serial8250_port("init_memory_area_from pvh boot end\n\0".as_bytes()); 115 log::info!( 116 "Total memory size: {:#x}, Usable memory size: {:#x}", 117 total_mem_size, 118 usable_mem_size 119 ); 120 Ok(()) 121 } 122 } 123 124 #[inline(never)] 125 pub(super) fn early_linux32_pvh_init(params_ptr: usize) -> Result<(), SystemError> { 126 let start_info = unsafe { *(params_ptr as *const HvmStartInfo) }; 127 if start_info.magic != HvmStartInfo::XEN_HVM_START_MAGIC_VALUE { 128 send_to_default_serial8250_port( 129 "early_linux32_pvh_init failed: Magic number not matched.\n\0".as_bytes(), 130 ); 131 132 loop { 133 spin_loop(); 134 } 135 } 136 137 START_INFO.init(start_info); 138 139 register_boot_callbacks(&PvhBootCallback); 140 send_to_default_serial8250_port("early_linux32_pvh_init done.\n\0".as_bytes()); 141 Ok(()) 142 } 143