diff --git a/arch/x86_64/src/acpi/madt.rs b/arch/x86_64/src/acpi/madt.rs index bd1a5d2..dac16dc 100644 --- a/arch/x86_64/src/acpi/madt.rs +++ b/arch/x86_64/src/acpi/madt.rs @@ -85,7 +85,7 @@ pub enum MadtEntry { InvalidIoApic(usize), IntSrcOverride(&'static MadtIntSrcOverride), InvalidIntSrcOverride(usize), - Unknown + Unknown(u8) } pub struct MadtIter { @@ -117,7 +117,7 @@ impl Iterator for MadtIter { } else { MadtEntry::InvalidIntSrcOverride(entry_len) }, - _ => MadtEntry::Unknown + _ => MadtEntry::Unknown(entry_type) }; self.i += entry_len; diff --git a/arch/x86_64/src/elf.rs b/arch/x86_64/src/elf.rs new file mode 100644 index 0000000..3d2b7e4 --- /dev/null +++ b/arch/x86_64/src/elf.rs @@ -0,0 +1,92 @@ +pub const ELF_CLASS: u8 = 2; +pub type ElfAddr = u64; +pub type ElfOff = u64; +pub type ElfHalf = u16; +pub type ElfWord = u32; +pub type ElfXword = u64; + +/// An ELF header +#[repr(packed)] +#[derive(Debug)] +pub struct ElfHeader { + /// The "magic number" (4 bytes) + pub magic: [u8; 4], + /// 64 or 32 bit? + pub class: u8, + /// Little (1) or big endianness (2)? + pub endian: u8, + /// The ELF version (set to 1 for default) + pub ver: u8, + /// Operating system ABI (0x03 for Linux) + pub abi: [u8; 2], + /// Unused + pub pad: [u8; 7], + /// Specify whether the object is relocatable, executable, shared, or core (in order). + pub _type: ElfHalf, + /// Instruction set archcitecture + pub machine: ElfHalf, + /// Second version + pub ver_2: ElfWord, + /// The ELF entry + pub entry: ElfAddr, + /// The program header table offset + pub ph_off: ElfOff, + /// The section header table offset + pub sh_off: ElfOff, + /// The flags set + pub flags: ElfWord, + /// The header table length + pub h_len: ElfHalf, + /// The program header table entry length + pub ph_ent_len: ElfHalf, + /// The program head table length + pub ph_len: ElfHalf, + /// The section header table entry length + pub sh_ent_len: ElfHalf, + /// The section header table length + pub sh_len: ElfHalf, + /// The section header table string index + pub sh_str_index: ElfHalf, +} + +/// An ELF segment +#[repr(packed)] +#[derive(Debug)] +pub struct ElfSegment { + pub _type: ElfWord, + pub flags: ElfWord, + pub off: ElfOff, + pub vaddr: ElfAddr, + pub paddr: ElfAddr, + pub file_len: ElfXword, + pub mem_len: ElfXword, + pub align: ElfXword, +} + +/// An ELF section +#[repr(packed)] +#[derive(Debug)] +pub struct ElfSection { + pub name: ElfWord, + pub _type: ElfWord, + pub flags: ElfXword, + pub addr: ElfAddr, + pub off: ElfOff, + pub len: ElfXword, + pub link: ElfWord, + pub info: ElfWord, + pub addr_align: ElfXword, + pub ent_len: ElfXword, +} + +/// An ELF symbol +#[repr(packed)] +#[derive(Debug)] +pub struct ElfSymbol { + pub name: ElfWord, + pub info: u8, + pub other: u8, + pub sh_index: ElfHalf, + pub value: ElfAddr, + pub size: ElfXword, +} diff --git a/arch/x86_64/src/idt.rs b/arch/x86_64/src/idt.rs index a5839ba..ab2c52e 100644 --- a/arch/x86_64/src/idt.rs +++ b/arch/x86_64/src/idt.rs @@ -20,6 +20,7 @@ pub unsafe fn init() { entry.set_flags(IDT_PRESENT | IDT_RING_0 | IDT_INTERRUPT); entry.set_offset(8, blank as usize); } + IDT[0x80].set_offset(8, syscall as usize); IDTR.set_slice(&IDT); init_ap(); @@ -54,6 +55,29 @@ interrupt_error!(page_fault, { } }); +#[naked] +pub unsafe extern fn syscall() { + extern { + fn syscall(a: usize, b: usize, c: usize, d: usize, e: usize, f: usize) -> usize; + } + + let a; + let b; + let c; + let d; + let e; + let f; + asm!("" : "={rax}"(a), "={rbx}"(b), "={rcx}"(c), "={rdx}"(d), "={rsi}"(e), "={rdi}"(f) + : : : "intel", "volatile"); + + let a = syscall(a, b, c, d, e, f); + + asm!("" : : "{rax}"(a) : : "intel", "volatile"); + + // Pop scratch registers, error code, and return + asm!("iretq" : : : : "intel", "volatile"); +} + bitflags! { pub flags IdtFlags: u8 { const IDT_PRESENT = 1 << 7, diff --git a/arch/x86_64/src/lib.rs b/arch/x86_64/src/lib.rs index e360614..ba2391d 100644 --- a/arch/x86_64/src/lib.rs +++ b/arch/x86_64/src/lib.rs @@ -119,6 +119,9 @@ macro_rules! interrupt_error { /// ACPI table parsing pub mod acpi; +/// ELF file handling +pub mod elf; + /// Memcpy, memmove, etc. pub mod externs; diff --git a/arch/x86_64/src/start.rs b/arch/x86_64/src/start.rs index 0439ef8..798baf5 100644 --- a/arch/x86_64/src/start.rs +++ b/arch/x86_64/src/start.rs @@ -27,7 +27,7 @@ extern { /// Kernel main function fn kmain() -> !; /// Kernel main for APs - fn kmain_ap() -> !; + fn kmain_ap(id: usize) -> !; } /// The entry to Rust, all things must be initialized @@ -88,8 +88,6 @@ pub unsafe extern fn kstart() -> ! { } BSP_READY.store(true, Ordering::SeqCst); - - print!("BSP\n"); } kmain(); @@ -115,7 +113,5 @@ pub unsafe extern fn kstart_ap(stack_start: usize, stack_end: usize) -> ! { asm!("pause" : : : : "intel", "volatile"); } - print!("{}", ::core::str::from_utf8_unchecked(&[b'A', b'P', b' ', ap_number as u8 + b'0', b'\n'])); - - kmain_ap(); + kmain_ap(ap_number); } diff --git a/bootloader/x86/harddrive.asm b/bootloader/x86/harddrive.asm index 3adda0d..2a50fed 100644 --- a/bootloader/x86/harddrive.asm +++ b/bootloader/x86/harddrive.asm @@ -17,5 +17,3 @@ kernel_file: .end: .length equ kernel_file.end - kernel_file .length_sectors equ .length / 512 - -times 1024*1024-($-$$) db 0 diff --git a/bootloader/x86/kernel.ld b/bootloader/x86/kernel.ld index 09d9958..c81df10 100644 --- a/bootloader/x86/kernel.ld +++ b/bootloader/x86/kernel.ld @@ -1,16 +1,14 @@ ENTRY(kstart) OUTPUT_FORMAT(elf64-x86-64) -KERNEL_OFFSET = 0; +KERNEL_OFFSET = 0x100000; SECTIONS { - . = 0x100000; + . = KERNEL_OFFSET; . += SIZEOF_HEADERS; . = ALIGN(4096); - . += KERNEL_OFFSET; - .text : AT(ADDR(.text) - KERNEL_OFFSET) { __text_start = .; *(.text*) diff --git a/kernel/elf.rs b/kernel/elf.rs new file mode 100644 index 0000000..c223bb1 --- /dev/null +++ b/kernel/elf.rs @@ -0,0 +1,120 @@ +//! ELF executables + +use collections::{String, Vec}; + +use core::{mem, ptr, str, slice}; + +pub use arch::elf::*; + +/// An ELF executable +pub struct Elf<'a> { + pub data: &'a [u8], +} + +impl<'a> Elf<'a> { + /// Create a ELF executable from data + pub fn from(data: &'a [u8]) -> Result, String> { + if data.len() < mem::size_of::() { + Err(format!("Elf: Not enough data: {} < {}", data.len(), mem::size_of::())) + } else if &data[..4] != b"\x7FELF" { + Err(format!("Elf: Invalid magic: {:?} != {:?}", &data[..4], b"\x7FELF")) + } else if data.get(4) != Some(&ELF_CLASS) { + Err(format!("Elf: Invalid architecture: {:?} != {:?}", data.get(4), Some(&ELF_CLASS))) + } else { + Ok(Elf { data: data }) + } + } + + pub unsafe fn load_segments(&self) -> Vec { + let mut segments = Vec::new(); + + let header = &*(self.data.as_ptr() as usize as *const ElfHeader); + + for i in 0..header.ph_len { + let segment = ptr::read((self.data.as_ptr() as usize + header.ph_off as usize + i as usize * header.ph_ent_len as usize) as *const ElfSegment); + + if segment._type == 1 || segment._type == 7 { + segments.push(segment); + } + } + + segments + } + + /// Get the entry field of the header + pub unsafe fn entry(&self) -> usize { + let header = &*(self.data.as_ptr() as usize as *const ElfHeader); + header.entry as usize + } + + /// ELF symbol + pub unsafe fn symbol(&self, name: &str) -> usize { + let header = &*(self.data.as_ptr() as usize as *const ElfHeader); + + let sh_str_section = + &*((self.data.as_ptr() as usize + header.sh_off as usize + + header.sh_str_index as usize * + header.sh_ent_len as usize) as *const ElfSection); + + let mut sym_section = &*((self.data.as_ptr() as usize + header.sh_off as usize) as *const ElfSection); + + let mut str_section = &*((self.data.as_ptr() as usize + header.sh_off as usize) as *const ElfSection); + + for i in 0..header.sh_len { + let section = + &*((self.data.as_ptr() as usize + header.sh_off as usize + + i as usize * + header.sh_ent_len as usize) as *const ElfSection); + + let section_name_ptr = + (self.data.as_ptr() as usize + sh_str_section.off as usize + section.name as usize) as *const u8; + let mut section_name_len = 0; + for j in 0..4096 { + section_name_len = j; + if ptr::read(section_name_ptr.offset(j)) == 0 { + break; + } + } + let section_name = + str::from_utf8_unchecked(slice::from_raw_parts(section_name_ptr, + section_name_len as usize)); + + if section_name == ".symtab" { + sym_section = section; + } else if section_name == ".strtab" { + str_section = section; + } + } + + if sym_section.off > 0 && str_section.off > 0 { + if sym_section.ent_len > 0 { + let len = sym_section.len / sym_section.ent_len; + for i in 0..len { + let symbol = &*((self.data.as_ptr() as usize + sym_section.off as usize + i as usize * sym_section.ent_len as usize) as *const ElfSymbol); + + let symbol_name_ptr = + (self.data.as_ptr() as usize + str_section.off as usize + + symbol.name as usize) as *const u8; + let mut symbol_name_len = 0; + for j in 0..4096 { + symbol_name_len = j; + if ptr::read(symbol_name_ptr.offset(j)) == 0 { + break; + } + } + let symbol_name = str::from_utf8_unchecked(slice::from_raw_parts(symbol_name_ptr, symbol_name_len as usize)); + + if name == symbol_name { + return symbol.value as usize; + } + } + } else { + print!("No sym_section ent len\n"); + } + } else { + print!("No sym_section or str_section\n"); + } + + 0 + } +} diff --git a/kernel/lib.rs b/kernel/lib.rs index 5b8d135..474c30e 100644 --- a/kernel/lib.rs +++ b/kernel/lib.rs @@ -65,6 +65,7 @@ //! In this case, it is recommended to add one page, 4096 bytes, to the buffer and retry. #![feature(alloc)] +#![feature(asm)] #![feature(collections)] #![feature(const_fn)] #![feature(drop_types_in_const)] @@ -94,6 +95,9 @@ extern crate spin; /// Context management pub mod context; +/// ELF file parsing +pub mod elf; + /// Schemes, filesystem handlers pub mod scheme; @@ -106,16 +110,18 @@ pub mod tests; #[no_mangle] pub extern fn kmain() { + print!("{}", format!("BSP\n")); + loop { unsafe { interrupt::enable_and_halt(); } - print!("INT BSP\n"); } } #[no_mangle] -pub extern fn kmain_ap() { +pub extern fn kmain_ap(id: usize) { + print!("{}", format!("ASP {}\n", id)); + loop { unsafe { interrupt::enable_and_halt() } - print!("INT AP\n"); } } diff --git a/kernel/syscall/mod.rs b/kernel/syscall/mod.rs index df9b6d3..8512f52 100644 --- a/kernel/syscall/mod.rs +++ b/kernel/syscall/mod.rs @@ -106,3 +106,11 @@ pub fn handle(a: usize, b: usize, c: usize, d: usize, e: usize, _f: usize) -> :: Call::Unknown => Err(Error::NoCall) }.map_err(|err| err.into()) } + +#[no_mangle] +pub extern fn syscall(a: usize, b: usize, c: usize, d: usize, e: usize, f: usize) -> usize { + match handle(a, b, c, d, e, f) { + Ok(value) => value, + Err(value) => !value + } +} diff --git a/x86_64-unknown-redox.json b/x86_64-unknown-redox.json index 437af20..34400b2 100644 --- a/x86_64-unknown-redox.json +++ b/x86_64-unknown-redox.json @@ -16,7 +16,7 @@ "code-model": "kernel", "disable-redzone": true, "eliminate-frame-pointer": false, - "exe-suffix": ".bin", + "exe-suffix": "", "has-rpath": false, "no-compiler-rt": true, "no-default-libraries": true,