|
| 1 | +mod gdt; |
| 2 | +mod page_tables; |
| 3 | +mod stack; |
| 4 | + |
| 5 | +use core::ptr::NonNull; |
| 6 | +use core::sync::atomic::{AtomicU32, Ordering}; |
| 7 | + |
| 8 | +use hermit_entry::boot_info::{BootInfo, HardwareInfo, LoadInfo, PlatformInfo, SerialPortBase, TlsInfo}; |
| 9 | +use pvh::start_info::reader::{IdentityMap, StartInfoReader}; |
| 10 | + |
| 11 | +use self::stack::{STACK, Stack}; |
| 12 | +use crate::env::setboot_info2; |
| 13 | +use crate::kernel::pre_init; |
| 14 | + |
| 15 | +/// The PVH entry point. |
| 16 | +#[unsafe(naked)] |
| 17 | +pub(crate) unsafe extern "C" fn pvh_start32() -> ! { |
| 18 | + core::arch::naked_asm!( |
| 19 | + ".code32", |
| 20 | + include_str!("pvh_start32.s"), |
| 21 | + ".code64", |
| 22 | + |
| 23 | + level_4_table = sym page_tables::LEVEL_4_TABLE, |
| 24 | + gdt_ptr = sym gdt::GDT_PTR, |
| 25 | + kernel_data_selector = const gdt::Gdt::kernel_data_selector().0, |
| 26 | + |
| 27 | + stack = sym STACK, |
| 28 | + stack_size = const size_of::<Stack>(), |
| 29 | + kernel_code_selector = const gdt::Gdt::kernel_code_selector().0, |
| 30 | + rust_start = sym rust_start, |
| 31 | + ); |
| 32 | +} |
| 33 | + |
| 34 | +pvh::xen_elfnote_phys32_entry!(pvh_start32); |
| 35 | + |
| 36 | +/// The native ELF entry point. |
| 37 | +#[unsafe(no_mangle)] |
| 38 | +#[unsafe(naked)] |
| 39 | +unsafe extern "C" fn _start() -> ! { |
| 40 | + core::arch::naked_asm!("2: jmp 2b"); |
| 41 | +} |
| 42 | + |
| 43 | +static START_INFO_PADDR: AtomicU32 = AtomicU32::new(0); |
| 44 | + |
| 45 | +pub fn start_info<'a>() -> StartInfoReader<'a, IdentityMap> { |
| 46 | + let paddr = START_INFO_PADDR.load(Ordering::Relaxed); |
| 47 | + unsafe { StartInfoReader::from_paddr_identity(paddr).unwrap() } |
| 48 | +} |
| 49 | + |
| 50 | +/// The Rust entry point. |
| 51 | +unsafe extern "C" fn rust_start(start_info_paddr: u32) -> ! { |
| 52 | + START_INFO_PADDR.store(start_info_paddr, Ordering::Relaxed); |
| 53 | + |
| 54 | + let start_info = start_info(); |
| 55 | + |
| 56 | + println!("Start info:\n{start_info:#?}"); |
| 57 | + |
| 58 | + dbg!(tdata()); |
| 59 | + |
| 60 | + let boot_info = BootInfo { |
| 61 | + hardware_info: HardwareInfo { |
| 62 | + phys_addr_range: 0..0, |
| 63 | + serial_port_base: SerialPortBase::new(0x3f8), |
| 64 | + device_tree: None, |
| 65 | + }, |
| 66 | + load_info: LoadInfo { |
| 67 | + kernel_image_addr_range: executable_start() as u64..executable_end() as u64, |
| 68 | + tls_info: dbg!(find_tls_ranges()), |
| 69 | + }, |
| 70 | + platform_info: PlatformInfo::Fdt, |
| 71 | + }; |
| 72 | + |
| 73 | + println!("boot_info = {boot_info:#x?}"); |
| 74 | + |
| 75 | + setboot_info2(boot_info); |
| 76 | + |
| 77 | + unsafe { pre_init(None, 0) } |
| 78 | +} |
| 79 | + |
| 80 | +pub fn executable_start() -> *mut () { |
| 81 | + unsafe extern "C" { |
| 82 | + static mut __executable_start: u8; |
| 83 | + } |
| 84 | + |
| 85 | + (&raw mut __executable_start).cast::<()>() |
| 86 | +} |
| 87 | + |
| 88 | +pub fn executable_end() -> *mut () { |
| 89 | + unsafe extern "C" { |
| 90 | + static mut _end: u8; |
| 91 | + } |
| 92 | + |
| 93 | + (&raw mut _end).cast::<()>() |
| 94 | +} |
| 95 | + |
| 96 | +pub fn tdata() -> *mut () { |
| 97 | + unsafe extern "C" { |
| 98 | + static mut __ehdr_start: u8; |
| 99 | + } |
| 100 | + |
| 101 | + (&raw mut __ehdr_start).cast::<()>() |
| 102 | +} |
| 103 | + |
| 104 | + |
| 105 | +use core::slice; |
| 106 | + |
| 107 | +const PT_LOAD: u32 = 1; |
| 108 | +const PT_TLS: u32 = 7; |
| 109 | + |
| 110 | +#[repr(C)] |
| 111 | +struct Elf64Ehdr { |
| 112 | + e_ident: [u8; 16], |
| 113 | + e_type: u16, |
| 114 | + e_machine: u16, |
| 115 | + e_version: u32, |
| 116 | + e_entry: u64, |
| 117 | + e_phoff: u64, |
| 118 | + e_shoff: u64, |
| 119 | + e_flags: u32, |
| 120 | + e_ehsize: u16, |
| 121 | + e_phentsize: u16, |
| 122 | + e_phnum: u16, |
| 123 | + e_shentsize: u16, |
| 124 | + e_shnum: u16, |
| 125 | + e_shstrndx: u16, |
| 126 | +} |
| 127 | + |
| 128 | +#[repr(C)] |
| 129 | +struct Elf64Phdr { |
| 130 | + p_type: u32, |
| 131 | + p_flags: u32, |
| 132 | + p_offset: u64, |
| 133 | + p_vaddr: u64, |
| 134 | + p_paddr: u64, |
| 135 | + p_filesz: u64, |
| 136 | + p_memsz: u64, |
| 137 | + p_align: u64, |
| 138 | +} |
| 139 | + |
| 140 | +// Provided by the default ELF linker scripts for executables |
| 141 | +unsafe extern "C" { |
| 142 | + static __ehdr_start: Elf64Ehdr; |
| 143 | +} |
| 144 | + |
| 145 | +#[derive(Debug, Clone, Copy)] |
| 146 | +pub struct TlsRanges { |
| 147 | + pub tdata_start: *const u8, |
| 148 | + pub tdata_end: *const u8, |
| 149 | + pub tbss_start: *const u8, |
| 150 | + pub tbss_end: *const u8, |
| 151 | +} |
| 152 | + |
| 153 | +unsafe fn find_tls_ranges() -> Option<TlsInfo> { |
| 154 | + let ehdr = &__ehdr_start as *const Elf64Ehdr; |
| 155 | + let ehdr_ref = &*ehdr; |
| 156 | + |
| 157 | + // Optional: check ELF magic |
| 158 | + if ehdr_ref.e_ident[0..4] != [0x7f, b'E', b'L', b'F'] { |
| 159 | + return None; |
| 160 | + } |
| 161 | + |
| 162 | + // Program headers |
| 163 | + let phdr_ptr = (ehdr as *const u8).add(ehdr_ref.e_phoff as usize) as *const Elf64Phdr; |
| 164 | + let phdrs = slice::from_raw_parts(phdr_ptr, ehdr_ref.e_phnum as usize); |
| 165 | + |
| 166 | + // Find PT_LOAD segment that contains file offset 0 (usually p_offset == 0) |
| 167 | + let first_load = phdrs |
| 168 | + .iter() |
| 169 | + .find(|ph| ph.p_type == PT_LOAD && ph.p_offset == 0)? |
| 170 | + ; |
| 171 | + |
| 172 | + // Compute load base of the main executable |
| 173 | + let ehdr_addr = &__ehdr_start as *const _ as usize; |
| 174 | + let base = ehdr_addr.wrapping_sub(first_load.p_vaddr as usize); |
| 175 | + |
| 176 | + // Find PT_TLS segment |
| 177 | + let tls_ph = phdrs.iter().find(|ph| ph.p_type == PT_TLS)?; |
| 178 | + |
| 179 | + let tdata_start = (base + tls_ph.p_vaddr as usize) as *const u8; |
| 180 | + let tdata_end = tdata_start.add(tls_ph.p_filesz as usize); |
| 181 | + let tbss_start = tdata_end; |
| 182 | + let tbss_end = tdata_start.add(tls_ph.p_memsz as usize); |
| 183 | + |
| 184 | + Some(TlsInfo { start: tls_ph.p_vaddr, filesz: tls_ph.p_filesz, memsz: tls_ph.p_memsz, align: tls_ph.p_align }) |
| 185 | +} |
0 commit comments