mirror of
https://github.com/XunilGroup/XunilOS.git
synced 2026-04-25 11:49:03 +02:00
Add ET_EXEC ELF loading and validation, and a non-working ET_REL
implementation, running support, also basic syscalls to test if it works. add a syscall ABI and a new libxunil ABI for calling back to the kernel with syscalls, add user mode protection when running ELF, add TSS Privilege Stack table to fix GPF issues, add invalid opcode handler, fix rust panics using rectangle_filled instead of fb clear. Also add a hello world example binary that runs in usermode at startup.
This commit is contained in:
@@ -1,9 +1,14 @@
|
||||
use crate::driver::timer::TIMER;
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
use core::alloc::GlobalAlloc;
|
||||
use core::arch::asm;
|
||||
use limine::response::{HhdmResponse, MemoryMapResponse};
|
||||
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
use crate::arch::x86_64::{init::init_x86_64, paging::XunilFrameAllocator};
|
||||
use crate::arch::x86_64::{
|
||||
elf::run_elf_x86_64, heap::ALLOCATOR, init::init_x86_64, paging::XunilFrameAllocator,
|
||||
usermode::enter_usermode_x86_64,
|
||||
};
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
use x86_64::structures::paging::OffsetPageTable;
|
||||
|
||||
@@ -15,6 +20,24 @@ pub fn init<'a>(
|
||||
return init_x86_64(hhdm_response, memory_map_response);
|
||||
}
|
||||
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
pub fn enter_usermode(user_rip: u64, user_rsp: u64) {
|
||||
return enter_usermode_x86_64(user_rip, user_rsp);
|
||||
}
|
||||
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
pub fn run_elf(
|
||||
entry_point: *const u8,
|
||||
frame_allocator: &mut XunilFrameAllocator,
|
||||
mapper: &mut OffsetPageTable,
|
||||
) {
|
||||
run_elf_x86_64(entry_point, frame_allocator, mapper);
|
||||
}
|
||||
|
||||
pub fn get_allocator<'a>() -> &'static impl GlobalAlloc {
|
||||
return &ALLOCATOR;
|
||||
}
|
||||
|
||||
pub fn idle() {
|
||||
unsafe {
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
|
||||
47
kernel/src/arch/x86_64/elf.rs
Normal file
47
kernel/src/arch/x86_64/elf.rs
Normal file
@@ -0,0 +1,47 @@
|
||||
use alloc::vec::Vec;
|
||||
use x86_64::{
|
||||
VirtAddr,
|
||||
structures::paging::{
|
||||
FrameAllocator, Mapper, OffsetPageTable, Page, PageTableFlags, PhysFrame, Size4KiB,
|
||||
},
|
||||
};
|
||||
|
||||
use crate::arch::x86_64::{paging::XunilFrameAllocator, usermode::enter_usermode_x86_64};
|
||||
|
||||
pub fn run_elf_x86_64(
|
||||
entry_point: *const u8,
|
||||
frame_allocator: &mut XunilFrameAllocator,
|
||||
mapper: &mut OffsetPageTable,
|
||||
) {
|
||||
let stack_base: u64 = 0x0000_7fff_0000_0000;
|
||||
let page_count = 3;
|
||||
let page_size = 0x1000u64;
|
||||
|
||||
let mut frames: Vec<PhysFrame<Size4KiB>> = Vec::new();
|
||||
for i in 0..page_count {
|
||||
let frame = frame_allocator.allocate_frame().unwrap();
|
||||
frames.push(frame);
|
||||
|
||||
let virt_addr = VirtAddr::new(stack_base + i as u64 * page_size);
|
||||
let page = Page::<Size4KiB>::containing_address(virt_addr);
|
||||
|
||||
unsafe {
|
||||
mapper
|
||||
.map_to(
|
||||
page,
|
||||
frame,
|
||||
PageTableFlags::PRESENT
|
||||
| PageTableFlags::WRITABLE
|
||||
| PageTableFlags::USER_ACCESSIBLE,
|
||||
frame_allocator,
|
||||
)
|
||||
.unwrap()
|
||||
.flush();
|
||||
}
|
||||
}
|
||||
|
||||
let stack_top = stack_base + (page_count as u64 * page_size);
|
||||
let rsp = (stack_top & !0xF) - 8;
|
||||
|
||||
enter_usermode_x86_64(entry_point as u64, rsp);
|
||||
}
|
||||
@@ -9,12 +9,6 @@ use x86_64::structures::{
|
||||
|
||||
pub const DOUBLE_FAULT_IST_INDEX: u16 = 0;
|
||||
|
||||
struct Selectors {
|
||||
code_selector: SegmentSelector,
|
||||
data_selector: SegmentSelector,
|
||||
tss_selector: SegmentSelector,
|
||||
}
|
||||
|
||||
lazy_static! {
|
||||
static ref TSS: TaskStateSegment = {
|
||||
let mut tss = TaskStateSegment::new();
|
||||
@@ -26,23 +20,44 @@ lazy_static! {
|
||||
let stack_end = stack_start + STACK_SIZE as u64;
|
||||
stack_end
|
||||
};
|
||||
tss.privilege_stack_table[0] = {
|
||||
const STACK_SIZE: usize = 4096 * 5;
|
||||
static mut STACK: [u8; STACK_SIZE] = [0; STACK_SIZE];
|
||||
|
||||
let stack_start = VirtAddr::from_ptr(&raw const STACK);
|
||||
let stack_end = stack_start + STACK_SIZE as u64;
|
||||
stack_end
|
||||
};
|
||||
tss
|
||||
};
|
||||
}
|
||||
|
||||
lazy_static! {
|
||||
static ref GDT: (GlobalDescriptorTable, Selectors) = {
|
||||
pub static ref GDT: (
|
||||
GlobalDescriptorTable,
|
||||
(
|
||||
SegmentSelector,
|
||||
SegmentSelector,
|
||||
SegmentSelector,
|
||||
SegmentSelector,
|
||||
SegmentSelector
|
||||
)
|
||||
) = {
|
||||
let mut gdt = GlobalDescriptorTable::new();
|
||||
let code_selector = gdt.append(Descriptor::kernel_code_segment());
|
||||
let data_selector = gdt.append(Descriptor::kernel_data_segment());
|
||||
let kernel_code_selector = gdt.append(Descriptor::kernel_code_segment());
|
||||
let kernel_data_selector = gdt.append(Descriptor::kernel_data_segment());
|
||||
let user_code_selector = gdt.append(Descriptor::user_code_segment());
|
||||
let user_data_selector = gdt.append(Descriptor::user_data_segment());
|
||||
let tss_selector = gdt.append(Descriptor::tss_segment(&TSS));
|
||||
(
|
||||
gdt,
|
||||
Selectors {
|
||||
code_selector,
|
||||
data_selector,
|
||||
(
|
||||
kernel_code_selector,
|
||||
kernel_data_selector,
|
||||
user_code_selector,
|
||||
user_data_selector,
|
||||
tss_selector,
|
||||
},
|
||||
),
|
||||
)
|
||||
};
|
||||
}
|
||||
@@ -51,10 +66,18 @@ pub fn load_gdt_x86_64() {
|
||||
GDT.0.load();
|
||||
|
||||
unsafe {
|
||||
CS::set_reg(GDT.1.code_selector);
|
||||
DS::set_reg(GDT.1.data_selector);
|
||||
ES::set_reg(GDT.1.data_selector);
|
||||
SS::set_reg(GDT.1.data_selector);
|
||||
load_tss(GDT.1.tss_selector);
|
||||
CS::set_reg(GDT.1.0);
|
||||
DS::set_reg(GDT.1.1);
|
||||
ES::set_reg(GDT.1.1);
|
||||
SS::set_reg(GDT.1.1);
|
||||
load_tss(GDT.1.4);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn user_code_selector() -> SegmentSelector {
|
||||
GDT.1.2
|
||||
}
|
||||
|
||||
pub fn user_data_selector() -> SegmentSelector {
|
||||
GDT.1.3
|
||||
}
|
||||
|
||||
@@ -17,7 +17,7 @@ fn align_up(addr: usize, align: usize) -> usize {
|
||||
}
|
||||
|
||||
#[global_allocator]
|
||||
static ALLOCATOR: Locked<LinkedListAllocator> = Locked::new(LinkedListAllocator::new());
|
||||
pub static ALLOCATOR: Locked<LinkedListAllocator> = Locked::new(LinkedListAllocator::new());
|
||||
|
||||
pub const HEAP_START: usize = 0x_4444_4444_0000;
|
||||
pub const HEAP_SIZE: usize = 256 * 1024 * 1024; // 256 MiB
|
||||
|
||||
@@ -12,6 +12,7 @@ use pc_keyboard::DecodedKey;
|
||||
use pic8259::ChainedPics;
|
||||
use spin::Mutex;
|
||||
use x86_64::{
|
||||
VirtAddr,
|
||||
instructions::port::Port,
|
||||
registers::control::Cr2,
|
||||
structures::idt::{InterruptDescriptorTable, InterruptStackFrame, PageFaultErrorCode},
|
||||
@@ -48,12 +49,17 @@ lazy_static! {
|
||||
idt.double_fault
|
||||
.set_handler_fn(double_fault_handler)
|
||||
.set_stack_index(gdt::DOUBLE_FAULT_IST_INDEX);
|
||||
#[allow(function_casts_as_integer)]
|
||||
idt[0x80]
|
||||
.set_handler_addr(VirtAddr::new(syscall_interrupt_handler as u64))
|
||||
.set_privilege_level(x86_64::PrivilegeLevel::Ring3);
|
||||
}
|
||||
idt[InterruptIndex::Timer.as_u8()].set_handler_fn(timer_interrupt_handler);
|
||||
idt.page_fault.set_handler_fn(page_fault_handler);
|
||||
idt.general_protection_fault.set_handler_fn(gpf_handler);
|
||||
idt[InterruptIndex::Keyboard.as_u8()].set_handler_fn(keyboard_interrupt_handler);
|
||||
idt[InterruptIndex::Mouse.as_u8()].set_handler_fn(mouse_interrupt_handler);
|
||||
idt.invalid_opcode.set_handler_fn(invalid_opcode_handler);
|
||||
idt
|
||||
};
|
||||
}
|
||||
@@ -92,6 +98,10 @@ pub extern "x86-interrupt" fn gpf_handler(stack_frame: InterruptStackFrame, erro
|
||||
);
|
||||
}
|
||||
|
||||
pub extern "x86-interrupt" fn invalid_opcode_handler(stack_frame: InterruptStackFrame) {
|
||||
panic!("EXCEPTION: INVALID OPCODE\n{:#?}", stack_frame);
|
||||
}
|
||||
|
||||
extern "x86-interrupt" fn timer_interrupt_handler(_stack_frame: InterruptStackFrame) {
|
||||
TIMER.interrupt();
|
||||
|
||||
@@ -143,3 +153,49 @@ pub extern "x86-interrupt" fn keyboard_interrupt_handler(_stack_frame: Interrupt
|
||||
.notify_end_of_interrupt(InterruptIndex::Keyboard.as_u8());
|
||||
}
|
||||
}
|
||||
|
||||
#[unsafe(naked)]
|
||||
unsafe extern "C" fn syscall_interrupt_handler() {
|
||||
core::arch::naked_asm!(
|
||||
// push all registers
|
||||
"push r15",
|
||||
"push r14",
|
||||
"push r13",
|
||||
"push r12",
|
||||
"push r11",
|
||||
"push r10",
|
||||
"push r9",
|
||||
"push r8",
|
||||
"push rbp",
|
||||
"push rbx",
|
||||
"push rcx",
|
||||
"push rdx",
|
||||
"push rsi",
|
||||
"push rdi",
|
||||
"push rax",
|
||||
"sub rsp, 8",
|
||||
"mov rcx, rdx", // arg2
|
||||
"mov rdx, rsi", // arg1
|
||||
"mov rsi, rdi", // arg0
|
||||
"mov rdi, rax", // num
|
||||
"call syscall_dispatch",
|
||||
"add rsp, 8",
|
||||
"add rsp, 8",
|
||||
// pop them in reverse orser
|
||||
"pop rbx",
|
||||
"pop rcx",
|
||||
"pop rdx",
|
||||
"pop rsi",
|
||||
"pop rdi",
|
||||
"pop rbp",
|
||||
"pop r8",
|
||||
"pop r9",
|
||||
"pop r10",
|
||||
"pop r11",
|
||||
"pop r12",
|
||||
"pop r13",
|
||||
"pop r14",
|
||||
"pop r15",
|
||||
"iretq",
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
pub mod elf;
|
||||
pub mod gdt;
|
||||
pub mod heap;
|
||||
pub mod init;
|
||||
pub mod interrupts;
|
||||
pub mod mouse;
|
||||
pub mod paging;
|
||||
pub mod usermode;
|
||||
|
||||
42
kernel/src/arch/x86_64/usermode.rs
Normal file
42
kernel/src/arch/x86_64/usermode.rs
Normal file
@@ -0,0 +1,42 @@
|
||||
use x86_64::{
|
||||
registers::segmentation::{DS, ES, Segment},
|
||||
structures::gdt::SegmentSelector,
|
||||
};
|
||||
|
||||
use crate::arch::x86_64::gdt::{user_code_selector, user_data_selector};
|
||||
|
||||
fn with_rpl3(ss: SegmentSelector) -> u64 {
|
||||
(ss.0 as u64) | 3
|
||||
}
|
||||
|
||||
// entry point and stack
|
||||
pub fn enter_usermode_x86_64(user_rip: u64, user_rsp: u64) -> ! {
|
||||
let user_cs = with_rpl3(user_code_selector());
|
||||
let user_ss = with_rpl3(user_data_selector());
|
||||
|
||||
unsafe {
|
||||
DS::set_reg(user_data_selector());
|
||||
ES::set_reg(user_data_selector());
|
||||
}
|
||||
|
||||
let rflags: u64 = 0x202;
|
||||
|
||||
unsafe {
|
||||
core::arch::asm!(
|
||||
"cli",
|
||||
"push {user_ss}",
|
||||
"push {user_rsp}",
|
||||
"push {rflags}",
|
||||
"push {user_cs}",
|
||||
"push {user_rip}",
|
||||
"iretq",
|
||||
|
||||
user_ss = in(reg) user_ss,
|
||||
user_rsp = in(reg) user_rsp,
|
||||
rflags = in(reg) rflags,
|
||||
user_cs = in(reg) user_cs,
|
||||
user_rip = in(reg) user_rip,
|
||||
options(noreturn)
|
||||
);
|
||||
}
|
||||
}
|
||||
175
kernel/src/driver/elf/header.rs
Normal file
175
kernel/src/driver/elf/header.rs
Normal file
@@ -0,0 +1,175 @@
|
||||
// this is not made by me, but AI, im not going to type these out...
|
||||
|
||||
// e_ident indices
|
||||
pub const EI_MAG0: usize = 0;
|
||||
pub const EI_MAG1: usize = 1;
|
||||
pub const EI_MAG2: usize = 2;
|
||||
pub const EI_MAG3: usize = 3;
|
||||
pub const EI_CLASS: usize = 4;
|
||||
pub const EI_DATA: usize = 5;
|
||||
pub const EI_VERSION: usize = 6;
|
||||
pub const EI_OSABI: usize = 7;
|
||||
|
||||
// Magic bytes
|
||||
pub const ELFMAG0: u8 = 0x7f;
|
||||
pub const ELFMAG1: u8 = b'E';
|
||||
pub const ELFMAG2: u8 = b'L';
|
||||
pub const ELFMAG3: u8 = b'F';
|
||||
pub const ELF_MAGIC: [u8; 4] = [ELFMAG0, ELFMAG1, ELFMAG2, ELFMAG3];
|
||||
|
||||
// EI_CLASS
|
||||
pub const ELFCLASS32: u8 = 1;
|
||||
pub const ELFCLASS64: u8 = 2;
|
||||
|
||||
// EI_DATA
|
||||
pub const ELFDATA2LSB: u8 = 1; // little-endian
|
||||
pub const ELFDATA2MSB: u8 = 2; // big-endian
|
||||
|
||||
// e_type
|
||||
pub const ET_NONE: u16 = 0;
|
||||
pub const ET_REL: u16 = 1;
|
||||
pub const ET_EXEC: u16 = 2;
|
||||
pub const ET_DYN: u16 = 3;
|
||||
|
||||
// e_machine
|
||||
pub const EM_X86_64: u16 = 0x3E;
|
||||
pub const EM_AARCH64: u16 = 0xB7;
|
||||
|
||||
// p_type
|
||||
pub const PT_NULL: u32 = 0;
|
||||
pub const PT_LOAD: u32 = 1;
|
||||
pub const PT_DYNAMIC: u32 = 2;
|
||||
pub const PT_INTERP: u32 = 3;
|
||||
pub const PT_NOTE: u32 = 4;
|
||||
pub const PT_PHDR: u32 = 6;
|
||||
pub const PT_TLS: u32 = 7;
|
||||
|
||||
// p_flags
|
||||
pub const PF_X: u32 = 1;
|
||||
pub const PF_W: u32 = 2;
|
||||
pub const PF_R: u32 = 4;
|
||||
|
||||
// sh_type
|
||||
pub const SHT_NULL: u32 = 0;
|
||||
pub const SHT_PROGBITS: u32 = 1;
|
||||
pub const SHT_SYMTAB: u32 = 2;
|
||||
pub const SHT_STRTAB: u32 = 3;
|
||||
pub const SHT_RELA: u32 = 4;
|
||||
pub const SHT_NOBITS: u32 = 8;
|
||||
pub const SHT_REL: u32 = 9;
|
||||
|
||||
// sh_flags
|
||||
pub const SHF_WRITE: u64 = 1;
|
||||
pub const SHF_ALLOC: u64 = 2;
|
||||
pub const SHF_EXECINSTR: u64 = 4;
|
||||
|
||||
// st_info binding
|
||||
pub const STB_LOCAL: u8 = 0;
|
||||
pub const STB_GLOBAL: u8 = 1;
|
||||
pub const STB_WEAK: u8 = 2;
|
||||
|
||||
// st_info type
|
||||
pub const STT_NOTYPE: u8 = 0;
|
||||
pub const STT_OBJECT: u8 = 1;
|
||||
pub const STT_FUNC: u8 = 2;
|
||||
pub const STT_SECTION: u8 = 3;
|
||||
|
||||
// st_shndx special values
|
||||
pub const SHN_UNDEF: u16 = 0;
|
||||
pub const SHN_ABS: u16 = 0xfff1;
|
||||
|
||||
// x86_64 relocation types
|
||||
pub const R_X86_64_NONE: u32 = 0;
|
||||
pub const R_X86_64_64: u32 = 1;
|
||||
pub const R_X86_64_PC32: u32 = 2;
|
||||
pub const R_X86_64_PLT32: u32 = 4;
|
||||
pub const R_X86_64_GLOB_DAT: u32 = 6;
|
||||
pub const R_X86_64_JUMP_SLOT: u32 = 7;
|
||||
pub const R_X86_64_RELATIVE: u32 = 8;
|
||||
pub const R_X86_64_32: u32 = 10;
|
||||
pub const R_X86_64_32S: u32 = 11;
|
||||
|
||||
// Auxiliary vector types
|
||||
pub const AT_PHDR: u64 = 3;
|
||||
pub const AT_PHENT: u64 = 4;
|
||||
pub const AT_PHNUM: u64 = 5;
|
||||
pub const AT_PAGESZ: u64 = 6;
|
||||
pub const AT_BASE: u64 = 7;
|
||||
pub const AT_FLAGS: u64 = 8;
|
||||
pub const AT_ENTRY: u64 = 9;
|
||||
pub const AT_UID: u64 = 11;
|
||||
pub const AT_GID: u64 = 13;
|
||||
pub const AT_NULL: u64 = 0;
|
||||
|
||||
#[repr(C)]
|
||||
pub struct Elf64Ehdr {
|
||||
pub e_ident: [u8; 16],
|
||||
pub e_type: u16,
|
||||
pub e_machine: u16,
|
||||
pub e_version: u32,
|
||||
pub e_entry: u64,
|
||||
pub e_phoff: u64,
|
||||
pub e_shoff: u64,
|
||||
pub e_flags: u32,
|
||||
pub e_ehsize: u16,
|
||||
pub e_phentsize: u16,
|
||||
pub e_phnum: u16,
|
||||
pub e_shentsize: u16,
|
||||
pub e_shnum: u16,
|
||||
pub e_shstrndx: u16,
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
pub struct Elf64Phdr {
|
||||
pub p_type: u32,
|
||||
pub p_flags: u32,
|
||||
pub p_offset: u64,
|
||||
pub p_vaddr: u64,
|
||||
pub p_paddr: u64,
|
||||
pub p_filesz: u64,
|
||||
pub p_memsz: u64,
|
||||
pub p_align: u64,
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
pub struct Elf64Shdr {
|
||||
pub sh_name: u32,
|
||||
pub sh_type: u32,
|
||||
pub sh_flags: u64,
|
||||
pub sh_addr: u64,
|
||||
pub sh_offset: u64,
|
||||
pub sh_size: u64,
|
||||
pub sh_link: u32,
|
||||
pub sh_info: u32,
|
||||
pub sh_addralign: u64,
|
||||
pub sh_entsize: u64,
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
pub struct Elf64Sym {
|
||||
pub st_name: u32,
|
||||
pub st_info: u8,
|
||||
pub st_other: u8,
|
||||
pub st_shndx: u16,
|
||||
pub st_value: u64,
|
||||
pub st_size: u64,
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
pub struct Elf64Rela {
|
||||
pub r_offset: u64,
|
||||
pub r_info: u64,
|
||||
pub r_addend: i64,
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
pub struct Elf64Rel {
|
||||
pub r_offset: u64,
|
||||
pub r_info: u64,
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
pub struct Elf64AuxvEntry {
|
||||
pub a_type: u64,
|
||||
pub a_val: u64,
|
||||
}
|
||||
111
kernel/src/driver/elf/loader.rs
Normal file
111
kernel/src/driver/elf/loader.rs
Normal file
@@ -0,0 +1,111 @@
|
||||
use core::ptr::null;
|
||||
|
||||
use x86_64::structures::paging::OffsetPageTable;
|
||||
|
||||
use crate::{
|
||||
arch::x86_64::paging::XunilFrameAllocator,
|
||||
driver::{
|
||||
elf::{
|
||||
header::{
|
||||
ET_DYN, ET_EXEC, ET_REL, Elf64Ehdr, Elf64Rel, Elf64Shdr, SHF_ALLOC, SHT_NOBITS,
|
||||
SHT_REL,
|
||||
},
|
||||
program::load_program,
|
||||
reloc::elf_do_reloc,
|
||||
section::elf_sheader,
|
||||
validation::validate_elf,
|
||||
},
|
||||
syscall::{malloc, memset},
|
||||
},
|
||||
};
|
||||
|
||||
pub fn load_file(
|
||||
frame_allocator: &mut XunilFrameAllocator,
|
||||
mapper: &mut OffsetPageTable,
|
||||
elf_bytes: &[u8],
|
||||
) -> *const u8 {
|
||||
// elf header size
|
||||
if elf_bytes.len() < 64 {
|
||||
return null();
|
||||
}
|
||||
|
||||
let elf_header: &Elf64Ehdr = unsafe { &*(elf_bytes.as_ptr() as *const Elf64Ehdr) };
|
||||
|
||||
if !validate_elf(elf_header, elf_bytes.len()) {
|
||||
return null();
|
||||
}
|
||||
|
||||
return match elf_header.e_type {
|
||||
ET_EXEC => unsafe { load_program(frame_allocator, mapper, elf_header, elf_bytes) },
|
||||
ET_DYN => return null(), // TODO
|
||||
ET_REL => return null(),
|
||||
_ => return null(),
|
||||
};
|
||||
}
|
||||
|
||||
// TODO: make ET_REL work
|
||||
pub unsafe fn elf_load_stage1(hdr: *const Elf64Ehdr) {
|
||||
let shdr = unsafe { elf_sheader(hdr) } as *mut Elf64Shdr;
|
||||
let mut i: u16 = 0;
|
||||
let shnum = unsafe { (*hdr).e_shnum };
|
||||
|
||||
while i < shnum {
|
||||
let section: &mut Elf64Shdr = unsafe { &mut *(shdr.add(i as usize)) };
|
||||
|
||||
if section.sh_type == SHT_NOBITS {
|
||||
if section.sh_size == 0 {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (section.sh_flags & SHF_ALLOC) != 1 {
|
||||
let mem =
|
||||
unsafe { malloc(section.sh_size as usize, section.sh_addralign as usize) };
|
||||
|
||||
if mem.is_null() {
|
||||
continue; // handle OOM
|
||||
}
|
||||
|
||||
unsafe {
|
||||
// zero the memory
|
||||
memset(mem, 0, section.sh_size as usize);
|
||||
}
|
||||
section.sh_offset = (mem.addr() + hdr.addr()) as u64;
|
||||
}
|
||||
}
|
||||
|
||||
i += 1;
|
||||
}
|
||||
}
|
||||
|
||||
pub unsafe fn elf_load_stage2(hdr: *const Elf64Ehdr) -> i8 {
|
||||
let shdr = unsafe { elf_sheader(hdr) } as *mut Elf64Shdr;
|
||||
let mut i: u16 = 0;
|
||||
let mut idx: u64;
|
||||
let shnum = unsafe { (*hdr).e_shnum };
|
||||
|
||||
while i < shnum {
|
||||
let section: &mut Elf64Shdr = unsafe { &mut *(shdr.add(i as usize)) };
|
||||
|
||||
if section.sh_type == SHT_REL {
|
||||
idx = 0;
|
||||
while idx < section.sh_size / section.sh_entsize {
|
||||
let reltab: *const Elf64Rel = unsafe {
|
||||
((hdr as *const u8).add(section.sh_offset as usize) as *const Elf64Rel)
|
||||
.add(idx as usize)
|
||||
};
|
||||
|
||||
let result: i8 = unsafe { elf_do_reloc(hdr, reltab, section) };
|
||||
|
||||
if result == -1 {
|
||||
return -1;
|
||||
}
|
||||
|
||||
idx += 1;
|
||||
}
|
||||
}
|
||||
|
||||
i += 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
6
kernel/src/driver/elf/mod.rs
Normal file
6
kernel/src/driver/elf/mod.rs
Normal file
@@ -0,0 +1,6 @@
|
||||
mod header;
|
||||
pub mod loader;
|
||||
mod program;
|
||||
mod reloc;
|
||||
mod section;
|
||||
pub mod validation;
|
||||
110
kernel/src/driver/elf/program.rs
Normal file
110
kernel/src/driver/elf/program.rs
Normal file
@@ -0,0 +1,110 @@
|
||||
use x86_64::{
|
||||
VirtAddr,
|
||||
structures::paging::{
|
||||
FrameAllocator, Mapper, OffsetPageTable, Page, PageTableFlags, Size4KiB, mapper::MapToError,
|
||||
},
|
||||
};
|
||||
|
||||
use crate::{
|
||||
arch::x86_64::paging::XunilFrameAllocator,
|
||||
driver::{
|
||||
elf::header::{Elf64Ehdr, Elf64Phdr, PF_X, PT_LOAD},
|
||||
syscall::memset,
|
||||
},
|
||||
util::{align_down, align_up},
|
||||
};
|
||||
|
||||
const PAGE_SIZE: u64 = 4096;
|
||||
|
||||
pub unsafe fn elf_pheader(hdr: *const Elf64Ehdr) -> *const Elf64Phdr {
|
||||
unsafe { (hdr as *const u8).add((*hdr).e_phoff as usize) as *const Elf64Phdr }
|
||||
}
|
||||
|
||||
pub unsafe fn load_program(
|
||||
frame_allocator: &mut XunilFrameAllocator,
|
||||
mapper: &mut OffsetPageTable,
|
||||
hdr: *const Elf64Ehdr,
|
||||
elf_bytes: &[u8],
|
||||
) -> *const u8 {
|
||||
let phdr = unsafe { elf_pheader(hdr) };
|
||||
let phnum = unsafe { (*hdr).e_phnum };
|
||||
|
||||
for i in 0..phnum {
|
||||
let program_header = unsafe { phdr.add(i as usize) };
|
||||
|
||||
if unsafe { (*program_header).p_type } == PT_LOAD {
|
||||
load_segment_to_memory(frame_allocator, mapper, program_header, elf_bytes);
|
||||
}
|
||||
}
|
||||
|
||||
return unsafe { (*hdr).e_entry as *const u8 };
|
||||
}
|
||||
|
||||
pub fn load_segment_to_memory(
|
||||
frame_allocator: &mut XunilFrameAllocator,
|
||||
mapper: &mut OffsetPageTable,
|
||||
phdr: *const Elf64Phdr,
|
||||
elf_bytes: &[u8],
|
||||
) {
|
||||
let mem_size: u64 = unsafe { (*phdr).p_memsz };
|
||||
let p_offset: u64 = unsafe { (*phdr).p_offset };
|
||||
let file_size: u64 = unsafe { (*phdr).p_filesz };
|
||||
|
||||
let vaddr: *mut u8 = unsafe { (*phdr).p_vaddr as *mut u8 };
|
||||
|
||||
if p_offset > elf_bytes.len() as u64
|
||||
|| file_size > elf_bytes.len() as u64
|
||||
|| p_offset + file_size > elf_bytes.len() as u64
|
||||
{
|
||||
return;
|
||||
} // invalid, could read past it's memory
|
||||
|
||||
if file_size > mem_size {
|
||||
return;
|
||||
}
|
||||
|
||||
let seg_start = align_down(vaddr as u64, PAGE_SIZE);
|
||||
let seg_end = align_up(vaddr as u64 + mem_size, PAGE_SIZE);
|
||||
|
||||
let mut flags =
|
||||
PageTableFlags::PRESENT | PageTableFlags::USER_ACCESSIBLE | PageTableFlags::WRITABLE;
|
||||
|
||||
if unsafe { ((*phdr).p_flags & PF_X) != 0 } {
|
||||
} else {
|
||||
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);
|
||||
|
||||
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, frame_allocator)
|
||||
.map_err(|e| e)
|
||||
.expect("test")
|
||||
.flush();
|
||||
}
|
||||
}
|
||||
|
||||
unsafe {
|
||||
core::ptr::copy_nonoverlapping(
|
||||
elf_bytes.as_ptr().add(p_offset as usize),
|
||||
vaddr,
|
||||
file_size as usize,
|
||||
);
|
||||
|
||||
if mem_size > file_size {
|
||||
memset(
|
||||
vaddr.add(file_size as usize),
|
||||
0,
|
||||
(mem_size - file_size) as usize,
|
||||
);
|
||||
}
|
||||
};
|
||||
}
|
||||
40
kernel/src/driver/elf/reloc.rs
Normal file
40
kernel/src/driver/elf/reloc.rs
Normal file
@@ -0,0 +1,40 @@
|
||||
use crate::driver::elf::{
|
||||
header::{Elf64Ehdr, Elf64Rel, Elf64Rela, Elf64Shdr, R_X86_64_64},
|
||||
section::{elf_get_symval, elf_section},
|
||||
};
|
||||
|
||||
pub trait ArchRelocate {
|
||||
fn apply_relocation(&self, rela: &Elf64Rela, base: usize, sym_value: usize) -> Result<(), i8>;
|
||||
|
||||
fn setup_entry(&self, entry: usize, stack_top: usize, argv: &[&str]) -> !;
|
||||
}
|
||||
|
||||
// TODO: make ET_REL work
|
||||
|
||||
pub unsafe fn elf_do_reloc(
|
||||
hdr: *const Elf64Ehdr,
|
||||
rel: *const Elf64Rel,
|
||||
reltab: *mut Elf64Shdr,
|
||||
) -> i8 {
|
||||
let target = unsafe { elf_section(hdr, (*reltab).sh_info as usize) };
|
||||
let addr = unsafe { (hdr as *const u8).add((*target).sh_offset as usize) };
|
||||
let reference = unsafe { addr.add((*rel).r_offset as usize) as *mut u64 };
|
||||
|
||||
let symval;
|
||||
|
||||
if unsafe { ((*rel).r_info) >> 32 } != 0 {
|
||||
symval = unsafe { elf_get_symval(hdr, (*reltab).sh_link as u64, (*rel).r_info >> 32) };
|
||||
if symval == 1 {
|
||||
return -1;
|
||||
}
|
||||
|
||||
match unsafe { ((*rel).r_info & 0xffff_ffff) as u32 } {
|
||||
x if x == R_X86_64_64 as u32 => unsafe { *reference = symval.wrapping_add(*reference) },
|
||||
_ => return -1,
|
||||
}
|
||||
|
||||
return symval as i8;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
87
kernel/src/driver/elf/section.rs
Normal file
87
kernel/src/driver/elf/section.rs
Normal file
@@ -0,0 +1,87 @@
|
||||
use crate::driver::elf::header::{Elf64Ehdr, Elf64Shdr, Elf64Sym, SHN_ABS, SHN_UNDEF, STB_WEAK};
|
||||
use core::ffi::CStr;
|
||||
|
||||
// TODO: make ET_REL work
|
||||
|
||||
pub unsafe fn elf_sheader(hdr: *const Elf64Ehdr) -> *const Elf64Shdr {
|
||||
unsafe { (hdr as *const u8).add((*hdr).e_shoff as usize) as *const Elf64Shdr }
|
||||
}
|
||||
|
||||
pub unsafe fn elf_section(hdr: *const Elf64Ehdr, idx: usize) -> *const Elf64Shdr {
|
||||
unsafe { elf_sheader(hdr).add(idx) }
|
||||
}
|
||||
|
||||
// pub unsafe fn elf_str_table(hdr: *const Elf64Ehdr) -> *const u8 {
|
||||
// if unsafe { (*hdr).e_shstrndx == SHN_UNDEF } {
|
||||
// return core::ptr::null();
|
||||
// }
|
||||
|
||||
// let shdr = unsafe { elf_section(hdr, (*hdr).e_shstrndx as usize) };
|
||||
|
||||
// unsafe { (hdr as *const u8).add((*shdr).sh_offset as usize) }
|
||||
// }
|
||||
|
||||
// pub unsafe fn elf_lookup_string(hdr: *const Elf64Ehdr, offset: usize) -> *const u8 {
|
||||
// let str_tab: *const u8 = unsafe { elf_str_table(hdr) };
|
||||
|
||||
// if str_tab.is_null() {
|
||||
// return core::ptr::null();
|
||||
// }
|
||||
|
||||
// return unsafe { str_tab.add(offset) };
|
||||
// }
|
||||
|
||||
pub fn elf_lookup_symbol(name: &CStr) -> *const u8 {
|
||||
return core::ptr::null();
|
||||
}
|
||||
|
||||
pub unsafe fn elf_get_symval(hdr: *const Elf64Ehdr, table: u64, idx: u64) -> u64 {
|
||||
if table == SHN_UNDEF as u64 || idx == SHN_UNDEF as u64 {
|
||||
return 0;
|
||||
}
|
||||
|
||||
let symtab: *const Elf64Shdr = unsafe { elf_section(hdr, table as usize) };
|
||||
|
||||
if unsafe { (*symtab).sh_entsize == 0 } {
|
||||
return 255; // TODO: replace with error
|
||||
}
|
||||
|
||||
let symtab_entries: u64 = unsafe { (*symtab).sh_size / (*symtab).sh_entsize };
|
||||
|
||||
if idx >= symtab_entries {
|
||||
return 255; // TODO: replace with error
|
||||
}
|
||||
|
||||
let symaddr = unsafe { (hdr as *const u8).add((*symtab).sh_offset as usize) };
|
||||
let sym_table = symaddr as *const Elf64Sym;
|
||||
let symbol: &Elf64Sym = unsafe { &*sym_table.add(idx as usize) };
|
||||
|
||||
if symbol.st_shndx == SHN_UNDEF {
|
||||
// the symbol is external
|
||||
let strtab: *const Elf64Shdr = unsafe { elf_section(hdr, (*symtab).sh_link as usize) };
|
||||
let name_pointer: *const u8 = unsafe {
|
||||
(hdr as *const u8)
|
||||
.add((*strtab).sh_offset as usize)
|
||||
.add((*symbol).st_name as usize)
|
||||
};
|
||||
let name = unsafe { CStr::from_ptr(name_pointer as *const core::ffi::c_char) };
|
||||
|
||||
let target = elf_lookup_symbol(name);
|
||||
if target == core::ptr::null() {
|
||||
if (symbol.st_info >> 4) == STB_WEAK {
|
||||
return 0; // Weak symbol initialized as 0
|
||||
} else {
|
||||
return 255; // // TODO: replace with error Undefined External Symbol
|
||||
}
|
||||
} else {
|
||||
return target as u64;
|
||||
}
|
||||
} else if symbol.st_shndx == SHN_ABS {
|
||||
return symbol.st_value; // absolute symbol easy
|
||||
} else {
|
||||
let target: *const Elf64Shdr = unsafe { elf_section(hdr, symbol.st_shndx as usize) };
|
||||
return unsafe {
|
||||
((hdr as *const u8).add((symbol.st_value + (*target).sh_offset) as usize)) as u64
|
||||
};
|
||||
}
|
||||
}
|
||||
29
kernel/src/driver/elf/validation.rs
Normal file
29
kernel/src/driver/elf/validation.rs
Normal file
@@ -0,0 +1,29 @@
|
||||
use crate::driver::elf::header::{
|
||||
EI_CLASS, EI_DATA, EI_VERSION, ELF_MAGIC, EM_X86_64, ET_DYN, ET_EXEC, Elf64Ehdr,
|
||||
};
|
||||
|
||||
pub fn validate_elf(elf_header: &Elf64Ehdr, elf_len: usize) -> bool {
|
||||
#[allow(unused_mut)]
|
||||
let mut required_machine = EM_X86_64;
|
||||
#[cfg(target_arch = "aarch64")]
|
||||
{
|
||||
use crate::driver::elf::header::EM_AARCH64;
|
||||
required_machine = EM_AARCH64;
|
||||
}
|
||||
|
||||
elf_header.e_ident[0..4] == ELF_MAGIC
|
||||
// 64 bit
|
||||
&& elf_header.e_ident[EI_CLASS] == 2
|
||||
// little-endian
|
||||
&& elf_header.e_ident[EI_DATA] == 1
|
||||
&& elf_header.e_ident[EI_VERSION] == 1
|
||||
&& elf_header.e_version == 1
|
||||
// check architecture
|
||||
&& elf_header.e_machine == required_machine
|
||||
// disallow object files
|
||||
&& [ET_DYN, ET_EXEC].contains(&elf_header.e_type)
|
||||
// standard elf64
|
||||
&& elf_header.e_phentsize == 56
|
||||
&& elf_header.e_phnum != 0 // zero program headers
|
||||
&& (elf_header.e_phoff + (elf_header.e_phnum*elf_header.e_phentsize) as u64) <= elf_len as u64
|
||||
}
|
||||
@@ -1,5 +1,7 @@
|
||||
pub mod elf;
|
||||
pub mod graphics;
|
||||
pub mod keyboard;
|
||||
pub mod mouse;
|
||||
pub mod serial;
|
||||
pub mod syscall;
|
||||
pub mod timer;
|
||||
|
||||
73
kernel/src/driver/syscall.rs
Normal file
73
kernel/src/driver/syscall.rs
Normal file
@@ -0,0 +1,73 @@
|
||||
use core::{
|
||||
alloc::{GlobalAlloc, Layout},
|
||||
ptr::null_mut,
|
||||
};
|
||||
|
||||
use crate::{arch::arch::get_allocator, driver::graphics::framebuffer::with_framebuffer, println};
|
||||
|
||||
const SYS_EXIT: usize = 1;
|
||||
const SYS_WRITE: usize = 60;
|
||||
|
||||
pub unsafe fn malloc(size: usize, align: usize) -> *mut u8 {
|
||||
let align = if align < 1 {
|
||||
1
|
||||
} else {
|
||||
align.next_power_of_two()
|
||||
};
|
||||
let layout = match Layout::from_size_align(size, align) {
|
||||
Ok(l) => l,
|
||||
Err(_) => return null_mut(),
|
||||
};
|
||||
|
||||
unsafe { GlobalAlloc::alloc(get_allocator(), layout) }
|
||||
}
|
||||
|
||||
pub unsafe fn free(ptr: *mut u8, size: usize, align: usize) {
|
||||
if ptr.is_null() {
|
||||
// very important, do not double free
|
||||
return;
|
||||
}
|
||||
|
||||
let align = if align < 1 {
|
||||
1
|
||||
} else {
|
||||
align.next_power_of_two()
|
||||
};
|
||||
|
||||
if let Ok(layout) = Layout::from_size_align(size.max(1), align.max(1)) {
|
||||
unsafe { GlobalAlloc::dealloc(get_allocator(), ptr, layout) }
|
||||
}
|
||||
}
|
||||
|
||||
#[unsafe(no_mangle)]
|
||||
pub unsafe extern "C" fn syscall_dispatch(
|
||||
num: usize,
|
||||
arg0: usize,
|
||||
arg1: usize,
|
||||
arg2: usize,
|
||||
) -> isize {
|
||||
match num {
|
||||
SYS_WRITE => {
|
||||
let buf_ptr = arg1 as *const u8;
|
||||
let len = arg2 as usize;
|
||||
let bytes: &[u8] = unsafe { core::slice::from_raw_parts(buf_ptr, len) };
|
||||
let s = core::str::from_utf8(bytes).unwrap_or("<non-utf8>");
|
||||
println!("SYS_WRITE called: {:?} {:?}", s, len);
|
||||
with_framebuffer(|fb| fb.swap());
|
||||
0
|
||||
}
|
||||
SYS_EXIT => {
|
||||
println!("Program exit.");
|
||||
with_framebuffer(|fb| fb.swap());
|
||||
0
|
||||
}
|
||||
_ => -38, // syscall not found
|
||||
}
|
||||
}
|
||||
|
||||
pub unsafe fn memset(ptr: *mut u8, val: u8, count: usize) {
|
||||
unsafe { core::ptr::write_bytes(ptr, val, count) };
|
||||
}
|
||||
|
||||
pub type Fd = i32;
|
||||
pub type Off = i64;
|
||||
@@ -15,13 +15,9 @@ pub mod driver;
|
||||
pub mod userspace_stub;
|
||||
pub mod util;
|
||||
|
||||
use crate::arch::arch::{infinite_idle, init, kernel_crash, sleep};
|
||||
use crate::arch::arch::{infinite_idle, init, kernel_crash};
|
||||
use crate::driver::graphics::base::rgb;
|
||||
use crate::driver::graphics::framebuffer::{init_framebuffer, with_framebuffer};
|
||||
use crate::driver::graphics::primitives::{
|
||||
circle_filled, circle_outline, rectangle_filled, rectangle_outline, triangle_outline,
|
||||
};
|
||||
use crate::driver::mouse::MOUSE;
|
||||
use crate::driver::serial::{ConsoleWriter, init_serial_console, with_serial_console};
|
||||
use crate::driver::timer::TIMER;
|
||||
use crate::userspace_stub::userspace_init;
|
||||
@@ -98,8 +94,8 @@ unsafe extern "C" fn kmain() -> ! {
|
||||
// removed by the linker.
|
||||
assert!(BASE_REVISION.is_supported());
|
||||
|
||||
let mapper;
|
||||
let frame_allocator;
|
||||
let mut mapper;
|
||||
let mut frame_allocator;
|
||||
|
||||
if let Some(hhdm_response) = HHDM_REQUEST.get_response() {
|
||||
if let Some(memory_map_response) = MEMORY_MAP_REQUEST.get_response() {
|
||||
@@ -125,14 +121,13 @@ unsafe extern "C" fn kmain() -> ! {
|
||||
println!("Could not get date at boot. Will default to 0.")
|
||||
}
|
||||
|
||||
userspace_init()
|
||||
userspace_init(&mut frame_allocator, &mut mapper)
|
||||
}
|
||||
|
||||
#[panic_handler]
|
||||
fn rust_panic(_info: &core::panic::PanicInfo) -> ! {
|
||||
with_framebuffer(|mut fb| {
|
||||
let (width, height) = (fb.width.clone(), fb.height.clone());
|
||||
rectangle_filled(&mut fb, 0, 0, width, height, rgb(180, 0, 0));
|
||||
fb.clear(rgb(180, 0, 0));
|
||||
|
||||
with_serial_console(|console| {
|
||||
console.clear(5, 5);
|
||||
|
||||
@@ -1,8 +1,10 @@
|
||||
use alloc::string::ToString;
|
||||
use x86_64::structures::paging::OffsetPageTable;
|
||||
|
||||
use crate::{
|
||||
arch::arch::sleep,
|
||||
arch::{arch::run_elf, x86_64::paging::XunilFrameAllocator},
|
||||
driver::{
|
||||
elf::loader::load_file,
|
||||
graphics::{
|
||||
base::rgb,
|
||||
framebuffer::with_framebuffer,
|
||||
@@ -20,6 +22,7 @@ use crate::{
|
||||
};
|
||||
|
||||
static CURSOR_BYTES: &[u8] = include_bytes!("../../assets/cursors/default.bmp");
|
||||
static TEST_ELF_BYTES: &[u8] = include_bytes!("../../assets/helloworld.elf");
|
||||
const BMP_HEADER_SIZE: usize = 138;
|
||||
pub const CURSOR_W: usize = 24;
|
||||
pub const CURSOR_H: usize = 24;
|
||||
@@ -72,84 +75,97 @@ fn boot_animation() {
|
||||
});
|
||||
}
|
||||
|
||||
pub fn userspace_init() -> ! {
|
||||
pub fn userspace_init(
|
||||
frame_allocator: &mut XunilFrameAllocator,
|
||||
mapper: &mut OffsetPageTable,
|
||||
) -> ! {
|
||||
// this is just a stub
|
||||
boot_animation();
|
||||
|
||||
let mut mouse_status = 0;
|
||||
let mut width = 0;
|
||||
let mut height = 0;
|
||||
let mut mouse_x = 100;
|
||||
let mut mouse_y = 100;
|
||||
let entry_point = load_file(frame_allocator, mapper, TEST_ELF_BYTES);
|
||||
println!("{:?}", entry_point);
|
||||
|
||||
loop {
|
||||
with_serial_console(|serial_console| serial_console.clear(0, 0));
|
||||
with_framebuffer(|fb| fb.clear(rgb(253, 129, 0)));
|
||||
test_performance(|| {
|
||||
mouse_status = MOUSE.get_status();
|
||||
with_framebuffer(|mut fb| {
|
||||
width = fb.width;
|
||||
height = fb.height;
|
||||
with_framebuffer(|fb| fb.swap());
|
||||
|
||||
let (x_delta, y_delta) = MOUSE.take_motion();
|
||||
run_elf(entry_point, frame_allocator, mapper);
|
||||
|
||||
if x_delta != 0 {
|
||||
mouse_x = (mouse_x as isize + x_delta as isize).max(0) as usize;
|
||||
}
|
||||
if y_delta != 0 {
|
||||
mouse_y = (mouse_y as isize + y_delta as isize).max(0) as usize;
|
||||
}
|
||||
if mouse_x > width {
|
||||
mouse_x = width - CURSOR_W;
|
||||
}
|
||||
if mouse_y > height {
|
||||
mouse_y = height - CURSOR_H;
|
||||
}
|
||||
loop {}
|
||||
|
||||
rectangle_filled(&mut fb, 700, 400, 200, 200, rgb(0, 0, 0));
|
||||
rectangle_outline(&mut fb, 400, 400, 100, 100, rgb(0, 0, 0));
|
||||
circle_filled(&mut fb, 200, 200, 100, rgb(0, 0, 0));
|
||||
circle_outline(&mut fb, 400, 200, 100, rgb(0, 0, 0));
|
||||
triangle_outline(&mut fb, 100, 400, 200, 400, 150, 600, rgb(0, 0, 0));
|
||||
// boot_animation();
|
||||
|
||||
let pixels = &CURSOR_BYTES[BMP_HEADER_SIZE..]; // remove header
|
||||
// let mut mouse_status = 0;
|
||||
// let mut width = 0;
|
||||
// let mut height = 0;
|
||||
// let mut mouse_x = 100;
|
||||
// let mut mouse_y = 100;
|
||||
|
||||
for row in 0..CURSOR_H {
|
||||
let src_row = (CURSOR_H - 1 - row) * CURSOR_W * 4;
|
||||
for col in 0..CURSOR_W {
|
||||
let i = src_row + col * 4; // 4 because rgba
|
||||
// loop {
|
||||
// with_serial_console(|serial_console| serial_console.clear(0, 0));
|
||||
// with_framebuffer(|fb| fb.clear(rgb(253, 129, 0)));
|
||||
// test_performance(|| {
|
||||
// mouse_status = MOUSE.get_status();
|
||||
// with_framebuffer(|mut fb| {
|
||||
// width = fb.width;
|
||||
// height = fb.height;
|
||||
|
||||
let b = pixels[i];
|
||||
let g = pixels[i + 1];
|
||||
let r = pixels[i + 2];
|
||||
let a = pixels[i + 3];
|
||||
// let (x_delta, y_delta) = MOUSE.take_motion();
|
||||
|
||||
if a < 255 {
|
||||
continue;
|
||||
}
|
||||
// if x_delta != 0 {
|
||||
// mouse_x = (mouse_x as isize + x_delta as isize).max(0) as usize;
|
||||
// }
|
||||
// if y_delta != 0 {
|
||||
// mouse_y = (mouse_y as isize + y_delta as isize).max(0) as usize;
|
||||
// }
|
||||
// if mouse_x > width {
|
||||
// mouse_x = width - CURSOR_W;
|
||||
// }
|
||||
// if mouse_y > height {
|
||||
// mouse_y = height - CURSOR_H;
|
||||
// }
|
||||
|
||||
let color = rgb(r, g, b);
|
||||
// rectangle_filled(&mut fb, 700, 400, 200, 200, rgb(0, 0, 0));
|
||||
// rectangle_outline(&mut fb, 400, 400, 100, 100, rgb(0, 0, 0));
|
||||
// circle_filled(&mut fb, 200, 200, 100, rgb(0, 0, 0));
|
||||
// circle_outline(&mut fb, 400, 200, 100, rgb(0, 0, 0));
|
||||
// triangle_outline(&mut fb, 100, 400, 200, 400, 150, 600, rgb(0, 0, 0));
|
||||
|
||||
fb.put_pixel((mouse_x + col) as usize, (mouse_y + row) as usize, color);
|
||||
}
|
||||
}
|
||||
});
|
||||
// let pixels = &CURSOR_BYTES[BMP_HEADER_SIZE..]; // remove header
|
||||
|
||||
let (hours, minutes, seconds) =
|
||||
unix_to_hms(TIMER.get_date_at_boot() + (TIMER.now().elapsed()) / 1000);
|
||||
// for row in 0..CURSOR_H {
|
||||
// let src_row = (CURSOR_H - 1 - row) * CURSOR_W * 4;
|
||||
// for col in 0..CURSOR_W {
|
||||
// let i = src_row + col * 4; // 4 because rgba
|
||||
|
||||
print!(
|
||||
"{:?}:{:?}:{:?}\nMouse status: {:?}\nDesktop Size: {:?}",
|
||||
hours,
|
||||
minutes,
|
||||
seconds,
|
||||
mouse_status,
|
||||
(width, height)
|
||||
);
|
||||
});
|
||||
with_framebuffer(|fb| {
|
||||
fb.swap();
|
||||
});
|
||||
sleep(1000 / 165);
|
||||
}
|
||||
// let b = pixels[i];
|
||||
// let g = pixels[i + 1];
|
||||
// let r = pixels[i + 2];
|
||||
// let a = pixels[i + 3];
|
||||
|
||||
// if a < 255 {
|
||||
// continue;
|
||||
// }
|
||||
|
||||
// let color = rgb(r, g, b);
|
||||
|
||||
// fb.put_pixel((mouse_x + col) as usize, (mouse_y + row) as usize, color);
|
||||
// }
|
||||
// }
|
||||
// });
|
||||
|
||||
// let (hours, minutes, seconds) =
|
||||
// unix_to_hms(TIMER.get_date_at_boot() + (TIMER.now().elapsed()) / 1000);
|
||||
|
||||
// print!(
|
||||
// "{:?}:{:?}:{:?}\nMouse status: {:?}\nDesktop Size: {:?}",
|
||||
// hours,
|
||||
// minutes,
|
||||
// seconds,
|
||||
// mouse_status,
|
||||
// (width, height)
|
||||
// );
|
||||
// });
|
||||
// with_framebuffer(|fb| {
|
||||
// fb.swap();
|
||||
// });
|
||||
// sleep(1000 / 165);
|
||||
// }
|
||||
}
|
||||
|
||||
@@ -46,3 +46,24 @@ pub fn test_performance<F: FnOnce()>(function: F) {
|
||||
pub fn get_bit(value: u8, position: u8) -> u8 {
|
||||
(value >> position) & 1
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub const fn align_down(addr: u64, align: u64) -> u64 {
|
||||
assert!(align.is_power_of_two(), "`align` must be a power of two");
|
||||
addr & !(align - 1)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub const fn align_up(addr: u64, align: u64) -> u64 {
|
||||
assert!(align.is_power_of_two(), "`align` must be a power of two");
|
||||
let align_mask = align - 1;
|
||||
if addr & align_mask == 0 {
|
||||
addr
|
||||
} else {
|
||||
if let Some(aligned) = (addr | align_mask).checked_add(1) {
|
||||
aligned
|
||||
} else {
|
||||
panic!("attempt to add with overflow")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user