mirror of
https://github.com/XunilGroup/XunilOS.git
synced 2026-06-02 12:44:24 +02:00
Patched everything for aarch64, aside from scheduler, add more linker
points to aarch64 ld, add aarch64 heap, init, page tables and usermode, make hhdm_offset a global atomic, aarch64 uses semihosting for output, add generic PageTable type, add a function that creates and maps pages, use allow to remove warnings, add a bufwriter so kernel panic always works
This commit is contained in:
@@ -1,4 +1,5 @@
|
||||
/limine
|
||||
/.zed
|
||||
/edk2-ovmf
|
||||
*.iso
|
||||
*.hdd
|
||||
|
||||
@@ -54,6 +54,7 @@ run-aarch64: edk2-ovmf $(IMAGE_NAME).iso
|
||||
-serial stdio \
|
||||
-drive if=pflash,unit=0,format=raw,file=edk2-ovmf/ovmf-code-$(KARCH).fd,readonly=on \
|
||||
-cdrom $(IMAGE_NAME).iso \
|
||||
-semihosting-config enable=on,target=native \
|
||||
$(QEMUFLAGS)
|
||||
|
||||
.PHONY: run-hdd-aarch64
|
||||
|
||||
+10
-18
@@ -22,38 +22,30 @@ SECTIONS
|
||||
/* that is the beginning of the region. */
|
||||
. = 0xffffffff80000000;
|
||||
|
||||
.text : {
|
||||
*(.text .text.*)
|
||||
} :text
|
||||
|
||||
/* Move to the next memory page for .rodata */
|
||||
__kernel_start = .;
|
||||
__text_start = .;
|
||||
.text : { *(.text .text.*) } :text
|
||||
. = ALIGN(CONSTANT(MAXPAGESIZE));
|
||||
__text_end = .;
|
||||
|
||||
.rodata : {
|
||||
*(.rodata .rodata.*)
|
||||
} :rodata
|
||||
|
||||
/* Move to the next memory page for .data */
|
||||
__rodata_start = .;
|
||||
.rodata : { *(.rodata .rodata.*) } :rodata
|
||||
. = ALIGN(CONSTANT(MAXPAGESIZE));
|
||||
__rodata_end = .;
|
||||
|
||||
__data_start = .;
|
||||
.data : {
|
||||
*(.data .data.*)
|
||||
|
||||
/* Place the sections that contain the Limine requests as part of the .data */
|
||||
/* output section. */
|
||||
KEEP(*(.requests_start_marker))
|
||||
KEEP(*(.requests))
|
||||
KEEP(*(.requests_end_marker))
|
||||
} :data
|
||||
|
||||
/* NOTE: .bss needs to be the last thing mapped to :data, otherwise lots of */
|
||||
/* unnecessary zeros will be written to the binary. */
|
||||
/* If you need, for example, .init_array and .fini_array, those should be placed */
|
||||
/* above this. */
|
||||
.bss : {
|
||||
*(.bss .bss.*)
|
||||
*(COMMON)
|
||||
} :data
|
||||
__data_end = .;
|
||||
__kernel_end = .;
|
||||
|
||||
/* Discard .note.* and .eh_frame* since they may cause issues on some hosts. */
|
||||
/DISCARD/ : {
|
||||
|
||||
@@ -1,3 +1,24 @@
|
||||
use crate::{mm::heap::LinkedListAllocator, util::Locked};
|
||||
use crate::{
|
||||
arch::aarch64::paging::{AArchPageTable, alloc_frame, kernel_data_flags},
|
||||
mm::heap::LinkedListAllocator,
|
||||
util::Locked,
|
||||
};
|
||||
#[global_allocator]
|
||||
pub static ALLOCATOR: Locked<LinkedListAllocator> = Locked::new(LinkedListAllocator::new());
|
||||
|
||||
pub const HEAP_START: usize = 0xffffffff90000000;
|
||||
pub const HEAP_SIZE: usize = 64 * 1024 * 1024; // 64 MiB
|
||||
|
||||
pub fn init_heap(mapper: &mut AArchPageTable) {
|
||||
let pages = HEAP_SIZE / 4096;
|
||||
|
||||
for i in 0..pages {
|
||||
let phys = alloc_frame().expect("frame allocator out of frames");
|
||||
let virt = HEAP_START as u64 + i as u64 * 4096;
|
||||
mapper.map_page(virt, phys, kernel_data_flags());
|
||||
}
|
||||
|
||||
unsafe {
|
||||
ALLOCATOR.lock().init(HEAP_START, HEAP_SIZE);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,2 +1,21 @@
|
||||
use limine::response::{HhdmResponse, MemoryMapResponse};
|
||||
pub fn init_aarch64<'a>(hhdm_response: &HhdmResponse, memory_map_response: &'a MemoryMapResponse) {}
|
||||
use crate::arch::aarch64::{
|
||||
heap::init_heap,
|
||||
paging::{AArchPageTable, initialize_paging_aarch64},
|
||||
};
|
||||
use limine::response::{ExecutableAddressResponse, HhdmResponse, MemoryMapResponse};
|
||||
|
||||
pub fn init_aarch64<'a>(
|
||||
hhdm_response: &HhdmResponse,
|
||||
memory_map_response: &'a MemoryMapResponse,
|
||||
executable_address_response: &ExecutableAddressResponse,
|
||||
) -> AArchPageTable {
|
||||
let mut mapper = initialize_paging_aarch64(
|
||||
hhdm_response,
|
||||
memory_map_response,
|
||||
executable_address_response,
|
||||
);
|
||||
|
||||
init_heap(&mut mapper);
|
||||
|
||||
return mapper;
|
||||
}
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
// TODO: add interrupts
|
||||
@@ -0,0 +1 @@
|
||||
// TODO: add keyboard logic
|
||||
@@ -1,3 +1,7 @@
|
||||
pub mod heap;
|
||||
pub mod init;
|
||||
pub mod interrupts;
|
||||
pub mod mouse;
|
||||
pub mod paging;
|
||||
pub mod syscall;
|
||||
pub mod usermode;
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
// TODO: add mouse logic
|
||||
@@ -1,5 +1,281 @@
|
||||
use crate::arch::arch::XunilFrameAllocator;
|
||||
use crate::arch::arch::{HHDM_OFFSET, XunilFrameAllocator, safe_lock};
|
||||
use limine::{
|
||||
memory_map::EntryType,
|
||||
response::{ExecutableAddressResponse, HhdmResponse, MemoryMapResponse},
|
||||
};
|
||||
use spin::Mutex;
|
||||
|
||||
pub static FRAME_ALLOCATOR_AARCH64: Mutex<XunilFrameAllocator> =
|
||||
Mutex::new(XunilFrameAllocator::new());
|
||||
|
||||
// Constants
|
||||
const VALID: u64 = 1 << 0;
|
||||
const TABLE: u64 = 1 << 1;
|
||||
const PAGE: u64 = 1 << 1;
|
||||
const AF: u64 = 1 << 10;
|
||||
const SH_INNER: u64 = 0b11 << 8;
|
||||
|
||||
const ATTR_NORMAL: u64 = 0 << 2;
|
||||
const ATTR_DEVICE: u64 = 1 << 2;
|
||||
|
||||
// AP bits
|
||||
const AP_RW_EL1: u64 = 0b00 << 6; // kernel RW
|
||||
const AP_RO_EL1: u64 = 0b10 << 6; // kernel RO
|
||||
const AP_RW_EL0: u64 = 0b01 << 6; // kernel RW, user RW
|
||||
const AP_RO_EL0: u64 = 0b11 << 6; // kernel RO, user RO
|
||||
|
||||
pub const UXN: u64 = 1 << 54; // unprivileged execute never
|
||||
const PXN: u64 = 1 << 53; // privileged execute never
|
||||
|
||||
pub fn kernel_data_flags() -> u64 {
|
||||
VALID | PAGE | AF | SH_INNER | AP_RW_EL1 | UXN | ATTR_NORMAL
|
||||
}
|
||||
|
||||
pub fn kernel_code_flags() -> u64 {
|
||||
VALID | PAGE | AF | SH_INNER | AP_RO_EL1 | ATTR_NORMAL // no UXN
|
||||
}
|
||||
|
||||
pub fn user_data_flags() -> u64 {
|
||||
VALID | PAGE | AF | SH_INNER | AP_RW_EL0 | UXN | PXN | ATTR_NORMAL
|
||||
}
|
||||
|
||||
pub fn user_code_flags() -> u64 {
|
||||
VALID | PAGE | AF | SH_INNER | AP_RO_EL0 | ATTR_NORMAL // no UXN
|
||||
}
|
||||
|
||||
pub fn device_flags() -> u64 {
|
||||
VALID | PAGE | AF | AP_RW_EL1 | UXN | PXN | ATTR_DEVICE
|
||||
// no SH bits for device memory
|
||||
}
|
||||
|
||||
fn phys_to_virt(phys: u64) -> *mut u64 {
|
||||
let hhdm_offset = HHDM_OFFSET.load(core::sync::atomic::Ordering::Relaxed);
|
||||
(phys + hhdm_offset) as *mut u64
|
||||
}
|
||||
|
||||
pub fn tlb_flush() {
|
||||
unsafe {
|
||||
core::arch::asm!(
|
||||
"tlbi vmalle1is", // invalidate TLB
|
||||
"dsb ish", // wait for tlb flush
|
||||
"isb",
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn set_page_table(root_phys: u64) {
|
||||
unsafe {
|
||||
core::arch::asm!(
|
||||
"msr ttbr1_el1, {root}", // set to new page table
|
||||
"isb",
|
||||
root = in(reg) root_phys
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
// translation control register: handles addresses
|
||||
fn setup_tcr() {
|
||||
unsafe {
|
||||
let tcr: u64 = (16 << 0) | // T0SZ: 48-bit VA for TTBR0 (64-48=16)
|
||||
(16 << 16) | // T1SZ: 48-bit VA for TTBR1
|
||||
(0b00 << 14)| // TG0: 4K granule
|
||||
(0b10 << 30)| // TG1: 4K granule
|
||||
(0b11 << 12)| // SH0: inner shareable
|
||||
(0b11 << 28)| // SH1: inner shareable
|
||||
(0b01 << 10)| // ORGN0: normal WB RAWA
|
||||
(0b01 << 26)| // ORGN1
|
||||
(0b01 << 8) | // IRGN0
|
||||
(0b01 << 24); // IRGN1
|
||||
core::arch::asm!("msr tcr_el1, {0}", in(reg) tcr);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn initialize_paging_aarch64<'a>(
|
||||
hhdm_response: &HhdmResponse,
|
||||
memory_map_response: &'a MemoryMapResponse,
|
||||
executable_address_response: &ExecutableAddressResponse,
|
||||
) -> AArchPageTable {
|
||||
let mut frame_allocator = FRAME_ALLOCATOR_AARCH64.lock();
|
||||
frame_allocator.initialize(memory_map_response.entries());
|
||||
drop(frame_allocator);
|
||||
|
||||
let page_table = AArchPageTable::new();
|
||||
|
||||
unsafe extern "C" {
|
||||
static __text_end: u8;
|
||||
static __kernel_start: u8;
|
||||
static __kernel_end: u8;
|
||||
}
|
||||
|
||||
let k_phys_base = executable_address_response.physical_base();
|
||||
let k_virt_base = executable_address_response.virtual_base();
|
||||
|
||||
let text_end = unsafe { &__text_end as *const u8 as u64 };
|
||||
let k_start_virt = unsafe { (&__kernel_start as *const u8) as u64 };
|
||||
let k_end_virt = unsafe { (&__kernel_end as *const u8) as u64 };
|
||||
|
||||
let k_phys = k_phys_base + (k_start_virt - k_virt_base);
|
||||
|
||||
// map the kernel so we dont crash lol
|
||||
page_table.map_range(
|
||||
k_start_virt,
|
||||
k_phys,
|
||||
text_end - k_start_virt,
|
||||
kernel_code_flags(),
|
||||
);
|
||||
|
||||
page_table.map_range(
|
||||
text_end,
|
||||
k_phys + (text_end - k_start_virt),
|
||||
k_end_virt - text_end,
|
||||
kernel_data_flags(),
|
||||
);
|
||||
|
||||
// i need to map the entire memory range
|
||||
for entry in memory_map_response.entries() {
|
||||
if entry.entry_type == EntryType::BAD_MEMORY || entry.entry_type == EntryType::RESERVED {
|
||||
continue;
|
||||
}
|
||||
|
||||
let flags = if entry.entry_type == EntryType::FRAMEBUFFER {
|
||||
device_flags()
|
||||
} else {
|
||||
kernel_data_flags()
|
||||
};
|
||||
|
||||
page_table.map_range(
|
||||
entry.base + hhdm_response.offset(),
|
||||
entry.base,
|
||||
entry.length,
|
||||
flags,
|
||||
);
|
||||
}
|
||||
|
||||
page_table.map_page(0xFFFF_0000_0900_0000, 0x0900_0000, device_flags()); // the UART
|
||||
|
||||
setup_tcr();
|
||||
set_page_table(page_table.root_phys);
|
||||
tlb_flush();
|
||||
|
||||
return page_table;
|
||||
}
|
||||
|
||||
pub struct AArchPageTable {
|
||||
pub root_phys: u64,
|
||||
}
|
||||
|
||||
pub fn alloc_frame() -> Option<u64> {
|
||||
let mut frame_allocator = safe_lock(|| FRAME_ALLOCATOR_AARCH64.lock());
|
||||
let frame = frame_allocator.allocate_frame();
|
||||
drop(frame_allocator);
|
||||
return frame;
|
||||
}
|
||||
|
||||
impl AArchPageTable {
|
||||
pub fn new() -> AArchPageTable {
|
||||
let mut frame_allocator = safe_lock(|| FRAME_ALLOCATOR_AARCH64.lock());
|
||||
let root_phys = frame_allocator
|
||||
.allocate_frame()
|
||||
.expect("Could not allocate frame for page table");
|
||||
|
||||
unsafe {
|
||||
core::ptr::write_bytes(phys_to_virt(root_phys), 0, 512);
|
||||
}
|
||||
|
||||
AArchPageTable { root_phys }
|
||||
}
|
||||
|
||||
pub fn table_ptr(&self, table_phys: u64, index: usize) -> *mut u64 {
|
||||
let table_virt = phys_to_virt(table_phys);
|
||||
|
||||
unsafe { table_virt.add(index) }
|
||||
}
|
||||
|
||||
pub fn get_or_create_table(&self, parent_phys: u64, index: usize) -> u64 {
|
||||
let entry_ptr = self.table_ptr(parent_phys, index);
|
||||
let entry = unsafe { entry_ptr.read_volatile() };
|
||||
|
||||
if entry & VALID != 0 {
|
||||
return entry & 0x0000_FFFF_FFFF_F000;
|
||||
} else {
|
||||
let child = alloc_frame().expect("Could not allocate frame when creating page table");
|
||||
unsafe {
|
||||
core::ptr::write_bytes(phys_to_virt(child), 0, 512);
|
||||
entry_ptr.write_volatile(child | VALID | TABLE);
|
||||
}
|
||||
return child;
|
||||
}
|
||||
}
|
||||
|
||||
pub fn map_page(&self, virt: u64, phys: u64, flags: u64) {
|
||||
let l0 = ((virt >> 39) & 0x1FF) as usize;
|
||||
let l1 = ((virt >> 30) & 0x1FF) as usize;
|
||||
let l2 = ((virt >> 21) & 0x1FF) as usize;
|
||||
let l3 = ((virt >> 12) & 0x1FF) as usize;
|
||||
|
||||
let l1_phys = self.get_or_create_table(self.root_phys, l0);
|
||||
let l2_phys = self.get_or_create_table(l1_phys, l1);
|
||||
let l3_phys = self.get_or_create_table(l2_phys, l2);
|
||||
|
||||
let entry_ptr = self.table_ptr(l3_phys, l3);
|
||||
|
||||
unsafe {
|
||||
entry_ptr.write_volatile(phys | flags);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn map_range(&self, virt: u64, phys: u64, size: u64, flags: u64) {
|
||||
let pages = (size + 4095) / 4096;
|
||||
|
||||
for i in 0..pages {
|
||||
self.map_page(virt + i * 4096, phys + i * 4096, flags);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl XunilFrameAllocator {
|
||||
pub fn allocate_frame(&mut self) -> Option<u64> {
|
||||
let hhdm_offset = HHDM_OFFSET.load(core::sync::atomic::Ordering::Relaxed);
|
||||
while self.region_index < self.usable_region_count {
|
||||
let region = self.usable_regions[self.region_index];
|
||||
let frame_count = region.length / 4096;
|
||||
|
||||
if self.region_offset < frame_count as usize {
|
||||
let addr = region.base + (self.region_offset as u64 * 4096);
|
||||
self.region_offset += 1;
|
||||
|
||||
unsafe {
|
||||
core::ptr::write_bytes((addr + hhdm_offset) as *mut u8, 0, 4096);
|
||||
}
|
||||
|
||||
return Some(addr);
|
||||
}
|
||||
|
||||
self.region_index += 1;
|
||||
self.region_offset = 0;
|
||||
}
|
||||
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
pub fn create_and_map_multiple_pages(
|
||||
mapper: &mut AArchPageTable,
|
||||
page_count: u64,
|
||||
base: u64,
|
||||
flags: u64,
|
||||
) {
|
||||
let mut frame_allocator = FRAME_ALLOCATOR_AARCH64.lock();
|
||||
|
||||
for i in 0..page_count {
|
||||
let frame = frame_allocator.allocate_frame().unwrap();
|
||||
|
||||
let virt = base + i as u64 * 4096;
|
||||
|
||||
mapper.map_page(virt, frame, flags);
|
||||
}
|
||||
|
||||
tlb_flush();
|
||||
|
||||
drop(frame_allocator);
|
||||
}
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
// TODO: add syscalls
|
||||
@@ -0,0 +1,15 @@
|
||||
#[allow(unused_variables)]
|
||||
pub fn enter_usermode_aarch64(entry: u64, stack_ptr: u64, should_swapgs: bool) -> ! {
|
||||
unsafe {
|
||||
core::arch::asm!(
|
||||
"msr sp_el0, {sp}",
|
||||
"msr elr_el1, {entry}",
|
||||
"msr spsr_el1, xzr",
|
||||
"isb",
|
||||
"eret",
|
||||
sp = in(reg) stack_ptr,
|
||||
entry = in(reg) entry,
|
||||
options(noreturn)
|
||||
)
|
||||
};
|
||||
}
|
||||
+62
-29
@@ -1,16 +1,35 @@
|
||||
#![allow(dead_code, unused_imports)]
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
pub use crate::arch::x86_64::paging::FRAME_ALLOCATOR_X86_64 as FRAME_ALLOCATOR;
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
use crate::arch::x86_64::{init::init_x86_64, usermode::enter_usermode_x86_64};
|
||||
#[cfg(target_arch = "aarch64")]
|
||||
use limine::response::ExecutableAddressResponse;
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
use x86_64::{
|
||||
instructions::interrupts::without_interrupts,
|
||||
structures::paging::{FrameAllocator, OffsetPageTable, PhysFrame, Size4KiB},
|
||||
};
|
||||
|
||||
#[cfg(target_arch = "aarch64")]
|
||||
pub use crate::arch::aarch64::paging::FRAME_ALLOCATOR_AARCH64 as FRAME_ALLOCATOR;
|
||||
#[cfg(target_arch = "aarch64")]
|
||||
use crate::arch::aarch64::{
|
||||
init::init_aarch64, paging::AArchPageTable, usermode::enter_usermode_aarch64,
|
||||
};
|
||||
|
||||
use crate::{driver::timer::TIMER, util::align_up};
|
||||
use core::arch::asm;
|
||||
use core::{arch::asm, sync::atomic::AtomicU64};
|
||||
use limine::{
|
||||
memory_map::{Entry, EntryType},
|
||||
response::{HhdmResponse, MemoryMapResponse},
|
||||
};
|
||||
|
||||
#[cfg(target_arch = "aarch64")]
|
||||
const UART: *mut u8 = 0x0900_0000 as *mut u8;
|
||||
|
||||
pub static HHDM_OFFSET: AtomicU64 = AtomicU64::new(0);
|
||||
|
||||
#[derive(Clone, Copy)]
|
||||
#[allow(dead_code)]
|
||||
pub struct UsableRegion {
|
||||
@@ -40,7 +59,7 @@ impl XunilFrameAllocator {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn initialize(&mut self, hhdm_offset: u64, memory_map: &[&Entry]) {
|
||||
pub fn initialize(&mut self, memory_map: &[&Entry]) {
|
||||
let mut regions = [EMPTY_REGION; 1024];
|
||||
let mut count = 0usize;
|
||||
|
||||
@@ -63,7 +82,7 @@ impl XunilFrameAllocator {
|
||||
}
|
||||
}
|
||||
|
||||
self.hhdm_offset = hhdm_offset;
|
||||
self.hhdm_offset = HHDM_OFFSET.load(core::sync::atomic::Ordering::Relaxed);
|
||||
self.usable_regions = regions;
|
||||
self.usable_region_count = count;
|
||||
self.region_index = 0;
|
||||
@@ -71,16 +90,6 @@ impl XunilFrameAllocator {
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
use crate::arch::x86_64::{
|
||||
elf::run_elf_x86_64, init::init_x86_64, usermode::enter_usermode_x86_64,
|
||||
};
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
use x86_64::{instructions::interrupts::without_interrupts, structures::paging::OffsetPageTable};
|
||||
|
||||
#[cfg(target_arch = "aarch64")]
|
||||
use crate::arch::aarch64::init::init_aarch64;
|
||||
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
pub fn init<'a>(
|
||||
hhdm_response: &HhdmResponse,
|
||||
@@ -90,28 +99,26 @@ pub fn init<'a>(
|
||||
}
|
||||
|
||||
#[cfg(target_arch = "aarch64")]
|
||||
pub fn init<'a>(hhdm_response: &HhdmResponse, memory_map_response: &'a MemoryMapResponse) {
|
||||
return init_aarch64(hhdm_response, memory_map_response);
|
||||
pub fn init<'a>(
|
||||
hhdm_response: &HhdmResponse,
|
||||
memory_map_response: &'a MemoryMapResponse,
|
||||
executable_address_response: &ExecutableAddressResponse,
|
||||
) -> AArchPageTable {
|
||||
return init_aarch64(
|
||||
hhdm_response,
|
||||
memory_map_response,
|
||||
executable_address_response,
|
||||
);
|
||||
}
|
||||
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
pub fn enter_usermode(user_rip: u64, user_rsp: u64, should_swapgs: bool) {
|
||||
enter_usermode_x86_64(user_rip, user_rsp, should_swapgs);
|
||||
pub fn enter_usermode(entry: u64, stack_ptr: u64, should_swapgs: bool) {
|
||||
enter_usermode_x86_64(entry, stack_ptr, should_swapgs);
|
||||
}
|
||||
|
||||
#[cfg(target_arch = "aarch64")]
|
||||
pub fn enter_usermode(user_rip: u64, user_rsp: u64, should_swapgs: bool) {
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
pub fn run_elf(file_bytes: &[u8], should_swapgs: bool) {
|
||||
run_elf_x86_64(file_bytes, should_swapgs);
|
||||
}
|
||||
|
||||
#[cfg(target_arch = "aarch64")]
|
||||
pub fn run_elf(file_bytes: &[u8], should_swapgs: bool) {
|
||||
unimplemented!()
|
||||
pub fn enter_usermode(entry: u64, stack_ptr: u64, should_swapgs: bool) {
|
||||
enter_usermode_aarch64(entry, stack_ptr, should_swapgs);
|
||||
}
|
||||
|
||||
pub fn safe_lock<R, F: FnOnce() -> R>(f: F) -> R {
|
||||
@@ -121,6 +128,32 @@ pub fn safe_lock<R, F: FnOnce() -> R>(f: F) -> R {
|
||||
return f();
|
||||
}
|
||||
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
pub fn serial_print_byte(b: u8) {
|
||||
unsafe {
|
||||
core::arch::asm!("out dx, al", in("dx") 0x3F8u16, in("al") b);
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(target_arch = "aarch64")]
|
||||
pub fn serial_print_byte(b: u8) {
|
||||
unsafe {
|
||||
let buf = [b];
|
||||
core::arch::asm!(
|
||||
"hlt #0xF000",
|
||||
in("x0") 0x03u64, // SYS_WRITEC
|
||||
in("x1") buf.as_ptr(),
|
||||
options(nostack)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn serial_print(s: &str) {
|
||||
for &b in s.as_bytes() {
|
||||
serial_print_byte(b);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn idle() {
|
||||
unsafe {
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
|
||||
+47
-74
@@ -1,16 +1,22 @@
|
||||
#![allow(dead_code)]
|
||||
|
||||
#![allow(dead_code, unused_imports)]
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
use crate::arch::x86_64::paging::create_and_map_multiple_pages;
|
||||
use alloc::vec;
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
use x86_64::{
|
||||
PhysAddr, VirtAddr,
|
||||
instructions::interrupts,
|
||||
structures::paging::{FrameAllocator, Mapper, Page, PageTableFlags, PhysFrame, Size4KiB},
|
||||
structures::paging::{
|
||||
FrameAllocator, Mapper, OffsetPageTable, Page, PageTableFlags, PhysFrame, Size4KiB,
|
||||
},
|
||||
};
|
||||
|
||||
#[cfg(target_arch = "aarch64")]
|
||||
use crate::arch::aarch64::paging::AArchPageTable;
|
||||
use crate::{
|
||||
arch::arch::{FRAME_ALLOCATOR, run_elf, sleep},
|
||||
arch::arch::{FRAME_ALLOCATOR, sleep},
|
||||
driver::{
|
||||
elf::loader::run_elf,
|
||||
fs::vfs::{vfs_close, vfs_lseek, vfs_open, vfs_read},
|
||||
graphics::framebuffer::{FRAMEBUFFER, USER_FB_BASE, with_framebuffer},
|
||||
keyboard::{KeyboardEvent, process_scancodes},
|
||||
@@ -24,7 +30,6 @@ use crate::{
|
||||
util::{align_down, align_up},
|
||||
};
|
||||
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
use crate::{
|
||||
arch::arch::safe_lock,
|
||||
mm::usercopy::{copy_cstr_from_user, copy_to_user},
|
||||
@@ -56,7 +61,12 @@ const SLEEP: usize = 909090; // zzz haha
|
||||
pub const MAP_FRAMEBUFFER: usize = 5555;
|
||||
pub const FRAMEBUFFER_SWAP: usize = 6666;
|
||||
|
||||
#[cfg(target_arch = "aarch64")]
|
||||
type PageTable = AArchPageTable;
|
||||
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
type PageTable<'a> = OffsetPageTable<'a>;
|
||||
|
||||
fn map_framebuffer() -> isize {
|
||||
let pid = current_pid().unwrap_or(0);
|
||||
if pid == 0 {
|
||||
@@ -76,18 +86,20 @@ fn map_framebuffer() -> isize {
|
||||
let pixel_map_end = align_up(buf_phys + buf_size, 4096);
|
||||
drop(framebuffer);
|
||||
|
||||
let mut frame_allocator = FRAME_ALLOCATOR.lock();
|
||||
|
||||
SCHEDULER
|
||||
.with_process(pid, |process| {
|
||||
let address_space = match process.address_space.as_mut() {
|
||||
Some(a) => a,
|
||||
None => return -1,
|
||||
};
|
||||
|
||||
#[allow(dead_code, unused_mut, unused_variables)]
|
||||
let mut map_page = |virt: u64, phys: u64| {};
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
let mut map_page = |virt: u64, phys: u64| unsafe {
|
||||
let frame = PhysFrame::<Size4KiB>::containing_address(PhysAddr::new(phys));
|
||||
let page = Page::<Size4KiB>::containing_address(VirtAddr::new(virt));
|
||||
let mut frame_allocator = FRAME_ALLOCATOR.lock();
|
||||
|
||||
address_space
|
||||
.mapper
|
||||
.map_to(
|
||||
@@ -101,6 +113,14 @@ fn map_framebuffer() -> isize {
|
||||
)
|
||||
.unwrap()
|
||||
.flush();
|
||||
|
||||
drop(frame_allocator);
|
||||
};
|
||||
#[cfg(target_arch = "aarch64")]
|
||||
let map_page = |virt: u64, phys: u64| {
|
||||
use crate::arch::aarch64::paging::user_data_flags;
|
||||
|
||||
address_space.mapper.map_page(virt, phys, user_data_flags());
|
||||
};
|
||||
|
||||
map_page(USER_FB_BASE, struct_phys);
|
||||
@@ -114,12 +134,6 @@ fn map_framebuffer() -> isize {
|
||||
.unwrap_or(-1)
|
||||
}
|
||||
|
||||
#[cfg(target_arch = "aarch64")]
|
||||
fn map_framebuffer() -> isize {
|
||||
0
|
||||
}
|
||||
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
fn read(ptr: isize, size: isize, nmemb: isize, fd: isize) -> isize {
|
||||
let pid = current_pid().unwrap_or(0);
|
||||
if pid == 0 {
|
||||
@@ -155,12 +169,6 @@ fn read(ptr: isize, size: isize, nmemb: isize, fd: isize) -> isize {
|
||||
.unwrap_or(-1)
|
||||
}
|
||||
|
||||
#[cfg(target_arch = "aarch64")]
|
||||
fn read(ptr: isize, size: isize, nmemb: isize, fd: isize) -> isize {
|
||||
0
|
||||
}
|
||||
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
fn open(path: isize, mode: isize) -> isize {
|
||||
let pid = current_pid().unwrap_or(0);
|
||||
if pid == 0 {
|
||||
@@ -179,16 +187,10 @@ fn open(path: isize, mode: isize) -> isize {
|
||||
.unwrap_or(-1)
|
||||
}
|
||||
|
||||
#[cfg(target_arch = "aarch64")]
|
||||
fn open(path: isize, mode: isize) -> isize {
|
||||
0
|
||||
}
|
||||
|
||||
fn close(fd: isize) -> isize {
|
||||
vfs_close(fd as i64) as isize
|
||||
}
|
||||
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
fn kbd_read(user_ptr: *mut KeyboardEvent, max_events: isize) -> isize {
|
||||
process_scancodes();
|
||||
if max_events <= 0 || user_ptr.is_null() {
|
||||
@@ -223,12 +225,6 @@ fn kbd_read(user_ptr: *mut KeyboardEvent, max_events: isize) -> isize {
|
||||
.unwrap_or(-1);
|
||||
}
|
||||
|
||||
#[cfg(target_arch = "aarch64")]
|
||||
fn kbd_read(user_ptr: *mut KeyboardEvent, max_events: isize) -> isize {
|
||||
0
|
||||
}
|
||||
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
pub unsafe fn sbrk(increment: isize) -> isize {
|
||||
let pid = current_pid().unwrap_or(0);
|
||||
|
||||
@@ -238,8 +234,6 @@ pub unsafe fn sbrk(increment: isize) -> isize {
|
||||
|
||||
return SCHEDULER
|
||||
.with_process(pid as u64, |process| {
|
||||
let mut frame_allocator = safe_lock(|| FRAME_ALLOCATOR.lock());
|
||||
|
||||
let (heap_end, heap_base, stack_top) =
|
||||
(process.heap_end, process.heap_base, process.stack_top);
|
||||
|
||||
@@ -262,40 +256,35 @@ pub unsafe fn sbrk(increment: isize) -> isize {
|
||||
|
||||
if new > old {
|
||||
let map_start = align_up(old, 4096);
|
||||
let map_end = align_up(new, 4096);
|
||||
|
||||
for addr in (map_start..map_end).step_by(4096) {
|
||||
if let Some(frame) = frame_allocator.allocate_frame() {
|
||||
// TODO: do not use x86_64 only
|
||||
let virt_addr = VirtAddr::new(addr);
|
||||
let page = Page::<Size4KiB>::containing_address(virt_addr);
|
||||
let page_count = (align_up(new, 4096) - map_start) / 4096;
|
||||
if let Some(address_space) = process.address_space.as_mut() {
|
||||
unsafe {
|
||||
address_space
|
||||
.mapper
|
||||
.map_to(
|
||||
page,
|
||||
frame,
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
create_and_map_multiple_pages(
|
||||
&mut address_space.mapper,
|
||||
page_count,
|
||||
map_start,
|
||||
PageTableFlags::PRESENT
|
||||
| PageTableFlags::WRITABLE
|
||||
| PageTableFlags::USER_ACCESSIBLE
|
||||
| PageTableFlags::NO_EXECUTE,
|
||||
&mut *frame_allocator,
|
||||
)
|
||||
.unwrap()
|
||||
.flush();
|
||||
);
|
||||
#[cfg(target_arch = "aarch64")]
|
||||
{
|
||||
use crate::arch::aarch64::paging::{
|
||||
create_and_map_multiple_pages, user_data_flags,
|
||||
};
|
||||
|
||||
core::ptr::write_bytes(virt_addr.as_mut_ptr::<u8>(), 0, 4096);
|
||||
create_and_map_multiple_pages(
|
||||
&mut address_space.mapper,
|
||||
page_count,
|
||||
map_start,
|
||||
user_data_flags(),
|
||||
);
|
||||
}
|
||||
} else {
|
||||
return -1;
|
||||
}
|
||||
} else {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
drop(frame_allocator);
|
||||
|
||||
process.heap_end = new;
|
||||
|
||||
@@ -304,12 +293,6 @@ pub unsafe fn sbrk(increment: isize) -> isize {
|
||||
.unwrap_or(-1);
|
||||
}
|
||||
|
||||
#[cfg(target_arch = "aarch64")]
|
||||
pub unsafe fn sbrk(increment: isize) -> isize {
|
||||
0
|
||||
}
|
||||
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
pub fn exec(arg0: isize) -> isize {
|
||||
let pid = current_pid().unwrap_or(0);
|
||||
if pid == 0 {
|
||||
@@ -374,11 +357,6 @@ pub fn exec(arg0: isize) -> isize {
|
||||
0
|
||||
}
|
||||
|
||||
#[cfg(target_arch = "aarch64")]
|
||||
pub fn exec(arg0: isize) -> isize {
|
||||
0
|
||||
}
|
||||
|
||||
pub fn set_reschedule(should_reschedule: bool) {
|
||||
let pid = current_pid().unwrap_or(0);
|
||||
|
||||
@@ -395,7 +373,6 @@ pub fn set_reschedule(should_reschedule: bool) {
|
||||
drop(scheduler);
|
||||
}
|
||||
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
pub fn exit() -> isize {
|
||||
let pid = current_pid().unwrap_or(0);
|
||||
if pid == 0 {
|
||||
@@ -427,11 +404,7 @@ pub fn exit() -> isize {
|
||||
crate::arch::arch::infinite_idle();
|
||||
}
|
||||
|
||||
#[cfg(target_arch = "aarch64")]
|
||||
pub fn exit() -> isize {
|
||||
0
|
||||
}
|
||||
|
||||
#[allow(unused_variables)]
|
||||
#[unsafe(no_mangle)]
|
||||
pub unsafe extern "C" fn syscall_dispatch(
|
||||
num: usize,
|
||||
|
||||
@@ -1,62 +0,0 @@
|
||||
use alloc::vec::Vec;
|
||||
use x86_64::{
|
||||
VirtAddr,
|
||||
structures::paging::{FrameAllocator, Mapper, Page, PageTableFlags, PhysFrame, Size4KiB},
|
||||
};
|
||||
|
||||
use crate::{
|
||||
arch::arch::FRAME_ALLOCATOR, driver::elf::loader::load_file, mm::address_space::AddressSpace,
|
||||
println, task::scheduler::SCHEDULER,
|
||||
};
|
||||
|
||||
pub fn run_elf_x86_64(file_bytes: &[u8], should_swapgs: bool) {
|
||||
let stack_base: u64 = 0x0000_7fff_0000_0000;
|
||||
let page_count = 4096; // 16 mib
|
||||
let page_size = 0x1000u64;
|
||||
let stack_top = stack_base + (page_count as u64 * page_size);
|
||||
|
||||
if let Some(mut address_space) = AddressSpace::new() {
|
||||
address_space.use_address_space();
|
||||
|
||||
let (entry_point, heap_base) = load_file(&mut address_space.mapper, file_bytes);
|
||||
|
||||
println!("Entry point: {:?}", entry_point);
|
||||
|
||||
let process_pid = SCHEDULER
|
||||
.spawn_process(entry_point as u64, stack_top, heap_base)
|
||||
.unwrap();
|
||||
|
||||
let mut frame_allocator = FRAME_ALLOCATOR.lock();
|
||||
|
||||
for i in 0..page_count {
|
||||
let frame = frame_allocator.allocate_frame().unwrap();
|
||||
|
||||
let virt_addr = VirtAddr::new(stack_base + i as u64 * page_size);
|
||||
let page = Page::<Size4KiB>::containing_address(virt_addr);
|
||||
|
||||
unsafe {
|
||||
address_space
|
||||
.mapper
|
||||
.map_to(
|
||||
page,
|
||||
frame,
|
||||
PageTableFlags::PRESENT
|
||||
| PageTableFlags::WRITABLE
|
||||
| PageTableFlags::USER_ACCESSIBLE,
|
||||
&mut *frame_allocator,
|
||||
)
|
||||
.unwrap()
|
||||
.flush();
|
||||
}
|
||||
}
|
||||
drop(frame_allocator);
|
||||
|
||||
SCHEDULER.with_process(process_pid, |process| {
|
||||
process.address_space = Some(address_space)
|
||||
});
|
||||
|
||||
SCHEDULER.switch_to(process_pid, should_swapgs);
|
||||
} else {
|
||||
return;
|
||||
};
|
||||
}
|
||||
@@ -1,11 +1,8 @@
|
||||
use crate::arch::x86_64::paging::create_and_map_multiple_pages;
|
||||
use crate::mm::heap::LinkedListAllocator;
|
||||
use crate::util::Locked;
|
||||
use crate::{arch::x86_64::paging::FRAME_ALLOCATOR_X86_64, mm::heap::LinkedListAllocator};
|
||||
use x86_64::{
|
||||
VirtAddr,
|
||||
structures::paging::{
|
||||
FrameAllocator, Mapper, OffsetPageTable, Page, PageTableFlags as Flags, Size4KiB,
|
||||
mapper::MapToError,
|
||||
},
|
||||
use x86_64::structures::paging::{
|
||||
OffsetPageTable, PageTableFlags as Flags, Size4KiB, mapper::MapToError,
|
||||
};
|
||||
|
||||
#[global_allocator]
|
||||
@@ -15,30 +12,14 @@ pub const HEAP_START: usize = 0xffffffff90000000;
|
||||
pub const HEAP_SIZE: usize = 64 * 1024 * 1024; // 64 MiB
|
||||
|
||||
pub fn init_heap(mapper: &mut OffsetPageTable) -> Result<(), MapToError<Size4KiB>> {
|
||||
let page_range = {
|
||||
let page_start = VirtAddr::new(HEAP_START as u64);
|
||||
let page_end = page_start + HEAP_SIZE as u64 - 1u64;
|
||||
let heap_start_page: Page<Size4KiB> = Page::containing_address(page_start);
|
||||
let heap_end_page: Page<Size4KiB> = Page::containing_address(page_end);
|
||||
Page::range_inclusive(heap_start_page, heap_end_page)
|
||||
};
|
||||
let page_count = HEAP_SIZE / 4096;
|
||||
|
||||
let mut frame_allocator = FRAME_ALLOCATOR_X86_64.lock();
|
||||
|
||||
for page in page_range {
|
||||
let frame = frame_allocator
|
||||
.allocate_frame()
|
||||
.ok_or(MapToError::<Size4KiB>::FrameAllocationFailed)?;
|
||||
let flags = Flags::PRESENT | Flags::WRITABLE;
|
||||
unsafe {
|
||||
mapper
|
||||
.map_to(page, frame, flags, &mut *frame_allocator)
|
||||
.map_err(|e| e)?
|
||||
.flush();
|
||||
}
|
||||
}
|
||||
|
||||
drop(frame_allocator);
|
||||
create_and_map_multiple_pages(
|
||||
mapper,
|
||||
page_count as u64,
|
||||
HEAP_START as u64,
|
||||
Flags::PRESENT | Flags::WRITABLE,
|
||||
);
|
||||
|
||||
unsafe {
|
||||
ALLOCATOR.lock().init(HEAP_START, HEAP_SIZE);
|
||||
|
||||
@@ -1,42 +1,35 @@
|
||||
use crate::{
|
||||
arch::x86_64::{
|
||||
gdt::load_gdt_x86_64,
|
||||
heap::init_heap,
|
||||
interrupts::{PICS, init_idt_x86_64},
|
||||
mouse::setup_mouse,
|
||||
paging::{FRAME_ALLOCATOR_X86_64, initialize_paging_x86_64},
|
||||
syscall::init_syscalls,
|
||||
},
|
||||
driver::mouse::MOUSE,
|
||||
};
|
||||
|
||||
use x86_64::{
|
||||
VirtAddr,
|
||||
instructions::{interrupts, interrupts::without_interrupts, port::Port},
|
||||
registers::control::{Cr0, Cr0Flags, Cr4, Cr4Flags},
|
||||
structures::paging::OffsetPageTable,
|
||||
};
|
||||
|
||||
use limine::response::{HhdmResponse, MemoryMapResponse};
|
||||
use x86_64::{
|
||||
instructions::interrupts::without_interrupts,
|
||||
registers::control::{Cr0, Cr0Flags},
|
||||
};
|
||||
use x86_64::{
|
||||
instructions::{interrupts, port::Port},
|
||||
registers::control::{Cr4, Cr4Flags},
|
||||
};
|
||||
|
||||
const TIMER_PRECISION_HZ: u32 = 1000;
|
||||
const PIT_DIVISOR: u16 = (1_193_182_u32 / TIMER_PRECISION_HZ) as u16;
|
||||
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
use crate::arch::x86_64::{
|
||||
heap::init_heap,
|
||||
paging::{FRAME_ALLOCATOR_X86_64, initialize_paging},
|
||||
};
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
use x86_64::{VirtAddr, structures::paging::OffsetPageTable};
|
||||
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
pub fn memory_management_init(
|
||||
hhdm_response: &HhdmResponse,
|
||||
memory_map_response: &MemoryMapResponse,
|
||||
) -> OffsetPageTable<'static> {
|
||||
let physical_offset = VirtAddr::new(hhdm_response.offset());
|
||||
let mapper = unsafe { initialize_paging(physical_offset) };
|
||||
let mapper = unsafe { initialize_paging_x86_64(physical_offset) };
|
||||
let mut frame_allocator = FRAME_ALLOCATOR_X86_64.lock();
|
||||
frame_allocator.initialize(hhdm_response.offset(), memory_map_response.entries());
|
||||
frame_allocator.initialize(memory_map_response.entries());
|
||||
drop(frame_allocator);
|
||||
mapper
|
||||
}
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
pub mod elf;
|
||||
pub mod gdt;
|
||||
pub mod heap;
|
||||
pub mod init;
|
||||
|
||||
@@ -2,10 +2,13 @@ use spin::mutex::Mutex;
|
||||
use x86_64::{
|
||||
PhysAddr, VirtAddr,
|
||||
registers::control::Cr3,
|
||||
structures::paging::{FrameAllocator, OffsetPageTable, PageTable, PhysFrame, Size4KiB},
|
||||
structures::paging::{
|
||||
FrameAllocator, Mapper, OffsetPageTable, Page, PageTable, PageTableFlags, PhysFrame,
|
||||
Size4KiB,
|
||||
},
|
||||
};
|
||||
|
||||
use crate::arch::arch::XunilFrameAllocator;
|
||||
use crate::arch::arch::{HHDM_OFFSET, XunilFrameAllocator};
|
||||
|
||||
unsafe fn active_level_4_table(mem_offset: VirtAddr) -> &'static mut PageTable {
|
||||
let (level_4_table, _) = Cr3::read();
|
||||
@@ -17,7 +20,9 @@ unsafe fn active_level_4_table(mem_offset: VirtAddr) -> &'static mut PageTable {
|
||||
unsafe { &mut *page_table_ptr }
|
||||
}
|
||||
|
||||
pub unsafe fn initialize_paging(physical_memory_offset: VirtAddr) -> OffsetPageTable<'static> {
|
||||
pub unsafe fn initialize_paging_x86_64(
|
||||
physical_memory_offset: VirtAddr,
|
||||
) -> OffsetPageTable<'static> {
|
||||
unsafe {
|
||||
let level_4_table = active_level_4_table(physical_memory_offset);
|
||||
OffsetPageTable::new(level_4_table, physical_memory_offset)
|
||||
@@ -34,8 +39,10 @@ unsafe impl FrameAllocator<Size4KiB> for XunilFrameAllocator {
|
||||
let addr = region.base + (self.region_offset as u64 * 4096);
|
||||
self.region_offset += 1;
|
||||
|
||||
let hhdm_offset = HHDM_OFFSET.load(core::sync::atomic::Ordering::Relaxed);
|
||||
|
||||
unsafe {
|
||||
core::ptr::write_bytes((addr + self.hhdm_offset) as *mut u8, 0, 4096);
|
||||
core::ptr::write_bytes((addr + hhdm_offset) as *mut u8, 0, 4096);
|
||||
}
|
||||
|
||||
return Some(PhysFrame::containing_address(PhysAddr::new(addr)));
|
||||
@@ -49,5 +56,29 @@ unsafe impl FrameAllocator<Size4KiB> for XunilFrameAllocator {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn create_and_map_multiple_pages(
|
||||
mapper: &mut OffsetPageTable,
|
||||
page_count: u64,
|
||||
base: u64,
|
||||
flags: PageTableFlags,
|
||||
) {
|
||||
let mut frame_allocator = FRAME_ALLOCATOR_X86_64.lock();
|
||||
|
||||
for i in 0..page_count {
|
||||
let frame = frame_allocator.allocate_frame().unwrap();
|
||||
|
||||
let virt_addr = VirtAddr::new(base + i as u64 * 4096);
|
||||
let page = Page::<Size4KiB>::containing_address(virt_addr);
|
||||
|
||||
unsafe {
|
||||
mapper
|
||||
.map_to(page, frame, flags, &mut *frame_allocator)
|
||||
.unwrap()
|
||||
.flush();
|
||||
}
|
||||
}
|
||||
drop(frame_allocator);
|
||||
}
|
||||
|
||||
pub static FRAME_ALLOCATOR_X86_64: Mutex<XunilFrameAllocator> =
|
||||
Mutex::new(XunilFrameAllocator::new());
|
||||
|
||||
@@ -10,7 +10,7 @@ fn with_rpl3(ss: SegmentSelector) -> u64 {
|
||||
}
|
||||
|
||||
// entry point and stack
|
||||
pub fn enter_usermode_x86_64(user_rip: u64, user_rsp: u64, should_swapgs: bool) -> ! {
|
||||
pub fn enter_usermode_x86_64(entry: u64, stack_ptr: u64, should_swapgs: bool) -> ! {
|
||||
let user_cs = with_rpl3(user_code_selector());
|
||||
let user_ss = with_rpl3(user_data_selector());
|
||||
|
||||
@@ -35,10 +35,10 @@ pub fn enter_usermode_x86_64(user_rip: u64, user_rsp: u64, should_swapgs: bool)
|
||||
"iretq",
|
||||
|
||||
user_ss = in(reg) user_ss,
|
||||
user_rsp = in(reg) user_rsp,
|
||||
user_rsp = in(reg) stack_ptr,
|
||||
rflags = in(reg) rflags,
|
||||
user_cs = in(reg) user_cs,
|
||||
user_rip = in(reg) user_rip,
|
||||
user_rip = in(reg) entry,
|
||||
options(noreturn)
|
||||
);
|
||||
}
|
||||
|
||||
@@ -91,6 +91,13 @@ pub const R_X86_64_RELATIVE: u32 = 8;
|
||||
pub const R_X86_64_32: u32 = 10;
|
||||
pub const R_X86_64_32S: u32 = 11;
|
||||
|
||||
// aarch64 relocation types
|
||||
pub const R_AARCH64_NONE: u32 = 0;
|
||||
pub const R_AARCH64_ABS64: u32 = 257;
|
||||
pub const R_AARCH64_GLOB_DAT: u32 = 1025;
|
||||
pub const R_AARCH64_JUMP_SLOT: u32 = 1026;
|
||||
pub const R_AARCH64_RELATIVE: u32 = 1027;
|
||||
|
||||
// Auxiliary vector types
|
||||
pub const AT_PHDR: u64 = 3;
|
||||
pub const AT_PHENT: u64 = 4;
|
||||
|
||||
@@ -1,22 +1,34 @@
|
||||
use core::ptr::null;
|
||||
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
use crate::arch::x86_64::paging::create_and_map_multiple_pages;
|
||||
#[allow(unused_imports)]
|
||||
use crate::driver::elf::{
|
||||
header::{
|
||||
EI_CLASS, EI_DATA, EI_VERSION, ELF_MAGIC, EM_X86_64, ET_DYN, ET_EXEC, ET_REL, Elf64Ehdr,
|
||||
EI_CLASS, EI_DATA, EI_VERSION, ELF_MAGIC, EM_AARCH64, EM_X86_64, ET_DYN, ET_EXEC, ET_REL,
|
||||
Elf64Ehdr,
|
||||
},
|
||||
program::load_program,
|
||||
};
|
||||
|
||||
#[cfg(target_arch = "aarch64")]
|
||||
use crate::arch::aarch64::paging::{
|
||||
AArchPageTable, create_and_map_multiple_pages, user_data_flags,
|
||||
};
|
||||
use crate::{mm::address_space::AddressSpace, println, task::scheduler::SCHEDULER};
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
use x86_64::structures::paging::OffsetPageTable;
|
||||
use x86_64::structures::paging::{OffsetPageTable, PageTableFlags};
|
||||
|
||||
#[cfg(target_arch = "aarch64")]
|
||||
type PageTable = AArchPageTable;
|
||||
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
type PageTable<'a> = OffsetPageTable<'a>;
|
||||
|
||||
pub fn validate_elf(elf_header: &Elf64Ehdr, elf_len: usize) -> bool {
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
let required_machine = EM_X86_64;
|
||||
|
||||
#[cfg(target_arch = "aarch64")]
|
||||
use crate::driver::elf::header::EM_AARCH64;
|
||||
#[cfg(target_arch = "aarch64")]
|
||||
let required_machine = EM_AARCH64;
|
||||
|
||||
@@ -37,8 +49,7 @@ pub fn validate_elf(elf_header: &Elf64Ehdr, elf_len: usize) -> bool {
|
||||
&& (elf_header.e_phoff + (elf_header.e_phnum*elf_header.e_phentsize) as u64) <= elf_len as u64
|
||||
}
|
||||
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
pub fn load_file(mapper: &mut OffsetPageTable, elf_bytes: &[u8]) -> (*const u8, u64) {
|
||||
pub fn load_file(mapper: &mut PageTable, elf_bytes: &[u8]) -> (*const u8, u64) {
|
||||
// elf header size
|
||||
if elf_bytes.len() < 64 {
|
||||
return (null(), 0);
|
||||
@@ -60,3 +71,46 @@ pub fn load_file(mapper: &mut OffsetPageTable, elf_bytes: &[u8]) -> (*const u8,
|
||||
_ => return (null(), 0),
|
||||
};
|
||||
}
|
||||
|
||||
pub fn run_elf(file_bytes: &[u8], should_swapgs: bool) {
|
||||
let stack_base: u64 = 0x0000_7fff_0000_0000;
|
||||
let page_count = 4096; // 16 mib
|
||||
let page_size = 0x1000u64;
|
||||
let stack_top = stack_base + (page_count as u64 * page_size);
|
||||
|
||||
if let Some(mut address_space) = AddressSpace::new() {
|
||||
address_space.use_address_space();
|
||||
|
||||
let (entry_point, heap_base) = load_file(&mut address_space.mapper, file_bytes);
|
||||
|
||||
println!("Entry point: {:?}", entry_point);
|
||||
|
||||
let process_pid = SCHEDULER
|
||||
.spawn_process(entry_point as u64, stack_top, heap_base)
|
||||
.unwrap();
|
||||
|
||||
#[cfg(target_arch = "aarch64")]
|
||||
create_and_map_multiple_pages(
|
||||
&mut address_space.mapper,
|
||||
page_count,
|
||||
stack_base,
|
||||
user_data_flags(),
|
||||
);
|
||||
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
create_and_map_multiple_pages(
|
||||
&mut address_space.mapper,
|
||||
page_count,
|
||||
stack_base,
|
||||
PageTableFlags::PRESENT | PageTableFlags::WRITABLE | PageTableFlags::USER_ACCESSIBLE,
|
||||
);
|
||||
|
||||
SCHEDULER.with_process(process_pid, |process| {
|
||||
process.address_space = Some(address_space)
|
||||
});
|
||||
|
||||
SCHEDULER.switch_to(process_pid, should_swapgs);
|
||||
} else {
|
||||
return;
|
||||
};
|
||||
}
|
||||
|
||||
@@ -1,6 +1,13 @@
|
||||
use alloc::vec::Vec;
|
||||
use core::ptr::{null, null_mut};
|
||||
|
||||
#[cfg(target_arch = "aarch64")]
|
||||
#[allow(unused_imports)]
|
||||
use crate::arch::aarch64::paging::{
|
||||
AArchPageTable, UXN, create_and_map_multiple_pages, user_code_flags,
|
||||
};
|
||||
|
||||
#[allow(unused_imports)]
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
use x86_64::{
|
||||
VirtAddr,
|
||||
@@ -9,13 +16,18 @@ use x86_64::{
|
||||
},
|
||||
};
|
||||
|
||||
#[allow(unused_imports)]
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
use crate::arch::x86_64::paging::create_and_map_multiple_pages;
|
||||
#[allow(unused_imports)]
|
||||
use crate::{
|
||||
arch::arch::FRAME_ALLOCATOR,
|
||||
driver::elf::header::{
|
||||
DT_JMPREL, DT_NEEDED, DT_NULL, DT_PLTREL, DT_PLTRELSZ, DT_RELA, DT_RELASZ, DT_STRSZ,
|
||||
DT_STRTAB, DT_SYMTAB, Elf64Dyn, Elf64Ehdr, Elf64Phdr, Elf64Rela, Elf64Sym, PF_X,
|
||||
PT_DYNAMIC, PT_LOAD, R_X86_64_64, R_X86_64_GLOB_DAT, R_X86_64_JUMP_SLOT, R_X86_64_NONE,
|
||||
R_X86_64_RELATIVE, SHN_UNDEF, STB_WEAK,
|
||||
PT_DYNAMIC, PT_LOAD, R_AARCH64_ABS64, R_AARCH64_GLOB_DAT, R_AARCH64_JUMP_SLOT,
|
||||
R_AARCH64_NONE, R_AARCH64_RELATIVE, R_X86_64_64, R_X86_64_GLOB_DAT, R_X86_64_JUMP_SLOT,
|
||||
R_X86_64_NONE, R_X86_64_RELATIVE, SHN_UNDEF, STB_WEAK,
|
||||
},
|
||||
util::{align_down, align_up},
|
||||
};
|
||||
@@ -30,9 +42,14 @@ pub fn get_vaddr(phdr: *const Elf64Phdr, load_bias: u64) -> *mut u8 {
|
||||
unsafe { ((*phdr).p_vaddr + load_bias) as *mut u8 }
|
||||
}
|
||||
|
||||
#[cfg(target_arch = "aarch64")]
|
||||
type PageTable = AArchPageTable;
|
||||
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
type PageTable<'a> = OffsetPageTable<'a>;
|
||||
|
||||
pub unsafe fn load_program(
|
||||
mapper: &mut OffsetPageTable,
|
||||
mapper: &mut PageTable,
|
||||
hdr: *const Elf64Ehdr,
|
||||
elf_bytes: &[u8],
|
||||
pie: bool,
|
||||
@@ -55,7 +72,6 @@ pub unsafe fn load_program(
|
||||
|
||||
if !pie {
|
||||
for program_header in program_headers {
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
load_segment_to_memory(mapper, program_header, elf_bytes, 0);
|
||||
}
|
||||
|
||||
@@ -74,7 +90,7 @@ pub unsafe fn load_program(
|
||||
align_up(highest_seg as u64, 4096),
|
||||
);
|
||||
} else {
|
||||
let base_address = 0x0000_0100_0000; // TODO: add per-process memory
|
||||
let base_address = 0x0000_0100_0000;
|
||||
let min_vaddr = align_down(
|
||||
program_headers
|
||||
.iter()
|
||||
@@ -98,7 +114,6 @@ pub unsafe fn load_program(
|
||||
}
|
||||
|
||||
for program_header in program_headers {
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
load_segment_to_memory(mapper, program_header, elf_bytes, load_bias);
|
||||
}
|
||||
|
||||
@@ -124,30 +139,7 @@ pub unsafe fn load_program(
|
||||
}
|
||||
}
|
||||
|
||||
// fn cstr_from_strtab(
|
||||
// strtab_ptr: *const u8,
|
||||
// strtab_size: u64,
|
||||
// off: u32,
|
||||
// ) -> Option<&'static core::ffi::CStr> {
|
||||
// let off = off as u64;
|
||||
// if strtab_ptr.is_null() || off >= strtab_size {
|
||||
// return None;
|
||||
// }
|
||||
|
||||
// let mut i = off;
|
||||
|
||||
// while i < strtab_size {
|
||||
// let b = unsafe { *strtab_ptr.add(i as usize) };
|
||||
// if b == 0 {
|
||||
// let start = unsafe { strtab_ptr.add(off as usize) } as *const core::ffi::c_char;
|
||||
// return Some(unsafe { CStr::from_ptr(start as *const i8) });
|
||||
// }
|
||||
// i += 1;
|
||||
// }
|
||||
|
||||
// None
|
||||
// }
|
||||
|
||||
#[allow(unused_variables)]
|
||||
pub fn dyn_get_symaddr(
|
||||
strtab_ptr: *const u8,
|
||||
strtab_size: u64,
|
||||
@@ -160,12 +152,11 @@ pub fn dyn_get_symaddr(
|
||||
return Ok(load_bias + sym.st_value);
|
||||
}
|
||||
|
||||
// let name = cstr_from_strtab(strtab_ptr, strtab_size, idx as u32);
|
||||
|
||||
let bind = sym.st_info >> 4;
|
||||
if bind == STB_WEAK { Ok(0) } else { Err(()) }
|
||||
}
|
||||
|
||||
#[allow(unused_variables)]
|
||||
fn apply_relocations(
|
||||
hdr: *const Elf64Ehdr,
|
||||
rela_ptr: *mut Elf64Rela,
|
||||
@@ -178,12 +169,13 @@ fn apply_relocations(
|
||||
for i in 0..rela_table_size as usize / size_of::<Elf64Rela>() {
|
||||
let rela_ptr = unsafe { rela_ptr.add(i) };
|
||||
let ptr = unsafe { (load_bias + (*rela_ptr).r_offset) as *mut u64 };
|
||||
#[allow(unused_assignments)]
|
||||
let mut value: u64 = 0;
|
||||
match unsafe { ((*rela_ptr).r_info & 0xffff_ffff) as u32 } {
|
||||
x if x == R_X86_64_RELATIVE as u32 => unsafe {
|
||||
x if x == R_X86_64_RELATIVE || x == R_AARCH64_RELATIVE => unsafe {
|
||||
value = (load_bias as i64 + (*rela_ptr).r_addend) as u64;
|
||||
},
|
||||
x if x == R_X86_64_64 as u32 => unsafe {
|
||||
x if x == R_X86_64_64 || x == R_AARCH64_ABS64 => unsafe {
|
||||
value = (dyn_get_symaddr(
|
||||
strtab_ptr,
|
||||
strtab_size,
|
||||
@@ -194,7 +186,14 @@ fn apply_relocations(
|
||||
.unwrap() as i64
|
||||
+ (*rela_ptr).r_addend) as u64;
|
||||
},
|
||||
x if [R_X86_64_GLOB_DAT, R_X86_64_JUMP_SLOT].contains(&x) => unsafe {
|
||||
x if [
|
||||
R_X86_64_GLOB_DAT,
|
||||
R_X86_64_JUMP_SLOT,
|
||||
R_AARCH64_GLOB_DAT,
|
||||
R_AARCH64_JUMP_SLOT,
|
||||
]
|
||||
.contains(&x) =>
|
||||
unsafe {
|
||||
value = dyn_get_symaddr(
|
||||
strtab_ptr,
|
||||
strtab_size,
|
||||
@@ -204,7 +203,7 @@ fn apply_relocations(
|
||||
)
|
||||
.unwrap() as u64;
|
||||
},
|
||||
x if x == R_X86_64_NONE as u32 => {
|
||||
x if x == R_X86_64_NONE || x == R_AARCH64_NONE => {
|
||||
continue; // explicitly do nothing
|
||||
}
|
||||
_ => {
|
||||
@@ -279,9 +278,8 @@ fn parse_dyn(
|
||||
);
|
||||
}
|
||||
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
pub fn load_segment_to_memory(
|
||||
mapper: &mut OffsetPageTable,
|
||||
mapper: &mut PageTable,
|
||||
phdr: *const Elf64Phdr,
|
||||
elf_bytes: &[u8],
|
||||
load_bias: u64,
|
||||
@@ -300,12 +298,13 @@ pub fn load_segment_to_memory(
|
||||
|
||||
let vaddr: u64 = get_vaddr(phdr, load_bias) as u64;
|
||||
let mem_page: u64 = align_down(vaddr, PAGE_SIZE);
|
||||
let file_page: u64 = align_down(p_offset, PAGE_SIZE);
|
||||
let page_off: u64 = vaddr - mem_page;
|
||||
|
||||
let seg_start = mem_page;
|
||||
let seg_end = align_up(vaddr + mem_size, PAGE_SIZE);
|
||||
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
{
|
||||
let mut flags =
|
||||
PageTableFlags::PRESENT | PageTableFlags::USER_ACCESSIBLE | PageTableFlags::WRITABLE;
|
||||
|
||||
@@ -313,27 +312,24 @@ pub fn load_segment_to_memory(
|
||||
flags |= PageTableFlags::NO_EXECUTE;
|
||||
}
|
||||
|
||||
let start_page: Page<Size4KiB> = Page::containing_address(VirtAddr::new(seg_start));
|
||||
let end_page: Page<Size4KiB> = Page::containing_address(VirtAddr::new(seg_end - 1));
|
||||
let page_range = Page::range_inclusive(start_page, end_page);
|
||||
let map_start = seg_start;
|
||||
let page_count = (seg_end - seg_start) / 4096;
|
||||
|
||||
let mut frame_allocator = FRAME_ALLOCATOR.lock();
|
||||
|
||||
for page in page_range {
|
||||
let frame = frame_allocator
|
||||
.allocate_frame()
|
||||
.ok_or(MapToError::<Size4KiB>::FrameAllocationFailed)
|
||||
.expect("test");
|
||||
unsafe {
|
||||
mapper
|
||||
.map_to(page, frame, flags, &mut *frame_allocator)
|
||||
.map_err(|e| e)
|
||||
.expect("test")
|
||||
.flush();
|
||||
create_and_map_multiple_pages(mapper, page_count, map_start, flags);
|
||||
}
|
||||
#[cfg(target_arch = "aarch64")]
|
||||
{
|
||||
let mut flags = user_code_flags();
|
||||
|
||||
if unsafe { ((*phdr).p_flags & PF_X) == 0 } {
|
||||
flags |= UXN;
|
||||
}
|
||||
|
||||
drop(frame_allocator);
|
||||
let map_start = seg_start;
|
||||
let page_count = (seg_end - seg_start) / 4096;
|
||||
|
||||
create_and_map_multiple_pages(mapper, page_count, map_start, flags);
|
||||
}
|
||||
|
||||
let dst = (mem_page + page_off) as *mut u8;
|
||||
let src = unsafe { elf_bytes.as_ptr().add(p_offset as usize) };
|
||||
|
||||
@@ -141,6 +141,7 @@ pub fn vfs_close(fd: Fd) -> i32 {
|
||||
}
|
||||
|
||||
#[unsafe(no_mangle)]
|
||||
#[allow(unused_variables)]
|
||||
pub fn vfs_write(ptr: *mut u8, size: usize, count: usize, fp: *mut FILE) -> usize {
|
||||
if ptr.is_null() || fp.is_null() || unsafe { (*fp).fd < 0 || (*fp).fd >= 16 } {
|
||||
return 0;
|
||||
|
||||
@@ -33,7 +33,6 @@ impl Framebuffer {
|
||||
let width = limine_fb.width() as usize;
|
||||
let height = limine_fb.height() as usize;
|
||||
let pitch = limine_fb.pitch() as usize / 4;
|
||||
|
||||
Framebuffer {
|
||||
addr: limine_fb.addr().cast::<u32>(),
|
||||
width,
|
||||
@@ -55,7 +54,7 @@ impl Framebuffer {
|
||||
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
pub fn setup_x86_64(&mut self) {
|
||||
use crate::arch::arch::FRAME_ALLOCATOR;
|
||||
use crate::arch::arch::{FRAME_ALLOCATOR, HHDM_OFFSET};
|
||||
use x86_64::structures::paging::{FrameAllocator, PhysFrame, Size4KiB};
|
||||
let buf_len = self.pitch * self.height;
|
||||
let byte_len = buf_len * core::mem::size_of::<u32>();
|
||||
@@ -66,7 +65,8 @@ impl Framebuffer {
|
||||
let struct_frame: PhysFrame<Size4KiB> =
|
||||
fa.allocate_frame().expect("framebuffer struct frame");
|
||||
let struct_phys = struct_frame.start_address().as_u64();
|
||||
let struct_virt = (struct_phys + fa.hhdm_offset) as *mut UserFrameBuffer;
|
||||
let hhdm_offset = HHDM_OFFSET.load(core::sync::atomic::Ordering::Relaxed);
|
||||
let struct_virt = (struct_phys + hhdm_offset) as *mut UserFrameBuffer;
|
||||
|
||||
let first_pixel_frame: PhysFrame<Size4KiB> =
|
||||
fa.allocate_frame().expect("framebuffer pixel frame 0");
|
||||
@@ -74,7 +74,44 @@ impl Framebuffer {
|
||||
for _ in 1..pixel_frames {
|
||||
fa.allocate_frame().expect("framebuffer pixel frame");
|
||||
}
|
||||
let buf_virt_kernel = (buf_phys + fa.hhdm_offset) as *mut u32;
|
||||
let buf_virt_kernel = (buf_phys + hhdm_offset) as *mut u32;
|
||||
drop(fa);
|
||||
|
||||
unsafe { core::ptr::write_bytes(buf_virt_kernel, 0, buf_len) };
|
||||
|
||||
unsafe {
|
||||
struct_virt.write(UserFrameBuffer {
|
||||
buf_virt: (USER_FB_BASE + 0x1000) as *mut u32,
|
||||
width: self.width,
|
||||
height: self.height,
|
||||
pitch: self.pitch,
|
||||
});
|
||||
};
|
||||
|
||||
self.user_fb.buf_virt = buf_virt_kernel;
|
||||
self.meta.buf_phys = buf_phys;
|
||||
self.meta.buf_len = buf_len;
|
||||
self.meta.struct_phys = struct_phys;
|
||||
}
|
||||
|
||||
#[cfg(target_arch = "aarch64")]
|
||||
pub fn setup_aarch64(&mut self) {
|
||||
let hhdm_offset = HHDM_OFFSET.load(core::sync::atomic::Ordering::Relaxed);
|
||||
use crate::arch::arch::{FRAME_ALLOCATOR, HHDM_OFFSET};
|
||||
let buf_len = self.pitch * self.height;
|
||||
let byte_len = buf_len * core::mem::size_of::<u32>();
|
||||
let pixel_frames = (byte_len + 4095) / 4096;
|
||||
|
||||
let mut fa = safe_lock(|| FRAME_ALLOCATOR.lock());
|
||||
|
||||
let struct_phys: u64 = fa.allocate_frame().expect("framebuffer struct frame");
|
||||
let struct_virt = (struct_phys + hhdm_offset) as *mut UserFrameBuffer;
|
||||
|
||||
let buf_phys: u64 = fa.allocate_frame().expect("framebuffer pixel frame 0");
|
||||
for _ in 1..pixel_frames {
|
||||
fa.allocate_frame().expect("framebuffer pixel frame");
|
||||
}
|
||||
let buf_virt_kernel = (buf_phys + hhdm_offset) as *mut u32;
|
||||
drop(fa);
|
||||
|
||||
unsafe { core::ptr::write_bytes(buf_virt_kernel, 0, buf_len) };
|
||||
|
||||
+74
-8
@@ -7,8 +7,8 @@ use core::fmt::Write;
|
||||
|
||||
use limine::BaseRevision;
|
||||
use limine::request::{
|
||||
DateAtBootRequest, FramebufferRequest, HhdmRequest, MemoryMapRequest, RequestsEndMarker,
|
||||
RequestsStartMarker,
|
||||
DateAtBootRequest, ExecutableAddressRequest, FramebufferRequest, HhdmRequest, MemoryMapRequest,
|
||||
RequestsEndMarker, RequestsStartMarker,
|
||||
};
|
||||
pub mod arch;
|
||||
pub mod driver;
|
||||
@@ -16,17 +16,23 @@ pub mod mm;
|
||||
pub mod task;
|
||||
pub mod util;
|
||||
|
||||
use crate::arch::arch::{infinite_idle, init, kernel_crash, run_elf};
|
||||
use crate::arch::arch::{HHDM_OFFSET, infinite_idle, init, kernel_crash, serial_print};
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
use crate::driver::elf::loader::run_elf;
|
||||
use crate::driver::graphics::base::rgb;
|
||||
use crate::driver::graphics::framebuffer::{init_framebuffer, with_framebuffer};
|
||||
#[cfg(target_arch = "aarch64")]
|
||||
use crate::driver::graphics::primitives::rectangle_filled;
|
||||
use crate::driver::keyboard::init_keyboard;
|
||||
use crate::driver::serial::{ConsoleWriter, init_serial_console, with_serial_console};
|
||||
use crate::driver::timer::TIMER;
|
||||
use crate::util::serial_print;
|
||||
|
||||
#[repr(C, align(16))]
|
||||
#[allow(dead_code)]
|
||||
struct AlignedElf([u8; include_bytes!("../../assets/init").len()]);
|
||||
#[allow(dead_code)]
|
||||
static INIT_ELF: AlignedElf = AlignedElf(*include_bytes!("../../assets/init"));
|
||||
#[allow(dead_code)]
|
||||
static INIT_ELF_BYTES: &[u8] = &INIT_ELF.0;
|
||||
|
||||
/// Sets the base revision to the latest revision supported by the crate.
|
||||
@@ -53,6 +59,10 @@ static MEMORY_MAP_REQUEST: MemoryMapRequest = MemoryMapRequest::new();
|
||||
#[unsafe(link_section = ".requests")]
|
||||
static DATE_AT_BOOT_REQUEST: DateAtBootRequest = DateAtBootRequest::new();
|
||||
|
||||
#[used]
|
||||
#[unsafe(link_section = ".requests")]
|
||||
static EXECUTABLE_ADDRESS_REQUEST: ExecutableAddressRequest = ExecutableAddressRequest::new();
|
||||
|
||||
/// Define the stand and end markers for Limine requests.
|
||||
#[used]
|
||||
#[unsafe(link_section = ".requests_start_marker")]
|
||||
@@ -99,8 +109,24 @@ unsafe extern "C" fn kmain() -> ! {
|
||||
assert!(BASE_REVISION.is_supported());
|
||||
|
||||
if let Some(hhdm_response) = HHDM_REQUEST.get_response() {
|
||||
HHDM_OFFSET.store(
|
||||
hhdm_response.offset(),
|
||||
core::sync::atomic::Ordering::Relaxed,
|
||||
);
|
||||
if let Some(memory_map_response) = MEMORY_MAP_REQUEST.get_response() {
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
init(hhdm_response, memory_map_response);
|
||||
|
||||
#[cfg(target_arch = "aarch64")]
|
||||
if let Some(executable_address_response) = EXECUTABLE_ADDRESS_REQUEST.get_response() {
|
||||
init(
|
||||
hhdm_response,
|
||||
memory_map_response,
|
||||
executable_address_response,
|
||||
);
|
||||
} else {
|
||||
kernel_crash()
|
||||
}
|
||||
} else {
|
||||
kernel_crash(); // Could not get required info from Limine's memory map.
|
||||
}
|
||||
@@ -113,6 +139,10 @@ unsafe extern "C" fn kmain() -> ! {
|
||||
init_framebuffer(&limine_framebuffer);
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
with_framebuffer(|fb| fb.setup_x86_64());
|
||||
#[cfg(target_arch = "aarch64")]
|
||||
with_framebuffer(|fb| fb.setup_aarch64());
|
||||
} else {
|
||||
serial_print("no framebuffers found");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -126,20 +156,56 @@ unsafe extern "C" fn kmain() -> ! {
|
||||
println!("Could not get date at boot. Will default to 0.")
|
||||
}
|
||||
|
||||
#[cfg(target_arch = "aarch64")]
|
||||
{
|
||||
println!("Hello from Aarch64!");
|
||||
with_framebuffer(|fb| {
|
||||
with_serial_console(|sc| sc.render(fb));
|
||||
rectangle_filled(fb, 100, 100, 20, 20, rgb(255, 255, 255));
|
||||
fb.present();
|
||||
});
|
||||
}
|
||||
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
run_elf(INIT_ELF_BYTES, false);
|
||||
|
||||
loop {}
|
||||
}
|
||||
|
||||
struct BufWriter<'a> {
|
||||
buf: &'a mut [u8],
|
||||
pos: usize,
|
||||
}
|
||||
|
||||
impl<'a> BufWriter<'a> {
|
||||
fn new(buf: &'a mut [u8]) -> Self {
|
||||
Self { buf, pos: 0 }
|
||||
}
|
||||
}
|
||||
|
||||
impl core::fmt::Write for BufWriter<'_> {
|
||||
fn write_str(&mut self, s: &str) -> core::fmt::Result {
|
||||
let bytes = s.as_bytes();
|
||||
let remaining = &mut self.buf[self.pos..];
|
||||
let len = bytes.len().min(remaining.len());
|
||||
remaining[..len].copy_from_slice(&bytes[..len]);
|
||||
self.pos += len;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
#[panic_handler]
|
||||
fn rust_panic(_info: &core::panic::PanicInfo) -> ! {
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
{
|
||||
serial_print("\nKERNEL PANIC:\n");
|
||||
serial_print(_info.message().as_str().unwrap());
|
||||
let mut buf = [0u8; 512];
|
||||
let msg = {
|
||||
let mut w = BufWriter::new(&mut buf);
|
||||
let _ = core::fmt::write(&mut w, core::format_args!("{}", _info.message()));
|
||||
let len = w.pos;
|
||||
core::str::from_utf8(&buf[..len]).unwrap_or("(utf8 error)")
|
||||
};
|
||||
serial_print(msg);
|
||||
serial_print("\n");
|
||||
}
|
||||
with_framebuffer(|mut fb| {
|
||||
fb.clear(rgb(180, 0, 0));
|
||||
|
||||
|
||||
@@ -2,19 +2,34 @@
|
||||
use x86_64::{
|
||||
PhysAddr, VirtAddr,
|
||||
registers::control::{Cr3, Cr3Flags},
|
||||
structures::paging::{FrameAllocator, OffsetPageTable, PageTable, PhysFrame, Size4KiB},
|
||||
structures::paging::{
|
||||
FrameAllocator, OffsetPageTable, PageTable as X86PageTable, PhysFrame, Size4KiB,
|
||||
},
|
||||
};
|
||||
|
||||
use crate::arch::arch::FRAME_ALLOCATOR;
|
||||
#[cfg(target_arch = "aarch64")]
|
||||
use crate::arch::aarch64::paging::{AArchPageTable, tlb_flush};
|
||||
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
use crate::arch::arch::{FRAME_ALLOCATOR, HHDM_OFFSET};
|
||||
|
||||
#[cfg(target_arch = "aarch64")]
|
||||
type PageTable = AArchPageTable;
|
||||
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
type PageTable<'a> = OffsetPageTable<'a>;
|
||||
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
pub struct AddressSpace {
|
||||
cr3_frame: PhysFrame<Size4KiB>,
|
||||
pub mapper: OffsetPageTable<'static>,
|
||||
pub mapper: PageTable<'static>,
|
||||
}
|
||||
|
||||
#[cfg(target_arch = "aarch64")]
|
||||
pub struct AddressSpace {}
|
||||
pub struct AddressSpace {
|
||||
ttbr0_phys: u64,
|
||||
pub mapper: PageTable,
|
||||
}
|
||||
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
impl AddressSpace {
|
||||
@@ -22,19 +37,17 @@ impl AddressSpace {
|
||||
let mut frame_allocator = FRAME_ALLOCATOR.lock();
|
||||
let new_pml4 = frame_allocator.allocate_frame()?;
|
||||
|
||||
let hhdm_offset = HHDM_OFFSET.load(core::sync::atomic::Ordering::Relaxed);
|
||||
unsafe {
|
||||
let new_pml4_ptr =
|
||||
(frame_allocator.hhdm_offset + new_pml4.start_address().as_u64()) as *mut u64;
|
||||
let new_pml4_ptr = (hhdm_offset + new_pml4.start_address().as_u64()) as *mut u64;
|
||||
core::ptr::write_bytes(new_pml4_ptr, 0, 512);
|
||||
}
|
||||
|
||||
let (cur_pml4, _) = Cr3::read();
|
||||
|
||||
unsafe {
|
||||
let cur_pml4_ptr =
|
||||
physical_to_virt_pointer(cur_pml4.start_address(), frame_allocator.hhdm_offset);
|
||||
let new_pml4_ptr =
|
||||
physical_to_virt_pointer(new_pml4.start_address(), frame_allocator.hhdm_offset);
|
||||
let cur_pml4_ptr = physical_to_virt_pointer(cur_pml4.start_address());
|
||||
let new_pml4_ptr = physical_to_virt_pointer(new_pml4.start_address());
|
||||
|
||||
for i in 256..512 {
|
||||
let val = core::ptr::read(cur_pml4_ptr.add(i));
|
||||
@@ -43,13 +56,10 @@ impl AddressSpace {
|
||||
}
|
||||
|
||||
let mapper = unsafe {
|
||||
let addr = frame_allocator.hhdm_offset + new_pml4.start_address().as_u64();
|
||||
let addr = hhdm_offset + new_pml4.start_address().as_u64();
|
||||
let virtual_addr = VirtAddr::new(addr);
|
||||
let level_4_table: *mut PageTable = virtual_addr.as_mut_ptr();
|
||||
OffsetPageTable::new(
|
||||
&mut *level_4_table,
|
||||
VirtAddr::new(frame_allocator.hhdm_offset),
|
||||
)
|
||||
let level_4_table: *mut X86PageTable = virtual_addr.as_mut_ptr();
|
||||
OffsetPageTable::new(&mut *level_4_table, VirtAddr::new(hhdm_offset))
|
||||
};
|
||||
|
||||
drop(frame_allocator);
|
||||
@@ -65,7 +75,31 @@ impl AddressSpace {
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(target_arch = "aarch64")]
|
||||
impl AddressSpace {
|
||||
pub fn new() -> Option<AddressSpace> {
|
||||
let page_table = AArchPageTable::new();
|
||||
let ttbr0_phys = page_table.root_phys;
|
||||
Some(AddressSpace {
|
||||
ttbr0_phys,
|
||||
mapper: page_table,
|
||||
})
|
||||
}
|
||||
pub fn use_address_space(&mut self) {
|
||||
unsafe {
|
||||
core::arch::asm!(
|
||||
"msr ttbr0_el1, {root}",
|
||||
"isb",
|
||||
root = in(reg) self.ttbr0_phys
|
||||
);
|
||||
}
|
||||
|
||||
tlb_flush();
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
pub unsafe fn physical_to_virt_pointer(phys_addr: PhysAddr, hhdm_offset: u64) -> *mut u64 {
|
||||
pub unsafe fn physical_to_virt_pointer(phys_addr: PhysAddr) -> *mut u64 {
|
||||
let hhdm_offset = HHDM_OFFSET.load(core::sync::atomic::Ordering::Relaxed);
|
||||
(hhdm_offset + phys_addr.as_u64()) as *mut u64
|
||||
}
|
||||
|
||||
@@ -9,17 +9,29 @@ use x86_64::{
|
||||
structures::paging::{OffsetPageTable, PageTableFlags, Translate, mapper::TranslateResult},
|
||||
};
|
||||
|
||||
#[cfg(target_arch = "aarch64")]
|
||||
use crate::arch::aarch64::paging::AArchPageTable;
|
||||
|
||||
#[cfg(target_arch = "aarch64")]
|
||||
type PageTable = AArchPageTable;
|
||||
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
type PageTable<'a> = OffsetPageTable<'a>;
|
||||
|
||||
#[allow(unused_variables)]
|
||||
pub fn copy_to_user(
|
||||
mapper: &mut OffsetPageTable,
|
||||
mapper: &mut PageTable,
|
||||
buf: *mut u8,
|
||||
src: *const u8,
|
||||
len: usize,
|
||||
) -> Result<(), isize> {
|
||||
let start = buf as u64;
|
||||
let end = start + len as u64;
|
||||
#[allow(unused_mut)]
|
||||
let mut page_addr = start & !0xFFF;
|
||||
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
{
|
||||
while page_addr < end {
|
||||
let translate_result = mapper.translate(VirtAddr::new(page_addr));
|
||||
#[allow(non_shorthand_field_patterns)]
|
||||
@@ -42,12 +54,20 @@ pub fn copy_to_user(
|
||||
}
|
||||
|
||||
unsafe { core::ptr::copy_nonoverlapping(src, buf, len) };
|
||||
}
|
||||
|
||||
#[cfg(target_arch = "aarch64")]
|
||||
{
|
||||
// TODO: add checks
|
||||
unsafe { core::ptr::copy_nonoverlapping(src, buf, len) };
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
#[allow(unused_variables)]
|
||||
pub fn copy_from_user(
|
||||
mapper: &mut OffsetPageTable,
|
||||
mapper: &mut PageTable,
|
||||
buf: *mut u8,
|
||||
src: *const u8,
|
||||
len: usize,
|
||||
@@ -64,9 +84,11 @@ pub fn copy_from_user(
|
||||
.checked_add(len as u64)
|
||||
.ok_or(-1)
|
||||
.map_err(|err| err as isize)?;
|
||||
|
||||
#[allow(unused_mut)]
|
||||
let mut page_addr = start & !0xFFF;
|
||||
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
{
|
||||
while page_addr < end {
|
||||
let translate_result = mapper.translate(VirtAddr::new(page_addr));
|
||||
#[allow(non_shorthand_field_patterns)]
|
||||
@@ -86,12 +108,19 @@ pub fn copy_from_user(
|
||||
}
|
||||
|
||||
unsafe { core::ptr::copy_nonoverlapping(src, buf, len) };
|
||||
}
|
||||
|
||||
#[cfg(target_arch = "aarch64")]
|
||||
{
|
||||
// TODO: add checks
|
||||
unsafe { core::ptr::copy_nonoverlapping(src, buf, len) };
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
pub fn copy_cstr_from_user(
|
||||
mapper: &mut OffsetPageTable,
|
||||
mapper: &mut PageTable,
|
||||
user_ptr: *const u8,
|
||||
max_len: usize,
|
||||
) -> Result<String, isize> {
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
use crate::task::scheduler::{SCHEDULER, current_pid};
|
||||
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
#[repr(C)]
|
||||
#[derive(Clone, Copy)]
|
||||
pub struct UserContext {
|
||||
@@ -22,6 +23,11 @@ pub struct UserContext {
|
||||
pub rsp: u64, // user rsp
|
||||
}
|
||||
|
||||
#[cfg(target_arch = "aarch64")]
|
||||
#[repr(C)]
|
||||
#[derive(Clone, Copy)]
|
||||
pub struct UserContext {}
|
||||
|
||||
#[unsafe(no_mangle)]
|
||||
pub extern "C" fn ctx_save(regs: *const UserContext) {
|
||||
if let Some(pid) = current_pid() {
|
||||
|
||||
@@ -86,7 +86,6 @@ impl Locked<Scheduler> {
|
||||
};
|
||||
}
|
||||
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
pub fn switch_to(&self, pid: u64, should_swapgs: bool) {
|
||||
let (ctx_opt, entry, stack_top) = {
|
||||
let mut guard = safe_lock(|| self.lock());
|
||||
@@ -117,7 +116,9 @@ impl Locked<Scheduler> {
|
||||
set_current_pid(Some(pid));
|
||||
|
||||
match ctx_opt {
|
||||
#[allow(unused_variables, unused_unsafe)]
|
||||
Some(saved_ctx) => unsafe {
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
run_next((&saved_ctx) as *const UserContext, saved_ctx.rsp)
|
||||
},
|
||||
None => enter_usermode(entry as u64, (stack_top & !0xF) - 8, should_swapgs),
|
||||
@@ -163,3 +164,11 @@ unsafe fn run_next(ctx: *const UserContext, user_rsp: u64) {
|
||||
"sysretq",
|
||||
);
|
||||
}
|
||||
|
||||
#[cfg(target_arch = "aarch64")]
|
||||
#[unsafe(naked)]
|
||||
#[unsafe(no_mangle)]
|
||||
unsafe fn run_next(ctx: *const UserContext, user_rsp: u64) {
|
||||
// TODO: add switching logic
|
||||
core::arch::naked_asm!("udf #0");
|
||||
}
|
||||
|
||||
@@ -5,20 +5,6 @@ pub struct Locked<A> {
|
||||
inner: Mutex<A>,
|
||||
}
|
||||
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
pub fn serial_print_byte(b: u8) {
|
||||
unsafe {
|
||||
core::arch::asm!("out dx, al", in("dx") 0x3F8u16, in("al") b);
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
pub fn serial_print(s: &str) {
|
||||
for &b in s.as_bytes() {
|
||||
serial_print_byte(b);
|
||||
}
|
||||
}
|
||||
|
||||
impl<A> Locked<A> {
|
||||
pub const fn new(inner: A) -> Self {
|
||||
Locked {
|
||||
|
||||
+1
-1
Submodule user/libxunil updated: da6f056359...695da84901
Reference in New Issue
Block a user