diff --git a/.cargo/config.toml b/.cargo/config.toml new file mode 100644 index 0000000..0953166 --- /dev/null +++ b/.cargo/config.toml @@ -0,0 +1,6 @@ +[build] +target = "targets/i686.json" + +[unstable] +build-std = ["core"] +build-std-features = ["compiler-builtins-mem"] diff --git a/Cargo.toml b/Cargo.toml index 2dd5beb..6c2171c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -2,6 +2,7 @@ name = "xv6" version = "0.1.0" edition = "2021" +autobins = false [lib] name = "kernel" diff --git a/Makefile b/Makefile index 9e81b2f..23f31c8 100644 --- a/Makefile +++ b/Makefile @@ -16,18 +16,9 @@ TOOLPREFIX := $(shell if i386-jos-elf-objdump -i 2>&1 | grep '^elf32-i386$$' >/d then echo ''; \ else echo "***" 1>&2; \ echo "*** Error: Couldn't find an i386-*-elf version of GCC/binutils." 1>&2; \ - echo "*** Is the directory with i386-jos-elf-gcc in your PATH?" 1>&2; \ - echo "*** If your i386-*-elf toolchain is installed with a command" 1>&2; \ - echo "*** prefix other than 'i386-jos-elf-', set your TOOLPREFIX" 1>&2; \ - echo "*** environment variable to that prefix and run 'make' again." 1>&2; \ - echo "*** To turn off this error, run 'gmake TOOLPREFIX= ...'." 1>&2; \ - echo "***" 1>&2; exit 1; fi) + exit 1; fi) endif -# If the makefile can't find QEMU, specify its path here -# QEMU = qemu-system-i386 - -# Try to infer the correct QEMU ifndef QEMU QEMU = $(shell if which qemu > /dev/null; \ then echo qemu; exit; \ @@ -35,14 +26,7 @@ QEMU = $(shell if which qemu > /dev/null; \ then echo qemu-system-i386; exit; \ elif which qemu-system-x86_64 > /dev/null; \ then echo qemu-system-x86_64; exit; \ - else \ - qemu=/Applications/Q.app/Contents/MacOS/i386-softmmu.app/Contents/MacOS/i386-softmmu; \ - if test -x $$qemu; then echo $$qemu; exit; fi; fi; \ - echo "***" 1>&2; \ - echo "*** Error: Couldn't find a working QEMU executable." 1>&2; \ - echo "*** Is the directory containing the qemu binary in your PATH" 1>&2; \ - echo "*** or have you tried setting the QEMU variable in Makefile?" 1>&2; \ - echo "***" 1>&2; exit 1) + else echo "*** Error: Couldn't find QEMU." 1>&2; exit 1; fi) endif CC = $(TOOLPREFIX)gcc @@ -50,12 +34,13 @@ AS = $(TOOLPREFIX)gas LD = $(TOOLPREFIX)ld OBJCOPY = $(TOOLPREFIX)objcopy OBJDUMP = $(TOOLPREFIX)objdump + CFLAGS = -fno-pic -static -fno-builtin -fno-strict-aliasing -O2 -Wall -MD -ggdb -m32 -Werror -fno-omit-frame-pointer CFLAGS += $(shell $(CC) -fno-stack-protector -E -x c /dev/null >/dev/null 2>&1 && echo -fno-stack-protector) + ASFLAGS = -m32 -gdwarf-2 -Wa,-divide LDFLAGS += -m $(shell $(LD) -V | grep elf_i386 2>/dev/null | head -n 1) -# Disable PIE when possible (for Ubuntu 16.10 toolchain) ifneq ($(shell $(CC) -dumpspecs 2>/dev/null | grep -e '[^f]no-pie'),) CFLAGS += -fno-pie -no-pie endif @@ -76,13 +61,12 @@ fs.img: welcome.txt dd if=/dev/zero of=fs.img count=2 dd if=welcome.txt of=fs.img conv=notrunc -bootblock: bootasm.S bootmain.c +bootblock: bootasm.S bootmain.c linkers/bootblock.ld $(CC) $(CFLAGS) -fno-pic -O -nostdinc -I. -c bootmain.c $(CC) $(CFLAGS) -fno-pic -nostdinc -I. -c bootasm.S - $(LD) $(LDFLAGS) -N -e start -Ttext 0x7C00 -o bootblock.o bootasm.o bootmain.o - $(OBJDUMP) -S -D bootblock.o > bootblock.asm - $(OBJCOPY) -S -O binary -j .text bootblock.o bootblock - ./sign.pl bootblock + $(LD) $(LDFLAGS) -T linkers/bootblock.ld -o bootblock.o bootasm.o bootmain.o + $(OBJDUMP) -S bootblock.o > bootblock.asm + $(OBJCOPY) -S -O binary bootblock.o bootblock kernel.a: $(RS) cargo build -Z build-std=core -Z build-std-features=compiler-builtins-mem -Z json-target-spec \ @@ -94,7 +78,7 @@ kernel.a: $(RS) kernel: kernel.a $(OBJS) ./linkers/kernel.ld - ld -m elf_i386 -T ./linkers/kernel.ld -o kernel $(OBJS) kernel.a + $(LD) -m elf_i386 -T ./linkers/kernel.ld -o kernel $(OBJS) kernel.a $(OBJDUMP) -S -D kernel > kernel.asm $(OBJDUMP) -t kernel | sed '1,/SYMBOL TABLE/d; s/ .* / /; /^$$/d' > kernel.sym @@ -114,8 +98,9 @@ GDBPORT = $(shell expr `id -u` % 5000 + 25000) QEMUGDB = $(shell if $(QEMU) -help | grep -q '^-gdb'; \ then echo "-gdb tcp::$(GDBPORT)"; \ else echo "-s -p $(GDBPORT)"; fi) + ifndef CPUS - CPUS := 1 +CPUS := 1 endif # Attach fs.img as disk1 (index=1), like the C version @@ -131,4 +116,4 @@ qemu: xv6.img fs.img qemu-gdb: xv6.img fs .gdbinit @echo "*** Now run 'gdb'." 1>&2 - $(QEMU) -nographic $(QEMUOPTS) -S $(QEMUGDB) \ No newline at end of file + $(QEMU) -nographic $(QEMUOPTS) -S $(QEMUGDB) diff --git a/bootasm.S b/bootasm.S index 81c0d52..26f81d0 100644 --- a/bootasm.S +++ b/bootasm.S @@ -83,4 +83,6 @@ gdt: gdtdesc: .word (gdtdesc - gdt - 1) # sizeof(gdt) - 1 - .long gdt # address gdt \ No newline at end of file + .long gdt # address gdt + +.section .note.GNU-stack,"",@progbits \ No newline at end of file diff --git a/entry.S b/entry.S index a7f6755..26000a2 100644 --- a/entry.S +++ b/entry.S @@ -48,3 +48,6 @@ entry: call entryofrust .comm stack, KSTACKSIZE + +# Add .note.GNU-stack section for non-executable stack marking +.section .note.GNU-stack,"",@progbits diff --git a/linkers/bootblock.ld b/linkers/bootblock.ld new file mode 100644 index 0000000..6ac5c34 --- /dev/null +++ b/linkers/bootblock.ld @@ -0,0 +1,29 @@ +OUTPUT_FORMAT("elf32-i386", "elf32-i386", "elf32-i386") +OUTPUT_ARCH(i386) +ENTRY(start) + +SECTIONS +{ + . = 0x7c00; + + .text : { + *(.text .text.*) + } + + .rodata : { + *(.rodata .rodata.*) + } + + .data : { + *(.data .data.*) + } + + /DISCARD/ : { + *(.eh_frame .note.GNU-stack .comment) + } + + . = 0x7c00 + 510; + .signature : { + SHORT(0xaa55) + } +} diff --git a/rust-toolchain.toml b/rust-toolchain.toml index 5d56faf..87b5402 100644 --- a/rust-toolchain.toml +++ b/rust-toolchain.toml @@ -1,2 +1,3 @@ [toolchain] channel = "nightly" +components = ["rust-src"] \ No newline at end of file diff --git a/src/console.rs b/src/console.rs index 12abba1..61f0aa3 100644 --- a/src/console.rs +++ b/src/console.rs @@ -5,20 +5,80 @@ pub struct Console {} impl Write for Console { fn write_str(&mut self, s: &str) -> Result { for c in s.chars() { - consputc(c); + consputc(c as i32); } Ok(()) } } -const BACKSPACE: char = '\x08'; +const BACKSPACE: i32 = 0x100; +const INPUT_BUF: usize = 128; +const CTRL_D: i32 = C('D'); -pub fn consputc(c: char) { +#[allow(non_snake_case)] +const fn C(c: char) -> i32 { + (c as i32) - ('@' as i32) +} + +#[derive(Clone, Copy)] +struct Input { + buf: [u8; INPUT_BUF], + r: usize, + w: usize, + e: usize, +} + +static mut INPUT: Input = Input { + buf: [0; INPUT_BUF], + r: 0, + w: 0, + e: 0, +}; + +pub fn consputc(c: i32) { if c == BACKSPACE { - uartputc(BACKSPACE); - uartputc(' '); - uartputc(BACKSPACE); + uartputc('\x08' as i32); + uartputc(' ' as i32); + uartputc('\x08' as i32); } else { uartputc(c); } +} + +pub fn consoleintr(getc: fn() -> i32) { + loop { + let c = getc(); + if c < 0 { + break; + } + + unsafe { + let input = &raw mut INPUT; + match c { + x if x == C('U') => { + while (*input).e != (*input).w && (*input).buf[((*input).e - 1) % INPUT_BUF] != b'\n' { + (*input).e -= 1; + consputc(BACKSPACE); + } + } + x if x == C('H') || x == 0x7f => { + if (*input).e != (*input).w { + (*input).e -= 1; + consputc(BACKSPACE); + } + } + _ => { + if c != 0 && (*input).e.wrapping_sub((*input).r) < INPUT_BUF { + let c = if c == '\r' as i32 { '\n' as i32 } else { c }; + (*input).buf[(*input).e % INPUT_BUF] = c as u8; + (*input).e += 1; + consputc(c); + if c == '\n' as i32 || c == CTRL_D || (*input).e == (*input).r + INPUT_BUF { + (*input).w = (*input).e; + } + } + } + } + } + } } \ No newline at end of file diff --git a/src/ide.rs b/src/ide.rs index 4ae4ee2..180b78e 100644 --- a/src/ide.rs +++ b/src/ide.rs @@ -133,7 +133,9 @@ pub fn ideintr() { } } -// ide.rs +// Sync buf with disk. +// If B_DIRTY is set, write buf to disk, clear B_DIRTY, set B_VALID. +// Else if B_VALID is not set, read buf from disk, set B_VALID. pub fn iderw(idx: usize) { let b = crate::bio::buf_mut(idx); @@ -148,23 +150,31 @@ pub fn iderw(idx: usize) { } } - // PURE POLLING: issue the command directly (no IDEQUEUE). - idestart(idx); - - // Wait for completion. - if idewait(true) < 0 { - panic!("iderw: ide error"); + // Append b to idequeue. + b.qnext = None; + unsafe { + let mut pp: *mut Option = &raw mut IDEQUEUE; + while let Some(next_idx) = *pp { + pp = &raw mut crate::bio::buf_mut(next_idx).qnext; + } + *pp = Some(idx); } - // If it was a read, pull data now. - let flags_now = b.flags.load(Ordering::Acquire); - if (flags_now & B_DIRTY) == 0 { - unsafe { - crate::x86::insl(0x1F0, b.data.as_mut_ptr() as *mut u32, BSIZE / 4); + // Start disk if necessary. + unsafe { + if IDEQUEUE == Some(idx) { + idestart(idx); } } - // If it was a write, data was already pushed in idestart() via outsl(). - b.flags.fetch_or(B_VALID, Ordering::AcqRel); - b.flags.fetch_and(!B_DIRTY, Ordering::AcqRel); + // Wait for request to finish. + // The interrupt handler will set B_VALID when done. + loop { + let flags = b.flags.load(Ordering::Acquire); + if (flags & (B_VALID | B_DIRTY)) == B_VALID { + break; + } + // Force compiler to re-read b->flags which is modified by ideintr() + x86::noop(); + } } \ No newline at end of file diff --git a/src/ioapic.rs b/src/ioapic.rs index 15cf837..eaf9d70 100644 --- a/src/ioapic.rs +++ b/src/ioapic.rs @@ -1,7 +1,7 @@ use core::ptr::{read_volatile, write_volatile}; use crate::mp::MP_ONCE; -use crate::console::Console; -use core::fmt::Write; +// use crate::console::Console; +// use core::fmt::Write; use crate::println; // I/O APIC default physical address @@ -14,9 +14,9 @@ const REG_TABLE: u32 = 0x10; // Redirection table base (0x10 / 4) // Redirection table configuration bits const INT_DISABLED: u32 = 0x00010000; // Interrupt disabled -const INT_LEVEL: u32 = 0x00008000; // Level-triggered -const INT_ACTIVELOW: u32 = 0x00002000; // Active low -const INT_LOGICAL: u32 = 0x00000800; // Destination is CPU ID +// const INT_LEVEL: u32 = 0x00008000; // Unused in p3 - Level-triggered +// const INT_ACTIVELOW: u32 = 0x00002000; // Unused in p3 - Active low +// const INT_LOGICAL: u32 = 0x00000800; // Unused in p3 - Destination is CPU ID pub const T_IRQ0: u32 = 32; diff --git a/src/lapic.rs b/src/lapic.rs index 1ce725f..fc3dbca 100644 --- a/src/lapic.rs +++ b/src/lapic.rs @@ -1,6 +1,6 @@ use core::ptr::{read_volatile, write_volatile}; use crate::mp::MP_ONCE; -use crate::traps::{T_IRQ0, IRQ_TIMER, IRQ_SPURIOUS, IRQ_ERROR}; +use crate::constants::{IRQ_ERROR, IRQ_SPURIOUS, IRQ_TIMER, T_IRQ0}; const ID: isize = 0x0020 / 4; const VER: isize = 0x0030 / 4; @@ -14,14 +14,14 @@ const ESR: isize = 0x0280 / 4; const ICRLO: isize = 0x0300 / 4; const INIT: u32 = 0x00000500; -const STARTUP: u32 = 0x00000600; +// const STARTUP: u32 = 0x00000600; // Unused in p3 - for AP startup const DELIVS: u32 = 0x00001000; -const ASSERT: u32 = 0x00004000; -const DEASSERT: u32 = 0x00000000; +// const ASSERT: u32 = 0x00004000; // Unused in p3 - for IPI +// const DEASSERT: u32 = 0x00000000; // Unused in p3 - for IPI const LEVEL: u32 = 0x00008000; const BCAST: u32 = 0x00080000; -const BUSY: u32 = 0x00001000; -const FIXED: u32 = 0x00000000; +// const BUSY: u32 = 0x00001000; // Unused in p3 +// const FIXED: u32 = 0x00000000; // Unused in p3 const ICRHI: isize = 0x0310 / 4; const TIMER: isize = 0x0320 / 4; @@ -35,7 +35,7 @@ const ERROR: isize = 0x0370 / 4; const MASKED: u32 = 0x00010000; const TICR: isize = 0x0380 / 4; -const TCCR: isize = 0x0390 / 4; +// const TCCR: isize = 0x0390 / 4; // Unused in p3 - timer current count const TDCR: isize = 0x03E0 / 4; // Volatile write to LAPIC @@ -70,7 +70,7 @@ pub fn lapicinit() { // TICR would be calibrated using an external time source. lapicw(TDCR, X1); lapicw(TIMER, PERIODIC | (T_IRQ0 + IRQ_TIMER)); - lapicw(TICR, 1000000000); + lapicw(TICR, 10000000); // Disable logical interrupt lines. diff --git a/src/lib.rs b/src/lib.rs index 561ebcc..fad6293 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,7 +1,10 @@ #![no_std] // No standard library #![no_main] // No main function +#![allow(dead_code)] use core::panic::PanicInfo; +use crate::x86::cli; +use crate::lapic::lapicid; mod param; mod x86; @@ -32,8 +35,8 @@ macro_rules! println { fn halt() -> ! { println!("Bye COL{}\n\0", 331); loop { - x86::outw(0x604, 0x2000); - x86::outw(0xB004, 0x2000); + x86::outw(0x604, 0x2000); // QEMU isa-debug-exit device + x86::outw(0xB004, 0x2000); // VirtualBox shutdown port } } @@ -43,7 +46,7 @@ fn welcome() { for &byte in data0.iter() { if byte == 0 { break; } - console::consputc(byte as char); + console::consputc(byte as i32); } bio::brelse(b0); @@ -57,6 +60,7 @@ fn welcome() { bio::brelse(b1); } +// alltraps is an assembly label not a static function pointer in Rust extern "C" { pub fn alltraps(); } @@ -80,8 +84,15 @@ pub extern "C" fn entryofrust() -> ! { } } +static mut PANICKED: bool = false; + #[panic_handler] fn panic(info: &PanicInfo) -> ! { - println!("Kernel Panic: {:?}", info); + // Disable interrupts to prevent interrupt handlers from interfering + cli(); + // Print panic message with LAPIC ID to identify which CPU panicked + println!("lapicid {}:\n{:#?}", lapicid(), info); + unsafe { PANICKED = true; } + // Halt the system loop {} -} \ No newline at end of file +} diff --git a/src/mp.rs b/src/mp.rs index 9684f51..1b5117e 100644 --- a/src/mp.rs +++ b/src/mp.rs @@ -4,7 +4,8 @@ use crate::x86::{outb, inb}; use crate::proc::Cpu; use core::cell::OnceCell; -pub static mut IOAPICID: u8 = 0; +// Removed: replaced by MP_ONCE.ioapic_id OnceCell pattern +// pub static mut IOAPICID: u8 = 0; #[derive(Debug, Clone, Copy)] #[repr(C)] @@ -59,7 +60,7 @@ pub struct MpIoApic { } // Processor flags -pub const MPBOOT: u8 = 0x02; // This proc is the bootstrap processor +// pub const MPBOOT: u8 = 0x02; // Unused in p3 - This proc is the bootstrap processor // Table entry types pub const MPPROC: u8 = 0x00; // One per processor @@ -194,7 +195,8 @@ pub fn mpinit() { let conf = unsafe { *(mp.physaddr as *mut MpConf) }; let mut ismp = true; - MP_ONCE.lapic_base.set(conf.lapicaddr as *mut u32); + MP_ONCE.lapic_base.set(conf.lapicaddr as *mut u32) + .expect("lapic_base already initialized"); let mut p = (mp.physaddr as usize + mem::size_of::()) as *const u8; let e = (mp.physaddr as usize + conf.length as usize) as *const u8; @@ -218,7 +220,8 @@ pub fn mpinit() { MPIOAPIC => { let ioapic = p as *const MpIoApic; let ioapicid = unsafe { (*ioapic).apicno }; - MP_ONCE.ioapic_id.set(ioapicid); + MP_ONCE.ioapic_id.set(ioapicid) + .expect("ioapic_id already initialized"); // p = unsafe{ p.add(mem::size_of::()) }; p = p.wrapping_add(mem::size_of::()); } @@ -236,7 +239,8 @@ pub fn mpinit() { if !ismp { panic!("Didn't find a suitable machine"); } - MP_ONCE.cpus.set(cpus); + MP_ONCE.cpus.set(cpus) + .expect("cpus array already initialized"); if mp.imcrp != 0 { // Bochs doesn't support IMCR, so this doesn't run on Bochs. diff --git a/src/param.rs b/src/param.rs index 4341329..a28e84c 100644 --- a/src/param.rs +++ b/src/param.rs @@ -1,2 +1,2 @@ -pub const KSTACKSIZE: usize = 4096; // size of per-process kernel stack +// pub const KSTACKSIZE: usize = 4096; // size of per-process kernel stack (unused in p3) pub const NCPU: usize = 8; // maximum number of CPUs diff --git a/src/proc.rs b/src/proc.rs index 279364c..713ad58 100644 --- a/src/proc.rs +++ b/src/proc.rs @@ -1,5 +1,5 @@ use crate::mp::MP_ONCE; // Import the MP_ONCE static from mp.rs -use core::ptr; +// use core::ptr; use crate::x86::readeflags; use crate::constants::{FL_IF,NCPU}; use crate::lapic; diff --git a/src/traps.rs b/src/traps.rs index 6899856..bce99fc 100644 --- a/src/traps.rs +++ b/src/traps.rs @@ -1,27 +1,22 @@ use modular_bitfield::prelude::*; -use core::cell::{OnceCell, RefCell}; +use core::cell::OnceCell; +use core::sync::atomic::{AtomicU32, Ordering}; +use core::ptr::addr_of_mut; use crate::proc::cpuid; use crate::println; use crate::lapic::lapiceoi; -use crate::x86::{lidt,rcr2}; +use crate::x86::{lidt, rcr2, TrapFrame}; use crate::lapic; - -const SEG_KCODE: u16 = 1; -const STS_IG32: u8 = 0xE; // 32-bit Interrupt Gate -const STS_TG32: u8 = 0xF; // 32-bit Trap Gate - -pub const T_IRQ0: u32 = 32; -pub const IRQ_TIMER: u32 = 0; -pub const IRQ_ERROR: u32 = 19; -pub const IRQ_SPURIOUS: u32 = 31; +use crate::constants::{IRQ_COM1, IRQ_SPURIOUS, IRQ_TIMER, T_IRQ0, SEG_KCODE, STS_IG32, STS_TG32}; +use crate::uart::uartintr; extern "C" { - static vectors: [usize; 256]; // remove assembly. + static vectors: [usize; 256]; // in vectors.S: array of 256 entry pointers } #[bitfield] #[repr(C, packed)] -#[derive(Clone, Copy, Default)] // debug can be removed ? do we need to ? +#[derive(Clone, Copy, Default)] pub struct GateDesc { off_15_0: B16, // low 16 bits of offset in segment cs: B16, // code segment selector @@ -40,7 +35,7 @@ impl GateDesc { self.set_args(0); self.set_rsv1(0); let typ = if is_trap { STS_TG32 } else { STS_IG32 }; - self.set_r_type(typ); // for an interrupt gate, for example. + self.set_r_type(typ); self.set_s(0); self.set_dpl(dpl); self.set_p(1); @@ -49,58 +44,27 @@ impl GateDesc { } -#[repr(C)] -pub struct IDTOnce { - pub idt: OnceCell<[GateDesc; 256]>, - pub ticks: RefCell -} -unsafe impl Sync for IDTOnce {} -pub static IDT: IDTOnce = IDTOnce { idt: OnceCell::new(), ticks: RefCell::new(0) }; - - -#[repr(C)] -pub struct TrapFrame { - // registers as pushed by pusha - pub edi: u32, - pub esi: u32, - pub ebp: u32, - pub oesp: u32, // useless & ignored - pub ebx: u32, - pub edx: u32, - pub ecx: u32, - pub eax: u32, - - pub trapno: u32, - - // below here defined by x86 hardware - pub err: u32, - pub eip: u32, - pub cs: u16, - pub padding5: u16, - pub eflags: u32, - - // below here only when crossing rings, such as from user to kernel - pub esp: u32, - pub ss: u16, - pub padding6: u16, -} - +static mut IDT: OnceCell<[GateDesc; 256]> = OnceCell::new(); +pub static TICKS: AtomicU32 = AtomicU32::new(0); pub fn tvinit() { let mut arr = [GateDesc::default(); 256]; for i in 0..256 { arr[i].set_gate( - false, // Use an interrupt gate. - SEG_KCODE << 3, // Code segment selector (shifted as in the C code). - unsafe { vectors[i] }, // Offset from the external vector table. - 0 // Descriptor privilege level. + false, + SEG_KCODE << 3, + unsafe { vectors[i] }, + 0 ); } - let _ = IDT.idt.set(arr); + unsafe { + let _ = (*addr_of_mut!(IDT)).set(arr); + } } pub fn idtinit() { - lidt(IDT.idt.get().unwrap() , core::mem::size_of::<[GateDesc; 256]>() as usize); + let idt = unsafe { (*addr_of_mut!(IDT)).get().expect("IDT not initialized") }; + lidt(idt, core::mem::size_of::<[GateDesc; 256]>() as usize); } @@ -116,19 +80,23 @@ pub extern "C" fn trap(orig_tf: *mut TrapFrame) { const TIMER: u32 = T_IRQ0 + IRQ_TIMER; const SPURIOUS: u32 = T_IRQ0 + IRQ_SPURIOUS; const SEVEN: u32 = T_IRQ0 + 7; + match tf.trapno { - TIMER => { - *IDT.ticks.borrow_mut() += 1; - println!("Tick {}!", IDT.ticks.borrow()); - lapic::lapiceoi(); - } - SEVEN | SPURIOUS => { - println!( - "cpu{}: spurious interrupt at {}:{}\n", - cpuid() , - tf.cs, - tf.eip - ); + TIMER => { + TICKS.fetch_add(1, Ordering::Relaxed); + lapic::lapiceoi(); + } + x if x == T_IRQ0 + IRQ_COM1 => { + uartintr(); + lapiceoi(); + } + SEVEN | SPURIOUS => { + println!( + "cpu{}: spurious interrupt at {:x}:{:x}\n", + cpuid(), + tf.cs, + tf.eip + ); lapiceoi(); } crate::constants::IDE_TRAP => { diff --git a/src/uart.rs b/src/uart.rs index 9888088..aaf3137 100644 --- a/src/uart.rs +++ b/src/uart.rs @@ -1,7 +1,13 @@ -use crate::x86::{outb, inb}; +use crate::console::consoleintr; +use crate::x86::{inb, outb}; use crate::ioapic::ioapic_enable; +use core::sync::atomic::{AtomicBool, Ordering}; + const COM1: u16 = 0x3F8; // COM1 port address pub const IRQ_COM1: u32 = 4; + +static UART_READY: AtomicBool = AtomicBool::new(false); + pub fn uartinit() { // Turn off the FIFO. outb(COM1 + 2, 0); @@ -19,6 +25,7 @@ pub fn uartinit() { if inb(COM1 + 5) == 0xFF { return; } + UART_READY.store(true, Ordering::SeqCst); // Acknowledge pre-existing interrupt conditions; // enable interrupts. @@ -28,15 +35,33 @@ pub fn uartinit() { // Announce that the UART is active. for p in "xv6...\n".chars() { - uartputc(p); + uartputc(p as i32); } } -pub fn uartputc(c: char) { +pub fn uartputc(c: i32) { + if !UART_READY.load(Ordering::SeqCst) { + return; + } + for _ in 0..128 { if inb(COM1 + 5) & 0x20 != 0 { break; } } outb(COM1 + 0, c as u8); +} + +fn uartgetc() -> i32 { + if !UART_READY.load(Ordering::SeqCst) { + return -1; + } + if (inb(COM1 + 5) & 0x01) == 0 { + return -1; + } + inb(COM1) as i32 +} + +pub fn uartintr() { + consoleintr(uartgetc); } \ No newline at end of file diff --git a/src/x86.rs b/src/x86.rs index fb341ef..e8d8052 100644 --- a/src/x86.rs +++ b/src/x86.rs @@ -25,19 +25,6 @@ pub fn outb(port: u16, value: u8) { } } -pub fn inw(port: u16) -> u16 { - let result: u16; - unsafe { - asm!( - "in ax, dx", - in("dx") port, - out("ax") result, - options(nomem, nostack) - ); - result - } -} - pub fn outw(port: u16, value: u16) { unsafe { asm!( @@ -49,30 +36,6 @@ pub fn outw(port: u16, value: u16) { } } -pub fn inl(port: u16) -> u32 { - unsafe { - let result: u32; - asm!( - "in eax, dx", - in("dx") port, - out("eax") result, - options(nomem, nostack) - ); - result - } -} - -pub fn outl(port: u16, value: u32) { - unsafe { - asm!( - "out dx, eax", - in("dx") port, - in("eax") value, - options(nomem, nostack) - ); - } -} - pub fn readeflags() -> u32 { unsafe { let eflags: u32; @@ -129,22 +92,23 @@ pub unsafe fn insl(port: u16, addr: *mut u32, cnt: usize) { } - +// Output string of dwords to port using rep outsd instruction. +// Matches the C implementation: outsl(port, addr, cnt) +// Note: ESI must be saved/restored as LLVM restricts its use in 32-bit mode pub unsafe fn outsl(port: u16, addr: *const u32, cnt: usize) { - let mut p = addr; - for _ in 0..cnt { - let val = core::ptr::read(p); - asm!( - "out dx, eax", - in("dx") port, - in("eax") val, - options(nomem, nostack, preserves_flags), - ); - p = p.add(1); - } + let addr_val = addr as u32; + core::arch::asm!( + "push esi", + "mov esi, {addr}", + "cld", + "rep outsd", + "pop esi", + addr = in(reg) addr_val, + in("dx") port, + inout("ecx") cnt => _, + ); } - /// Halts the CPU until the next interrupt occurs. /// The `hlt` instruction: /// 1. Stops instruction execution and places the processor in a HALT state diff --git a/trapasm.S b/trapasm.S index 414dc20..be60855 100644 --- a/trapasm.S +++ b/trapasm.S @@ -17,3 +17,6 @@ trapret: popal addl $0x8, %esp # trapno and errcode iret + +# Add .note.GNU-stack section for non-executable stack marking +.section .note.GNU-stack,"",@progbits \ No newline at end of file diff --git a/vectors.pl b/vectors.pl index 57b49dd..0d75a7a 100755 --- a/vectors.pl +++ b/vectors.pl @@ -26,6 +26,7 @@ print " .long vector$i\n"; } +print ".section .note.GNU-stack,\"\",%progbits\n"; # sample output: # # handlers # .globl alltraps