Permalink
Browse files

[x86] add rust code to the platform side of the kernel, start initial…

…izing the interrupt system
  • Loading branch information...
1 parent 0af7620 commit d40cd1cdf5b9817dff8140ed0e23f10d7173aa6b @diodesign committed Dec 5, 2015
View
@@ -4,4 +4,5 @@
*.o
*.bin
*.iso
+*.lock
@@ -0,0 +1,107 @@
+; diosix microkernel 'menchi'
+;
+; Handle interrupts - exceptions and hardware IRQs
+;
+; Maintainer: Chris Williams (diosix.org)
+;
+
+global initialize_interrupts
+
+extern gdt.kdata
+extern kernel_interrupt_handler
+
+section .text
+bits 64
+
+; define an entry landing point for an exception with an
+; error code already stacked by the processor
+%macro interrupt_entry_with_error 1
+ global interrupt_%1_handler
+ interrupt_%1_handler:
+ push byte %1 ; push the interrupt number
+ jmp interrupt_to_kernel
+%endmacro
+
+; define an entry landing point for an exception without an
+; error code already stacked by the processor, or a hardware IRQ
+%macro interrupt_entry 1
+ global interrupt_%1_handler
+ interrupt_%1_handler:
+ push 0 ; push a dummy value
+ push byte %1 ; push the interrupt number
+ jmp interrupt_to_kernel
+%endmacro
+
+; interrupt_to_kernel
+;
+; Prepare the environment for calling a Rust kernel
+; handler function
+;
+interrupt_to_kernel:
+ ; need to preserve all the registers we're likely to clobber.
+ ; no need to save the SSE/FP registers because we've told rustc
+ ; to not use them. there's no need for them in a microkernel.
+ ; if we're switching to another thread, we'll save/restore
+ ; the FP state as required.
+ push rax
+ push rbx
+ push rcx
+ push rdx
+ push rbp
+ push rsi
+ push rdi
+ push r8
+ push r9
+ push r10
+ push r11
+ push r12
+ push r13
+ push r14
+ push r15
+
+ mov ax, ds
+ push ax ; preserve ds
+
+ mov ax, gdt.kdata ; kernel data segment
+ mov ds, ax ; select this segment
+ mov ss, ax
+ mov es, ax
+
+ mov rdi, rsp ; give Rust kernel visibility to interrupted state
+ call kernel_interrupt_handler
+
+ pop ax
+ mov ds, ax
+ mov ss, ax
+ mov es, ax
+
+ ; restore the bank of registers
+ pop r15
+ pop r14
+ pop r13
+ pop r12
+ pop r11
+ pop r10
+ pop r9
+ pop r8
+ pop rdi
+ pop rsi
+ pop rbp
+ pop rdx
+ pop rcx
+ pop rbx
+ pop rax
+
+ add rsp, 16 ; fix up the stack for the two 64-bit words pushed on entry
+ iretq
+
+section .bss
+
+; pointer to the interrupt descriptor table
+idtr:
+ resb 10
+
+; the interrupt descriptor table, 256 16-byte entries
+idt:
+ resb 16 * 256
+
@@ -5,7 +5,9 @@
; Maintainer: Chris Williams <diodesign@gmail.com>
;
-global start32
+global gdt.kdata ; make sure other code can see this segment
+global start32 ; so the bootloader can find us
+
extern start64
section .text
@@ -364,7 +366,7 @@ boot_video_line_nr:
resb 1
boot_stack_bottom:
- resb 64
+ resb 128
boot_stack_top:
; -----------------------------------------------------------------------------
@@ -62,8 +62,8 @@ $(iso): $(kernel) $(grubcfg)
$(kernel): cargo $(libkernel) $(asm_obj) $(ldscript)
@ld --gc-sections -n -T $(ldscript) -o $(kernel) $(asm_obj) $(libkernel)
-cargo:
- @cargo rustc --target $(target) -- -Z no-landing-pads -C no-redzone
+cargo: $(rust_src) $(kernel_src)
+ @cargo rustc --target $(target) -- -Z no-landing-pads -C no-redzone -C target-feature=-mmx,-sse,-sse2,-sse3,-ssse3,-sse4.1,-sse4.2,-3dnow,-3dnowa,-avx,-avx2
$(build)/%.o: asm/%.s
@mkdir -p $(build)
@@ -0,0 +1,23 @@
+/*
+ * diosix microkernel 'menchi'
+ *
+ * Handle interrupts for x86 systems
+ *
+ * Maintainer: Chris Williams (diosix.org)
+ *
+ */
+
+use ::hardware::pic;
+
+/* init()
+ *
+ * Initialize the interrupt system with basic exception
+ * and interrupt handling.
+ *
+ */
+pub fn init()
+{
+ /* first things first, move the legacy PICs out of the way */
+ pic::init();
+}
+
@@ -0,0 +1,41 @@
+/*
+ * diosix microkernel 'menchi'
+ *
+ * Do IO port access on x86 systems
+ *
+ * Maintainer: Chris Williams (diosix.org)
+ *
+ */
+
+/* read_byte
+ *
+ * Read a byte from an IO port.
+ * => port = port to read from
+ * <= returns byte from the port
+ */
+pub fn read_byte(port: u16) -> u8
+{
+ let data: u8;
+
+ unsafe
+ {
+ asm!("in %dx, %al" : "={al}"(data) : "{dx}"(port));
+ }
+
+ return data; /* return the byte */
+}
+
+/* write_byte
+ *
+ * Write a byte to an IO port.
+ * => port = port to write to
+ * data = byte to write
+ */
+pub fn write_byte(port: u16, data: u8)
+{
+ unsafe
+ {
+ asm!("outb %al, %dx" : : "{al}"(data), "{dx}"(port));
+ }
+}
+
@@ -0,0 +1,13 @@
+/*
+ * diosix microkernel 'menchi'
+ *
+ * Library of higher-level kernel routines specifically for x86 systems
+ *
+ * Maintainer: Chris Williams (diosix.org)
+ *
+ */
+
+mod io;
+mod pic;
+pub mod interrupts;
+
@@ -0,0 +1,86 @@
+/*
+ * diosix microkernel 'menchi'
+ *
+ * Manage the legacy Intel 8259 PICs in x86 systems
+ *
+ * Reference: https://github.com/diodesign/diosix-legacy/blob/master/kernel/ports/i386/hw/pic.c
+ * http://wiki.osdev.org/8259_PIC
+ *
+ * Maintainer: Chris Williams (diosix.org)
+ *
+ */
+
+use ::hardware::io;
+
+/* PIC IO addresses */
+const PIC_PRIMARY_IOADDR: u16 = 0x20; /* IO address base of the primary PIC */
+const PIC_SECONDARY_IOADDR: u16 = 0xa0; /* IO address base of the secondary PIC */
+
+const PIC_PRIMARY_COMMAND: u16 = PIC_PRIMARY_IOADDR; /* define primary PIC's registers */
+const PIC_PRIMARY_DATA: u16 = PIC_PRIMARY_IOADDR + 1;
+
+const PIC_SECONDARY_COMMAND: u16 = PIC_SECONDARY_IOADDR; /* define secondary PIC's registers */
+const PIC_SECONDARY_DATA: u16 = PIC_SECONDARY_IOADDR + 1;
+
+/* PIC commands */
+const PIC_ICW1_ICW4: u8 = 0x01; /* ICW4 (not) needed */
+const PIC_ICW1_INIT: u8 = 0x10; /* Initialization - required! */
+
+const PIC_ICW4_8086: u8 = 0x01; /* 8086/88 (MCS-80/85) mode */
+
+/* run the primary PIC from interrupt vector 32 to 39 inclusive.
+ * run the secondary PIC from interrupt vector 40 to 47 inclusive.
+ */
+const PIC_PRIMARY_VECTOR_BASE: u8 = 32;
+const PIC_SECONDARY_VECTOR_BASE: u8 = 40;
+
+/* remap
+ *
+ * Move the interrupt vector bases of the system's twin PICs.
+ * => primary_base = vector base for the primary PIC
+ * secondary_base = vector base for the secondary PIC
+ */
+fn remap(primary_base: u8, secondary_base: u8)
+{
+ let primary_mask = io::read_byte(PIC_PRIMARY_DATA);
+ let secondary_mask = io::read_byte(PIC_PRIMARY_DATA);
+
+ /* reinitialise the chipset */
+ io::write_byte(PIC_PRIMARY_COMMAND, PIC_ICW1_INIT + PIC_ICW1_ICW4);
+ io::write_byte(PIC_SECONDARY_COMMAND, PIC_ICW1_INIT + PIC_ICW1_ICW4);
+
+ /* send the new offsets */
+ io::write_byte(PIC_PRIMARY_DATA, primary_base);
+ io::write_byte(PIC_SECONDARY_DATA, secondary_base);
+
+ /* complete the reinitialisation sequence */
+ io::write_byte(PIC_PRIMARY_DATA, 4); /* there's a secondary PIC at IRQ2 */
+ io::write_byte(PIC_SECONDARY_DATA, 2); /* secondary PIC's cascade identity */
+ io::write_byte(PIC_PRIMARY_DATA, PIC_ICW4_8086);
+ io::write_byte(PIC_SECONDARY_DATA, PIC_ICW4_8086);
+
+ /* restore saved masks */
+ io::write_byte(PIC_PRIMARY_DATA, primary_mask);
+ io::write_byte(PIC_SECONDARY_DATA, secondary_mask);
+}
+
+/* init()
+ *
+ * Initialize the legacy PICs in x86 chipsets. Move them out of
+ * the way of the CPU's exceptions.
+ *
+ */
+pub fn init()
+{
+ kprintln!("[pic] Initializing basic interrupts");
+
+ /* the pair of PICs start up routing their interrupts to
+ * vectors 0x08 to 0x0f and 0x70 to 0x77. map them to
+ * somewhere more sensible - the vectors between 32
+ * and 47 inclusive.
+ */
+ remap(PIC_PRIMARY_VECTOR_BASE, PIC_SECONDARY_VECTOR_BASE);
+
+
+}
+
View
@@ -7,7 +7,7 @@
*
*/
-#![feature(no_std, lang_items, core_str_ext, const_fn)]
+#![feature(no_std, lang_items, core_str_ext, const_fn, asm)]
#![no_std]
/* bring in the kernel debugging features, provides kprintln! and kprint! */
@@ -22,12 +22,19 @@ extern crate rlibc;
* see: https://crates.io/crates/spin */
extern crate spin;
+/* library provided by the build target's platform code */
+#[cfg(target_arch = "x86_64")]
+#[path = "../platform/x86/src/mod.rs"] mod hardware;
+
/* entry point for our kernel */
#[no_mangle]
pub extern fn kmain()
{
/* display boot banner */
kprintln!("diosix {} 'menchi' now running", env!("CARGO_PKG_VERSION"));
+
+ /* initialize interrupts so we can catch exceptions at this early stage */
+ hardware::interrupts::init();
}
#[lang = "eh_personality"] extern fn eh_personality() {}

0 comments on commit d40cd1c

Please sign in to comment.