mod gdt;
#[cfg(target_os = "none")]
mod memory;
#[cfg(target_os = "none")]
mod output;
use self::gdt::GdtPtr;
use crate::memory::{MemoryEntry, MemoryMap, MemoryType};
use crate::output::Framebuffer;
use crate::{BootInfo, BootMode};
use core::arch::asm;
#[cfg(target_os = "none")]
use {self::memory::E820Map, self::output::VBEInfo};
#[cfg(target_os = "uefi")]
use {
uefi::boot::MemoryType as UefiMemoryType,
uefi::mem::memory_map::{MemoryMap as UefiMemoryMap, MemoryMapOwned},
};
#[used]
static GDT: [u64; 3] = [
0,
(1 << 43) | (1 << 44) | (1 << 47) | (1 << 53) | (0 << 22),
(1 << 44) | (1 << 47) | (1 << 41) | (1 << 53) | (1 << 55),
];
#[used]
static mut GDT_PTR: GdtPtr = GdtPtr {
limit: 25,
base: 0, };
pub fn loader_main(bootmode: BootMode) -> ! {
let framebuffer = get_framebuffer();
let memory_map = get_memory_map();
let boot_info = BootInfo::new(bootmode, memory_map, framebuffer);
unsafe {
let src = &boot_info as *const BootInfo;
let dst = 0x100000 as *mut BootInfo;
core::ptr::copy(src, dst, 1);
}
let kernel_start: u32 = 0;
#[cfg(target_os = "none")]
unsafe {
GDT_PTR.base = GDT.as_ptr() as u64;
asm!(
"lgdt [{0}]",
in(reg) &raw const GDT_PTR,
options(nomem, nostack)
);
asm!(
"and esp, 0xFFFFFF00",
in("ecx") 0x100000
);
asm!(
"push ecx",
"push 0xffff8000",
"push {entry:e}",
entry = in(reg) kernel_start
);
asm!("ljmp $0x8, $2f", "2:", options(att_syntax));
asm!(
".code64",
"mov {0}, 0x10",
"mov ds, {0}",
"mov es, {0}",
"mov ss, {0}",
"mov fs, {0}",
"mov gs, {0}",
"pop rax",
"pop rdi",
"jmp rax",
out(reg) _,
out("rax") _,
out("rdi") _,
);
}
#[cfg(target_os = "uefi")]
unsafe {
asm!(
"mov rax, 0xffff800000000000",
"add rax, rsi",
in("rdi") 0x100000,
in("rsi") kernel_start,
options(nomem, nostack)
);
asm!("jmp rax");
}
loop {}
}
#[cfg(target_os = "none")]
fn get_framebuffer() -> Framebuffer {
let vbe = VBEInfo::load(0x10000); let fb_addr: u64 = 0xffff800040000000u64; let width: u64 = vbe.x_resolution.into();
let height: u64 = vbe.y_resolution.into();
let bpp: u64 = (vbe.bits_per_pixel / 8).into();
let pitch: u64 = vbe.bytes_per_scan_line.into();
let fb = Framebuffer::new(fb_addr, width, height, bpp, pitch);
fb
}
#[cfg(target_os = "none")]
fn get_memory_map() -> MemoryMap {
let e820_map = E820Map::load(0x10100);
let mut memory_map = MemoryMap {
count: 0,
entries: [MemoryEntry {
base_addr: 0,
length: 0,
mem_type: MemoryType::Reserved,
}; 128],
};
let entries = e820_map.entries.as_slice();
let entry_count = entries.len().min(128);
let mut bad_count: u32 = 0;
for i in 0..entry_count {
let e820_entry = &entries[i];
let mem_type = match e820_entry.type_ {
1 => MemoryType::FreeRAM,
2 => MemoryType::Reserved,
3 => MemoryType::AcpiReclaim,
4 => MemoryType::AcpiNvs,
_ => MemoryType::BadMemory,
};
if mem_type == MemoryType::BadMemory {
bad_count += 1;
}
memory_map.entries[i] = MemoryEntry {
base_addr: e820_entry.addr,
length: e820_entry.size,
mem_type,
};
}
memory_map.count = (entry_count as u32) - bad_count;
memory_map
}
#[cfg(target_os = "uefi")]
fn get_memory_map() -> MemoryMap {
let memory_map_uefi = unsafe { &*(0x110100 as *const MemoryMapOwned) };
let mut memory_map = MemoryMap {
count: 0,
entries: [MemoryEntry {
base_addr: 0,
length: 0,
mem_type: MemoryType::Reserved,
}; 128],
};
let entries = memory_map_uefi.entries();
for entry in entries {
let mem_type = match entry.ty {
UefiMemoryType::CONVENTIONAL |
UefiMemoryType::LOADER_CODE |
UefiMemoryType::LOADER_DATA => MemoryType::FreeRAM,
UefiMemoryType::RESERVED => MemoryType::Reserved,
UefiMemoryType::MMIO => MemoryType::Reserved,
UefiMemoryType::ACPI_RECLAIM => MemoryType::AcpiReclaim,
UefiMemoryType::ACPI_NON_VOLATILE => MemoryType::AcpiNvs,
UefiMemoryType::BOOT_SERVICES_CODE |
UefiMemoryType::BOOT_SERVICES_DATA => MemoryType::FreeRAM, _ => MemoryType::BadMemory, };
if memory_map.count < 128 {
memory_map.entries[memory_map.count as usize] = MemoryEntry {
base_addr: entry.phys_start,
length: entry.page_count * 4096,
mem_type,
};
if !matches!(mem_type, MemoryType::BadMemory) {
memory_map.count += 1;
}
}
}
memory_map.clone()
}
#[cfg(target_os = "uefi")]
fn get_framebuffer() -> Framebuffer {
let fb_info = unsafe { &*(0x110000 as *const Framebuffer) };
let addr = 0xffff800040000000u64; let width = fb_info.width();
let height = fb_info.height();
let bpp = fb_info.bpp();
let pitch = fb_info.pitch();
Framebuffer::new(addr, width, height, bpp, pitch)
}