xref: /DragonOS/kernel/src/arch/x86_64/init/pvh/mod.rs (revision 4dd4856f933be0b4624c7f7ffa9e3d0c8c218873)
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