diff --git a/Makefile b/Makefile index 7012007..6968bc8 100644 --- a/Makefile +++ b/Makefile @@ -26,12 +26,14 @@ all: $(KBUILD)/harddrive.bin clean: cargo clean cargo clean --manifest-path libstd/Cargo.toml + cargo clean --manifest-path libstd_real/Cargo.toml cargo clean --manifest-path drivers/ahcid/Cargo.toml cargo clean --manifest-path drivers/e1000d/Cargo.toml cargo clean --manifest-path drivers/ps2d/Cargo.toml cargo clean --manifest-path drivers/pcid/Cargo.toml cargo clean --manifest-path drivers/rtl8168d/Cargo.toml cargo clean --manifest-path drivers/vesad/Cargo.toml + cargo clean --manifest-path programs/acid/Cargo.toml cargo clean --manifest-path programs/init/Cargo.toml cargo clean --manifest-path programs/ion/Cargo.toml cargo clean --manifest-path programs/coreutils/Cargo.toml @@ -75,12 +77,14 @@ doc-%: schemes/%/Cargo.toml all FORCE update: cargo update cargo update --manifest-path libstd/Cargo.toml + cargo update --manifest-path libstd_real/Cargo.toml cargo update --manifest-path drivers/ahcid/Cargo.toml cargo update --manifest-path drivers/e1000d/Cargo.toml cargo update --manifest-path drivers/ps2d/Cargo.toml cargo update --manifest-path drivers/pcid/Cargo.toml cargo update --manifest-path drivers/rtl8168d/Cargo.toml cargo update --manifest-path drivers/vesad/Cargo.toml + cargo update --manifest-path programs/acid/Cargo.toml cargo update --manifest-path programs/init/Cargo.toml cargo update --manifest-path programs/ion/Cargo.toml cargo update --manifest-path programs/coreutils/Cargo.toml @@ -211,16 +215,16 @@ $(BUILD)/libcore.rlib: rust/src/libcore/lib.rs mkdir -p $(BUILD) $(RUSTC) $(RUSTCFLAGS) -o $@ $< -$(BUILD)/librand.rlib: rust/src/librand/lib.rs $(BUILD)/libcore.rlib - $(RUSTC) $(RUSTCFLAGS) -o $@ $< - $(BUILD)/liballoc.rlib: rust/src/liballoc/lib.rs $(BUILD)/libcore.rlib $(RUSTC) $(RUSTCFLAGS) -o $@ $< -$(BUILD)/librustc_unicode.rlib: rust/src/librustc_unicode/lib.rs $(BUILD)/libcore.rlib +$(BUILD)/libcollections.rlib: rust/src/libcollections/lib.rs $(BUILD)/libcore.rlib $(BUILD)/liballoc.rlib $(BUILD)/librustc_unicode.rlib $(RUSTC) $(RUSTCFLAGS) -o $@ $< -$(BUILD)/libcollections.rlib: rust/src/libcollections/lib.rs $(BUILD)/libcore.rlib $(BUILD)/liballoc.rlib $(BUILD)/librustc_unicode.rlib +$(BUILD)/librand.rlib: rust/src/librand/lib.rs $(BUILD)/libcore.rlib + $(RUSTC) $(RUSTCFLAGS) -o $@ $< + +$(BUILD)/librustc_unicode.rlib: rust/src/librustc_unicode/lib.rs $(BUILD)/libcore.rlib $(RUSTC) $(RUSTCFLAGS) -o $@ $< openlibm/libopenlibm.a: @@ -432,7 +436,7 @@ $(BUILD)/filesystem.bin: \ filesystem/bin/smith \ filesystem/bin/tar rm -rf $@ $(BUILD)/filesystem/ - echo exit | cargo run --manifest-path schemes/redoxfs/Cargo.toml --bin redoxfs-utility $@ 64 + echo exit | cargo run --manifest-path schemes/redoxfs/Cargo.toml --bin redoxfs-utility $@ 128 mkdir -p $(BUILD)/filesystem/ cargo run --manifest-path schemes/redoxfs/Cargo.toml --bin redoxfs-fuse $@ $(BUILD)/filesystem/ & sleep 2 diff --git a/arch/x86_64/Cargo.toml b/arch/x86_64/Cargo.toml index 197f407..7b79e99 100644 --- a/arch/x86_64/Cargo.toml +++ b/arch/x86_64/Cargo.toml @@ -7,6 +7,7 @@ bitflags = "*" hole_list_allocator = { path = "../../crates/hole_list_allocator/" } io = { path = "../../crates/io/" } spin = "*" +syscall = { path = "../../syscall/" } [dependencies.x86] version = "0.7" diff --git a/arch/x86_64/src/acpi/local_apic.rs b/arch/x86_64/src/acpi/local_apic.rs deleted file mode 100644 index 17f6fb8..0000000 --- a/arch/x86_64/src/acpi/local_apic.rs +++ /dev/null @@ -1,77 +0,0 @@ -use core::intrinsics::{volatile_load, volatile_store}; -use x86::cpuid::CpuId; -use x86::msr::*; - -use memory::Frame; -use paging::{entry, ActivePageTable, PhysicalAddress}; - -/// Local APIC -pub struct LocalApic { - pub address: u32, - pub x2: bool -} - -impl LocalApic { - pub fn new(active_table: &mut ActivePageTable) -> Self { - let mut apic = LocalApic { - address: (unsafe { rdmsr(IA32_APIC_BASE) as u32 } & 0xFFFF0000), - x2: false - }; - - if CpuId::new().get_feature_info().unwrap().has_x2apic() { - unsafe { wrmsr(IA32_APIC_BASE, rdmsr(IA32_APIC_BASE) | 1 << 10) }; - apic.x2 = true; - } else { - active_table.identity_map(Frame::containing_address(PhysicalAddress::new(apic.address as usize)), entry::PRESENT | entry::WRITABLE | entry::NO_EXECUTE); - } - - apic - } - - unsafe fn read(&self, reg: u32) -> u32 { - volatile_load((self.address + reg) as *const u32) - } - - unsafe fn write(&self, reg: u32, value: u32) { - volatile_store((self.address + reg) as *mut u32, value); - } - - pub fn id(&self) -> u32 { - if self.x2 { - unsafe { rdmsr(IA32_X2APIC_APICID) as u32 } - } else { - unsafe { self.read(0x20) } - } - } - - pub fn version(&self) -> u32 { - if self.x2 { - unsafe { rdmsr(IA32_X2APIC_VERSION) as u32 } - } else { - unsafe { self.read(0x30) } - } - } - - pub fn icr(&self) -> u64 { - if self.x2 { - unsafe { rdmsr(IA32_X2APIC_ICR) } - } else { - unsafe { - (self.read(0x310) as u64) << 32 | self.read(0x300) as u64 - } - } - } - - pub fn set_icr(&mut self, value: u64) { - if self.x2 { - unsafe { wrmsr(IA32_X2APIC_ICR, value); } - } else { - unsafe { - while self.read(0x300) & 1 << 12 == 1 << 12 {} - self.write(0x310, (value >> 32) as u32); - self.write(0x300, value as u32); - while self.read(0x300) & 1 << 12 == 1 << 12 {} - } - } - } -} diff --git a/arch/x86_64/src/acpi/mod.rs b/arch/x86_64/src/acpi/mod.rs index 725817f..8411f1c 100644 --- a/arch/x86_64/src/acpi/mod.rs +++ b/arch/x86_64/src/acpi/mod.rs @@ -4,20 +4,19 @@ use core::intrinsics::{atomic_load, atomic_store}; use core::sync::atomic::Ordering; +use device::local_apic::LOCAL_APIC; use interrupt; use memory::{allocate_frames, Frame}; use paging::{entry, ActivePageTable, Page, PhysicalAddress, VirtualAddress}; use start::{kstart_ap, CPU_COUNT, AP_READY}; use self::dmar::{Dmar, DmarEntry}; -use self::local_apic::LocalApic; use self::madt::{Madt, MadtEntry}; use self::rsdt::Rsdt; use self::sdt::Sdt; use self::xsdt::Xsdt; pub mod dmar; -pub mod local_apic; pub mod madt; pub mod rsdt; pub mod sdt; @@ -35,7 +34,7 @@ pub fn init_sdt(sdt: &'static Sdt, active_table: &mut ActivePageTable) { if let Some(madt) = Madt::new(sdt) { println!(": {:>08X}: {}", madt.local_address, madt.flags); - let mut local_apic = LocalApic::new(active_table); + let mut local_apic = unsafe { &mut LOCAL_APIC }; let me = local_apic.id() as u8; @@ -60,7 +59,7 @@ pub fn init_sdt(sdt: &'static Sdt, active_table: &mut ActivePageTable) { } else { if ap_local_apic.flags & 1 == 1 { // Increase CPU ID - let cpu_id = CPU_COUNT.fetch_add(1, Ordering::SeqCst); + CPU_COUNT.fetch_add(1, Ordering::SeqCst); // Allocate a stack let stack_start = allocate_frames(64).expect("no more frames in acpi stack_start").start_address().get() + ::KERNEL_OFFSET; @@ -75,7 +74,7 @@ pub fn init_sdt(sdt: &'static Sdt, active_table: &mut ActivePageTable) { // Set the ap_ready to 0, volatile unsafe { atomic_store(ap_ready, 0) }; - unsafe { atomic_store(ap_cpu_id, cpu_id as u64) }; + unsafe { atomic_store(ap_cpu_id, ap_local_apic.id as u64) }; unsafe { atomic_store(ap_page_table, active_table.address() as u64) }; unsafe { atomic_store(ap_stack_start, stack_start as u64) }; unsafe { atomic_store(ap_stack_end, stack_end as u64) }; diff --git a/arch/x86_64/src/context.rs b/arch/x86_64/src/context.rs index 8482ec3..fb4f879 100644 --- a/arch/x86_64/src/context.rs +++ b/arch/x86_64/src/context.rs @@ -1,4 +1,4 @@ -use core::sync::atomic::{AtomicBool, ATOMIC_BOOL_INIT, Ordering}; +use core::sync::atomic::{AtomicBool, ATOMIC_BOOL_INIT}; /// This must be used by the kernel to ensure that context switches are done atomically /// Compare and exchange this to true when beginning a context switch on any CPU @@ -106,13 +106,5 @@ impl Context { asm!("mov $0, rbp" : "=r"(self.rbp) : : "memory" : "intel", "volatile"); asm!("mov rbp, $0" : : "r"(next.rbp) : "memory" : "intel", "volatile"); - - asm!("call context_switch_unlock" : : : "memory" : "intel", "volatile"); } } - -/// Unset global lock, set inside of kernel -#[no_mangle] -pub extern fn context_switch_unlock(){ - CONTEXT_SWITCH_LOCK.store(false, Ordering::SeqCst); -} diff --git a/arch/x86_64/src/device/local_apic.rs b/arch/x86_64/src/device/local_apic.rs new file mode 100644 index 0000000..d352c2c --- /dev/null +++ b/arch/x86_64/src/device/local_apic.rs @@ -0,0 +1,114 @@ +use core::intrinsics::{volatile_load, volatile_store}; +use x86::cpuid::CpuId; +use x86::msr::*; + +use memory::Frame; +use paging::{entry, ActivePageTable, PhysicalAddress, Page, VirtualAddress}; + +pub static mut LOCAL_APIC: LocalApic = LocalApic { + address: 0, + x2: false +}; + +pub unsafe fn init(active_table: &mut ActivePageTable) { + LOCAL_APIC.init(active_table); +} + +pub unsafe fn init_ap() { + LOCAL_APIC.init_ap(); +} + +/// Local APIC +pub struct LocalApic { + pub address: usize, + pub x2: bool +} + +impl LocalApic { + unsafe fn init(&mut self, active_table: &mut ActivePageTable) { + self.address = (rdmsr(IA32_APIC_BASE) as usize & 0xFFFF0000) + ::KERNEL_OFFSET; + self.x2 = CpuId::new().get_feature_info().unwrap().has_x2apic(); + + if ! self.x2 { + let page = Page::containing_address(VirtualAddress::new(self.address)); + let frame = Frame::containing_address(PhysicalAddress::new(self.address - ::KERNEL_OFFSET)); + active_table.map_to(page, frame, entry::PRESENT | entry::WRITABLE | entry::NO_EXECUTE); + } + + self.init_ap(); + } + + unsafe fn init_ap(&mut self) { + if self.x2 { + wrmsr(IA32_APIC_BASE, rdmsr(IA32_APIC_BASE) | 1 << 10); + wrmsr(IA32_X2APIC_SIVR, 0x100); + } else { + self.write(0xF0, 0x100); + } + } + + unsafe fn read(&self, reg: u32) -> u32 { + volatile_load((self.address + reg as usize) as *const u32) + } + + unsafe fn write(&mut self, reg: u32, value: u32) { + volatile_store((self.address + reg as usize) as *mut u32, value); + } + + pub fn id(&self) -> u32 { + if self.x2 { + unsafe { rdmsr(IA32_X2APIC_APICID) as u32 } + } else { + unsafe { self.read(0x20) } + } + } + + pub fn version(&self) -> u32 { + if self.x2 { + unsafe { rdmsr(IA32_X2APIC_VERSION) as u32 } + } else { + unsafe { self.read(0x30) } + } + } + + pub fn icr(&self) -> u64 { + if self.x2 { + unsafe { rdmsr(IA32_X2APIC_ICR) } + } else { + unsafe { + (self.read(0x310) as u64) << 32 | self.read(0x300) as u64 + } + } + } + + pub fn set_icr(&mut self, value: u64) { + if self.x2 { + unsafe { wrmsr(IA32_X2APIC_ICR, value); } + } else { + unsafe { + while self.read(0x300) & 1 << 12 == 1 << 12 {} + self.write(0x310, (value >> 32) as u32); + self.write(0x300, value as u32); + while self.read(0x300) & 1 << 12 == 1 << 12 {} + } + } + } + + pub fn ipi(&mut self, apic_id: usize) { + let mut icr = 0x4040; + if self.x2 { + icr |= (apic_id as u64) << 32; + } else { + icr |= (apic_id as u64) << 56; + } + self.set_icr(icr); + } + + pub unsafe fn eoi(&mut self) { + if self.x2 { + wrmsr(IA32_X2APIC_EOI, 0); + } else { + self.write(0xB0, 0); + } + } +} diff --git a/arch/x86_64/src/device/mod.rs b/arch/x86_64/src/device/mod.rs index 7a50f6e..db65aed 100644 --- a/arch/x86_64/src/device/mod.rs +++ b/arch/x86_64/src/device/mod.rs @@ -1,7 +1,15 @@ +use paging::ActivePageTable; + +pub mod local_apic; pub mod rtc; pub mod serial; -pub unsafe fn init(){ +pub unsafe fn init(active_table: &mut ActivePageTable){ + local_apic::init(active_table); rtc::init(); serial::init(); } + +pub unsafe fn init_ap() { + local_apic::init_ap(); +} diff --git a/arch/x86_64/src/idt.rs b/arch/x86_64/src/idt.rs index e53e259..0d0d95e 100644 --- a/arch/x86_64/src/idt.rs +++ b/arch/x86_64/src/idt.rs @@ -58,6 +58,9 @@ pub unsafe fn init() { IDT[46].set_func(irq::ata1); IDT[47].set_func(irq::ata2); + // Set IPI handler (null) + IDT[0x40].set_func(ipi::ipi); + // Set syscall function IDT[0x80].set_func(syscall::syscall); IDT[0x80].set_flags(IDT_PRESENT | IDT_RING_3 | IDT_INTERRUPT); diff --git a/arch/x86_64/src/interrupt/exception.rs b/arch/x86_64/src/interrupt/exception.rs index 369f448..2e797f1 100644 --- a/arch/x86_64/src/interrupt/exception.rs +++ b/arch/x86_64/src/interrupt/exception.rs @@ -1,115 +1,140 @@ use super::{halt, stack_trace}; -interrupt!(divide_by_zero, { - print!("Divide by zero fault\n"); +use syscall::flag::*; + +extern { + fn ksignal(signal: usize); +} + +interrupt_stack!(divide_by_zero, stack, { + println!("Divide by zero fault at {:>02X}:{:>016X}", stack.cs, stack.rip); + ksignal(SIGFPE); stack_trace(); loop { halt(); } }); -interrupt!(debug, { - print!("Debug trap\n"); +interrupt_stack!(debug, stack, { + println!("Debug trap at {:>02X}:{:>016X}", stack.cs, stack.rip); + ksignal(SIGTRAP); }); -interrupt!(non_maskable, { - print!("Non-maskable interrupt\n"); +interrupt_stack!(non_maskable, stack, { + println!("Non-maskable interrupt at {:>02X}:{:>016X}", stack.cs, stack.rip); }); -interrupt!(breakpoint, { - print!("Breakpoint trap\n"); +interrupt_stack!(breakpoint, stack, { + println!("Breakpoint trap at {:>02X}:{:>016X}", stack.cs, stack.rip); + ksignal(SIGTRAP); }); -interrupt!(overflow, { - print!("Overflow trap\n"); +interrupt_stack!(overflow, stack, { + println!("Overflow trap at {:>02X}:{:>016X}", stack.cs, stack.rip); + ksignal(SIGFPE); }); -interrupt!(bound_range, { - print!("Bound range exceeded fault\n"); +interrupt_stack!(bound_range, stack, { + println!("Bound range exceeded fault at {:>02X}:{:>016X}", stack.cs, stack.rip); + ksignal(SIGSEGV); stack_trace(); loop { halt(); } }); -interrupt!(invalid_opcode, { - print!("Invalid opcode fault\n"); +interrupt_stack!(invalid_opcode, stack, { + println!("Invalid opcode fault at {:>02X}:{:>016X}", stack.cs, stack.rip); + ksignal(SIGILL); stack_trace(); loop { halt(); } }); -interrupt!(device_not_available, { - print!("Device not available fault\n"); +interrupt_stack!(device_not_available, stack, { + println!("Device not available fault at {:>02X}:{:>016X}", stack.cs, stack.rip); + ksignal(SIGILL); stack_trace(); loop { halt(); } }); -interrupt_error!(double_fault, { - print!("Double fault\n"); +interrupt_error!(double_fault, stack, { + println!("Double fault: {:X} at {:>02X}:{:>016X}", stack.code, stack.cs, stack.rip); + ksignal(SIGSEGV); stack_trace(); loop { halt(); } }); -interrupt_error!(invalid_tss, { - print!("Invalid TSS fault\n"); +interrupt_error!(invalid_tss, stack, { + println!("Invalid TSS fault: {:X} at {:>02X}:{:>016X}", stack.code, stack.cs, stack.rip); + ksignal(SIGSEGV); stack_trace(); loop { halt(); } }); -interrupt_error!(segment_not_present, { - print!("Segment not present fault\n"); +interrupt_error!(segment_not_present, stack, { + println!("Segment not present fault: {:X} at {:>02X}:{:>016X}", stack.code, stack.cs, stack.rip); + ksignal(SIGSEGV); stack_trace(); loop { halt(); } }); -interrupt_error!(stack_segment, { - print!("Stack segment fault\n"); +interrupt_error!(stack_segment, stack, { + println!("Stack segment fault: {:X} at {:>02X}:{:>016X}", stack.code, stack.cs, stack.rip); + ksignal(SIGSEGV); stack_trace(); loop { halt(); } }); -interrupt_error!(protection, { - print!("Protection fault\n"); +interrupt_error!(protection, stack, { + println!("Protection fault: {:X} at {:>02X}:{:>016X}", stack.code, stack.cs, stack.rip); + ksignal(SIGSEGV); stack_trace(); loop { halt(); } }); -interrupt_error!(page, { +interrupt_error!(page, stack, { let cr2: usize; asm!("mov rax, cr2" : "={rax}"(cr2) : : : "intel", "volatile"); - println!("Page fault: {:>016X}", cr2); + println!("Page fault: {:>02X}:{:>016X} at {:>02X}:{:>016X}", stack.code, cr2, stack.cs, stack.rip); + ksignal(SIGSEGV); stack_trace(); loop { halt(); } }); -interrupt!(fpu, { - print!("FPU floating point fault\n"); +interrupt_stack!(fpu, stack, { + println!("FPU floating point fault at {:>02X}:{:>016X}", stack.cs, stack.rip); + ksignal(SIGFPE); stack_trace(); loop { halt(); } }); -interrupt_error!(alignment_check, { - print!("Alignment check fault\n"); +interrupt_error!(alignment_check, stack, { + println!("Alignment check fault: {:X} at {:>02X}:{:>016X}", stack.code, stack.cs, stack.rip); + ksignal(SIGBUS); stack_trace(); loop { halt(); } }); -interrupt!(machine_check, { - print!("Machine check fault\n"); +interrupt_stack!(machine_check, stack, { + println!("Machine check fault at {:>02X}:{:>016X}", stack.cs, stack.rip); + ksignal(SIGBUS); stack_trace(); loop { halt(); } }); -interrupt!(simd, { - print!("SIMD floating point fault\n"); +interrupt_stack!(simd, stack, { + println!("SIMD floating point fault at {:>02X}:{:>016X}", stack.cs, stack.rip); + ksignal(SIGFPE); stack_trace(); loop { halt(); } }); -interrupt!(virtualization, { - print!("Virtualization fault\n"); +interrupt_stack!(virtualization, stack, { + println!("Virtualization fault at {:>02X}:{:>016X}", stack.cs, stack.rip); + ksignal(SIGBUS); stack_trace(); loop { halt(); } }); -interrupt_error!(security, { - print!("Security exception\n"); +interrupt_error!(security, stack, { + println!("Security exception: {:X} at {:>02X}:{:>016X}", stack.code, stack.cs, stack.rip); + ksignal(SIGBUS); stack_trace(); loop { halt(); } }); diff --git a/arch/x86_64/src/interrupt/ipi.rs b/arch/x86_64/src/interrupt/ipi.rs new file mode 100644 index 0000000..325d9d8 --- /dev/null +++ b/arch/x86_64/src/interrupt/ipi.rs @@ -0,0 +1,5 @@ +use device::local_apic::LOCAL_APIC; + +interrupt!(ipi, { + LOCAL_APIC.eoi(); +}); diff --git a/arch/x86_64/src/interrupt/mod.rs b/arch/x86_64/src/interrupt/mod.rs index e34f1d6..3cc5caa 100644 --- a/arch/x86_64/src/interrupt/mod.rs +++ b/arch/x86_64/src/interrupt/mod.rs @@ -5,6 +5,7 @@ use core::mem; use paging::{ActivePageTable, VirtualAddress}; pub mod exception; +pub mod ipi; pub mod irq; pub mod syscall; diff --git a/arch/x86_64/src/interrupt/syscall.rs b/arch/x86_64/src/interrupt/syscall.rs index d97154e..cc44ea0 100644 --- a/arch/x86_64/src/interrupt/syscall.rs +++ b/arch/x86_64/src/interrupt/syscall.rs @@ -23,17 +23,21 @@ pub unsafe extern fn syscall() { asm!("" : : "{rax}"(a) : : "intel", "volatile"); } - asm!("push fs - push rax - mov rax, 0x18 - mov fs, ax - pop rax" + asm!("push r15 + rdfsbase r15 + push r15 + push fs + mov r15, 0x18 + mov fs, r15" : : : : "intel", "volatile"); inner(); // Interrupt return asm!("pop fs + pop r15 + wrfsbase r15 + pop r15 iretq" : : : : "intel", "volatile"); } diff --git a/arch/x86_64/src/lib.rs b/arch/x86_64/src/lib.rs index 300cb1e..a0224ba 100644 --- a/arch/x86_64/src/lib.rs +++ b/arch/x86_64/src/lib.rs @@ -17,6 +17,7 @@ extern crate hole_list_allocator as allocator; extern crate bitflags; extern crate io; extern crate spin; +extern crate syscall; pub extern crate x86; // Because the memory map is so important to not be aliased, it is defined here, in one place @@ -40,7 +41,7 @@ pub extern crate x86; /// Offset to kernel percpu variables //TODO: Use 64-bit fs offset to enable this pub const KERNEL_PERCPU_OFFSET: usize = KERNEL_HEAP_OFFSET - PML4_SIZE; - pub const KERNEL_PERCPU_OFFSET: usize = 0xC0000000; + pub const KERNEL_PERCPU_OFFSET: usize = 0xC000_0000; /// Size of kernel percpu variables pub const KERNEL_PERCPU_SIZE: usize = 64 * 1024; // 64 KB @@ -61,8 +62,11 @@ pub extern crate x86; /// Size of user stack pub const USER_STACK_SIZE: usize = 1024 * 1024; // 1 MB + /// Offset to user TLS + pub const USER_TLS_OFFSET: usize = USER_STACK_OFFSET + PML4_SIZE; + /// Offset to user temporary image (used when cloning) - pub const USER_TMP_OFFSET: usize = USER_STACK_OFFSET + PML4_SIZE; + pub const USER_TMP_OFFSET: usize = USER_TLS_OFFSET + PML4_SIZE; /// Offset to user temporary heap (used when cloning) pub const USER_TMP_HEAP_OFFSET: usize = USER_TMP_OFFSET + PML4_SIZE; @@ -73,6 +77,9 @@ pub extern crate x86; /// Offset to user temporary stack (used when cloning) pub const USER_TMP_STACK_OFFSET: usize = USER_TMP_GRANT_OFFSET + PML4_SIZE; + /// Offset to user temporary tls (used when cloning) + pub const USER_TMP_TLS_OFFSET: usize = USER_TMP_STACK_OFFSET + PML4_SIZE; + /// Print to console #[macro_export] @@ -111,6 +118,8 @@ macro_rules! interrupt { push r9 push r10 push r11 + rdfsbase rax + push rax push fs mov rax, 0x18 mov fs, ax" @@ -121,6 +130,8 @@ macro_rules! interrupt { // Pop scratch registers and return asm!("pop fs + pop rax + wrfsbase rax pop r11 pop r10 pop r9 @@ -136,13 +147,101 @@ macro_rules! interrupt { }; } +#[repr(packed)] +pub struct InterruptStack { + fs: usize, + r11: usize, + r10: usize, + r9: usize, + r8: usize, + rsi: usize, + rdi: usize, + rdx: usize, + rcx: usize, + rax: usize, + rip: usize, + cs: usize, + rflags: usize, +} + #[macro_export] -macro_rules! interrupt_error { - ($name:ident, $func:block) => { +macro_rules! interrupt_stack { + ($name:ident, $stack: ident, $func:block) => { #[naked] pub unsafe extern fn $name () { #[inline(never)] - unsafe fn inner() { + unsafe fn inner($stack: &$crate::InterruptStack) { + $func + } + + // Push scratch registers + asm!("push rax + push rcx + push rdx + push rdi + push rsi + push r8 + push r9 + push r10 + push r11 + rdfsbase rax + push rax + push fs + mov rax, 0x18 + mov fs, ax" + : : : : "intel", "volatile"); + + // Get reference to stack variables + let rsp: usize; + asm!("" : "={rsp}"(rsp) : : : "intel", "volatile"); + + // Call inner rust function + inner(&*(rsp as *const $crate::InterruptStack)); + + // Pop scratch registers and return + asm!("pop fs + pop rax + wrfsbase rax + pop r11 + pop r10 + pop r9 + pop r8 + pop rsi + pop rdi + pop rdx + pop rcx + pop rax + iretq" + : : : : "intel", "volatile"); + } + }; +} + +#[repr(packed)] +pub struct InterruptErrorStack { + fs: usize, + r11: usize, + r10: usize, + r9: usize, + r8: usize, + rsi: usize, + rdi: usize, + rdx: usize, + rcx: usize, + rax: usize, + code: usize, + rip: usize, + cs: usize, + rflags: usize, +} + +#[macro_export] +macro_rules! interrupt_error { + ($name:ident, $stack:ident, $func:block) => { + #[naked] + pub unsafe extern fn $name () { + #[inline(never)] + unsafe fn inner($stack: &$crate::InterruptErrorStack) { $func } @@ -162,8 +261,12 @@ macro_rules! interrupt_error { mov fs, ax" : : : : "intel", "volatile"); + // Get reference to stack variables + let rsp: usize; + asm!("" : "={rsp}"(rsp) : : : "intel", "volatile"); + // Call inner rust function - inner(); + inner(&*(rsp as *const $crate::InterruptErrorStack)); // Pop scratch registers, error code, and return asm!("pop fs diff --git a/arch/x86_64/src/start.rs b/arch/x86_64/src/start.rs index 0302204..a9da113 100644 --- a/arch/x86_64/src/start.rs +++ b/arch/x86_64/src/start.rs @@ -109,7 +109,7 @@ pub unsafe extern fn kstart() -> ! { } // Initialize devices - device::init(); + device::init(&mut active_table); // Read ACPI tables, starts APs acpi::init(&mut active_table); @@ -145,6 +145,9 @@ pub unsafe extern fn kstart_ap(cpu_id: usize, bsp_table: usize, stack_start: usi assert_eq!(TDATA_TEST_NONZERO, 0xFFFFFFFFFFFFFFFE); } + // Initialize devices (for AP) + device::init_ap(); + AP_READY.store(true, Ordering::SeqCst); } @@ -155,24 +158,27 @@ pub unsafe extern fn kstart_ap(cpu_id: usize, bsp_table: usize, stack_start: usi kmain_ap(cpu_id); } -pub unsafe fn usermode(ip: usize, sp: usize) -> ! { +pub unsafe fn usermode(ip: usize, sp: usize, fs: usize) -> ! { // Go to usermode - asm!("mov ds, ax + asm!("xchg bx, bx + mov ds, ax mov es, ax mov fs, ax mov gs, ax + wrfsbase rbx push rax - push rbx push rcx push rdx push rsi + push rdi iretq" : // No output because it never returns - : "{rax}"(gdt::GDT_USER_DATA << 3 | 3), // Stack segment - "{rbx}"(sp), // Stack pointer - "{rcx}"(3 << 12 | 1 << 9), // Flags - Set IOPL and interrupt enable flag - "{rdx}"(gdt::GDT_USER_CODE << 3 | 3), // Code segment - "{rsi}"(ip) // IP + : "{rax}"(gdt::GDT_USER_DATA << 3 | 3), // Data segment + "{rbx}"(fs), // TLS segment + "{rcx}"(sp), // Stack pointer + "{rdx}"(3 << 12 | 1 << 9), // Flags - Set IOPL and interrupt enable flag + "{rsi}"(gdt::GDT_USER_CODE << 3 | 3), // Code segment + "{rdi}"(ip) // IP : // No clobers because it never returns : "intel", "volatile"); unreachable!(); diff --git a/bootloader/x86_64/startup-x86_64.asm b/bootloader/x86_64/startup-x86_64.asm index d49c532..f3abdf9 100644 --- a/bootloader/x86_64/startup-x86_64.asm +++ b/bootloader/x86_64/startup-x86_64.asm @@ -26,9 +26,9 @@ startup_ap: mov edi, 0x70000 mov cr3, edi - ;enable Page Global, Page Address Extension, and Page Size Extension + ;enable FSGSBASE, FXSAVE/FXRSTOR, Page Global, Page Address Extension, and Page Size Extension mov eax, cr4 - or eax, 1 << 7 | 1 << 5 | 1 << 4 + or eax, 1 << 16 | 1 << 9 | 1 << 7 | 1 << 5 | 1 << 4 mov cr4, eax ; load protected mode GDT @@ -91,9 +91,9 @@ startup_arch: mov edi, 0x70000 mov cr3, edi - ;enable Page Global, Page Address Extension, and Page Size Extension + ;enable FSGSBASE, FXSAVE/FXRSTOR, Page Global, Page Address Extension, and Page Size Extension mov eax, cr4 - or eax, 1 << 7 | 1 << 5 | 1 << 4 + or eax, 1 << 16 | 1 << 9 | 1 << 7 | 1 << 5 | 1 << 4 mov cr4, eax ; load protected mode GDT diff --git a/crates/event/src/lib.rs b/crates/event/src/lib.rs index 18fabbf..a3662a0 100644 --- a/crates/event/src/lib.rs +++ b/crates/event/src/lib.rs @@ -31,7 +31,7 @@ impl EventQueue { /// Err can be used to allow the callback to return an I/O error, and break the /// event loop pub fn add Result> + 'static>(&mut self, fd: RawFd, callback: F) -> Result<()> { - syscall::fevent(fd, syscall::EVENT_READ).map_err(|x| Error::from_sys(x))?; + syscall::fevent(fd, syscall::EVENT_READ).map_err(|x| Error::from_raw_os_error(x.errno))?; self.callbacks.insert(fd, Box::new(callback)); @@ -41,7 +41,7 @@ impl EventQueue { /// Remove a file from the event queue, returning its callback if found pub fn remove(&mut self, fd: RawFd) -> Result Result>>>> { if let Some(callback) = self.callbacks.remove(&fd) { - syscall::fevent(fd, 0).map_err(|x| Error::from_sys(x))?; + syscall::fevent(fd, 0).map_err(|x| Error::from_raw_os_error(x.errno))?; Ok(Some(callback)) } else { diff --git a/drivers/ahcid/src/main.rs b/drivers/ahcid/src/main.rs index 02a5145..3bc17eb 100644 --- a/drivers/ahcid/src/main.rs +++ b/drivers/ahcid/src/main.rs @@ -30,11 +30,6 @@ fn main() { print!("{}", format!(" + AHCI on: {:X} IRQ: {}\n", bar, irq)); thread::spawn(move || { - unsafe { - syscall::iopl(3).expect("ahcid: failed to get I/O permission"); - asm!("cli" :::: "intel", "volatile"); - } - let address = unsafe { syscall::physmap(bar, 4096, MAP_WRITE).expect("ahcid: failed to map address") }; { let socket_fd = syscall::open(":disk", syscall::O_RDWR | syscall::O_CREAT | syscall::O_NONBLOCK).expect("ahcid: failed to create disk scheme"); @@ -56,7 +51,7 @@ fn main() { let mut packet = Packet::default(); if socket.read(&mut packet).expect("ahcid: failed to read disk scheme") == 0 { break; - } + } scheme.handle(&mut packet); socket.write(&mut packet).expect("ahcid: failed to write disk scheme"); } diff --git a/drivers/e1000d/src/main.rs b/drivers/e1000d/src/main.rs index 90f2590..f3baf1b 100644 --- a/drivers/e1000d/src/main.rs +++ b/drivers/e1000d/src/main.rs @@ -30,11 +30,6 @@ fn main() { print!("{}", format!(" + E1000 on: {:X}, IRQ: {}\n", bar, irq)); thread::spawn(move || { - unsafe { - syscall::iopl(3).expect("e1000d: failed to get I/O permission"); - asm!("cli" :::: "intel", "volatile"); - } - let socket_fd = syscall::open(":network", syscall::O_RDWR | syscall::O_CREAT | syscall::O_NONBLOCK).expect("e1000d: failed to create network scheme"); let socket = Arc::new(RefCell::new(unsafe { File::from_raw_fd(socket_fd) })); diff --git a/drivers/ps2d/src/main.rs b/drivers/ps2d/src/main.rs index ba5e330..3a0615c 100644 --- a/drivers/ps2d/src/main.rs +++ b/drivers/ps2d/src/main.rs @@ -122,7 +122,7 @@ fn main() { thread::spawn(|| { unsafe { iopl(3).expect("ps2d: failed to get I/O permission"); - asm!("cli" :::: "intel", "volatile"); + asm!("cli" : : : : "intel", "volatile"); } let input = File::open("display:input").expect("ps2d: failed to open display:input"); diff --git a/drivers/rtl8168d/src/main.rs b/drivers/rtl8168d/src/main.rs index ca441cd..00d6f33 100644 --- a/drivers/rtl8168d/src/main.rs +++ b/drivers/rtl8168d/src/main.rs @@ -31,11 +31,6 @@ fn main() { print!("{}", format!(" + RTL8168 on: {:X}, IRQ: {}\n", bar, irq)); thread::spawn(move || { - unsafe { - syscall::iopl(3).expect("rtl8168d: failed to get I/O permission"); - asm!("cli" :::: "intel", "volatile"); - } - let socket_fd = syscall::open(":network", syscall::O_RDWR | syscall::O_CREAT | syscall::O_NONBLOCK).expect("rtl8168d: failed to create network scheme"); let socket = Arc::new(RefCell::new(unsafe { File::from_raw_fd(socket_fd) })); diff --git a/filesystem/etc/init.rc b/filesystem/etc/init.rc index 27ac5e9..2f29146 100644 --- a/filesystem/etc/init.rc +++ b/filesystem/etc/init.rc @@ -8,4 +8,4 @@ dhcpd httpd getty display:2 getty display:3 -#orbital display:4 +orbital display:4 diff --git a/kernel/context/context.rs b/kernel/context/context.rs index c280dae..1563e6f 100644 --- a/kernel/context/context.rs +++ b/kernel/context/context.rs @@ -5,7 +5,7 @@ use spin::Mutex; use arch; use context::file::File; -use context::memory::{Grant, Memory, SharedMemory}; +use context::memory::{Grant, Memory, SharedMemory, Tls}; use syscall::data::Event; use sync::{WaitCondition, WaitQueue}; @@ -36,7 +36,7 @@ pub struct Context { /// Context running or not pub running: bool, /// CPU ID, if locked - pub cpuid: Option, + pub cpu_id: Option, /// Context is halting parent pub vfork: bool, /// Context is being waited on @@ -55,6 +55,8 @@ pub struct Context { pub heap: Option, /// User stack pub stack: Option, + /// User Tls + pub tls: Option, /// User grants pub grants: Arc>>, /// The name of the context @@ -81,7 +83,7 @@ impl Context { egid: 0, status: Status::Blocked, running: false, - cpuid: None, + cpu_id: None, vfork: false, waitpid: Arc::new(WaitCondition::new()), wake: None, @@ -91,6 +93,7 @@ impl Context { image: Vec::new(), heap: None, stack: None, + tls: None, grants: Arc::new(Mutex::new(Vec::new())), name: Arc::new(Mutex::new(Vec::new())), cwd: Arc::new(Mutex::new(Vec::new())), @@ -153,6 +156,13 @@ impl Context { pub fn unblock(&mut self) -> bool { if self.status == Status::Blocked { self.status = Status::Runnable; + if let Some(cpu_id) = self.cpu_id { + if cpu_id != ::cpu_id() { + // Send IPI if not on current CPU + // TODO: Make this more architecture independent + unsafe { arch::device::local_apic::LOCAL_APIC.ipi(cpu_id) }; + } + } true } else { false diff --git a/kernel/context/memory.rs b/kernel/context/memory.rs index 911f619..bc74005 100644 --- a/kernel/context/memory.rs +++ b/kernel/context/memory.rs @@ -332,3 +332,10 @@ impl Drop for Memory { self.unmap(true); } } + +#[derive(Debug)] +pub struct Tls { + pub master: VirtualAddress, + pub file_size: usize, + pub mem: Memory +} diff --git a/kernel/context/mod.rs b/kernel/context/mod.rs index 882eb6c..1562d93 100644 --- a/kernel/context/mod.rs +++ b/kernel/context/mod.rs @@ -50,7 +50,7 @@ pub fn init() { context.kfx = Some(fx); context.status = Status::Runnable; context.running = true; - context.cpuid = Some(::cpu_id()); + context.cpu_id = Some(::cpu_id()); CONTEXT_ID.store(context.id, Ordering::SeqCst); } diff --git a/kernel/context/switch.rs b/kernel/context/switch.rs index ccc5176..f3ace74 100644 --- a/kernel/context/switch.rs +++ b/kernel/context/switch.rs @@ -16,27 +16,34 @@ pub unsafe fn switch() -> bool { arch::interrupt::pause(); } + let cpu_id = ::cpu_id(); + let from_ptr; let mut to_ptr = 0 as *mut Context; { let contexts = contexts(); { - let context_lock = contexts.current().expect("context::switch: Not inside of context"); + let context_lock = contexts.current().expect("context::switch: not inside of context"); let mut context = context_lock.write(); from_ptr = context.deref_mut() as *mut Context; } let check_context = |context: &mut Context| -> bool { - if context.cpuid == None || context.cpuid == Some(::cpu_id()) { - if context.status == Status::Blocked && context.wake.is_some() { - let wake = context.wake.expect("context::switch: wake not set"); + if context.cpu_id == None && cpu_id == 0 { + context.cpu_id = Some(cpu_id); + println!("{}: take {} {}", cpu_id, context.id, ::core::str::from_utf8_unchecked(&context.name.lock())); + } - let current = arch::time::monotonic(); - if current.0 > wake.0 || (current.0 == wake.0 && current.1 >= wake.1) { - context.unblock(); - } + if context.status == Status::Blocked && context.wake.is_some() { + let wake = context.wake.expect("context::switch: wake not set"); + + let current = arch::time::monotonic(); + if current.0 > wake.0 || (current.0 == wake.0 && current.1 >= wake.1) { + context.unblock(); } + } + if context.cpu_id == Some(cpu_id) { if context.status == Status::Runnable && ! context.running { return true; } @@ -74,8 +81,6 @@ pub unsafe fn switch() -> bool { return false; } - // println!("{}: Switch {} to {}", ::cpu_id(), (&*from_ptr).id, (&*to_ptr).id); - (&mut *from_ptr).running = false; (&mut *to_ptr).running = true; if let Some(ref stack) = (*to_ptr).kstack { @@ -83,6 +88,9 @@ pub unsafe fn switch() -> bool { } CONTEXT_ID.store((&mut *to_ptr).id, Ordering::SeqCst); + // Unset global lock before switch, as arch is only usable by the current CPU at this time + arch::context::CONTEXT_SWITCH_LOCK.store(false, Ordering::SeqCst); + (&mut *from_ptr).arch.switch_to(&mut (&mut *to_ptr).arch); true diff --git a/kernel/lib.rs b/kernel/lib.rs index 5da383d..baefe32 100644 --- a/kernel/lib.rs +++ b/kernel/lib.rs @@ -152,6 +152,19 @@ pub extern fn userspace_init() { panic!("initfs:init returned") } +/// Allow exception handlers to send signal to arch-independant kernel +#[no_mangle] +pub extern fn ksignal(signal: usize) { + println!("SIGNAL {}, CPU {}, PID {}", signal, cpu_id(), context::context_id()); + { + let contexts = context::contexts(); + if let Some(context_lock) = contexts.current() { + let context = context_lock.read(); + println!("NAME {}", unsafe { ::core::str::from_utf8_unchecked(&context.name.lock()) }); + } + } +} + #[no_mangle] pub extern fn kmain(cpus: usize) { CPU_ID.store(0, Ordering::SeqCst); @@ -195,6 +208,14 @@ pub extern fn kmain_ap(id: usize) { println!("AP {}: {:?}", id, pid); loop { - unsafe { interrupt::enable_and_halt() } + unsafe { + interrupt::disable(); + if context::switch() { + interrupt::enable_and_nop(); + } else { + // Enable interrupts, then halt CPU (to save power) until the next interrupt is actually fired. + interrupt::enable_and_halt(); + } + } } } diff --git a/kernel/scheme/sys/context.rs b/kernel/scheme/sys/context.rs index 8c99a16..75b5e4f 100644 --- a/kernel/scheme/sys/context.rs +++ b/kernel/scheme/sys/context.rs @@ -5,12 +5,13 @@ use context; use syscall::error::Result; pub fn resource() -> Result> { - let mut string = format!("{:<6}{:<6}{:<6}{:<6}{:<6}{:<8}{}\n", + let mut string = format!("{:<6}{:<6}{:<6}{:<6}{:<6}{:<6}{:<8}{}\n", "PID", "PPID", "UID", "GID", "STAT", + "CPU", "MEM", "NAME"); { @@ -18,6 +19,35 @@ pub fn resource() -> Result> { for (_id, context_lock) in contexts.iter() { let context = context_lock.read(); + let mut stat_string = String::new(); + if context.stack.is_some() { + stat_string.push('U'); + } else { + stat_string.push('K'); + } + match context.status { + context::Status::Runnable => { + stat_string.push('R'); + }, + context::Status::Blocked => if context.wake.is_some() { + stat_string.push('S'); + } else { + stat_string.push('B'); + }, + context::Status::Exited(_status) => { + stat_string.push('Z'); + } + } + if context.running { + stat_string.push('+'); + } + + let cpu_string = if let Some(cpu_id) = context.cpu_id { + format!("{}", cpu_id) + } else { + format!("?") + }; + let mut memory = 0; if let Some(ref kfx) = context.kstack { memory += kfx.len(); @@ -49,38 +79,16 @@ pub fn resource() -> Result> { format!("{} B", memory) }; - let mut stat_string = String::new(); - if context.stack.is_some() { - stat_string.push('U'); - } else { - stat_string.push('K'); - } - match context.status { - context::Status::Runnable => { - stat_string.push('R'); - }, - context::Status::Blocked => if context.wake.is_some() { - stat_string.push('S'); - } else { - stat_string.push('B'); - }, - context::Status::Exited(_status) => { - stat_string.push('Z'); - } - } - if context.running { - stat_string.push('+'); - } - let name_bytes = context.name.lock(); let name = str::from_utf8(&name_bytes).unwrap_or(""); - string.push_str(&format!("{:<6}{:<6}{:<6}{:<6}{:<6}{:<8}{}\n", + string.push_str(&format!("{:<6}{:<6}{:<6}{:<6}{:<6}{:<6}{:<8}{}\n", context.id, context.ppid, context.euid, context.egid, stat_string, + cpu_string, memory_string, name)); } diff --git a/kernel/syscall/process.rs b/kernel/syscall/process.rs index e3cd886..39309cf 100644 --- a/kernel/syscall/process.rs +++ b/kernel/syscall/process.rs @@ -62,6 +62,7 @@ pub fn clone(flags: usize, stack_base: usize) -> Result { let rgid; let euid; let egid; + let mut cpu_id = None; let arch; let vfork; let mut kfx_option = None; @@ -70,6 +71,7 @@ pub fn clone(flags: usize, stack_base: usize) -> Result { let mut image = vec![]; let mut heap_option = None; let mut stack_option = None; + let mut tls_option = None; let grants; let name; let cwd; @@ -88,6 +90,10 @@ pub fn clone(flags: usize, stack_base: usize) -> Result { euid = context.euid; egid = context.egid; + if flags & CLONE_VM == CLONE_VM { + cpu_id = context.cpu_id; + } + arch = context.arch.clone(); if let Some(ref fx) = context.kfx { @@ -181,6 +187,29 @@ pub fn clone(flags: usize, stack_base: usize) -> Result { stack_option = Some(new_stack); } + if let Some(ref tls) = context.tls { + let mut new_tls = context::memory::Tls { + master: tls.master, + file_size: tls.file_size, + mem: context::memory::Memory::new( + VirtualAddress::new(arch::USER_TMP_TLS_OFFSET), + tls.mem.size(), + entry::PRESENT | entry::NO_EXECUTE | entry::WRITABLE, + true, + false + ) + }; + + unsafe { + arch::externs::memcpy(new_tls.mem.start_address().get() as *mut u8, + tls.master.get() as *const u8, + tls.file_size); + } + + new_tls.mem.remap(tls.mem.flags(), true); + tls_option = Some(new_tls); + } + if flags & CLONE_VM == CLONE_VM { grants = context.grants.clone(); } else { @@ -277,6 +306,8 @@ pub fn clone(flags: usize, stack_base: usize) -> Result { context.euid = euid; context.egid = egid; + context.cpu_id = cpu_id; + context.status = context::Status::Runnable; context.vfork = vfork; @@ -393,6 +424,12 @@ pub fn clone(flags: usize, stack_base: usize) -> Result { context.stack = Some(stack); } + // Setup user TLS + if let Some(mut tls) = tls_option { + tls.mem.move_to(VirtualAddress::new(arch::USER_TLS_OFFSET), &mut new_table, &mut temporary_page, true); + context.tls = Some(tls); + } + context.name = name; context.cwd = cwd; @@ -411,6 +448,7 @@ pub fn clone(flags: usize, stack_base: usize) -> Result { pub fn exec(path: &[u8], arg_ptrs: &[[usize; 2]]) -> Result { let entry; let mut sp = arch::USER_STACK_OFFSET + arch::USER_STACK_SIZE - 256; + let fs = arch::USER_STACK_OFFSET; { let mut args = Vec::new(); @@ -466,11 +504,12 @@ pub fn exec(path: &[u8], arg_ptrs: &[[usize; 2]]) -> Result { // Set name context.name = Arc::new(Mutex::new(canonical)); - // Unmap previous image and stack + // Unmap previous image, heap, grants, stack, and tls context.image.clear(); drop(context.heap.take()); - drop(context.stack.take()); context.grants = Arc::new(Mutex::new(Vec::new())); + drop(context.stack.take()); + drop(context.tls.take()); if stat.st_mode & syscall::flag::MODE_SETUID == syscall::flag::MODE_SETUID { context.euid = stat.st_uid; @@ -481,6 +520,7 @@ pub fn exec(path: &[u8], arg_ptrs: &[[usize; 2]]) -> Result { } // Map and copy new segments + let mut tls_option = None; for segment in elf.segments() { if segment.p_type == program_header::PT_LOAD { let mut memory = context::memory::Memory::new( @@ -514,6 +554,12 @@ pub fn exec(path: &[u8], arg_ptrs: &[[usize; 2]]) -> Result { memory.remap(flags, true); context.image.push(memory.to_shared()); + } else if segment.p_type == program_header::PT_TLS { + tls_option = Some(( + VirtualAddress::new(segment.p_vaddr as usize), + segment.p_filesz as usize, + segment.p_memsz as usize + )); } } @@ -535,6 +581,35 @@ pub fn exec(path: &[u8], arg_ptrs: &[[usize; 2]]) -> Result { true )); + // Map TLS + if let Some((master, file_size, size)) = tls_option { + let tls = context::memory::Tls { + master: master, + file_size: file_size, + mem: context::memory::Memory::new( + VirtualAddress::new(arch::USER_TLS_OFFSET), + size, + entry::NO_EXECUTE | entry::WRITABLE | entry::USER_ACCESSIBLE, + true, + true + ) + }; + + unsafe { + // Copy file data + memcpy(tls.mem.start_address().get() as *mut u8, + master.get() as *const u8, + file_size); + } + + // Set TLS pointer + //TODO: Do not use stack to store TLS pointer, use a TCB structure instead + unsafe { *(arch::USER_STACK_OFFSET as *mut usize) = tls.mem.start_address().get() + size; } + + context.tls = Some(tls); + } + + // Push arguments let mut arg_size = 0; for arg in args.iter().rev() { sp -= mem::size_of::(); @@ -597,7 +672,7 @@ pub fn exec(path: &[u8], arg_ptrs: &[[usize; 2]]) -> Result { } // Go to usermode - unsafe { usermode(entry, sp); } + unsafe { usermode(entry, sp, fs); } } pub fn exit(status: usize) -> ! { @@ -897,6 +972,7 @@ pub fn virttophys(virtual_address: usize) -> Result { pub fn waitpid(pid: usize, status_ptr: usize, flags: usize) -> Result { loop { let mut exited = false; + let mut running; let waitpid; { let contexts = context::contexts(); @@ -909,10 +985,23 @@ pub fn waitpid(pid: usize, status_ptr: usize, flags: usize) -> Result { } exited = true; } + running = context.running; waitpid = context.waitpid.clone(); } if exited { + // Spin until not running + while running { + { + let contexts = context::contexts(); + let context_lock = contexts.get(pid).ok_or(Error::new(ESRCH))?; + let context = context_lock.read(); + running = context.running; + } + + arch::interrupt::pause(); + } + let mut contexts = context::contexts_mut(); return contexts.remove(pid).ok_or(Error::new(ESRCH)).and(Ok(pid)); } else if flags & WNOHANG == WNOHANG { diff --git a/libstd b/libstd index 8a29d8f..263ed59 160000 --- a/libstd +++ b/libstd @@ -1 +1 @@ -Subproject commit 8a29d8ff3304b78d74e0259270ba50cb33765a63 +Subproject commit 263ed59929e68073bd4e47ba07f2fbe283ee2854 diff --git a/libstd_real/Cargo.toml b/libstd_real/Cargo.toml new file mode 100644 index 0000000..7b766cd --- /dev/null +++ b/libstd_real/Cargo.toml @@ -0,0 +1,18 @@ +[package] +name = "redox_std" +version = "0.1.0" +authors = ["Jeremy Soller "] + +[lib] +name = "std" +path = "../rust/src/libstd/lib.rs" + +[dependencies] +alloc_system = { path = "alloc_system" } +compiler_builtins = { path = "compiler_builtins" } +panic_unwind = { path = "panic_unwind" } +libc = { path = "libc" } +unwind = { path = "unwind" } + +[replace] +"libc:0.2.17" = { git = "https://github.com/redox-os/liblibc.git", branch = "new_kernel" } diff --git a/libstd_real/alloc_system/Cargo.toml b/libstd_real/alloc_system/Cargo.toml new file mode 100644 index 0000000..8cdca8a --- /dev/null +++ b/libstd_real/alloc_system/Cargo.toml @@ -0,0 +1,12 @@ +[package] +name = "alloc_system" +version = "0.0.0" +authors = ["Jeremy Soller "] + +[dependencies.ralloc] +path = "../../ralloc/" +default-features = false +features = ["allocator"] + +[replace] +"libc:0.2.17" = { git = "https://github.com/redox-os/liblibc.git", branch = "new_kernel" } diff --git a/libstd_real/alloc_system/src/lib.rs b/libstd_real/alloc_system/src/lib.rs new file mode 100644 index 0000000..c877fda --- /dev/null +++ b/libstd_real/alloc_system/src/lib.rs @@ -0,0 +1,6 @@ +#![allocator] +#![feature(allocator)] +#![no_std] + +#[allocator] +extern crate ralloc; diff --git a/libstd_real/compiler_builtins/Cargo.toml b/libstd_real/compiler_builtins/Cargo.toml new file mode 100644 index 0000000..c53ec83 --- /dev/null +++ b/libstd_real/compiler_builtins/Cargo.toml @@ -0,0 +1,4 @@ +[package] +name = "compiler_builtins" +version = "0.1.0" +authors = ["Jeremy Soller "] diff --git a/libstd_real/compiler_builtins/src/lib.rs b/libstd_real/compiler_builtins/src/lib.rs new file mode 100644 index 0000000..08d020f --- /dev/null +++ b/libstd_real/compiler_builtins/src/lib.rs @@ -0,0 +1,72 @@ +#![no_std] + +/// Memcpy +/// +/// Copy N bytes of memory from one location to another. +#[no_mangle] +pub unsafe extern fn memcpy(dest: *mut u8, src: *const u8, + n: usize) -> *mut u8 { + let mut i = 0; + while i < n { + *((dest as usize + i) as *mut u8) = *((src as usize + i) as *const u8); + i += 1; + } + + dest +} + +/// Memmove +/// +/// Copy N bytes of memory from src to dest. The memory areas may overlap. +#[no_mangle] +pub unsafe extern fn memmove(dest: *mut u8, src: *const u8, + n: usize) -> *mut u8 { + if src < dest as *const u8 { + let mut i = n; + while i != 0 { + i -= 1; + *((dest as usize + i) as *mut u8) = *((src as usize + i) as *const u8); + } + } else { + let mut i = 0; + while i < n { + *((dest as usize + i) as *mut u8) = *((src as usize + i) as *const u8); + i += 1; + } + } + + dest +} + +/// Memset +/// +/// Fill a block of memory with a specified value. +#[no_mangle] +pub unsafe extern fn memset(dest: *mut u8, c: i32, n: usize) -> *mut u8 { + let mut i = 0; + while i < n { + *((dest as usize + i) as *mut u8) = c as u8; + i += 1; + } + + dest +} + +/// Memcmp +/// +/// Compare two blocks of memory. +#[no_mangle] +pub unsafe extern fn memcmp(s1: *const u8, s2: *const u8, n: usize) -> i32 { + let mut i = 0; + + while i < n { + let a = *((s1 as usize + i) as *const u8); + let b = *((s2 as usize + i) as *const u8); + if a != b { + return a as i32 - b as i32 + } + i += 1; + } + + 0 +} diff --git a/libstd_real/libc/Cargo.toml b/libstd_real/libc/Cargo.toml new file mode 100644 index 0000000..f63f100 --- /dev/null +++ b/libstd_real/libc/Cargo.toml @@ -0,0 +1,7 @@ +[package] +name = "libc" +version = "0.1.0" +authors = ["Jeremy Soller "] + +[dependencies] +syscall = { path = "../../syscall/" } diff --git a/libstd_real/libc/src/funcs.rs b/libstd_real/libc/src/funcs.rs new file mode 100644 index 0000000..45b1930 --- /dev/null +++ b/libstd_real/libc/src/funcs.rs @@ -0,0 +1,19 @@ +use super::{c_char, size_t}; + +pub unsafe extern fn strlen(ptr: *const c_char) -> size_t { + let mut i: size_t = 0; + while *ptr.offset(i as isize) != 0 { + i += 1; + } + i +} + +pub unsafe extern fn random() -> u64 { + let rand; + asm!("rdrand rax" + : "={rax}"(rand) + : + : + : "intel", "volatile"); + rand +} diff --git a/libstd_real/libc/src/lib.rs b/libstd_real/libc/src/lib.rs new file mode 100644 index 0000000..c7142ef --- /dev/null +++ b/libstd_real/libc/src/lib.rs @@ -0,0 +1,18 @@ +#![no_std] +#![allow(non_camel_case_types)] +#![feature(asm)] +#![feature(naked_functions)] + +pub use types::*; +pub use funcs::*; +pub use start::*; +pub use syscall::*; + +/// Basic types (not usually system specific) +mod types; +/// Basic functions (not system specific) +mod funcs; +/// Start function and call in to libstd +mod start; +/// Conversion for syscall library (specific to Redox) +mod syscall; diff --git a/libstd_real/libc/src/start.rs b/libstd_real/libc/src/start.rs new file mode 100644 index 0000000..e7cfe43 --- /dev/null +++ b/libstd_real/libc/src/start.rs @@ -0,0 +1,40 @@ +use super::exit; + +#[no_mangle] +#[naked] +#[cfg(target_arch = "x86")] +pub unsafe fn _start() { + asm!("push esp + call _start_stack + pop esp" + : + : + : "memory" + : "intel", "volatile"); + let _ = exit(0); +} + +#[no_mangle] +#[naked] +#[cfg(target_arch = "x86_64")] +pub unsafe fn _start() { + asm!("mov rdi, rsp + and rsp, 0xFFFFFFFFFFFFFFF0 + call _start_stack" + : + : + : "memory" + : "intel", "volatile"); + let _ = exit(0); +} + +#[no_mangle] +pub unsafe extern "C" fn _start_stack(stack: *const usize){ + extern "C" { + fn main(argc: usize, argv: *const *const u8) -> usize; + } + + let argc = *stack as usize; + let argv = stack.offset(1) as *const *const u8; + let _ = exit(main(argc, argv)); +} diff --git a/libstd_real/libc/src/syscall.rs b/libstd_real/libc/src/syscall.rs new file mode 100644 index 0000000..e24c58e --- /dev/null +++ b/libstd_real/libc/src/syscall.rs @@ -0,0 +1,87 @@ +/// Convert syscall types to libc types +extern crate syscall; + +use super::{c_int, sa_family_t}; + +use self::syscall::data::{Stat, TimeSpec}; + +pub use self::syscall::error::*; +pub use self::syscall::flag::*; +pub use self::syscall::{ + clock_gettime, clone, execve as exec, exit, futex, getpid, kill, nanosleep, setgid, setuid, waitpid, + chdir, getcwd, open, mkdir, rmdir, unlink, dup, pipe2, + read, write, fpath, fstat, fsync, ftruncate, lseek, close +}; + +//TODO: Thread local +pub static mut errno: c_int = 0; + +pub type stat = Stat; +pub type timespec = TimeSpec; + +pub const AF_INET: sa_family_t = 1; +pub const AF_INET6: sa_family_t = 2; + +pub const STDIN_FILENO: usize = 0; +pub const STDOUT_FILENO: usize = 1; +pub const STDERR_FILENO: usize = 2; + +fn cvt(result: syscall::Result) -> c_int { + match result { + Ok(res) => res as c_int, + Err(err) => { + unsafe { errno = err.errno }; + -1 + } + } +} + +// ralloc shims { +/// Cooperatively gives up a timeslice to the OS scheduler. +#[no_mangle] +pub unsafe extern "C" fn sched_yield() -> c_int { + cvt(syscall::sched_yield()) +} + +/// Increment data segment of this process by some, _n_, return a pointer to the new data segment +/// start. +/// +/// This uses the system call BRK as backend. +/// +/// This is unsafe for multiple reasons. Most importantly, it can create an inconsistent state, +/// because it is not atomic. Thus, it can be used to create Undefined Behavior. +#[no_mangle] +pub extern "C" fn sbrk(n: isize) -> *mut u8 { + let orig_seg_end = match unsafe { syscall::brk(0) } { + Ok(end) => end, + Err(_) => return !0 as *mut u8 + }; + + if n == 0 { + return orig_seg_end as *mut u8; + } + + let expected_end = match orig_seg_end.checked_add(n as usize) { + Some(end) => end, + None => return !0 as *mut u8 + }; + + let new_seg_end = match unsafe { syscall::brk(expected_end) } { + Ok(end) => end, + Err(_) => return !0 as *mut u8 + }; + + if new_seg_end != expected_end { + // Reset the break. + let _ = unsafe { syscall::brk(orig_seg_end) }; + + !0 as *mut u8 + } else { + orig_seg_end as *mut u8 + } +} +// } ralloc shims + +pub unsafe fn fcntl(_fd: usize, _cmd: c_int, _arg: c_int) -> c_int { + cvt(Err(Error::new(ENOSYS))) +} diff --git a/libstd_real/libc/src/types.rs b/libstd_real/libc/src/types.rs new file mode 100644 index 0000000..0fbc3d8 --- /dev/null +++ b/libstd_real/libc/src/types.rs @@ -0,0 +1,96 @@ +// Use repr(u8) as LLVM expects `void*` to be the same as `i8*` to help enable +// more optimization opportunities around it recognizing things like +// malloc/free. +#[repr(u8)] +pub enum c_void { + // Two dummy variants so the #[repr] attribute can be used. + #[doc(hidden)] + __variant1, + #[doc(hidden)] + __variant2, +} + +pub type int8_t = i8; +pub type int16_t = i16; +pub type int32_t = i32; +pub type int64_t = i64; +pub type uint8_t = u8; +pub type uint16_t = u16; +pub type uint32_t = u32; +pub type uint64_t = u64; + +pub type c_schar = i8; +pub type c_uchar = u8; +pub type c_short = i16; +pub type c_ushort = u16; +pub type c_float = f32; +pub type c_double = f64; + +pub type intmax_t = i64; +pub type uintmax_t = u64; + +pub type c_char = i8; +pub type c_int = i32; +pub type c_uint = u32; +pub type c_long = i64; +pub type c_ulong = u64; +pub type c_longlong = i64; +pub type c_ulonglong = u64; + +pub type off_t = usize; +pub type size_t = usize; +pub type ptrdiff_t = isize; +pub type intptr_t = isize; +pub type uintptr_t = usize; +pub type ssize_t = isize; + +pub type mode_t = u16; +pub type time_t = i64; +pub type pid_t = usize; +pub type gid_t = usize; +pub type uid_t = usize; + +pub type in_addr_t = u32; +pub type in_port_t = u16; + +pub type socklen_t = u32; +pub type sa_family_t = u16; + +#[derive(Copy, Clone)] +#[repr(C)] +pub struct in_addr { + pub s_addr: in_addr_t, +} + +#[derive(Copy, Clone)] +#[repr(C)] +pub struct in6_addr { + pub s6_addr: [u8; 16], + __align: [u32; 0], +} + +#[derive(Copy, Clone)] +#[repr(C)] +pub struct sockaddr { + pub sa_family: sa_family_t, + pub sa_data: [::c_char; 14], +} + +#[derive(Copy, Clone)] +#[repr(C)] +pub struct sockaddr_in { + pub sin_family: sa_family_t, + pub sin_port: ::in_port_t, + pub sin_addr: ::in_addr, + pub sin_zero: [u8; 8], +} + +#[derive(Copy, Clone)] +#[repr(C)] +pub struct sockaddr_in6 { + pub sin6_family: sa_family_t, + pub sin6_port: in_port_t, + pub sin6_flowinfo: u32, + pub sin6_addr: ::in6_addr, + pub sin6_scope_id: u32, +} diff --git a/libstd_real/panic_unwind/Cargo.toml b/libstd_real/panic_unwind/Cargo.toml new file mode 100644 index 0000000..defb0e0 --- /dev/null +++ b/libstd_real/panic_unwind/Cargo.toml @@ -0,0 +1,7 @@ +[package] +name = "panic_unwind" +version = "0.0.0" +authors = ["Jeremy Soller "] + +[dependencies] +syscall = { path = "../../syscall/" } diff --git a/libstd_real/panic_unwind/src/lib.rs b/libstd_real/panic_unwind/src/lib.rs new file mode 100644 index 0000000..bae8220 --- /dev/null +++ b/libstd_real/panic_unwind/src/lib.rs @@ -0,0 +1,27 @@ +#![no_std] +#![feature(core_intrinsics)] +#![feature(lang_items)] +#![feature(panic_runtime)] +#![panic_runtime] + +#[no_mangle] +pub unsafe extern fn __rust_maybe_catch_panic(f: fn(*mut u8), data: *mut u8, + _data_ptr: *mut usize, _vtable_ptr: *mut usize) -> u32 { + f(data); + 0 +} + +#[no_mangle] +pub unsafe extern fn __rust_start_panic(_data: usize, _vtable: usize) -> u32 { + core::intrinsics::abort(); +} + +#[lang = "eh_personality"] +pub extern fn eh_personality() {} + +#[allow(non_snake_case)] +#[no_mangle] +/// Required to handle panics +pub unsafe extern "C" fn _Unwind_Resume() -> ! { + core::intrinsics::abort(); +} diff --git a/libstd_real/unwind/Cargo.toml b/libstd_real/unwind/Cargo.toml new file mode 100644 index 0000000..41c966d --- /dev/null +++ b/libstd_real/unwind/Cargo.toml @@ -0,0 +1,4 @@ +[package] +name = "unwind" +version = "0.0.0" +authors = ["Jeremy Soller "] diff --git a/libstd_real/unwind/src/lib.rs b/libstd_real/unwind/src/lib.rs new file mode 100644 index 0000000..0c9ac1a --- /dev/null +++ b/libstd_real/unwind/src/lib.rs @@ -0,0 +1 @@ +#![no_std] diff --git a/programs/acid b/programs/acid index 1afcf7a..519d988 160000 --- a/programs/acid +++ b/programs/acid @@ -1 +1 @@ -Subproject commit 1afcf7ab26ca3f697082674e6a72c94dd211c74b +Subproject commit 519d98880c7c0a6b40111e7861259cf46998cee3 diff --git a/programs/coreutils b/programs/coreutils index 7d52331..a6e4162 160000 --- a/programs/coreutils +++ b/programs/coreutils @@ -1 +1 @@ -Subproject commit 7d5233187721918f4c00726771c3ec2d44a1f8c6 +Subproject commit a6e4162839279e639057b616ac79d34421f85754 diff --git a/rust b/rust index 17af6b9..123d08b 160000 --- a/rust +++ b/rust @@ -1 +1 @@ -Subproject commit 17af6b94b2ea39414e4449c17cc4ab066d790e8f +Subproject commit 123d08b3d3901d5725af8303c1329b007089cde5 diff --git a/schemes/ethernetd/src/scheme.rs b/schemes/ethernetd/src/scheme.rs index 9dba500..7b1b3bd 100644 --- a/schemes/ethernetd/src/scheme.rs +++ b/schemes/ethernetd/src/scheme.rs @@ -6,7 +6,7 @@ use std::{cmp, str, u16}; use netutils::{getcfg, MacAddr, EthernetII}; use syscall; -use syscall::error::{Error, Result, EACCES, EBADF, EINVAL, EWOULDBLOCK}; +use syscall::error::{Error, Result, EACCES, EBADF, EINVAL, EIO, EWOULDBLOCK}; use syscall::flag::O_NONBLOCK; use syscall::scheme::SchemeMut; @@ -63,7 +63,7 @@ impl EthernetScheme { impl SchemeMut for EthernetScheme { fn open(&mut self, url: &[u8], flags: usize, uid: u32, _gid: u32) -> Result { if uid == 0 { - let mac_addr = MacAddr::from_str(&getcfg("mac").map_err(|err| err.into_sys())?); + let mac_addr = MacAddr::from_str(&getcfg("mac").map_err(|err| Error::new(err.raw_os_error().unwrap_or(EIO)))?); let path = try!(str::from_utf8(url).or(Err(Error::new(EINVAL)))); let ethertype = u16::from_str_radix(path, 16).unwrap_or(0); @@ -121,7 +121,7 @@ impl SchemeMut for EthernetScheme { if let Some(mut frame) = EthernetII::from_bytes(buf) { frame.header.src = handle.host_addr; frame.header.ethertype.set(handle.ethertype); - self.network.write(&frame.to_bytes()).map_err(|err| err.into_sys()) + self.network.write(&frame.to_bytes()).map_err(|err| Error::new(err.raw_os_error().unwrap_or(EIO))) } else { Err(Error::new(EINVAL)) } diff --git a/schemes/ipd/src/main.rs b/schemes/ipd/src/main.rs index 47b9a1f..96b6d62 100644 --- a/schemes/ipd/src/main.rs +++ b/schemes/ipd/src/main.rs @@ -12,7 +12,7 @@ use std::os::unix::io::FromRawFd; use std::rc::Rc; use std::{slice, str, thread}; use syscall::data::Packet; -use syscall::error::{Error, Result, EACCES, EADDRNOTAVAIL, EBADF, EINVAL, ENOENT, EWOULDBLOCK}; +use syscall::error::{Error, Result, EACCES, EADDRNOTAVAIL, EBADF, EIO, EINVAL, ENOENT, EWOULDBLOCK}; use syscall::flag::{EVENT_READ, O_NONBLOCK}; use syscall::scheme::SchemeMut; @@ -275,7 +275,7 @@ impl SchemeMut for Ipd { data: ip.to_bytes() }; - interface.ip_file.write(&frame.to_bytes()).map_err(|err| err.into_sys())?; + interface.ip_file.write(&frame.to_bytes()).map_err(|err| Error::new(err.raw_os_error().unwrap_or(EIO)))?; return Ok(buf.len()); } diff --git a/schemes/tcpd/src/main.rs b/schemes/tcpd/src/main.rs index 1c0e85f..847acb1 100644 --- a/schemes/tcpd/src/main.rs +++ b/schemes/tcpd/src/main.rs @@ -15,7 +15,7 @@ use std::rc::Rc; use event::EventQueue; use netutils::{n16, n32, Ipv4, Ipv4Addr, Ipv4Header, Tcp, TcpHeader, Checksum, TCP_FIN, TCP_SYN, TCP_RST, TCP_PSH, TCP_ACK}; use syscall::data::Packet; -use syscall::error::{Error, Result, EACCES, EADDRINUSE, EBADF, EINVAL, EISCONN, EMSGSIZE, ENOTCONN, EWOULDBLOCK}; +use syscall::error::{Error, Result, EACCES, EADDRINUSE, EBADF, EIO, EINVAL, EISCONN, EMSGSIZE, ENOTCONN, EWOULDBLOCK}; use syscall::flag::{EVENT_READ, O_CREAT, O_RDWR, O_NONBLOCK}; use syscall::scheme::SchemeMut; @@ -274,7 +274,7 @@ impl Tcpd { let tcp = handle.create_tcp(TCP_ACK | TCP_PSH, buf.to_vec()); let ip = handle.create_ip(self.rng.gen(), tcp.to_bytes()); - let result = self.tcp_file.write(&ip.to_bytes()).map_err(|err| err.into_sys()); + let result = self.tcp_file.write(&ip.to_bytes()).map_err(|err| Error::new(err.raw_os_error().unwrap_or(EIO))); if result.is_ok() { handle.seq += buf.len() as u32; } @@ -422,7 +422,7 @@ impl SchemeMut for Tcpd { let tcp = handle.create_tcp(TCP_SYN, Vec::new()); let ip = handle.create_ip(self.rng.gen(), tcp.to_bytes()); - self.tcp_file.write(&ip.to_bytes()).map_err(|err| err.into_sys())?; + self.tcp_file.write(&ip.to_bytes()).map_err(|err| Error::new(err.raw_os_error().unwrap_or(EIO)))?; handle.seq += 1; } @@ -469,7 +469,7 @@ impl SchemeMut for Tcpd { let tcp = new_handle.create_tcp(TCP_SYN | TCP_ACK, Vec::new()); let ip = new_handle.create_ip(self.rng.gen(), tcp.to_bytes()); - self.tcp_file.write(&ip.to_bytes()).map_err(|err| err.into_sys()).and(Ok(buf.len()))?; + self.tcp_file.write(&ip.to_bytes()).map_err(|err| Error::new(err.raw_os_error().unwrap_or(EIO))).and(Ok(buf.len()))?; new_handle.seq += 1; } else { @@ -506,7 +506,7 @@ impl SchemeMut for Tcpd { let tcp = new_handle.create_tcp(TCP_SYN, Vec::new()); let ip = new_handle.create_ip(self.rng.gen(), tcp.to_bytes()); - self.tcp_file.write(&ip.to_bytes()).map_err(|err| err.into_sys()).and(Ok(buf.len()))?; + self.tcp_file.write(&ip.to_bytes()).map_err(|err| Error::new(err.raw_os_error().unwrap_or(EIO))).and(Ok(buf.len()))?; } else { return Err(Error::new(EINVAL)); } @@ -559,7 +559,7 @@ impl SchemeMut for Tcpd { State::Established => { let tcp = handle.create_tcp(TCP_ACK | TCP_PSH, buf.to_vec()); let ip = handle.create_ip(self.rng.gen(), tcp.to_bytes()); - self.tcp_file.write(&ip.to_bytes()).map_err(|err| err.into_sys())?; + self.tcp_file.write(&ip.to_bytes()).map_err(|err| Error::new(err.raw_os_error().unwrap_or(EIO)))?; handle.seq += buf.len() as u32; Ok(buf.len()) }, @@ -611,7 +611,7 @@ impl SchemeMut for Tcpd { let tcp = handle.create_tcp(TCP_FIN | TCP_ACK, Vec::new()); let ip = handle.create_ip(self.rng.gen(), tcp.to_bytes()); - self.tcp_file.write(&ip.to_bytes()).map_err(|err| err.into_sys())?; + self.tcp_file.write(&ip.to_bytes()).map_err(|err| Error::new(err.raw_os_error().unwrap_or(EIO)))?; handle.seq += 1; @@ -622,7 +622,7 @@ impl SchemeMut for Tcpd { let tcp = handle.create_tcp(TCP_FIN | TCP_ACK, Vec::new()); let ip = handle.create_ip(self.rng.gen(), tcp.to_bytes()); - self.tcp_file.write(&ip.to_bytes()).map_err(|err| err.into_sys())?; + self.tcp_file.write(&ip.to_bytes()).map_err(|err| Error::new(err.raw_os_error().unwrap_or(EIO)))?; handle.seq += 1; diff --git a/schemes/udpd/src/main.rs b/schemes/udpd/src/main.rs index c0317cc..ba43abf 100644 --- a/schemes/udpd/src/main.rs +++ b/schemes/udpd/src/main.rs @@ -15,7 +15,7 @@ use std::rc::Rc; use event::EventQueue; use netutils::{n16, Ipv4, Ipv4Addr, Ipv4Header, Udp, UdpHeader, Checksum}; use syscall::data::Packet; -use syscall::error::{Error, Result, EACCES, EADDRINUSE, EBADF, EINVAL, EMSGSIZE, ENOTCONN, EWOULDBLOCK}; +use syscall::error::{Error, Result, EACCES, EADDRINUSE, EBADF, EIO, EINVAL, EMSGSIZE, ENOTCONN, EWOULDBLOCK}; use syscall::flag::{EVENT_READ, O_CREAT, O_RDWR, O_NONBLOCK}; use syscall::scheme::SchemeMut; @@ -265,7 +265,7 @@ impl SchemeMut for Udpd { data: ip_data }; - self.udp_file.write(&ip.to_bytes()).map_err(|err| err.into_sys()).and(Ok(buf.len())) + self.udp_file.write(&ip.to_bytes()).map_err(|err| Error::new(err.raw_os_error().unwrap_or(EIO))).and(Ok(buf.len())) } } diff --git a/syscall/src/data.rs b/syscall/src/data.rs index a92a199..56e8dde 100644 --- a/syscall/src/data.rs +++ b/syscall/src/data.rs @@ -61,7 +61,13 @@ pub struct Stat { pub st_mode: u16, pub st_uid: u32, pub st_gid: u32, - pub st_size: u64 + pub st_size: u64, + pub st_mtime: u64, + pub st_mtime_nsec: u32, + pub st_atime: u64, + pub st_atime_nsec: u32, + pub st_ctime: u64, + pub st_ctime_nsec: u32, } impl Deref for Stat { diff --git a/syscall/src/error.rs b/syscall/src/error.rs index 5481f9f..7cbcbe9 100644 --- a/syscall/src/error.rs +++ b/syscall/src/error.rs @@ -2,13 +2,13 @@ use core::{fmt, result}; #[derive(Eq, PartialEq)] pub struct Error { - pub errno: isize, + pub errno: i32, } pub type Result = result::Result; impl Error { - pub fn new(errno: isize) -> Error { + pub fn new(errno: i32) -> Error { Error { errno: errno } } @@ -20,8 +20,8 @@ impl Error { } pub fn demux(value: usize) -> Result { - let errno = -(value as isize); - if errno >= 1 && errno < STR_ERROR.len() as isize { + let errno = -(value as i32); + if errno >= 1 && errno < STR_ERROR.len() as i32 { Err(Error::new(errno)) } else { Ok(value) @@ -49,137 +49,137 @@ impl fmt::Display for Error { } } -pub const EPERM: isize = 1; /* Operation not permitted */ -pub const ENOENT: isize = 2; /* No such file or directory */ -pub const ESRCH: isize = 3; /* No such process */ -pub const EINTR: isize = 4; /* Interrupted system call */ -pub const EIO: isize = 5; /* I/O error */ -pub const ENXIO: isize = 6; /* No such device or address */ -pub const E2BIG: isize = 7; /* Argument list too long */ -pub const ENOEXEC: isize = 8; /* Exec format error */ -pub const EBADF: isize = 9; /* Bad file number */ -pub const ECHILD: isize = 10; /* No child processes */ -pub const EAGAIN: isize = 11; /* Try again */ -pub const ENOMEM: isize = 12; /* Out of memory */ -pub const EACCES: isize = 13; /* Permission denied */ -pub const EFAULT: isize = 14; /* Bad address */ -pub const ENOTBLK: isize = 15; /* Block device required */ -pub const EBUSY: isize = 16; /* Device or resource busy */ -pub const EEXIST: isize = 17; /* File exists */ -pub const EXDEV: isize = 18; /* Cross-device link */ -pub const ENODEV: isize = 19; /* No such device */ -pub const ENOTDIR: isize = 20; /* Not a directory */ -pub const EISDIR: isize = 21; /* Is a directory */ -pub const EINVAL: isize = 22; /* Invalid argument */ -pub const ENFILE: isize = 23; /* File table overflow */ -pub const EMFILE: isize = 24; /* Too many open files */ -pub const ENOTTY: isize = 25; /* Not a typewriter */ -pub const ETXTBSY: isize = 26; /* Text file busy */ -pub const EFBIG: isize = 27; /* File too large */ -pub const ENOSPC: isize = 28; /* No space left on device */ -pub const ESPIPE: isize = 29; /* Illegal seek */ -pub const EROFS: isize = 30; /* Read-only file system */ -pub const EMLINK: isize = 31; /* Too many links */ -pub const EPIPE: isize = 32; /* Broken pipe */ -pub const EDOM: isize = 33; /* Math argument out of domain of func */ -pub const ERANGE: isize = 34; /* Math result not representable */ -pub const EDEADLK: isize = 35; /* Resource deadlock would occur */ -pub const ENAMETOOLONG: isize = 36; /* File name too long */ -pub const ENOLCK: isize = 37; /* No record locks available */ -pub const ENOSYS: isize = 38; /* Function not implemented */ -pub const ENOTEMPTY: isize = 39; /* Directory not empty */ -pub const ELOOP: isize = 40; /* Too many symbolic links encountered */ -pub const EWOULDBLOCK: isize = 41; /* Operation would block */ -pub const ENOMSG: isize = 42; /* No message of desired type */ -pub const EIDRM: isize = 43; /* Identifier removed */ -pub const ECHRNG: isize = 44; /* Channel number out of range */ -pub const EL2NSYNC: isize = 45; /* Level 2 not synchronized */ -pub const EL3HLT: isize = 46; /* Level 3 halted */ -pub const EL3RST: isize = 47; /* Level 3 reset */ -pub const ELNRNG: isize = 48; /* Link number out of range */ -pub const EUNATCH: isize = 49; /* Protocol driver not attached */ -pub const ENOCSI: isize = 50; /* No CSI structure available */ -pub const EL2HLT: isize = 51; /* Level 2 halted */ -pub const EBADE: isize = 52; /* Invalid exchange */ -pub const EBADR: isize = 53; /* Invalid request descriptor */ -pub const EXFULL: isize = 54; /* Exchange full */ -pub const ENOANO: isize = 55; /* No anode */ -pub const EBADRQC: isize = 56; /* Invalid request code */ -pub const EBADSLT: isize = 57; /* Invalid slot */ -pub const EDEADLOCK: isize = 58; /* Resource deadlock would occur */ -pub const EBFONT: isize = 59; /* Bad font file format */ -pub const ENOSTR: isize = 60; /* Device not a stream */ -pub const ENODATA: isize = 61; /* No data available */ -pub const ETIME: isize = 62; /* Timer expired */ -pub const ENOSR: isize = 63; /* Out of streams resources */ -pub const ENONET: isize = 64; /* Machine is not on the network */ -pub const ENOPKG: isize = 65; /* Package not installed */ -pub const EREMOTE: isize = 66; /* Object is remote */ -pub const ENOLINK: isize = 67; /* Link has been severed */ -pub const EADV: isize = 68; /* Advertise error */ -pub const ESRMNT: isize = 69; /* Srmount error */ -pub const ECOMM: isize = 70; /* Communication error on send */ -pub const EPROTO: isize = 71; /* Protocol error */ -pub const EMULTIHOP: isize = 72; /* Multihop attempted */ -pub const EDOTDOT: isize = 73; /* RFS specific error */ -pub const EBADMSG: isize = 74; /* Not a data message */ -pub const EOVERFLOW: isize = 75; /* Value too large for defined data type */ -pub const ENOTUNIQ: isize = 76; /* Name not unique on network */ -pub const EBADFD: isize = 77; /* File descriptor in bad state */ -pub const EREMCHG: isize = 78; /* Remote address changed */ -pub const ELIBACC: isize = 79; /* Can not access a needed shared library */ -pub const ELIBBAD: isize = 80; /* Accessing a corrupted shared library */ -pub const ELIBSCN: isize = 81; /* .lib section in a.out corrupted */ -pub const ELIBMAX: isize = 82; /* Attempting to link in too many shared libraries */ -pub const ELIBEXEC: isize = 83; /* Cannot exec a shared library directly */ -pub const EILSEQ: isize = 84; /* Illegal byte sequence */ -pub const ERESTART: isize = 85; /* Interrupted system call should be restarted */ -pub const ESTRPIPE: isize = 86; /* Streams pipe error */ -pub const EUSERS: isize = 87; /* Too many users */ -pub const ENOTSOCK: isize = 88; /* Socket operation on non-socket */ -pub const EDESTADDRREQ: isize = 89; /* Destination address required */ -pub const EMSGSIZE: isize = 90; /* Message too long */ -pub const EPROTOTYPE: isize = 91; /* Protocol wrong type for socket */ -pub const ENOPROTOOPT: isize = 92; /* Protocol not available */ -pub const EPROTONOSUPPORT: isize = 93; /* Protocol not supported */ -pub const ESOCKTNOSUPPORT: isize = 94; /* Socket type not supported */ -pub const EOPNOTSUPP: isize = 95; /* Operation not supported on transport endpoint */ -pub const EPFNOSUPPORT: isize = 96; /* Protocol family not supported */ -pub const EAFNOSUPPORT: isize = 97; /* Address family not supported by protocol */ -pub const EADDRINUSE: isize = 98; /* Address already in use */ -pub const EADDRNOTAVAIL: isize = 99; /* Cannot assign requested address */ -pub const ENETDOWN: isize = 100; /* Network is down */ -pub const ENETUNREACH: isize = 101; /* Network is unreachable */ -pub const ENETRESET: isize = 102; /* Network dropped connection because of reset */ -pub const ECONNABORTED: isize = 103; /* Software caused connection abort */ -pub const ECONNRESET: isize = 104; /* Connection reset by peer */ -pub const ENOBUFS: isize = 105; /* No buffer space available */ -pub const EISCONN: isize = 106; /* Transport endpoint is already connected */ -pub const ENOTCONN: isize = 107; /* Transport endpoint is not connected */ -pub const ESHUTDOWN: isize = 108; /* Cannot send after transport endpoint shutdown */ -pub const ETOOMANYREFS: isize = 109; /* Too many references: cannot splice */ -pub const ETIMEDOUT: isize = 110; /* Connection timed out */ -pub const ECONNREFUSED: isize = 111; /* Connection refused */ -pub const EHOSTDOWN: isize = 112; /* Host is down */ -pub const EHOSTUNREACH: isize = 113; /* No route to host */ -pub const EALREADY: isize = 114; /* Operation already in progress */ -pub const EINPROGRESS: isize = 115; /* Operation now in progress */ -pub const ESTALE: isize = 116; /* Stale NFS file handle */ -pub const EUCLEAN: isize = 117; /* Structure needs cleaning */ -pub const ENOTNAM: isize = 118; /* Not a XENIX named type file */ -pub const ENAVAIL: isize = 119; /* No XENIX semaphores available */ -pub const EISNAM: isize = 120; /* Is a named type file */ -pub const EREMOTEIO: isize = 121; /* Remote I/O error */ -pub const EDQUOT: isize = 122; /* Quota exceeded */ -pub const ENOMEDIUM: isize = 123; /* No medium found */ -pub const EMEDIUMTYPE: isize = 124; /* Wrong medium type */ -pub const ECANCELED: isize = 125; /* Operation Canceled */ -pub const ENOKEY: isize = 126; /* Required key not available */ -pub const EKEYEXPIRED: isize = 127; /* Key has expired */ -pub const EKEYREVOKED: isize = 128; /* Key has been revoked */ -pub const EKEYREJECTED: isize = 129; /* Key was rejected by service */ -pub const EOWNERDEAD: isize = 130; /* Owner died */ -pub const ENOTRECOVERABLE: isize = 131; /* State not recoverable */ +pub const EPERM: i32 = 1; /* Operation not permitted */ +pub const ENOENT: i32 = 2; /* No such file or directory */ +pub const ESRCH: i32 = 3; /* No such process */ +pub const EINTR: i32 = 4; /* Interrupted system call */ +pub const EIO: i32 = 5; /* I/O error */ +pub const ENXIO: i32 = 6; /* No such device or address */ +pub const E2BIG: i32 = 7; /* Argument list too long */ +pub const ENOEXEC: i32 = 8; /* Exec format error */ +pub const EBADF: i32 = 9; /* Bad file number */ +pub const ECHILD: i32 = 10; /* No child processes */ +pub const EAGAIN: i32 = 11; /* Try again */ +pub const ENOMEM: i32 = 12; /* Out of memory */ +pub const EACCES: i32 = 13; /* Permission denied */ +pub const EFAULT: i32 = 14; /* Bad address */ +pub const ENOTBLK: i32 = 15; /* Block device required */ +pub const EBUSY: i32 = 16; /* Device or resource busy */ +pub const EEXIST: i32 = 17; /* File exists */ +pub const EXDEV: i32 = 18; /* Cross-device link */ +pub const ENODEV: i32 = 19; /* No such device */ +pub const ENOTDIR: i32 = 20; /* Not a directory */ +pub const EISDIR: i32 = 21; /* Is a directory */ +pub const EINVAL: i32 = 22; /* Invalid argument */ +pub const ENFILE: i32 = 23; /* File table overflow */ +pub const EMFILE: i32 = 24; /* Too many open files */ +pub const ENOTTY: i32 = 25; /* Not a typewriter */ +pub const ETXTBSY: i32 = 26; /* Text file busy */ +pub const EFBIG: i32 = 27; /* File too large */ +pub const ENOSPC: i32 = 28; /* No space left on device */ +pub const ESPIPE: i32 = 29; /* Illegal seek */ +pub const EROFS: i32 = 30; /* Read-only file system */ +pub const EMLINK: i32 = 31; /* Too many links */ +pub const EPIPE: i32 = 32; /* Broken pipe */ +pub const EDOM: i32 = 33; /* Math argument out of domain of func */ +pub const ERANGE: i32 = 34; /* Math result not representable */ +pub const EDEADLK: i32 = 35; /* Resource deadlock would occur */ +pub const ENAMETOOLONG: i32 = 36; /* File name too long */ +pub const ENOLCK: i32 = 37; /* No record locks available */ +pub const ENOSYS: i32 = 38; /* Function not implemented */ +pub const ENOTEMPTY: i32 = 39; /* Directory not empty */ +pub const ELOOP: i32 = 40; /* Too many symbolic links encountered */ +pub const EWOULDBLOCK: i32 = 41; /* Operation would block */ +pub const ENOMSG: i32 = 42; /* No message of desired type */ +pub const EIDRM: i32 = 43; /* Identifier removed */ +pub const ECHRNG: i32 = 44; /* Channel number out of range */ +pub const EL2NSYNC: i32 = 45; /* Level 2 not synchronized */ +pub const EL3HLT: i32 = 46; /* Level 3 halted */ +pub const EL3RST: i32 = 47; /* Level 3 reset */ +pub const ELNRNG: i32 = 48; /* Link number out of range */ +pub const EUNATCH: i32 = 49; /* Protocol driver not attached */ +pub const ENOCSI: i32 = 50; /* No CSI structure available */ +pub const EL2HLT: i32 = 51; /* Level 2 halted */ +pub const EBADE: i32 = 52; /* Invalid exchange */ +pub const EBADR: i32 = 53; /* Invalid request descriptor */ +pub const EXFULL: i32 = 54; /* Exchange full */ +pub const ENOANO: i32 = 55; /* No anode */ +pub const EBADRQC: i32 = 56; /* Invalid request code */ +pub const EBADSLT: i32 = 57; /* Invalid slot */ +pub const EDEADLOCK: i32 = 58; /* Resource deadlock would occur */ +pub const EBFONT: i32 = 59; /* Bad font file format */ +pub const ENOSTR: i32 = 60; /* Device not a stream */ +pub const ENODATA: i32 = 61; /* No data available */ +pub const ETIME: i32 = 62; /* Timer expired */ +pub const ENOSR: i32 = 63; /* Out of streams resources */ +pub const ENONET: i32 = 64; /* Machine is not on the network */ +pub const ENOPKG: i32 = 65; /* Package not installed */ +pub const EREMOTE: i32 = 66; /* Object is remote */ +pub const ENOLINK: i32 = 67; /* Link has been severed */ +pub const EADV: i32 = 68; /* Advertise error */ +pub const ESRMNT: i32 = 69; /* Srmount error */ +pub const ECOMM: i32 = 70; /* Communication error on send */ +pub const EPROTO: i32 = 71; /* Protocol error */ +pub const EMULTIHOP: i32 = 72; /* Multihop attempted */ +pub const EDOTDOT: i32 = 73; /* RFS specific error */ +pub const EBADMSG: i32 = 74; /* Not a data message */ +pub const EOVERFLOW: i32 = 75; /* Value too large for defined data type */ +pub const ENOTUNIQ: i32 = 76; /* Name not unique on network */ +pub const EBADFD: i32 = 77; /* File descriptor in bad state */ +pub const EREMCHG: i32 = 78; /* Remote address changed */ +pub const ELIBACC: i32 = 79; /* Can not access a needed shared library */ +pub const ELIBBAD: i32 = 80; /* Accessing a corrupted shared library */ +pub const ELIBSCN: i32 = 81; /* .lib section in a.out corrupted */ +pub const ELIBMAX: i32 = 82; /* Attempting to link in too many shared libraries */ +pub const ELIBEXEC: i32 = 83; /* Cannot exec a shared library directly */ +pub const EILSEQ: i32 = 84; /* Illegal byte sequence */ +pub const ERESTART: i32 = 85; /* Interrupted system call should be restarted */ +pub const ESTRPIPE: i32 = 86; /* Streams pipe error */ +pub const EUSERS: i32 = 87; /* Too many users */ +pub const ENOTSOCK: i32 = 88; /* Socket operation on non-socket */ +pub const EDESTADDRREQ: i32 = 89; /* Destination address required */ +pub const EMSGSIZE: i32 = 90; /* Message too long */ +pub const EPROTOTYPE: i32 = 91; /* Protocol wrong type for socket */ +pub const ENOPROTOOPT: i32 = 92; /* Protocol not available */ +pub const EPROTONOSUPPORT: i32 = 93; /* Protocol not supported */ +pub const ESOCKTNOSUPPORT: i32 = 94; /* Socket type not supported */ +pub const EOPNOTSUPP: i32 = 95; /* Operation not supported on transport endpoint */ +pub const EPFNOSUPPORT: i32 = 96; /* Protocol family not supported */ +pub const EAFNOSUPPORT: i32 = 97; /* Address family not supported by protocol */ +pub const EADDRINUSE: i32 = 98; /* Address already in use */ +pub const EADDRNOTAVAIL: i32 = 99; /* Cannot assign requested address */ +pub const ENETDOWN: i32 = 100; /* Network is down */ +pub const ENETUNREACH: i32 = 101; /* Network is unreachable */ +pub const ENETRESET: i32 = 102; /* Network dropped connection because of reset */ +pub const ECONNABORTED: i32 = 103; /* Software caused connection abort */ +pub const ECONNRESET: i32 = 104; /* Connection reset by peer */ +pub const ENOBUFS: i32 = 105; /* No buffer space available */ +pub const EISCONN: i32 = 106; /* Transport endpoint is already connected */ +pub const ENOTCONN: i32 = 107; /* Transport endpoint is not connected */ +pub const ESHUTDOWN: i32 = 108; /* Cannot send after transport endpoint shutdown */ +pub const ETOOMANYREFS: i32 = 109; /* Too many references: cannot splice */ +pub const ETIMEDOUT: i32 = 110; /* Connection timed out */ +pub const ECONNREFUSED: i32 = 111; /* Connection refused */ +pub const EHOSTDOWN: i32 = 112; /* Host is down */ +pub const EHOSTUNREACH: i32 = 113; /* No route to host */ +pub const EALREADY: i32 = 114; /* Operation already in progress */ +pub const EINPROGRESS: i32 = 115; /* Operation now in progress */ +pub const ESTALE: i32 = 116; /* Stale NFS file handle */ +pub const EUCLEAN: i32 = 117; /* Structure needs cleaning */ +pub const ENOTNAM: i32 = 118; /* Not a XENIX named type file */ +pub const ENAVAIL: i32 = 119; /* No XENIX semaphores available */ +pub const EISNAM: i32 = 120; /* Is a named type file */ +pub const EREMOTEIO: i32 = 121; /* Remote I/O error */ +pub const EDQUOT: i32 = 122; /* Quota exceeded */ +pub const ENOMEDIUM: i32 = 123; /* No medium found */ +pub const EMEDIUMTYPE: i32 = 124; /* Wrong medium type */ +pub const ECANCELED: i32 = 125; /* Operation Canceled */ +pub const ENOKEY: i32 = 126; /* Required key not available */ +pub const EKEYEXPIRED: i32 = 127; /* Key has expired */ +pub const EKEYREVOKED: i32 = 128; /* Key has been revoked */ +pub const EKEYREJECTED: i32 = 129; /* Key was rejected by service */ +pub const EOWNERDEAD: i32 = 130; /* Owner died */ +pub const ENOTRECOVERABLE: i32 = 131; /* State not recoverable */ pub static STR_ERROR: [&'static str; 132] = ["Success", "Operation not permitted", diff --git a/syscall/src/flag.rs b/syscall/src/flag.rs index 47e3939..6dd73f8 100644 --- a/syscall/src/flag.rs +++ b/syscall/src/flag.rs @@ -47,6 +47,7 @@ pub const O_CLOEXEC: usize = 0x0100_0000; pub const O_CREAT: usize = 0x0200_0000; pub const O_TRUNC: usize = 0x0400_0000; pub const O_EXCL: usize = 0x0800_0000; +pub const O_ACCMODE: usize = O_RDONLY | O_WRONLY | O_RDWR; pub const SEEK_SET: usize = 0; pub const SEEK_CUR: usize = 1;