├── .gitignore ├── Makefile ├── bochsrc ├── boot.asm ├── iso └── boot │ └── grub │ ├── menu.lst │ └── stage2_eltorito ├── linker.ld ├── programs ├── do_nothing.asm ├── hello_world.c ├── syscalls.h └── test_fork.c ├── rost ├── arch │ ├── gdt.rs │ ├── handlers.asm │ ├── idt.rs │ ├── io.rs │ ├── irq.rs │ ├── mod.rs │ └── segments.asm ├── drivers │ ├── ansi.rs │ ├── keyboard.rs │ ├── mod.rs │ ├── serial.rs │ ├── timer.rs │ └── vga.rs ├── exec │ ├── elf.rs │ ├── mod.rs │ ├── process.asm │ ├── syscalls.rs │ └── tasking.rs ├── kernel │ ├── console.rs │ ├── log.rs │ └── mod.rs ├── macros.rs ├── memory │ ├── malloc.rs │ ├── mod.rs │ ├── physical.rs │ └── virt.rs ├── mod.rs └── util │ ├── bitflags.rs │ ├── list.rs │ ├── mem.rs │ └── mod.rs └── runtime.asm /.gitignore: -------------------------------------------------------------------------------- 1 | *.bc 2 | *.o 3 | *.rlib 4 | 5 | *.elf 6 | *.embed 7 | *.bin 8 | *.iso 9 | 10 | serial.log 11 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | TARGET=i386-intel-linux 2 | CC=i386-elf-gcc 3 | AS=i386-elf-as 4 | LD=i386-elf-ld 5 | NASM=nasm 6 | RUSTC=rustc 7 | RUSTCFLAGS := -O --cfg debug --target $(TARGET) --debuginfo 2 -L . 8 | MKISOFS := mkisofs 9 | CLANG=clang 10 | CLANGFLAGS = -target $(TARGET) -O2 -ffreestanding -Wall 11 | 12 | LCORE=libcore-c5ed6fb4-0.11.0-pre.rlib 13 | LLIBC=liblibc-4f9a876d-0.11.0-pre.rlib 14 | LRLIBC=librlibc-d1ece24e-0.11.0-pre.rlib 15 | LALLOC=liballoc-1085c790-0.11.0-pre.rlib 16 | 17 | QEMU=qemu-system-i386 18 | 19 | SOURCES := $(foreach suffix, asm c, $(shell find rost -name '*.$(suffix)')) 20 | SOURCES += boot.asm runtime.asm 21 | OBJECTS := $(patsubst %.asm, %.o, $(patsubst %.c, %.o, $(SOURCES))) 22 | 23 | RUST_SOURCES := $(shell find rost/ -name '*.rs') 24 | 25 | .SUFFIXES: .o .c .rs .asm .bc 26 | 27 | kernel.elf: linker.ld rost.o $(OBJECTS) core.o libc.o rlibc.o alloc.o do_nothing.embed hello_world.embed test_fork.embed 28 | $(LD) -T linker.ld -o $@ rost.o $(OBJECTS) core.o libc.o rlibc.o alloc.o do_nothing.embed hello_world.embed test_fork.embed 29 | 30 | kernel.iso: kernel.elf 31 | $(MKISOFS) -quiet -R -b boot/grub/stage2_eltorito \ 32 | -no-emul-boot -boot-load-size 4 -boot-info-table -o $@ -V 'RUST-OS' \ 33 | ./iso kernel.elf 34 | 35 | run: kernel.elf 36 | $(QEMU) -serial file:serial.log -kernel kernel.elf 37 | 38 | runbochs: kernel.iso 39 | bochs -q 40 | 41 | rost.o: $(RUST_SOURCES) 42 | $(RUSTC) $(RUSTCFLAGS) --crate-type staticlib -o $@ --emit=obj rost/mod.rs 43 | 44 | main.o: arch/.* drivers/.* kernel/.* memory/.* 45 | 46 | core.o: $(LCORE) 47 | ar -x $(LCORE) core.o 48 | 49 | libc.o: $(LLIBC) 50 | ar -x $(LLIBC) libc.o 51 | 52 | rlibc.o: $(LRLIBC) 53 | ar -x $(LRLIBC) rlibc.o 54 | 55 | alloc.o: $(LALLOC) 56 | ar -x $(LALLOC) alloc.o 57 | 58 | %.embed: %.elf 59 | i386-elf-objcopy -I binary -O elf32-i386 -B i386 $< $@ 60 | 61 | %.elf: programs/%.o 62 | $(LD) -o $@ $< 63 | 64 | .asm.o: 65 | $(NASM) -f elf32 -Wall -o $@ $< 66 | 67 | .rs.o: 68 | $(RUSTC) $(RUSTCFLAGS) --crate-type staticlib -o $@ --emit obj $< 69 | 70 | .c.o: 71 | $(CLANG) $(CLANGFLAGS) -o $@ -c $< 72 | 73 | clean: 74 | rm -f *.{o,bin,bc,elf,embed,iso} $(OBJECTS) programs/*.o 75 | -------------------------------------------------------------------------------- /bochsrc: -------------------------------------------------------------------------------- 1 | #log: bochsout.log 2 | 3 | magic_break: enabled=1 4 | 5 | memory: guest=32, host=32 6 | 7 | # Guest clock speed in terms of emulated instructions per virtual second 8 | cpu: count=1, ips=50000000, reset_on_triple_fault=1 9 | 10 | # Dynamic processor features. 11 | cpuid: level=6, mmx=1, sep=1, sse=sse4_2, apic=xapic, aes=1, movbe=1, xsave=1 12 | #cpuid: mmx=1, sep=1, sse=sse2, xapic=1, aes=0, movbe=0, xsave=0, cpuid_limit_winnt=0 13 | 14 | romimage: file="/usr/local/Cellar/bochs/2.6.2/share/bochs/BIOS-bochs-latest" 15 | vgaromimage: file="/usr/local/Cellar/bochs/2.6.2/share/bochs/VGABIOS-lgpl-latest" 16 | mouse: enabled=0, toggle=f12 17 | 18 | ata0: enabled=1, ioaddr1=0x1f0, ioaddr2=0x3f0, irq=14 19 | ata1: enabled=1, ioaddr1=0x170, ioaddr2=0x370, irq=15 20 | 21 | # CD-ROM image 22 | ata0-slave: type=cdrom, path="kernel.iso", status=inserted 23 | boot: cdrom 24 | 25 | # Pipe serial to file 26 | com1: enabled=1, mode=file, dev=serial.log 27 | -------------------------------------------------------------------------------- /boot.asm: -------------------------------------------------------------------------------- 1 | ; Multiboot constants 2 | %define MB_PAGE_ALIGN 1<<0 ; align loaded modules on page boundaries 3 | %define MB_MEMORY_INFO 1<<1 ; provide memory map 4 | %define MB_FLAGS (MB_PAGE_ALIGN | MB_MEMORY_INFO) ; this is the Multiboot 'flag' field 5 | %define MB_MAGIC 0x1BADB002 ; 'magic number' lets bootloader find the header 6 | 7 | ; Multiboot header 8 | section .multiboot 9 | align 4 10 | dd MB_MAGIC 11 | dd MB_FLAGS 12 | dd -(MB_MAGIC + MB_FLAGS) ; multiboot checksum 13 | times 5 dd 0 ; memory settings: don't need because ELF 14 | dd 1 ; graphics mode: text 15 | dd 0 ; width: don't care 16 | dd 0 ; height: don't care 17 | dd 0 ; depth: especially don't care 18 | 19 | ; Our stack 20 | section .bootstrap_stack 21 | align 4 22 | stack_bottom: 23 | times 16 * 1024 db 0 24 | stack_top: 25 | 26 | section .text 27 | global _start 28 | _start: 29 | ; Set up our stack 30 | mov esp, stack_top 31 | 32 | ; Rust functions compare esp against [gs:0x30] as a sort of stack guard thing 33 | ; as long as we set [gs:0x30] to dword 0, it should be ok 34 | mov [gs:0x30], dword stack_bottom 35 | 36 | extern kernel_main 37 | call kernel_main 38 | 39 | ; If kernel_main ever returns (it shouldn't), make sure we freeze 40 | cli 41 | hlt 42 | jmp $ 43 | -------------------------------------------------------------------------------- /iso/boot/grub/menu.lst: -------------------------------------------------------------------------------- 1 | default 0 2 | timeout 0 3 | 4 | #title Boot from hard disk 5 | #chainloader (hd0)+1 6 | 7 | title Rust-OS 8 | kernel /kernel.elf 9 | -------------------------------------------------------------------------------- /iso/boot/grub/stage2_eltorito: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lexs/rust-os/97184eeacbd34e8ecae8104a2304ad80f1e76bdd/iso/boot/grub/stage2_eltorito -------------------------------------------------------------------------------- /linker.ld: -------------------------------------------------------------------------------- 1 | /* The bootloader will look at this image and start execution at the symbol 2 | designated as the entry point. */ 3 | ENTRY(_start) 4 | 5 | /* Tell where the various sections of the object files will be put in the final 6 | kernel image. */ 7 | SECTIONS 8 | { 9 | /* Begin putting sections at 1 MiB, a conventional place for kernels to be 10 | loaded at by the bootloader. */ 11 | . = 1M; 12 | 13 | /* First put the multiboot header, as it is required to be put very early 14 | early in the image or the bootloader won't recognize the file format. 15 | Next we'll put the .text section. */ 16 | .text BLOCK(4K) : ALIGN(4K) 17 | { 18 | *(.multiboot) 19 | *(.text) 20 | } 21 | 22 | /* Read-only data. */ 23 | .rodata BLOCK(4K) : ALIGN(4K) 24 | { 25 | *(.rodata) 26 | } 27 | 28 | /* Read-write data (initialized) */ 29 | .data BLOCK(4K) : ALIGN(4K) 30 | { 31 | *(.data) 32 | } 33 | 34 | /* Read-write data (uninitialized) and stack */ 35 | .bss BLOCK(4K) : ALIGN(4K) 36 | { 37 | *(COMMON) 38 | *(.bss) 39 | *(.bootstrap_stack) 40 | } 41 | 42 | kernel_end = .; 43 | } 44 | -------------------------------------------------------------------------------- /programs/do_nothing.asm: -------------------------------------------------------------------------------- 1 | global _start 2 | _start: 3 | mov ebx, 1337 ; exit code 127 4 | mov eax, 1 ; syscall #1, exit 5 | int 0x80 6 | -------------------------------------------------------------------------------- /programs/hello_world.c: -------------------------------------------------------------------------------- 1 | #include "syscalls.h" 2 | 3 | void _start() { 4 | write(1, "Hello world", 11); 5 | for (;;); 6 | } 7 | -------------------------------------------------------------------------------- /programs/syscalls.h: -------------------------------------------------------------------------------- 1 | void exit(int code) { 2 | asm volatile("int $0x80" :: "a"(1), "b"(code)); 3 | } 4 | 5 | void write(int fd, const void *buf, unsigned int len) { 6 | asm volatile("int $0x80" :: "a"(2), "b"(fd), "c"(buf), "d"(len)); 7 | } 8 | 9 | unsigned fork() { 10 | unsigned value; 11 | asm volatile("int $0x80" : "=a"(value) : "a"(3)); 12 | return value; 13 | } 14 | 15 | void sleep(int duration) { 16 | asm volatile("int $0x80" :: "a"(4), "b"(duration)); 17 | } 18 | -------------------------------------------------------------------------------- /programs/test_fork.c: -------------------------------------------------------------------------------- 1 | #include "syscalls.h" 2 | 3 | unsigned strlen(const char* str) { 4 | const char* s; 5 | for (s = str; *s; ++s); 6 | return s - str; 7 | } 8 | 9 | void loop(const char* message) { 10 | while (1) { 11 | write(1, message, strlen(message)); 12 | sleep(100); 13 | } 14 | } 15 | 16 | void _start() { 17 | if (fork() != 0) { 18 | loop("Parent\n"); 19 | } else { 20 | if (fork() != 0) { 21 | loop("Child 1\n"); 22 | } else { 23 | loop("Child 2\n"); 24 | } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /rost/arch/gdt.rs: -------------------------------------------------------------------------------- 1 | use core::mem::{size_of, transmute}; 2 | 3 | use arch::RING3; 4 | 5 | static GDT_SIZE: uint = 6; 6 | type GdtTable = [GdtEntry, ..GDT_SIZE]; 7 | 8 | static GRANULARITY: u8 = 0xc0; // 4kb blocks and 32-bit protected 9 | 10 | static ACCESSED: u8 = 1 << 0; 11 | static RW: u8 = 1 << 1; 12 | static EXECUTE: u8 = 1 << 3; 13 | static ALWAYS1: u8 = 1 << 4; 14 | static PRESENT: u8 = 1 << 7; 15 | 16 | static USER: u8 = RING3 << 5; // Ring 3 17 | 18 | static CODE: u8 = PRESENT | ALWAYS1 | EXECUTE | RW; 19 | static DATA: u8 = PRESENT | ALWAYS1 | RW; 20 | 21 | #[allow(dead_code)] 22 | #[packed] 23 | struct GdtEntry { 24 | limit_low: u16, 25 | base_low: u16, 26 | base_middle: u8, 27 | access: u8, 28 | granularity: u8, 29 | base_high: u8 30 | } 31 | 32 | #[allow(dead_code)] 33 | #[packed] 34 | struct GdtPtr { 35 | limit: u16, 36 | base: *const GdtTable 37 | } 38 | 39 | #[allow(dead_code)] 40 | #[packed] 41 | struct TssEntry { 42 | prev_tss: u32, 43 | esp0: u32, 44 | ss0: u32, 45 | unused: [u32, ..15], 46 | es: u32, 47 | cs: u32, 48 | ss: u32, 49 | ds: u32, 50 | fs: u32, 51 | gs: u32, 52 | ldt: u32, 53 | trap: u16, 54 | iomap_base: u16 55 | } 56 | 57 | impl GdtEntry { 58 | fn new(base: uint, limit: uint, access: u8, granularity: u8) -> GdtEntry { 59 | GdtEntry { 60 | base_low: (base & 0xFFFF) as u16, 61 | base_middle: ((base >> 16) & 0xFF) as u8, 62 | base_high: ((base >> 24) & 0xFF) as u8, 63 | limit_low: (limit & 0xFFFF) as u16, 64 | granularity: (((limit >> 16) & 0x0F) as u8) | (granularity & 0xF0), 65 | access: access 66 | } 67 | } 68 | 69 | fn null() -> GdtEntry { 70 | GdtEntry::new(0, 0, 0, 0) 71 | } 72 | 73 | fn flat(access: u8, granularity: u8) -> GdtEntry { 74 | GdtEntry::new(0, 0xFFFFFFFF, access, granularity) 75 | } 76 | } 77 | 78 | impl GdtPtr { 79 | fn new(table: *const GdtTable) -> GdtPtr { 80 | GdtPtr { 81 | limit: size_of::() as u16, 82 | base: table 83 | } 84 | } 85 | } 86 | 87 | impl TssEntry { 88 | fn as_gdt_entry(&self) -> GdtEntry { 89 | let base: uint = unsafe { transmute(self) }; 90 | let limit = size_of::(); 91 | GdtEntry::new(base, limit, PRESENT | EXECUTE | ACCESSED, 0) 92 | } 93 | } 94 | 95 | static mut entries: GdtTable = [ 96 | GdtEntry { 97 | base_low: 0, 98 | base_middle: 0, 99 | base_high: 0, 100 | limit_low: 0, 101 | granularity: 0, 102 | access: 0 103 | }, ..GDT_SIZE 104 | ]; 105 | 106 | static mut table: GdtPtr = GdtPtr { limit: 0, base: 0 as *const GdtTable }; 107 | 108 | static mut tss: TssEntry = TssEntry { 109 | prev_tss: 0, 110 | esp0: 0, 111 | ss0: 0, 112 | unused: [0, ..15], 113 | es: 0, 114 | cs: 0, 115 | ss: 0, 116 | ds: 0, 117 | fs: 0, 118 | gs: 0, 119 | ldt: 0, 120 | trap: 0, 121 | iomap_base: 0 122 | }; 123 | 124 | pub fn init() { 125 | unsafe { 126 | entries[0] = GdtEntry::null(); 127 | entries[1] = GdtEntry::flat(CODE, GRANULARITY); 128 | entries[2] = GdtEntry::flat(DATA, GRANULARITY); 129 | entries[3] = GdtEntry::flat(USER | CODE, GRANULARITY); 130 | entries[4] = GdtEntry::flat(USER | DATA, GRANULARITY); 131 | entries[5] = write_tss(0x10, 0x0); 132 | 133 | table = GdtPtr::new(&entries); 134 | 135 | gdt_flush(&table); 136 | tss_flush(0x28 | 0x3); 137 | } 138 | } 139 | 140 | pub fn set_kernel_stack(stack_top: u32) { 141 | unsafe { 142 | tss.esp0 = stack_top; 143 | } 144 | } 145 | 146 | unsafe fn write_tss(ss0: u32, esp0: u32) -> GdtEntry { 147 | tss.ss0 = ss0; 148 | tss.esp0 = esp0; 149 | 150 | tss.iomap_base = size_of::() as u16; 151 | 152 | tss.as_gdt_entry() 153 | } 154 | 155 | pub fn set_segments(dataseg: u16) { 156 | unsafe { 157 | asm!("mov %ax, %ds; 158 | mov %ax, %es; 159 | mov %ax, %fs; 160 | mov %ax, %gs;" :: "{ax}"(dataseg) :: "volatile"); 161 | } 162 | } 163 | 164 | fn set_all_segments(dataseg: u16) { 165 | unsafe { 166 | asm!("mov %ax, %ds; 167 | mov %ax, %es; 168 | mov %ax, %fs; 169 | mov %ax, %gs; 170 | mov %ax, %ss;" :: "{ax}"(dataseg) :: "volatile"); 171 | } 172 | } 173 | 174 | unsafe fn gdt_flush(ptr: *const GdtPtr) { 175 | asm!("lgdt ($0)" :: "r"(ptr) :: "volatile"); 176 | 177 | set_all_segments(0x10); 178 | extern { fn load_code_segment(); } 179 | load_code_segment(); 180 | } 181 | 182 | unsafe fn tss_flush(seg: u16) { 183 | asm!("ltr %ax" :: "{ax}"(seg) :: "volatile"); 184 | } 185 | -------------------------------------------------------------------------------- /rost/arch/handlers.asm: -------------------------------------------------------------------------------- 1 | common_trap_handler: 2 | push ds 3 | push es 4 | push fs 5 | push gs 6 | 7 | pusha 8 | 9 | mov ax, 0x10 10 | mov ds, ax 11 | mov es, ax 12 | mov fs, ax 13 | mov gs, ax 14 | 15 | push esp 16 | 17 | extern trap_handler 18 | call trap_handler 19 | add esp, 4 20 | 21 | global ret_from_trap 22 | ret_from_trap: 23 | 24 | popa 25 | 26 | pop gs 27 | pop fs 28 | pop es 29 | pop ds 30 | 31 | add esp, 8 ; trap no and err 32 | iret 33 | 34 | %macro TRAP_HANDLER 1 35 | global _trap_handler_%1 36 | 37 | _trap_handler_%1: 38 | push dword 0 ; push dummy error code 39 | push dword %1 40 | jmp common_trap_handler 41 | %endmacro 42 | 43 | %macro TRAP_HANDLER_ERROR 1 44 | global _trap_handler_%1 45 | 46 | _trap_handler_%1: 47 | push dword %1 48 | jmp common_trap_handler 49 | %endmacro 50 | 51 | TRAP_HANDLER 0 52 | TRAP_HANDLER 1 53 | TRAP_HANDLER 2 54 | TRAP_HANDLER 3 55 | TRAP_HANDLER 4 56 | TRAP_HANDLER 5 57 | TRAP_HANDLER 6 58 | TRAP_HANDLER 7 59 | TRAP_HANDLER_ERROR 8 60 | TRAP_HANDLER 9 61 | TRAP_HANDLER_ERROR 10 62 | TRAP_HANDLER_ERROR 11 63 | TRAP_HANDLER_ERROR 12 64 | TRAP_HANDLER_ERROR 13 65 | TRAP_HANDLER_ERROR 14 66 | 67 | %assign i 15 68 | %rep 256 - 15 69 | TRAP_HANDLER i 70 | %assign i i+1 71 | %endrep 72 | 73 | global trap_handler_array 74 | trap_handler_array: 75 | 76 | %macro TRAP_HANDLER_ENTRY 1 77 | dd _trap_handler_%1 78 | %endmacro 79 | 80 | %assign i 0 81 | %rep 256 82 | TRAP_HANDLER_ENTRY i 83 | %assign i i+1 84 | %endrep 85 | -------------------------------------------------------------------------------- /rost/arch/idt.rs: -------------------------------------------------------------------------------- 1 | use core::prelude::*; 2 | use core::mem::size_of; 3 | 4 | use arch::io; 5 | 6 | use arch::RING3; 7 | 8 | use exec::tasking; 9 | 10 | static PRESENT: u8 = 1 << 7; 11 | static USER: u8 = RING3 << 5; 12 | 13 | static INTERRUPT_GATE: u8 = 0xE; 14 | 15 | static IDT_SIZE: uint = 256; 16 | type IdtTable = [IdtEntry, ..IDT_SIZE]; 17 | 18 | #[allow(dead_code)] 19 | #[packed] 20 | struct IdtEntry { 21 | handler_low: u16, 22 | selector: u16, 23 | always0: u8, 24 | flags: u8, 25 | handler_high: u16 26 | } 27 | 28 | #[allow(dead_code)] 29 | #[packed] 30 | struct IdtPtr { 31 | limit: u16, 32 | base: *const IdtTable 33 | } 34 | 35 | #[allow(dead_code)] 36 | #[packed] 37 | pub struct Registers { 38 | pub edi: u32, pub esi: u32, pub ebp: u32, pub esp: u32, pub ebx: u32, pub edx: u32, pub ecx: u32, pub eax: u32, 39 | pub gs: u32, pub fs: u32, pub es: u32, pub ds: u32, 40 | pub int_no: u32, pub err_code: u32, 41 | pub eip: u32, pub cs: u32, pub eflags: u32, pub useresp: u32, pub ss: u32 42 | } 43 | 44 | impl IdtEntry { 45 | fn new(handler: u32, selector: u16, flags: u8) -> IdtEntry { 46 | IdtEntry { 47 | handler_low: (handler & 0xFFFF) as u16, 48 | handler_high: ((handler >> 16) & 0xFFFF) as u16, 49 | selector: selector, 50 | always0: 0, 51 | flags: flags 52 | } 53 | } 54 | } 55 | 56 | impl IdtPtr { 57 | fn new(table: &IdtTable) -> IdtPtr { 58 | IdtPtr { 59 | limit: (size_of::() * table.len() - 1) as u16, 60 | base: table as *const IdtTable 61 | } 62 | } 63 | } 64 | 65 | static mut entries: IdtTable = [ 66 | IdtEntry { 67 | handler_low: 0, 68 | selector: 0, 69 | always0: 0, 70 | flags: 0, 71 | handler_high: 0 72 | }, ..IDT_SIZE 73 | ]; 74 | 75 | static mut table: IdtPtr = IdtPtr { 76 | limit: 0, 77 | base: 0 as *const IdtTable 78 | }; 79 | 80 | static EXCEPTIONS: &'static [&'static str] = &[ 81 | "Divide-by-zero Error", 82 | "Debug", 83 | "Non-maskable Interrupt", 84 | "Breakpoint", 85 | "Overflow", 86 | "Bound Range Exceeded", 87 | "Invalid Opcode", 88 | "Device Not Available", 89 | "Double Fault", 90 | "Coprocessor Segment Overrun", 91 | "Invalid TSS", 92 | "Segment Not Present", 93 | "Stack-Segment Fault", 94 | "General Protection Fault", 95 | "Page Fault", 96 | "Reserved", 97 | "x87 Floating-Point Exception", 98 | "Alignment Check", 99 | "Machine Check", 100 | "SIMD Floating-Point Exception", 101 | "Virtualization Exception", 102 | ]; 103 | 104 | fn dummy_handler(regs: &mut Registers) { 105 | panic!("Unhandled interrupt: {}, error: {}", regs.int_no, regs.err_code); 106 | } 107 | 108 | fn exception_handler(regs: &mut Registers) { 109 | panic!("{}, error: {:x}", EXCEPTIONS[regs.int_no as uint], regs.err_code); 110 | } 111 | 112 | static mut interrupt_handlers: [fn(regs: &mut Registers), ..IDT_SIZE] = [ 113 | dummy_handler, ..IDT_SIZE 114 | ]; 115 | 116 | pub fn init() { 117 | unsafe { 118 | table = IdtPtr::new(&entries); 119 | idt_flush(&table); 120 | idt_enable(); 121 | 122 | // Register default exception handlers 123 | for i in range(0, EXCEPTIONS.len()) { 124 | register_interrupt(i, exception_handler); 125 | } 126 | } 127 | } 128 | 129 | pub fn register_user_interrupt(which: uint, f: fn(regs: &mut Registers)) { 130 | register_handler(which, INTERRUPT_GATE | USER, f); 131 | } 132 | 133 | pub fn register_interrupt(which: uint, f: fn(regs: &mut Registers)) { 134 | register_handler(which, INTERRUPT_GATE, f); 135 | } 136 | 137 | fn register_handler(which: uint, flags: u8, f: fn(regs: &mut Registers)) { 138 | // Defined in handlers.asm 139 | extern { static trap_handler_array: [u32, ..IDT_SIZE]; } 140 | 141 | unsafe { 142 | entries[which] = IdtEntry::new(trap_handler_array[which], 0x08, PRESENT | flags); 143 | interrupt_handlers[which] = f; 144 | } 145 | } 146 | 147 | pub fn trap_handler(regs: &mut Registers) { 148 | unsafe { 149 | // TODO: Tasking should been initialized before we receive 150 | // an interrupt 151 | tasking::current_task.as_mut().map(|task| { 152 | task.regs = regs as *mut Registers; 153 | }); 154 | } 155 | 156 | let which = regs.int_no; 157 | 158 | // If this is a irq we need to eoi it 159 | if which >= 32 && which <= 47 { 160 | let irq = which - 32; 161 | if irq <= 7 { 162 | io::write_port(0x20, 0x20); // Master 163 | } 164 | io::write_port(0xA0, 0x20); // Slave 165 | } 166 | 167 | unsafe { interrupt_handlers[which as uint](regs); } 168 | } 169 | 170 | unsafe fn idt_enable() { 171 | asm!("sti"); 172 | } 173 | 174 | unsafe fn idt_flush(ptr: *const IdtPtr) { 175 | asm!("lidt ($0)" :: "r"(ptr)); 176 | } 177 | -------------------------------------------------------------------------------- /rost/arch/io.rs: -------------------------------------------------------------------------------- 1 | #[inline(always)] 2 | pub fn write_port(port: u16, val: u8) { 3 | unsafe { 4 | asm!("out $0, $1" :: "{al}"(val), "{dx}"(port) :: "volatile"); 5 | } 6 | } 7 | 8 | #[inline(always)] 9 | pub fn read_port(port: u16) -> u8 { 10 | unsafe { 11 | let mut val: u8; 12 | asm!("in $1, $0" : "={ax}"(val) : "N{dx}"(port) :: "volatile"); 13 | val 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /rost/arch/irq.rs: -------------------------------------------------------------------------------- 1 | use arch::idt; 2 | use arch::io; 3 | 4 | static IRQ_BASE: uint = 32; 5 | 6 | pub fn init() { 7 | // Remap the irq table. 8 | io::write_port(0x20, 0x11); 9 | io::write_port(0xA0, 0x11); 10 | io::write_port(0x21, 0x20); 11 | io::write_port(0xA1, 0x28); 12 | io::write_port(0x21, 0x04); 13 | io::write_port(0xA1, 0x02); 14 | io::write_port(0x21, 0x01); 15 | io::write_port(0xA1, 0x01); 16 | io::write_port(0x21, 0x0); 17 | io::write_port(0xA1, 0x0); 18 | 19 | // Disable all lines 20 | io::write_port(0x21, 0xFF); 21 | io::write_port(0xA1, 0xFF); 22 | } 23 | 24 | pub fn register_handler(irq: uint, f: fn(regs: &mut idt::Registers)) { 25 | idt::register_interrupt(irq + IRQ_BASE, f); 26 | enable(irq); 27 | } 28 | 29 | pub fn enable(irq: uint) { 30 | if irq > 7 { 31 | let actual = irq - 8; 32 | let curr: u8 = io::read_port(0xA1); 33 | io::write_port(0xA1, curr & !((1u << actual) as u8)) 34 | } else { 35 | let curr: u8 = io::read_port(0x21); 36 | io::write_port(0x21, curr & !((1u << irq) as u8)) 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /rost/arch/mod.rs: -------------------------------------------------------------------------------- 1 | pub mod io; 2 | pub mod gdt; 3 | pub mod idt; 4 | pub mod irq; 5 | 6 | static RING3: u8 = 3; 7 | -------------------------------------------------------------------------------- /rost/arch/segments.asm: -------------------------------------------------------------------------------- 1 | global load_code_segment 2 | load_code_segment: 3 | jmp 0x08:.g 4 | .g: 5 | ret 6 | -------------------------------------------------------------------------------- /rost/drivers/ansi.rs: -------------------------------------------------------------------------------- 1 | use core::prelude::*; 2 | use core::mem::swap; 3 | 4 | static ESCAPE: char = '\x1b'; 5 | 6 | static LOW: char = 'A'; 7 | static HIGH: char = 'z'; 8 | 9 | static CUU: char = 'A'; // Cursor up 10 | static CUD: char = 'B'; // Cursor down 11 | static CUF: char = 'C'; // Cursor forward 12 | static CUB: char = 'D'; // Cursor back 13 | 14 | static SGR: char = 'm'; // Select Graphic Rendition 15 | 16 | #[deriving(FromPrimitive)] 17 | #[repr(u8)] 18 | pub enum Color { 19 | Black, 20 | Red, 21 | Green, 22 | Yellow, 23 | Blue, 24 | Magenta, 25 | Cyan, 26 | White 27 | } 28 | 29 | bitflags!( 30 | #[packed] 31 | flags Flags: u8 { 32 | static BRIGHT = 1, 33 | static UNDERLINE = 1 << 1, 34 | static BLINK = 1 << 2 35 | } 36 | ) 37 | 38 | enum Status { 39 | Idle, 40 | Pending, 41 | Escaped 42 | } 43 | 44 | pub trait Device { 45 | fn write(&mut self, c: char); 46 | fn set_cursor(&mut self, x: uint, y: uint); 47 | fn get_cursor(&self) -> (uint, uint); 48 | fn set_color(&mut self, fg: Color, bg: Color, flags: Flags); 49 | } 50 | 51 | pub struct Ansi { 52 | status: Status, 53 | buffer: [char, ..100], 54 | buffer_pos: uint, 55 | state: State 56 | } 57 | 58 | struct State { 59 | fg: Color, 60 | bg: Color, 61 | flags: Flags 62 | } 63 | 64 | impl State { 65 | fn default() -> State { 66 | State { 67 | fg: White, 68 | bg: Black, 69 | flags: Flags::empty() 70 | } 71 | } 72 | } 73 | 74 | impl Ansi { 75 | pub fn new() -> Ansi { 76 | Ansi { 77 | status: Idle, 78 | buffer: ['\0', ..100], 79 | buffer_pos: 0, 80 | state: State::default() 81 | } 82 | } 83 | 84 | pub fn put(&mut self, c: char, device: &mut Device) { 85 | match (self.status, c) { 86 | (Idle, ESCAPE) => { 87 | self.put_buf(c); 88 | self.status = Pending; 89 | }, 90 | (Idle, c) => device.write(c), 91 | (Pending, '[') => { 92 | self.put_buf(c); 93 | self.status = Escaped; 94 | }, 95 | (Pending, c) => { 96 | // We were not escaped 97 | self.dump_buf(c, |c| device.write(c)); 98 | self.status = Idle; 99 | }, 100 | (Escaped, LOW..HIGH) => { 101 | self.handle_code(c, device); 102 | self.clear_buf(); 103 | self.status = Idle; 104 | }, 105 | (Escaped, c) => self.put_buf(c) 106 | } 107 | } 108 | 109 | fn handle_code(&mut self, c: char, device: &mut Device) { 110 | let buffer = self.buffer.slice(0, self.buffer_pos); 111 | let mut args = match buffer.split(|&c| c == '[').nth(1) { 112 | None => return, 113 | Some(options) => options.split(|&c| c == ';') 114 | }; 115 | 116 | match c { 117 | SGR => { 118 | let mut had_args = false; 119 | for arg in args { 120 | had_args = true; 121 | 122 | self.state.handle_sgr(arg); 123 | } 124 | 125 | if !had_args { 126 | self.state.handle_sgr(['0']); 127 | } 128 | 129 | device.set_color(self.state.fg, self.state.bg, self.state.flags); 130 | 131 | }, 132 | CUU..CUB => { 133 | let (direction_x, direction_y) = match c { 134 | CUU => (-1, 0), 135 | CUD => (1, 0), 136 | CUF => (0, 1), 137 | CUB => (0, -1), 138 | _ => unreachable!() 139 | }; 140 | 141 | let distance = self.first_or(&mut args, 1); 142 | let (x, y) = device.get_cursor(); 143 | device.set_cursor(direction_x * distance * x, direction_y * distance * y); 144 | } 145 | _ => klog!("Unsuppored ansi code: {}", c) 146 | } 147 | } 148 | 149 | fn first_or<'a, T: Iterator<&'a [char]>>(&self, args: &mut T, default: uint) -> uint { 150 | args.nth(0).and_then(from_str).unwrap_or(default) 151 | } 152 | 153 | fn put_buf(&mut self, c: char) { 154 | self.buffer[self.buffer_pos] = c; 155 | self.buffer_pos += 1; 156 | kassert!(self.buffer_pos < 100); 157 | } 158 | 159 | fn dump_buf(&mut self, c: char, write: |c: char|) { 160 | for &c in self.buf().iter() { 161 | write(c); 162 | } 163 | write(c); 164 | self.buffer_pos = 0; 165 | } 166 | 167 | fn clear_buf(&mut self) { 168 | self.buffer_pos = 0; 169 | } 170 | 171 | fn buf<'a>(&'a self) -> &'a [char] { 172 | self.buffer.slice(0, self.buffer_pos) 173 | } 174 | } 175 | 176 | static SGR_RESET: uint = 0; 177 | static SGR_BOLD: uint = 1; 178 | static SGR_UNDERLINE: uint = 4; 179 | static SGR_BLINK: uint = 5; 180 | static SGR_REVERSE: uint = 7; 181 | static SGR_FG_LOW: uint = 30; 182 | static SGR_FG_HIGH: uint = 37; 183 | static SGR_FG_RESET: uint = 39; 184 | static SGR_BG_LOW: uint = 40; 185 | static SGR_BG_HIGH: uint = 47; 186 | static SGR_BG_RESET: uint = 49; 187 | 188 | impl State { 189 | fn handle_sgr(&mut self, arg: &[char]) { 190 | let value = match from_str(arg) { 191 | None => return, 192 | Some(value) => value 193 | }; 194 | 195 | match value { 196 | SGR_RESET => *self = State::default(), 197 | SGR_BOLD => self.flags.insert(BRIGHT), 198 | SGR_UNDERLINE => self.flags.insert(UNDERLINE), 199 | SGR_BLINK => self.flags.insert(BLINK), 200 | SGR_REVERSE => swap(&mut self.fg, &mut self.bg), 201 | SGR_FG_LOW..SGR_FG_HIGH => self.fg = fg(value - SGR_FG_LOW), 202 | SGR_FG_RESET => self.fg = White, 203 | SGR_BG_LOW..SGR_BG_HIGH => self.bg = bg(value - SGR_BG_LOW), 204 | SGR_BG_RESET => self.bg = Black, 205 | _ => () 206 | } 207 | } 208 | } 209 | 210 | fn fg(color: uint) -> Color { 211 | FromPrimitive::from_uint(color).unwrap_or(White) 212 | } 213 | 214 | fn bg(color: uint) -> Color { 215 | FromPrimitive::from_uint(color).unwrap_or(Black) 216 | } 217 | 218 | fn from_str(text: &[char]) -> Option { 219 | let mut value = 0; 220 | for &c in text.iter() { 221 | value = value * 10 + match c.to_digit(10) { 222 | None => return None, 223 | Some(digit) => digit 224 | } 225 | } 226 | Some(value) 227 | } 228 | -------------------------------------------------------------------------------- /rost/drivers/keyboard.rs: -------------------------------------------------------------------------------- 1 | #![allow(dead_code)] 2 | 3 | use core::prelude::*; 4 | 5 | use arch::irq; 6 | use arch::idt; 7 | use arch::io; 8 | use drivers::vga; 9 | 10 | static KEYMAP: &'static str = "\ 11 | \x00\x1B1234567890-=\x08\tqwertyuiop[]\n?asdfghjkl;'`?\\zxcvbnm,./?*? ?????????????789-456+1230.?????"; 12 | static KEYMAP_SHIFTED: &'static str = "\ 13 | \x00\x1B!@#$%^&*()_+\x08\tQWERTYUIOP{}\n?ASDFGHJKL:\"~?|ZXCVBNM<>??*? ?????????????789-456+1230.?????"; 14 | 15 | static LEFT_SHIFT: u8 = 0x2a; 16 | static RIGHT_SHIFT: u8 = 0x36; 17 | static CAPS_LOCK: u8 = 0x3a; 18 | static NUMBER_LOCK: u8 = 0x45; 19 | static SCROLL_LOCK: u8 = 0x46; 20 | 21 | static mut shifted: bool = false; 22 | static mut caps_lock: bool = false; 23 | 24 | pub fn init() { 25 | irq::register_handler(1, keyboard_handler); 26 | } 27 | 28 | fn keyboard_handler(_: &mut idt::Registers) { 29 | let status: u8 = io::read_port(0x64); 30 | if status & 0x1 == 0 { 31 | return; 32 | } 33 | 34 | let scancode: u8 = io::read_port(0x60); 35 | 36 | // Top bit means key released 37 | if scancode & 0x80 != 0 { 38 | key_up(!0x80); 39 | } else { 40 | key_down(scancode); 41 | } 42 | } 43 | 44 | fn key_up(scancode: u8) { 45 | match scancode { 46 | LEFT_SHIFT | RIGHT_SHIFT => unsafe { shifted = false; }, 47 | _ => {} 48 | } 49 | } 50 | 51 | fn key_down(scancode: u8) { 52 | match scancode { 53 | LEFT_SHIFT | RIGHT_SHIFT => unsafe { shifted = true; }, 54 | CAPS_LOCK => unsafe { caps_lock = !caps_lock; }, 55 | _ => { write(scancode); } 56 | } 57 | } 58 | 59 | fn write(scancode: u8) { 60 | if scancode > KEYMAP.len() as u8 { return; } 61 | 62 | let c: char = unsafe { 63 | if shifted ^ caps_lock { 64 | KEYMAP_SHIFTED.char_at(scancode as uint) 65 | } else { 66 | KEYMAP.char_at(scancode as uint) 67 | } 68 | }; 69 | 70 | vga::putch(c); 71 | } 72 | -------------------------------------------------------------------------------- /rost/drivers/mod.rs: -------------------------------------------------------------------------------- 1 | pub mod vga; 2 | pub mod keyboard; 3 | pub mod timer; 4 | pub mod serial; 5 | pub mod ansi; 6 | 7 | pub fn init() { 8 | timer::init(); 9 | keyboard::init(); 10 | serial::init(); 11 | } 12 | -------------------------------------------------------------------------------- /rost/drivers/serial.rs: -------------------------------------------------------------------------------- 1 | use arch::io; 2 | 3 | static PORT: u16 = 0x3f8; 4 | 5 | pub fn init() { 6 | io::write_port(PORT + 1, 0x00); // Disable all interrupts 7 | io::write_port(PORT + 3, 0x80); // Enable DLAB (set baud rate divisor) 8 | io::write_port(PORT + 0, 0x03); // Set divisor to 3 (lo byte) 38400 baud 9 | io::write_port(PORT + 1, 0x00); // (hi byte) 10 | io::write_port(PORT + 3, 0x03); // 8 bits, no parity, one stop bit 11 | io::write_port(PORT + 2, 0xC7); // Enable FIFO, clear them, with 14-byte threshold 12 | io::write_port(PORT + 4, 0x0B); // IRQs enabled, RTS/DSR set 13 | } 14 | 15 | fn is_transmit_empty() -> bool { 16 | io::read_port(PORT + 5) & 0x20 != 0 17 | } 18 | 19 | pub fn write(c: u8) { 20 | loop { 21 | if is_transmit_empty() { break } 22 | } 23 | 24 | io::write_port(PORT, c); 25 | } 26 | -------------------------------------------------------------------------------- /rost/drivers/timer.rs: -------------------------------------------------------------------------------- 1 | use arch::io; 2 | use arch::idt; 3 | use arch::irq; 4 | use drivers::vga; 5 | 6 | use core::intrinsics::{volatile_load, volatile_store}; 7 | 8 | static HZ: u32 = 100; 9 | 10 | static mut tick: u32 = 0; 11 | 12 | pub fn init() { 13 | irq::register_handler(0, timer_handler); 14 | 15 | let divisor = 1193180 / HZ; 16 | 17 | io::write_port(0x43, 0x36); 18 | 19 | let low = (divisor & 0xff) as u8; 20 | let high = (divisor >> 8 & 0xff) as u8; 21 | 22 | // Send the frequency divisor. 23 | io::write_port(0x40, low); 24 | io::write_port(0x40, high); 25 | } 26 | 27 | #[inline(always)] 28 | pub fn read_ticks() -> u32 { 29 | unsafe { volatile_load(&tick) } 30 | } 31 | 32 | fn increment_ticks() -> u32 { 33 | unsafe { 34 | let current = volatile_load(&tick) + 1; 35 | volatile_store(&mut tick, current); 36 | current 37 | } 38 | } 39 | 40 | #[allow(dead_code)] 41 | pub fn sleep(duration: u32) { 42 | let target = read_ticks() + duration / 100; 43 | while read_ticks() < target {} 44 | } 45 | 46 | fn timer_handler(_: &mut idt::Registers) { 47 | if increment_ticks() % HZ == 0 { 48 | vga::puts("\nOne second has passed\n"); 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /rost/drivers/vga.rs: -------------------------------------------------------------------------------- 1 | use core::prelude::*; 2 | use core::intrinsics::volatile_store; 3 | 4 | use arch::io; 5 | 6 | bitflags!( 7 | #[packed] 8 | flags Color: u8 { 9 | static BRIGHT = 1 << 3, 10 | 11 | static BLACK = 0, 12 | 13 | static RED = 1 << 2, 14 | static GREEN = 1 << 1, 15 | static BLUE = 1 << 0, 16 | 17 | static CYAN = BLUE.bits | GREEN.bits, 18 | static MAGENTA = BLUE.bits | RED.bits, 19 | static BROWN = GREEN.bits | RED.bits, 20 | 21 | static WHITE = BLUE.bits | GREEN.bits | RED.bits 22 | } 23 | ) 24 | 25 | #[packed] 26 | struct Character { 27 | char: u8, 28 | attr: u8 29 | } 30 | 31 | impl Character { 32 | #[inline] 33 | fn make(c: char, fg: Color, bg: Color) -> Character { 34 | Character { char: c as u8, attr: fg.bits() | bg.bits() << 4 } 35 | } 36 | } 37 | 38 | pub static ROWS: uint = 25; 39 | pub static COLS: uint = 80; 40 | 41 | static screen: *mut Character = 0xb8000 as *mut Character; 42 | 43 | static mut cursor_x: uint = 0; 44 | static mut cursor_y: uint = 0; 45 | 46 | pub fn puts(s: &str) { 47 | for c in s.chars() { 48 | unsafe { do_putch(c); } 49 | } 50 | 51 | unsafe { update_cursor() } 52 | } 53 | 54 | pub fn putch(c: char) { 55 | unsafe { 56 | if cursor_y > ROWS { 57 | clear_screen(); 58 | } 59 | 60 | do_putch(c); 61 | update_cursor(); 62 | } 63 | } 64 | 65 | pub fn clear_screen() { 66 | for x in range(0, COLS) { 67 | for y in range(0, ROWS) { 68 | unsafe { write(y, x, Character::make(' ', WHITE, BLACK)); } 69 | } 70 | } 71 | move_cursor(0, 0); 72 | } 73 | 74 | pub fn get_cursor() -> (uint, uint) { 75 | unsafe { (cursor_x, cursor_y) } 76 | } 77 | 78 | pub fn move_cursor(x: uint, y: uint) { 79 | unsafe { 80 | cursor_x = x; 81 | cursor_y = y; 82 | update_cursor(); 83 | } 84 | } 85 | 86 | static mut fg: Color = WHITE; 87 | static mut bg: Color = BLACK; 88 | 89 | pub fn set_color(_fg: Color, _bg: Color) { 90 | unsafe { 91 | fg = _fg; 92 | bg = _bg; 93 | } 94 | } 95 | 96 | unsafe fn do_putch(c: char) { 97 | match c { 98 | '\n' => newline(), 99 | '\t' => tab(), 100 | '\u0008' => backspace(), 101 | _ => { 102 | write(cursor_y, cursor_x, Character::make(c, fg, bg)); 103 | forward_cursor(1); 104 | } 105 | } 106 | } 107 | 108 | unsafe fn tab() { 109 | forward_cursor(4 - (cursor_x + 4) % 4); 110 | } 111 | 112 | unsafe fn backspace() { 113 | if cursor_x != 0 { 114 | cursor_x -= 1; 115 | } else if cursor_y != 0 { 116 | cursor_x = COLS - 1; 117 | cursor_y -= 1; 118 | } 119 | 120 | write(cursor_y, cursor_x, Character::make(' ', WHITE, BLACK)); 121 | } 122 | 123 | #[inline] 124 | unsafe fn write(y: uint, x: uint, c: Character) { 125 | let offset = y * COLS + x; 126 | volatile_store(screen.offset(offset as int), c); 127 | } 128 | 129 | unsafe fn forward_cursor(steps: uint) { 130 | cursor_x += steps; 131 | 132 | while cursor_x >= COLS { 133 | cursor_x -= COLS; 134 | cursor_y += 1; 135 | } 136 | } 137 | 138 | unsafe fn newline() { 139 | cursor_x = 0; 140 | cursor_y += 1; 141 | } 142 | 143 | unsafe fn update_cursor() { 144 | let position = cursor_y * COLS + cursor_x; 145 | 146 | io::write_port(0x3D4, 0x0F); 147 | io::write_port(0x3D5, position as u8); 148 | io::write_port(0x3D4, 0x0E); 149 | io::write_port(0x3D5, (position >> 8) as u8); 150 | } 151 | -------------------------------------------------------------------------------- /rost/exec/elf.rs: -------------------------------------------------------------------------------- 1 | use core::prelude::*; 2 | use core::ptr::{copy_nonoverlapping_memory, set_memory}; 3 | 4 | use memory; 5 | use exec::tasking; 6 | 7 | // FIXME: Where should the stack go? 8 | static STACK_POSITION: u32 = 0x5600000; 9 | static STACK_SIZE: u32 = 8 * 1024; 10 | 11 | #[allow(dead_code)] 12 | #[packed] 13 | struct ELFIdent { 14 | ei_mag: [u8, ..4], 15 | ei_class: u8, 16 | ei_data: u8, 17 | ei_version: u8, 18 | ei_osabi: u8, 19 | ei_abiversion: u8, 20 | ei_pad: [u8, ..7] 21 | } 22 | 23 | #[allow(dead_code)] 24 | #[packed] 25 | struct ELFHeader { 26 | e_ident: ELFIdent, 27 | e_type: ObjectType, 28 | e_machine: u16, 29 | e_version: u32, 30 | e_entry: u32, 31 | e_phoff: u32, 32 | e_shoff: u32, 33 | e_flags: u32, 34 | e_ehsize: u16, 35 | e_phentsize: u16, 36 | e_phnum: u16, 37 | e_shentsize: u16, 38 | e_shnum: u16, 39 | e_shstrndx: u16 40 | } 41 | 42 | #[allow(non_camel_case_types)] 43 | #[repr(u16)] 44 | enum ObjectType { 45 | ET_NONE = 0, 46 | ET_REL = 1, 47 | ET_EXEC = 2 48 | } 49 | 50 | #[allow(non_camel_case_types)] 51 | #[repr(u32)] 52 | enum HeaderType { 53 | PT_NULL = 0, 54 | PT_LOAD = 1, 55 | PT_DYNAMIC = 2, 56 | PT_INTERP = 3, 57 | PT_NOTE = 4, 58 | PT_SHLIB = 5, 59 | PT_PHDR = 6, 60 | PT_TLS = 7, 61 | PT_LOOS = 0x60000000, // OS-specific 62 | PT_HIOS = 0x6fffffff, // OS-specific 63 | PT_GNU_STACK = 0x60000000 + 0x474e551 64 | } 65 | 66 | bitflags!( 67 | #[packed] 68 | flags HeaderFlags: u32 { 69 | static PT_X = 0x1, 70 | #[allow(dead_code)] 71 | static PT_R = 0x2, 72 | static PT_W = 0x4 73 | } 74 | ) 75 | 76 | #[allow(dead_code)] 77 | #[packed] 78 | struct ProgramHeader { 79 | p_type: HeaderType, 80 | p_offset: u32, 81 | p_vaddr: u32, 82 | p_paddr: u32, 83 | p_filesz: u32, 84 | p_memsz: u32, 85 | p_flags: HeaderFlags 86 | } 87 | 88 | pub fn probe(buffer: *const u8) -> bool { 89 | let header = buffer as *const ELFHeader; 90 | unsafe { check_magic(&(*header).e_ident) } 91 | } 92 | 93 | pub fn exec(buffer: *const u8) { 94 | unsafe { 95 | let header = buffer as *const ELFHeader; 96 | 97 | setup(buffer, header).map(|(entry, stack_top)| { 98 | tasking::user_mode(entry, stack_top) 99 | }); 100 | } 101 | } 102 | 103 | unsafe fn check_magic(ident: *const ELFIdent) -> bool { 104 | static MAGIC: &'static str = "\u007fELF"; 105 | (*ident).ei_mag == MAGIC.as_bytes() 106 | } 107 | 108 | unsafe fn setup(buffer: *const u8, header: *const ELFHeader) -> Option<(u32, u32)> { 109 | match (*header).e_type { 110 | ET_EXEC => (), 111 | _ => { 112 | kprintln!("Not executable"); 113 | return None; 114 | }, 115 | } 116 | 117 | let header_count = (*header).e_phnum as int; 118 | let header_size = (*header).e_phentsize as int; 119 | let header_base = buffer.offset((*header).e_phoff as int); 120 | 121 | // Does this program need an executable stack 122 | let mut stack_flags = memory::EXEC; 123 | 124 | for i in range(0, header_count) { 125 | let program_header = header_base.offset(i * header_size) as *const ProgramHeader; 126 | 127 | match (*program_header).p_type { 128 | PT_NULL => {}, // Ignore 129 | PT_LOAD => load_segment(buffer, program_header), 130 | PT_GNU_STACK => { 131 | // We don't need an executable stack if the exec flag is not set 132 | if !(*program_header).p_flags.contains(PT_X) { 133 | stack_flags.remove(memory::EXEC); 134 | } 135 | }, 136 | other => { 137 | kprintln!("Unsupported ELF segment: 0x{:x}", other as u32); 138 | return None; 139 | } 140 | } 141 | } 142 | 143 | memory::map(STACK_POSITION, STACK_SIZE, memory::USER | memory::WRITE | stack_flags); 144 | let stack_top = STACK_POSITION + STACK_SIZE; 145 | 146 | Some(((*header).e_entry, stack_top)) 147 | } 148 | 149 | unsafe fn load_segment(buffer: *const u8, header: *const ProgramHeader) { 150 | let mem_size = (*header).p_memsz as uint; // Size in memory 151 | let file_size = (*header).p_filesz as uint; // Size in file 152 | let mem_pos = (*header).p_vaddr as *mut u8; // Position in memory 153 | let file_pos = (*header).p_offset as int; // Position in file 154 | 155 | memory::map(mem_pos as u32, mem_size as u32, memory::USER | translate_flags(header)); 156 | 157 | copy_nonoverlapping_memory(mem_pos, buffer.offset(file_pos as int), file_size as uint); 158 | set_memory(mem_pos.offset(file_pos + file_size as int), 0, mem_size - file_size); 159 | } 160 | 161 | unsafe fn translate_flags(header: *const ProgramHeader) -> memory::Flags { 162 | if (*header).p_flags.contains(PT_W) { 163 | memory::WRITE 164 | } else { 165 | memory::NONE 166 | } 167 | } 168 | -------------------------------------------------------------------------------- /rost/exec/mod.rs: -------------------------------------------------------------------------------- 1 | pub mod tasking; 2 | pub mod elf; 3 | pub mod syscalls; 4 | -------------------------------------------------------------------------------- /rost/exec/process.asm: -------------------------------------------------------------------------------- 1 | global run_iret 2 | run_iret: 3 | add esp, 0x4 4 | iret 5 | -------------------------------------------------------------------------------- /rost/exec/syscalls.rs: -------------------------------------------------------------------------------- 1 | use core::prelude::*; 2 | 3 | use arch::idt; 4 | use exec::tasking; 5 | 6 | static NUM_SYSCALLS: uint = 128; 7 | 8 | static mut syscalls: [fn(regs: &mut idt::Registers), ..NUM_SYSCALLS] = [ 9 | unimplemented_syscall, ..NUM_SYSCALLS 10 | ]; 11 | 12 | macro_rules! syscall ( 13 | // no args 14 | (fn $name:ident() -> $ret:ty $func:expr) => ( 15 | fn $name(regs: &mut idt::Registers) { 16 | regs.eax = { $func } as $ret; 17 | } 18 | ); 19 | // 1 arg 20 | (fn $name:ident($a0:ident: $t0:ty) $func:expr) => ( 21 | fn $name(regs: &mut idt::Registers) { 22 | let $a0 = regs.ebx as $t0; 23 | $func 24 | } 25 | ); 26 | // 3 args 27 | (fn $name:ident($a0:ident: $t0:ty, $a1:ident: $t1:ty, $a2:ident: $t2:ty) -> $ret:ty $func:expr) => ( 28 | fn $name(regs: &mut idt::Registers) { 29 | let $a0 = regs.ebx as $t0; 30 | let $a1 = regs.ecx as $t1; 31 | let $a2 = regs.edx as $t2; 32 | regs.eax = { $func } as $ret; 33 | } 34 | ); 35 | (fn $name:ident($a0:ident: $t0:ty, $a1:ident: $t1:ty, $a2:ident: $t2:ty) $func:expr) => ( 36 | fn $name(regs: &mut idt::Registers) { 37 | let $a0 = regs.ebx as $t0; 38 | let $a1 = regs.ecx as $t1; 39 | let $a2 = regs.edx as $t2; 40 | $func 41 | } 42 | ); 43 | 44 | ) 45 | 46 | pub fn init() { 47 | unsafe { 48 | syscalls[1] = syscall_exit; 49 | syscalls[2] = syscall_write; 50 | syscalls[3] = syscall_fork; 51 | syscalls[4] = syscall_sleep; 52 | } 53 | 54 | idt::register_user_interrupt(0x80, syscall_handler); 55 | } 56 | 57 | fn syscall_handler(regs: &mut idt::Registers) { 58 | let index = regs.eax; 59 | if index as uint >= NUM_SYSCALLS { 60 | unimplemented_syscall(regs); 61 | } else { 62 | unsafe { syscalls[index as uint](regs); } 63 | } 64 | } 65 | 66 | fn unimplemented_syscall(regs: &mut idt::Registers) { 67 | kprintln!("Unimplemented syscall, number={}", regs.eax); 68 | } 69 | 70 | syscall!(fn syscall_exit(code: u32) { 71 | let pid = tasking::get_current_task().pid; 72 | kprintln!("Process {} exit with code {}", pid, code); 73 | tasking::kill(); 74 | }) 75 | 76 | syscall!(fn syscall_write(fd: u32, data: *const u8, len: u32) -> u32 { 77 | use kernel::console::AnsiConsole; 78 | kassert!(fd == 1); 79 | 80 | let mut i = 0; 81 | while i < len { 82 | let c = unsafe { *data.offset(i as int) as char }; 83 | AnsiConsole.print(c); 84 | 85 | i += 1; 86 | } 87 | i 88 | }) 89 | 90 | syscall!(fn syscall_fork() -> u32 { 91 | tasking::fork() 92 | }) 93 | 94 | syscall!(fn syscall_sleep(duration: u32) { 95 | // FIXME: We can't interrupt here so do a pseudo-sleep 96 | let mut i = 0; 97 | while i < duration * 1000000 { 98 | unsafe { asm!("nop" :::: "volatile"); } 99 | i += 1; 100 | } 101 | tasking::schedule(); 102 | }) 103 | -------------------------------------------------------------------------------- /rost/exec/tasking.rs: -------------------------------------------------------------------------------- 1 | use core::prelude::*; 2 | 3 | use core::mem::{transmute, size_of}; 4 | use core::ptr::copy_nonoverlapping_memory; 5 | 6 | use util::Unique; 7 | use util::list::{List, Node, Rawlink}; 8 | 9 | use arch::{gdt, idt}; 10 | use memory; 11 | 12 | pub type KernelStack = [u8, ..STACK_SIZE]; 13 | pub struct Task { 14 | pub pid: uint, 15 | pub esp: u32, 16 | pub eip: u32, 17 | pub pd: u32, 18 | pub regs: *mut idt::Registers, 19 | pub kernel_stack: KernelStack 20 | } 21 | 22 | static STACK_SIZE: uint = 8 * 1024; 23 | 24 | static mut next_pid: uint = 1; 25 | static mut tasks: List> = List { head: None, tail: Rawlink { p: 0 as *mut Node> }, length: 0 }; 26 | 27 | pub static mut current_task: Option> = None; 28 | 29 | impl Task { 30 | pub fn stack_top(&self) -> u32 { 31 | let stack_bottom: u32 = unsafe { transmute(&self.kernel_stack) }; 32 | stack_bottom + size_of::() as u32 33 | } 34 | } 35 | 36 | // We can't use the Unique::new() constructor becase it 37 | // creates the Task on the stack and then copies it into 38 | // the memory. This fails because this task is actually 39 | // larger than the stack we're operating on. 40 | macro_rules! new_task ( 41 | (Task { 42 | pid: $pid:expr, 43 | esp: $esp:expr, 44 | eip: $eip:expr, 45 | pd: $pd:expr, 46 | regs: $regs:expr 47 | 48 | }) => ({ 49 | let mut task: Unique = Unique::empty(); 50 | task.pid = $pid; 51 | task.eip = $eip; 52 | task.pd = $pd; 53 | task.regs = $regs; 54 | task 55 | }) 56 | ) 57 | 58 | pub fn init() { 59 | unsafe { 60 | let mut task = new_task!(Task { 61 | pid: 0, 62 | esp: 0, 63 | eip: 0, 64 | pd: memory::kernel_directory, 65 | regs: 0 as *mut idt::Registers 66 | }); 67 | 68 | gdt::set_kernel_stack(task.stack_top()); 69 | 70 | current_task = Some(task); 71 | } 72 | } 73 | 74 | pub fn get_current_task() -> &mut Unique { 75 | match unsafe { current_task.as_mut() } { 76 | None => panic!("Tasking not initialized!"), 77 | Some(task) => task 78 | } 79 | } 80 | 81 | pub fn kill() { 82 | unsafe { 83 | if get_current_task().pid == 0 { 84 | panic!("Can not kill idle task"); 85 | } 86 | 87 | current_task = tasks.pop_front(); 88 | replace_current(get_current_task()); 89 | } 90 | } 91 | 92 | pub fn exec(f: fn()) { 93 | let mut new_task = new_task!(Task { 94 | pid: aquire_pid(), 95 | esp: 0, 96 | eip: unsafe { transmute(f) }, 97 | pd: memory::clone_directory(), 98 | regs: 0 as *mut idt::Registers // FIXME 99 | }); 100 | 101 | new_task.esp = new_task.stack_top(); 102 | 103 | unsafe { tasks.append(new_task); } 104 | } 105 | 106 | pub fn fork() -> uint { 107 | unsafe { 108 | extern { static ret_from_trap: u32; } 109 | 110 | let mut new_task = new_task!(Task { 111 | pid: aquire_pid(), 112 | esp: 0, 113 | eip: transmute(&ret_from_trap), 114 | pd: memory::clone_directory(), 115 | regs: 0 as *mut idt::Registers 116 | }); 117 | 118 | let regs_end = new_task.stack_top() as *mut idt::Registers; 119 | let regs = regs_end.offset(-1); 120 | copy_nonoverlapping_memory(regs, get_current_task().regs as *const idt::Registers, 1); 121 | 122 | new_task.esp = regs as u32; 123 | (*regs).eax = 0; 124 | 125 | let child_pid = new_task.pid; 126 | 127 | tasks.append(new_task); 128 | 129 | child_pid 130 | } 131 | } 132 | 133 | fn read_eflags() -> u32 { 134 | unsafe { 135 | let mut eflags: u32; 136 | asm!("pushf; pop $0;" : "=r"(eflags) ::: "volatile"); 137 | eflags 138 | } 139 | } 140 | 141 | pub fn user_mode(entry: u32, stack: u32) { 142 | #[packed] 143 | #[allow(dead_code)] 144 | struct FakeStack { 145 | eip: u32, 146 | cs: u32, 147 | eflags: u32, 148 | esp: u32, 149 | ss: u32, 150 | }; 151 | 152 | let fake_stack = FakeStack { 153 | ss: 0x20 | 0x3, 154 | esp: stack, 155 | eflags: read_eflags() | 0x200, // Enable interrupts 156 | cs: 0x18 | 0x3, 157 | eip: entry 158 | }; 159 | 160 | gdt::set_segments(0x20 | 0x3); 161 | extern { fn run_iret(stack: FakeStack); } 162 | unsafe { run_iret(fake_stack); } 163 | } 164 | 165 | pub fn schedule() { 166 | unsafe { 167 | let task = match tasks.pop_front() { 168 | None => return, 169 | Some(task) => task 170 | }; 171 | 172 | let (last_task, next_task) = match current_task.take() { 173 | None => panic!("No current task, is tasking initialized?"), 174 | Some(current) => { 175 | tasks.append(current); 176 | current_task = Some(task); 177 | (tasks.back_mut().unwrap(), current_task.get_ref()) 178 | } 179 | }; 180 | 181 | switch_to(last_task, next_task); 182 | } 183 | } 184 | 185 | #[inline(never)] // We can't inline because then the label "resume" would fail to be found 186 | unsafe fn switch_to(prev: &mut Unique, next: &Unique) { 187 | // These blocks are split in two because we need to guarantee that the store 188 | // into prev.esp and prev.eip happens BEFORE the jmp. Optimally we would like 189 | // to use "=m" as a constraint but rustc/llvm doesn't seem to like that. 190 | // Without the explicit deref_mut() the values are borrowed as immutable. 191 | asm!( 192 | "cli; 193 | push %ebp; 194 | mov %esp, $0; 195 | lea resume, $1;" 196 | : "=r"(prev.deref_mut().esp), "=r"(prev.deref_mut().eip) ::: "volatile"); 197 | 198 | gdt::set_kernel_stack(next.stack_top()); 199 | memory::switch_page_directory(next.pd); 200 | 201 | asm!( 202 | "mov $0, %esp; 203 | sti; 204 | jmp *$1; 205 | resume: 206 | pop %ebp;" 207 | :: "m"(next.esp), "m"(next.eip) :: "volatile"); 208 | } 209 | 210 | unsafe fn replace_current(next: &Unique) { 211 | asm!( 212 | "mov $0, %esp; 213 | jmp *$1;" 214 | :: "m"(next.esp), "m"(next.eip) :: "volatile"); 215 | } 216 | 217 | fn aquire_pid() -> uint { 218 | unsafe { 219 | let pid = next_pid; 220 | next_pid += 1; 221 | pid 222 | } 223 | } 224 | -------------------------------------------------------------------------------- /rost/kernel/console.rs: -------------------------------------------------------------------------------- 1 | use core::prelude::*; 2 | use core::fmt; 3 | use core::fmt::FormatWriter; 4 | 5 | use drivers::{vga, ansi}; 6 | 7 | static mut ansi: Option = None; 8 | 9 | pub struct Console; 10 | pub struct AnsiConsole; 11 | 12 | impl Console { 13 | pub fn print(&mut self, c: char) { 14 | vga::putch(c); 15 | } 16 | } 17 | 18 | impl AnsiConsole { 19 | pub fn print(&mut self, c: char) { 20 | match unsafe { ansi.as_mut() } { 21 | None => return Console.print(c), 22 | Some(ansi) => self.print_ansi(c, ansi) 23 | }; 24 | } 25 | 26 | fn print_ansi(&mut self, c: char, ansi: &mut ansi::Ansi) { 27 | ansi.put(c, self); 28 | } 29 | } 30 | 31 | impl fmt::FormatWriter for Console { 32 | fn write(&mut self, bytes: &[u8]) -> fmt::Result { 33 | for &c in bytes.iter() { 34 | vga::putch(c as char); 35 | } 36 | Ok(()) 37 | } 38 | } 39 | 40 | impl fmt::FormatWriter for AnsiConsole { 41 | fn write(&mut self, bytes: &[u8]) -> fmt::Result { 42 | let ansi = match unsafe { ansi.as_mut() } { 43 | None => return Console.write(bytes), 44 | Some(ansi) => ansi 45 | }; 46 | 47 | for &c in bytes.iter() { 48 | self.print_ansi(c as char, ansi); 49 | } 50 | Ok(()) 51 | } 52 | } 53 | 54 | impl ansi::Device for AnsiConsole { 55 | fn write(&mut self, c: char) { 56 | Console.print(c); 57 | } 58 | 59 | fn set_cursor(&mut self, x: uint, y: uint) { 60 | vga::move_cursor(x, y); 61 | } 62 | 63 | fn get_cursor(&self) -> (uint, uint) { 64 | vga::get_cursor() 65 | } 66 | 67 | fn set_color(&mut self, fg: ansi::Color, bg: ansi::Color, flags: ansi::Flags) { 68 | vga::set_color(translate_fg(fg, flags), translate_bg(bg)); 69 | } 70 | } 71 | 72 | pub fn init() { 73 | unsafe { 74 | ansi = Some(ansi::Ansi::new()) 75 | } 76 | } 77 | 78 | fn translate_fg(color: ansi::Color, flags: ansi::Flags) -> vga::Color { 79 | translate_color(color, flags) 80 | } 81 | 82 | fn translate_bg(color: ansi::Color) -> vga::Color { 83 | translate_color(color, ansi::Flags::empty()) 84 | } 85 | 86 | fn translate_color(color: ansi::Color, flags: ansi::Flags) -> vga::Color { 87 | let vga_color = match color { 88 | ansi::Black => vga::BLACK, 89 | ansi::Blue => vga::BLUE, 90 | ansi::Green => vga::GREEN, 91 | ansi::Cyan => vga::CYAN, 92 | ansi::Red => vga::RED, 93 | ansi::Magenta => vga::MAGENTA, 94 | ansi::Yellow => vga::BROWN, 95 | ansi::White => vga::WHITE 96 | }; 97 | 98 | if flags.contains(ansi::BRIGHT) { 99 | vga_color | vga::BRIGHT 100 | } else { 101 | vga_color 102 | } 103 | } 104 | -------------------------------------------------------------------------------- /rost/kernel/log.rs: -------------------------------------------------------------------------------- 1 | use core::prelude::*; 2 | use core::fmt; 3 | use core::fmt::FormatWriter; 4 | 5 | use drivers::serial; 6 | 7 | struct Log; 8 | 9 | impl fmt::FormatWriter for Log { 10 | fn write(&mut self, bytes: &[u8]) -> fmt::Result { 11 | for &c in bytes.iter() { 12 | serial::write(c); 13 | } 14 | Ok(()) 15 | } 16 | } 17 | 18 | pub fn println_args(fmt: &fmt::Arguments) { 19 | do_print(|io| writeln!(io, "{}", fmt)); 20 | } 21 | 22 | fn do_print(f: |&mut fmt::FormatWriter| -> fmt::Result) { 23 | let result = f(&mut Log); 24 | match result { 25 | Ok(()) => {} 26 | Err(_) => fail!("failed printing to log: {}") 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /rost/kernel/mod.rs: -------------------------------------------------------------------------------- 1 | #![macro_escape] 2 | 3 | use core::prelude::*; 4 | use core::fmt; 5 | use core::fmt::FormatWriter; 6 | 7 | pub mod console; 8 | pub mod log; 9 | 10 | pub fn print_args(fmt: &fmt::Arguments) { 11 | do_print(|io| write!(io, "{}", fmt)); 12 | } 13 | 14 | pub fn println_args(fmt: &fmt::Arguments) { 15 | do_print(|io| writeln!(io, "{}", fmt)); 16 | } 17 | 18 | fn do_print(f: |&mut fmt::FormatWriter| -> fmt::Result) { 19 | use kernel::console::AnsiConsole; 20 | 21 | let result = f(&mut AnsiConsole); 22 | match result { 23 | Ok(()) => {} 24 | Err(_) => fail!("failed printing to stdout: {}") 25 | } 26 | } 27 | 28 | macro_rules! kprint( 29 | ($text:tt) => (kprint!("{}", $text)); 30 | ($($arg:tt)*) => (format_args!(::kernel::print_args, $($arg)*)); 31 | ) 32 | 33 | macro_rules! kprintln( 34 | ($text:tt) => (kprintln!("{}", $text)); 35 | ($($arg:tt)*) => (format_args!(::kernel::println_args, $($arg)*)); 36 | ) 37 | 38 | macro_rules! klog( 39 | ($text:tt) => (klog!("{}", $text)); 40 | ($($arg:tt)*) => (format_args!(::kernel::log::println_args, $($arg)*)); 41 | ) 42 | 43 | macro_rules! panic( 44 | () => ({ 45 | // Avoid warning about unneeded unsafe block 46 | fn freeze() -> ! { 47 | unsafe { asm!("cli"); } 48 | loop {} 49 | } 50 | freeze(); 51 | }); 52 | ($format:expr) => ({ 53 | kprint!("PANIC: "); 54 | kprintln!($format); 55 | panic!(); 56 | }); 57 | ($format:expr, $($arg:expr),*) => ({ 58 | kprint!("PANIC: "); 59 | kprintln!($format, $($arg),*); 60 | panic!(); 61 | }) 62 | ) 63 | -------------------------------------------------------------------------------- /rost/macros.rs: -------------------------------------------------------------------------------- 1 | #![macro_escape] 2 | 3 | #[cfg(debug)] 4 | macro_rules! kassert ( 5 | ($condition:expr) => { 6 | if !($condition) { 7 | let msg = concat!("assert failed: ", stringify!($condition), " at ", file!(), ":", line!()); 8 | panic!(msg); 9 | } 10 | } 11 | ) 12 | 13 | #[cfg(not(debug))] 14 | macro_rules! kassert ( 15 | ($condition:expr) => (()) 16 | ) 17 | -------------------------------------------------------------------------------- /rost/memory/malloc.rs: -------------------------------------------------------------------------------- 1 | use core::ptr::copy_nonoverlapping_memory; 2 | use libc::{size_t, c_void}; 3 | 4 | use memory; 5 | 6 | static PAGE_SIZE: u32 = 0x1000; 7 | 8 | static mut heap: u32 = 0xd0000000; 9 | static mut buffer: u32 = 0; 10 | 11 | pub unsafe fn malloc(size: size_t) -> *mut c_void { 12 | klog!("Allocating {} bytes", size); 13 | 14 | while buffer < size { 15 | memory::map(heap + buffer, PAGE_SIZE, memory::WRITE); 16 | buffer += PAGE_SIZE; 17 | } 18 | 19 | let ptr = heap; 20 | heap += size; 21 | buffer -= size; 22 | 23 | ptr as *mut c_void 24 | } 25 | 26 | pub unsafe fn realloc(p: *mut c_void, size: size_t) -> *mut c_void { 27 | let ptr = malloc(size); 28 | copy_nonoverlapping_memory(ptr, p as *const c_void, size as uint); 29 | free(p); 30 | ptr 31 | } 32 | 33 | pub unsafe fn free(_: *mut c_void) { 34 | // Do nothing :( 35 | } 36 | -------------------------------------------------------------------------------- /rost/memory/mod.rs: -------------------------------------------------------------------------------- 1 | pub use self::virt::{ 2 | kernel_directory, 3 | map, 4 | clone_directory, 5 | switch_page_directory, 6 | Flags, 7 | NONE, 8 | WRITE, 9 | USER, 10 | EXEC 11 | }; 12 | 13 | mod physical; 14 | mod virt; 15 | pub mod malloc; 16 | 17 | pub fn init() { 18 | physical::init(); 19 | virt::init(); 20 | } 21 | -------------------------------------------------------------------------------- /rost/memory/physical.rs: -------------------------------------------------------------------------------- 1 | static FRAME_SIZE: u32 = 0x1000; 2 | 3 | static mut next_frame: u32 = 1024 * 4; // First 4MB is in use, TODO: Make this nicer 4 | 5 | 6 | pub fn init() { 7 | /* 8 | unsafe { 9 | // Mark frames up to kernel_end as used 10 | extern { static kernel_end: u32; } 11 | next_frame = kernel_end % FRAME_SIZE + 1; 12 | } 13 | */ 14 | } 15 | 16 | pub fn allocate_frame() -> u32 { 17 | unsafe { 18 | let frame = next_frame; 19 | next_frame += 1; 20 | frame * FRAME_SIZE 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /rost/memory/virt.rs: -------------------------------------------------------------------------------- 1 | use core::prelude::*; 2 | use core::mem::{transmute, size_of}; 3 | use core::ptr::copy_nonoverlapping_memory; 4 | 5 | use arch::idt; 6 | use memory::physical; 7 | 8 | static PAGE_SIZE: u32 = 0x1000; 9 | static PAGE_MASK: u32 = 0xFFFFF000; 10 | static ENTRIES: u32 = 1024; 11 | 12 | bitflags!( 13 | #[packed] 14 | flags Flags: u32 { 15 | static NONE = 0, 16 | static PRESENT = 1 << 0, 17 | static WRITE = 1 << 1, 18 | static USER = 1 << 2, 19 | #[allow(dead_code)] 20 | static ACCESSED = 1 << 5, 21 | static EXEC = 1 << 7 22 | } 23 | ) 24 | 25 | #[packed] 26 | struct Page(u32); 27 | 28 | #[packed] 29 | struct Table { 30 | entries: [Page, ..ENTRIES] 31 | } 32 | 33 | type PageTable = Table; 34 | type PageDirectory = Table; 35 | 36 | static DIRECTORY: u32 = 0xFFFFF000; 37 | static DIRECTORY_SECONDARY: u32 = 0xFFBFF000; 38 | #[allow(dead_code)] 39 | static PAGES: u32 = 0xFFC00000; 40 | 41 | // Temporary virtual addresses useful for mapping in physical pages 42 | static TEMP1: u32 = 0xFF7FF000; 43 | static TEMP2: u32 = 0xFF7FE000; 44 | 45 | static current_directory: *mut PageDirectory = DIRECTORY as *mut PageDirectory; 46 | 47 | pub static mut kernel_directory: u32 = 0; 48 | 49 | pub fn init() { 50 | unsafe { 51 | let directory = physical::allocate_frame() as *mut PageDirectory; 52 | *directory = Table::empty(); 53 | 54 | let table = physical::allocate_frame() as *mut PageTable; 55 | *table = Table::empty(); 56 | 57 | // Identity map table the whole table, 4MB 58 | let mut i = 0; 59 | while i < PAGE_SIZE * ENTRIES { 60 | (*table).set(i, i, PRESENT | WRITE | USER); 61 | i += PAGE_SIZE; 62 | } 63 | 64 | (*directory).set(0, table as u32, PRESENT | WRITE | USER); 65 | 66 | // Map the directory itself as the last entry 67 | (*directory).set(DIRECTORY, directory as u32, PRESENT | WRITE); 68 | 69 | idt::register_interrupt(14, page_fault); 70 | 71 | kernel_directory = directory as u32; 72 | switch_page_directory(kernel_directory); 73 | enable_paging(); 74 | } 75 | } 76 | 77 | pub fn map(addr: u32, size: u32, flags: Flags) { 78 | let f = translate_flags(flags); 79 | 80 | unsafe { 81 | let mut current_addr = addr; 82 | while current_addr < addr + size { 83 | let table = (*current_directory).fetch_table(current_addr, f); 84 | 85 | let phys_addr = physical::allocate_frame(); 86 | (*table).set(current_addr, phys_addr, f); 87 | klog!("Mapping virtual {:x} to physical {:x}", current_addr, phys_addr); 88 | 89 | current_addr += PAGE_SIZE; 90 | } 91 | } 92 | } 93 | 94 | fn translate_flags(flags: Flags) -> Flags { 95 | // TODO: Have external flags 96 | let mut t = flags.clone(); 97 | 98 | if t.contains(EXEC) { 99 | klog!("mmap(): EXEC is currently ignored"); 100 | t.remove(EXEC); 101 | } 102 | 103 | t.insert(PRESENT); 104 | t 105 | } 106 | 107 | pub fn clone_directory() -> u32 { 108 | unsafe { 109 | let directory_physical = new_directory(); 110 | let directory = map_secondary_directory(directory_physical); 111 | 112 | // Link first 4MB 113 | (*directory).set_at(0, (*current_directory).get(0)); 114 | 115 | // Copy everything up to the kernel 116 | let mut i = ENTRIES * PAGE_SIZE; 117 | while i < 0xC0000000 { 118 | let src_page = (*current_directory).get_page(i); 119 | if src_page.present() { 120 | let dst_page = physical::allocate_frame(); 121 | (*directory).set_page(i, dst_page, src_page.flags()); 122 | copy_page(src_page.addr(), dst_page); 123 | } 124 | 125 | i += PAGE_SIZE; 126 | } 127 | 128 | // Link all kernel space 129 | while i < DIRECTORY_SECONDARY { 130 | // FIXME: Force table initialization, this is quite dirty but lets us skip 131 | // kernel space synchronisation for now 132 | (*current_directory).fetch_table(i, PRESENT | WRITE); 133 | 134 | (*directory).set_at(i, (*current_directory).get(i)); 135 | i += ENTRIES * PAGE_SIZE; 136 | } 137 | 138 | directory_physical 139 | } 140 | } 141 | 142 | unsafe fn map_secondary_directory(directory_physical: u32) -> *mut PageDirectory { 143 | (*current_directory).set(DIRECTORY_SECONDARY, directory_physical, PRESENT | WRITE); 144 | DIRECTORY_SECONDARY as *mut PageDirectory 145 | } 146 | 147 | unsafe fn new_directory() -> u32 { 148 | let directory_physical = physical::allocate_frame(); 149 | 150 | (*current_directory).set_page(TEMP1, directory_physical, PRESENT | WRITE); 151 | 152 | let directory = TEMP1 as *mut PageDirectory; 153 | *directory = Table::empty(); 154 | 155 | // Map the last page onto the directory itself 156 | (*directory).set(DIRECTORY, directory_physical, PRESENT | WRITE); 157 | 158 | directory_physical 159 | } 160 | 161 | unsafe fn copy_page(src: u32, dst: u32) { 162 | (*current_directory).set_page(TEMP1, src, PRESENT); 163 | (*current_directory).set_page(TEMP2, dst, PRESENT | WRITE); 164 | copy_nonoverlapping_memory(TEMP2 as *mut u8, TEMP1 as *const u8, PAGE_SIZE as uint); 165 | } 166 | 167 | fn page_fault(regs: &mut idt::Registers) { 168 | let address = read_faulting_address(); 169 | let flags = Flags::from_bits_truncate(regs.err_code); 170 | 171 | let reserved = regs.err_code & 0x8 == 0; 172 | panic!("page fault! ( {}{}{}{}) at 0x{:x}", 173 | if flags.contains(PRESENT) { "present " } else { "non-present " }, 174 | if flags.contains(WRITE) { "write " } else { " read " }, 175 | if flags.contains(USER) { "user-mode " } else { "kernel-mode " }, 176 | if reserved { "reserved " } else { "" }, 177 | address); 178 | } 179 | 180 | impl Page { 181 | fn empty() -> Page { Page(0) } 182 | 183 | fn new(addr: u32, flags: Flags) -> Page { 184 | Page(addr | flags.bits()) 185 | } 186 | 187 | fn addr(self) -> u32 { 188 | match self { 189 | Page(addr) => addr & PAGE_MASK 190 | } 191 | } 192 | 193 | fn flags(self) -> Flags { 194 | match self { 195 | Page(value) => Flags::from_bits_truncate(value) 196 | } 197 | } 198 | 199 | fn present(self) -> bool { 200 | self.flags().contains(PRESENT) 201 | } 202 | } 203 | 204 | impl Table { 205 | fn empty() -> Table { 206 | Table { entries: [Page::empty(), ..ENTRIES as uint] } 207 | } 208 | 209 | fn get(&mut self, addr: u32) -> Page { 210 | let level = size_of::() / size_of::(); 211 | let index = (addr / (PAGE_SIZE * level as u32)) % ENTRIES; 212 | self.entries[index as uint] 213 | } 214 | 215 | fn set(&mut self, addr: u32, phys: u32, flags: Flags) { 216 | self.set_at(addr, Page::new(phys, flags)); 217 | } 218 | 219 | fn set_at(&mut self, addr: u32, page: Page) { 220 | let level = size_of::() / size_of::(); 221 | let index = (addr / (PAGE_SIZE * level as u32)) % ENTRIES; 222 | self.entries[index as uint] = page; 223 | flush_tlb(addr); 224 | } 225 | } 226 | 227 | impl Table> { 228 | fn get_page(&self, addr: u32) -> Page { 229 | let index = addr / (PAGE_SIZE * ENTRIES); 230 | match self.entries[index as uint] { 231 | p if p.present() => unsafe { 232 | let table = self.table_at(index); 233 | (*table).get(addr) 234 | }, 235 | _ => Page::empty() 236 | } 237 | } 238 | 239 | fn set_page(&mut self, addr: u32, phys: u32, flags: Flags) { 240 | unsafe { 241 | let table = self.fetch_table(addr, flags); 242 | (*table).set(addr, phys, flags); 243 | } 244 | } 245 | 246 | fn fetch_table(&mut self, addr: u32, flags: Flags) -> *mut PageTable { 247 | let index = addr / (PAGE_SIZE * ENTRIES); 248 | match self.entries[index as uint] { 249 | p if p.present() => self.table_at(index), 250 | _ => unsafe { 251 | // Allocate table 252 | let table_physical = physical::allocate_frame(); 253 | 254 | self.entries[index as uint] = Page::new(table_physical, flags); 255 | 256 | let table = self.table_at(index); 257 | // Flush table so we can write to its virtual address 258 | flush_tlb(table); 259 | 260 | *table = Table::empty(); 261 | table 262 | } 263 | } 264 | } 265 | 266 | fn table_at(&self, index: u32) -> *mut PageTable { 267 | let self_addr: u32 = unsafe { transmute(self as *const PageDirectory) }; 268 | let size = size_of::() as u32; 269 | let start = self_addr - (ENTRIES - 1) * size; 270 | (start + index * size) as *mut PageTable 271 | } 272 | } 273 | 274 | fn flush_tlb(addr: T) { 275 | unsafe { 276 | asm!("invlpg ($0)" :: "r"(addr) : "memory" : "volatile"); 277 | } 278 | } 279 | 280 | pub fn switch_page_directory(directory: u32) { 281 | unsafe { 282 | asm!("mov $0, %cr3" :: "r"(directory) :: "volatile"); 283 | } 284 | } 285 | 286 | fn enable_paging() { 287 | unsafe { 288 | // Set the paging bit in CR0 to 1 289 | write_cr0(read_cr0() | 0x80000000); 290 | } 291 | } 292 | 293 | fn read_faulting_address() -> u32 { 294 | unsafe { 295 | let mut value; 296 | asm!("mov %cr2, $0" : "=r"(value)); 297 | value 298 | } 299 | } 300 | 301 | unsafe fn read_cr0() -> u32 { 302 | let mut value; 303 | asm!("mov %cr0, $0" : "=r"(value)); 304 | value 305 | } 306 | 307 | unsafe fn write_cr0(value: u32) { 308 | asm!("mov $0, %cr0" :: "r"(value) :: "volatile"); 309 | } 310 | -------------------------------------------------------------------------------- /rost/mod.rs: -------------------------------------------------------------------------------- 1 | #![crate_id = "rost#0.1"] 2 | #![crate_type = "staticlib"] 3 | #![no_std] 4 | #![feature(asm, macro_rules, lang_items, phase, globs)] 5 | 6 | #[phase(plugin, link)] 7 | 8 | extern crate core; 9 | extern crate libc; 10 | extern crate rlibc; 11 | extern crate alloc; 12 | 13 | use libc::{size_t, c_void, c_int}; 14 | 15 | 16 | mod macros; 17 | 18 | mod kernel; 19 | mod util; 20 | mod arch; 21 | mod drivers; 22 | mod memory; 23 | mod exec; 24 | 25 | 26 | mod std { 27 | // Macros refer to absolute paths 28 | pub use core::fmt; 29 | pub use core::num; 30 | pub use core::option; 31 | pub use core::cmp; 32 | pub use core::clone; 33 | } 34 | 35 | #[no_mangle] 36 | pub extern fn kernel_main() { 37 | arch::gdt::init(); 38 | arch::irq::init(); 39 | arch::idt::init(); 40 | drivers::init(); 41 | 42 | memory::init(); 43 | exec::tasking::init(); 44 | 45 | exec::syscalls::init(); 46 | 47 | kernel::console::init(); 48 | 49 | drivers::vga::clear_screen(); 50 | kprintln!("\x1b[33;1mWelcome to \x1b[0;30;47mROST\x1b[0;33;1m v0.1\x1b[m"); 51 | kprint!("Testing colors: ") 52 | kprintln!("\x1b[31;1mRED\x1b[32;1mGREEN\x1b[33;1mBROWN\x1b[34;1mBLUE\x1b[35;1mMAGENTA\x1b[36;1mCYAN\x1b[37;1mWHITE\x1b[m"); 53 | 54 | exec::tasking::exec(do_stuff); 55 | 56 | idle(); 57 | } 58 | 59 | fn idle() -> ! { 60 | loop { 61 | exec::tasking::schedule(); 62 | } 63 | } 64 | 65 | fn do_stuff() -> ! { 66 | extern { static _binary_test_fork_elf_start: u8; } 67 | let do_nothing = &_binary_test_fork_elf_start as *const u8; 68 | 69 | if exec::elf::probe(do_nothing) { 70 | kprintln!("Found program"); 71 | 72 | exec::elf::exec(do_nothing); 73 | } 74 | 75 | unreachable!(); 76 | } 77 | 78 | #[allow(visible_private_types)] 79 | #[no_mangle] 80 | pub extern fn trap_handler(regs: &mut arch::idt::Registers) { 81 | // TODO: Why? 82 | arch::idt::trap_handler(regs); 83 | } 84 | 85 | // These are for liballoc 86 | #[no_mangle] 87 | pub unsafe extern fn malloc(size: size_t) -> *mut c_void { 88 | use memory::malloc::malloc; 89 | malloc(size) 90 | } 91 | 92 | #[no_mangle] 93 | pub unsafe extern fn realloc(p: *mut c_void, size: size_t) -> *mut c_void { 94 | use memory::malloc::realloc; 95 | realloc(p, size) 96 | } 97 | 98 | #[no_mangle] 99 | pub unsafe extern fn free(p: *mut c_void) { 100 | use memory::malloc::free; 101 | free(p) 102 | } 103 | 104 | #[no_mangle] 105 | pub unsafe extern fn posix_memalign(memptr: *mut *mut c_void, align: size_t, size: size_t) -> c_int { 106 | kprintln!("Allocating {} bytes with align {}", size, align); 107 | *memptr = malloc(size); 108 | 0 109 | } 110 | 111 | #[lang = "begin_unwind"] 112 | extern fn begin_unwind(args: &core::fmt::Arguments, 113 | file: &str, 114 | line: uint) -> ! { 115 | panic!("{} in {}:{}", args, file, line); 116 | } 117 | 118 | #[lang = "stack_exhausted"] extern fn stack_exhausted() {} 119 | #[lang = "eh_personality"] extern fn eh_personality() {} 120 | -------------------------------------------------------------------------------- /rost/util/bitflags.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2014 The Rust Project Developers. See the COPYRIGHT 2 | // file at the top-level directory of this distribution and at 3 | // http://rust-lang.org/COPYRIGHT. 4 | // 5 | // Licensed under the Apache License, Version 2.0 or the MIT license 7 | // , at your 8 | // option. This file may not be copied, modified, or distributed 9 | // except according to those terms. 10 | 11 | //! The `bitflags!` macro generates a `struct` that holds a set of C-style 12 | //! bitmask flags. It is useful for creating typesafe wrappers for C APIs. 13 | //! 14 | //! The flags should only be defined for integer types, otherwise unexpected 15 | //! type errors may occur at compile time. 16 | //! 17 | //! # Example 18 | //! 19 | //! ~~~rust 20 | //! bitflags!( 21 | //! flags Flags: u32 { 22 | //! static FlagA = 0x00000001, 23 | //! static FlagB = 0x00000010, 24 | //! static FlagC = 0x00000100, 25 | //! static FlagABC = FlagA.bits 26 | //! | FlagB.bits 27 | //! | FlagC.bits 28 | //! } 29 | //! ) 30 | //! 31 | //! fn main() { 32 | //! let e1 = FlagA | FlagC; 33 | //! let e2 = FlagB | FlagC; 34 | //! assert!((e1 | e2) == FlagABC); // union 35 | //! assert!((e1 & e2) == FlagC); // intersection 36 | //! assert!((e1 - e2) == FlagA); // set difference 37 | //! assert!(!e2 == FlagA); // set complement 38 | //! } 39 | //! ~~~ 40 | //! 41 | //! The generated `struct`s can also be extended with type and trait implementations: 42 | //! 43 | //! ~~~rust 44 | //! use std::fmt; 45 | //! 46 | //! bitflags!( 47 | //! flags Flags: u32 { 48 | //! static FlagA = 0x00000001, 49 | //! static FlagB = 0x00000010 50 | //! } 51 | //! ) 52 | //! 53 | //! impl Flags { 54 | //! pub fn clear(&mut self) { 55 | //! self.bits = 0; // The `bits` field can be accessed from within the 56 | //! // same module where the `bitflags!` macro was invoked. 57 | //! } 58 | //! } 59 | //! 60 | //! impl fmt::Show for Flags { 61 | //! fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 62 | //! write!(f, "hi!") 63 | //! } 64 | //! } 65 | //! 66 | //! fn main() { 67 | //! let mut flags = FlagA | FlagB; 68 | //! flags.clear(); 69 | //! assert!(flags.is_empty()); 70 | //! assert_eq!(format!("{}", flags).as_slice(), "hi!"); 71 | //! } 72 | //! ~~~ 73 | //! 74 | //! # Attributes 75 | //! 76 | //! Attributes can be attached to the generated `struct` by placing them 77 | //! before the `flags` keyword. 78 | //! 79 | //! # Derived traits 80 | //! 81 | //! The `PartialEq` and `Clone` traits are automatically derived for the `struct` using 82 | //! the `deriving` attribute. Additional traits can be derived by providing an 83 | //! explicit `deriving` attribute on `flags`. 84 | //! 85 | //! # Operators 86 | //! 87 | //! The following operator traits are implemented for the generated `struct`: 88 | //! 89 | //! - `BitOr`: union 90 | //! - `BitAnd`: intersection 91 | //! - `Sub`: set difference 92 | //! - `Not`: set complement 93 | //! 94 | //! # Methods 95 | //! 96 | //! The following methods are defined for the generated `struct`: 97 | //! 98 | //! - `empty`: an empty set of flags 99 | //! - `all`: the set of all flags 100 | //! - `bits`: the raw value of the flags currently stored 101 | //! - `is_empty`: `true` if no flags are currently stored 102 | //! - `is_all`: `true` if all flags are currently set 103 | //! - `intersects`: `true` if there are flags common to both `self` and `other` 104 | //! - `contains`: `true` all of the flags in `other` are contained within `self` 105 | //! - `insert`: inserts the specified flags in-place 106 | //! - `remove`: removes the specified flags in-place 107 | 108 | #![macro_escape] 109 | 110 | #[macro_export] 111 | macro_rules! bitflags( 112 | ($(#[$attr:meta])* flags $BitFlags:ident: $T:ty { 113 | $($(#[$Flag_attr:meta])* static $Flag:ident = $value:expr),+ 114 | }) => ( 115 | #[deriving(PartialEq, Eq, Clone)] 116 | $(#[$attr])* 117 | pub struct $BitFlags { 118 | bits: $T, 119 | } 120 | 121 | $($(#[$Flag_attr])* pub static $Flag: $BitFlags = $BitFlags { bits: $value };)+ 122 | 123 | #[allow(dead_code)] 124 | impl $BitFlags { 125 | /// Returns an empty set of flags. 126 | pub fn empty() -> $BitFlags { 127 | $BitFlags { bits: 0 } 128 | } 129 | 130 | /// Returns the set containing all flags. 131 | pub fn all() -> $BitFlags { 132 | $BitFlags { bits: $($value)|+ } 133 | } 134 | 135 | /// Returns the raw value of the flags currently stored. 136 | pub fn bits(&self) -> $T { 137 | self.bits 138 | } 139 | 140 | /// Convert from underlying bit representation, unless that 141 | /// representation contains bits that do not correspond to a flag. 142 | pub fn from_bits(bits: $T) -> ::std::option::Option<$BitFlags> { 143 | if (bits & !$BitFlags::all().bits()) != 0 { 144 | ::std::option::None 145 | } else { 146 | ::std::option::Some($BitFlags { bits: bits }) 147 | } 148 | } 149 | 150 | /// Convert from underlying bit representation, dropping any bits 151 | /// that do not correspond to flags. 152 | pub fn from_bits_truncate(bits: $T) -> $BitFlags { 153 | $BitFlags { bits: bits } & $BitFlags::all() 154 | } 155 | 156 | /// Returns `true` if no flags are currently stored. 157 | pub fn is_empty(&self) -> bool { 158 | *self == $BitFlags::empty() 159 | } 160 | 161 | /// Returns `true` if all flags are currently set. 162 | pub fn is_all(&self) -> bool { 163 | *self == $BitFlags::all() 164 | } 165 | 166 | /// Returns `true` if there are flags common to both `self` and `other`. 167 | pub fn intersects(&self, other: $BitFlags) -> bool { 168 | !(self & other).is_empty() 169 | } 170 | 171 | /// Returns `true` all of the flags in `other` are contained within `self`. 172 | pub fn contains(&self, other: $BitFlags) -> bool { 173 | (self & other) == other 174 | } 175 | 176 | /// Inserts the specified flags in-place. 177 | pub fn insert(&mut self, other: $BitFlags) { 178 | self.bits |= other.bits; 179 | } 180 | 181 | /// Removes the specified flags in-place. 182 | pub fn remove(&mut self, other: $BitFlags) { 183 | self.bits &= !other.bits; 184 | } 185 | } 186 | 187 | impl BitOr<$BitFlags, $BitFlags> for $BitFlags { 188 | /// Returns the union of the two sets of flags. 189 | #[inline] 190 | fn bitor(&self, other: &$BitFlags) -> $BitFlags { 191 | $BitFlags { bits: self.bits | other.bits } 192 | } 193 | } 194 | 195 | impl BitAnd<$BitFlags, $BitFlags> for $BitFlags { 196 | /// Returns the intersection between the two sets of flags. 197 | #[inline] 198 | fn bitand(&self, other: &$BitFlags) -> $BitFlags { 199 | $BitFlags { bits: self.bits & other.bits } 200 | } 201 | } 202 | 203 | impl Sub<$BitFlags, $BitFlags> for $BitFlags { 204 | /// Returns the set difference of the two sets of flags. 205 | #[inline] 206 | fn sub(&self, other: &$BitFlags) -> $BitFlags { 207 | $BitFlags { bits: self.bits & !other.bits } 208 | } 209 | } 210 | 211 | impl Not<$BitFlags> for $BitFlags { 212 | /// Returns the complement of this set of flags. 213 | #[inline] 214 | fn not(&self) -> $BitFlags { 215 | $BitFlags { bits: !self.bits } & $BitFlags::all() 216 | } 217 | } 218 | ) 219 | ) 220 | -------------------------------------------------------------------------------- /rost/util/list.rs: -------------------------------------------------------------------------------- 1 | #![allow(dead_code)] 2 | 3 | use core::prelude::*; 4 | use core::mem; 5 | use core::mem::transmute; 6 | 7 | use util::Unique; 8 | 9 | type Link = Option>>; 10 | pub struct Node { 11 | value: T, 12 | next: Link 13 | } 14 | 15 | pub struct Rawlink { 16 | pub p: *mut T 17 | } 18 | 19 | pub struct List { 20 | pub head: Link, 21 | pub tail: Rawlink>, 22 | pub length: uint 23 | } 24 | 25 | /// Double-ended DList iterator 26 | //#[deriving(Clone)] 27 | pub struct Items<'a, T> { 28 | head: &'a Link, 29 | length: uint 30 | } 31 | 32 | macro_rules! count ( 33 | () => (0); 34 | ($head:expr $($tail:expr)*) => ( 35 | 1 + count!( $($tail)* ) 36 | ); 37 | ) 38 | 39 | macro_rules! link ( 40 | () => (None); 41 | ($head:expr $($tail:expr)*) => ( 42 | Some(Unique::new(Node { value: $head, next: link!( $($tail)* ) })) 43 | ); 44 | ) 45 | 46 | macro_rules! list ( 47 | ($($value:expr),*) => ( 48 | List { head: link!( $($value)* ), length: count!( $($value)* ) } 49 | ); 50 | ) 51 | 52 | impl Node { 53 | fn new(value: T, next: Link) -> Node { 54 | Node { value: value, next: next } 55 | } 56 | } 57 | 58 | impl Rawlink { 59 | fn none() -> Rawlink { 60 | Rawlink { p: 0 as *mut T } 61 | } 62 | 63 | fn some(n: &mut T) -> Rawlink { 64 | Rawlink { p: n } 65 | } 66 | 67 | fn resolve_immut(&self) -> Option<&T> { 68 | if self.p == 0 as *mut T { 69 | None 70 | } else { 71 | Some(unsafe { transmute(self.p) }) 72 | } 73 | } 74 | 75 | fn resolve(&mut self) -> Option<&mut T> { 76 | if self.p == 0 as *mut T { 77 | None 78 | } else { 79 | Some(unsafe { transmute(self.p) }) 80 | } 81 | } 82 | } 83 | 84 | impl List { 85 | pub fn new() -> List { 86 | List { head: None, tail: Rawlink { p: 0 as *mut Node }, length: 0 } 87 | } 88 | 89 | pub fn front<'a>(&'a self) -> Option<&'a T> { 90 | self.head.as_ref().map(|node| { 91 | &node.value 92 | }) 93 | } 94 | 95 | pub fn front_mut<'a>(&'a mut self) -> Option<&'a mut T> { 96 | self.head.as_mut().map(|node| { 97 | &mut node.value 98 | }) 99 | } 100 | 101 | pub fn back<'a>(&'a self) -> Option<&'a T> { 102 | self.tail.resolve_immut().map(|node| { 103 | &node.value 104 | }) 105 | } 106 | 107 | pub fn back_mut<'a>(&'a mut self) -> Option<&'a mut T> { 108 | self.tail.resolve().map(|node| { 109 | &mut node.value 110 | }) 111 | } 112 | 113 | pub fn prepend(&mut self, value: T) { 114 | let tail = mem::replace(&mut self.head, None); 115 | let mut head = Unique::new(Node::new(value, tail)); 116 | match self.tail.resolve() { 117 | None => self.tail = Rawlink::some(head.deref_mut()), 118 | _ => {} 119 | } 120 | self.head = Some(head); 121 | self.length += 1; 122 | } 123 | 124 | pub fn append(&mut self, value: T) { 125 | match self.tail.resolve() { 126 | None => return self.prepend(value), 127 | Some(tail) => { 128 | let mut new_tail = Unique::new(Node::new(value, None)); 129 | self.tail = Rawlink::some(new_tail.deref_mut()); 130 | tail.next = Some(new_tail); 131 | self.length += 1; 132 | } 133 | } 134 | } 135 | 136 | pub fn pop_front(&mut self) -> Option { 137 | self.pop_front_node().as_mut().map(|node| { 138 | node.take().value 139 | }) 140 | } 141 | 142 | fn pop_front_node(&mut self) -> Option>> { 143 | self.head.take().map(|mut front_node| { 144 | match front_node.next.take() { 145 | Some(node) => self.head = Some(node), 146 | None => self.tail = Rawlink::none() 147 | } 148 | self.length -= 1; 149 | front_node 150 | }) 151 | } 152 | 153 | /// Provide a forward iterator 154 | #[inline] 155 | pub fn iter<'a>(&'a self) -> Items<'a, T> { 156 | Items { length: self.len(), head: &self.head } 157 | } 158 | } 159 | 160 | impl Collection for List { 161 | #[inline] 162 | fn is_empty(&self) -> bool { 163 | self.len() == 0 164 | } 165 | 166 | #[inline] 167 | fn len(&self) -> uint { 168 | self.length 169 | } 170 | } 171 | 172 | impl<'a, A> Iterator<&'a A> for Items<'a, A> { 173 | #[inline] 174 | fn next(&mut self) -> Option<&'a A> { 175 | self.head.as_ref().map(|head| { 176 | self.head = &head.next; 177 | self.length -= 1; 178 | &head.value 179 | }) 180 | } 181 | 182 | #[inline] 183 | fn size_hint(&self) -> (uint, Option) { 184 | (self.length, Some(self.length)) 185 | } 186 | } 187 | -------------------------------------------------------------------------------- /rost/util/mem.rs: -------------------------------------------------------------------------------- 1 | //#![feature(unsafe_destructor)] 2 | 3 | extern crate libc; 4 | use libc::{c_void, size_t}; 5 | use core::prelude::*; 6 | 7 | use core::mem; 8 | use core::ptr; 9 | 10 | use memory::malloc::{malloc, free}; 11 | 12 | // Define a wrapper around the handle returned by the foreign code. 13 | // Unique has the same semantics as Box 14 | pub struct Unique { 15 | // It contains a single raw, mutable pointer to the object in question. 16 | ptr: *mut T 17 | } 18 | 19 | // Implement methods for creating and using the values in the box. 20 | 21 | // NB: For simplicity and correctness, we require that T has kind Send 22 | // (owned boxes relax this restriction, and can contain managed (GC) boxes). 23 | // This is because, as implemented, the garbage collector would not know 24 | // about any shared boxes stored in the malloc'd region of memory. 25 | #[allow(dead_code)] 26 | impl Unique { 27 | pub fn empty() -> Unique { 28 | unsafe { 29 | let ptr = malloc(mem::size_of::() as size_t) as *mut T; 30 | kassert!(!ptr.is_null()); 31 | 32 | ptr::zero_memory(ptr, 1); 33 | Unique{ptr: ptr} 34 | } 35 | } 36 | 37 | #[inline] 38 | pub fn new(value: T) -> Unique { 39 | unsafe { 40 | let ptr = malloc(mem::size_of::() as size_t) as *mut T; 41 | kassert!(!ptr.is_null()); 42 | 43 | ptr::write(&mut *ptr, value); 44 | Unique{ptr: ptr} 45 | } 46 | } 47 | 48 | pub fn take<'r>(&'r mut self) -> T { 49 | unsafe { 50 | let value = ptr::read(self.ptr as *const T); 51 | free(self.ptr as *mut c_void); 52 | self.ptr = 0 as *mut T; 53 | value 54 | } 55 | } 56 | 57 | pub fn drop(&mut self) { 58 | unsafe { 59 | // Copy the object out from the pointer onto the stack, 60 | // where it is covered by normal Rust destructor semantics 61 | // and cleans itself up, if necessary 62 | ptr::read(self.ptr as *const T); 63 | 64 | // clean-up our allocation 65 | free(self.ptr as *mut c_void) 66 | } 67 | } 68 | } 69 | 70 | /* 71 | // A key ingredient for safety, we associate a destructor with 72 | // Unique, making the struct manage the raw pointer: when the 73 | // struct goes out of scope, it will automatically free the raw pointer. 74 | // 75 | // NB: This is an unsafe destructor, because rustc will not normally 76 | // allow destructors to be associated with parameterized types, due to 77 | // bad interaction with managed boxes. (With the Send restriction, 78 | // we don't have this problem.) Note that the `#[unsafe_destructor]` 79 | // feature gate is required to use unsafe destructors. 80 | #[unsafe_destructor] 81 | impl Drop for Unique { 82 | fn drop(&mut self) { 83 | unsafe { 84 | // Copy the object out from the pointer onto the stack, 85 | // where it is covered by normal Rust destructor semantics 86 | // and cleans itself up, if necessary 87 | ptr::read(self.ptr as *const T); 88 | 89 | // clean-up our allocation 90 | free(self.ptr as *mut c_void) 91 | } 92 | } 93 | } 94 | */ 95 | 96 | impl Deref for Unique { 97 | #[inline] 98 | fn deref<'a>(&'a self) -> &'a T { 99 | unsafe { &*self.ptr } 100 | } 101 | } 102 | 103 | impl DerefMut for Unique { 104 | #[inline] 105 | fn deref_mut<'a>(&'a mut self) -> &'a mut T { 106 | unsafe { &mut *self.ptr } 107 | } 108 | } 109 | -------------------------------------------------------------------------------- /rost/util/mod.rs: -------------------------------------------------------------------------------- 1 | #![macro_escape] 2 | 3 | pub use self::mem::Unique; 4 | 5 | mod bitflags; 6 | pub mod list; 7 | mod mem; 8 | -------------------------------------------------------------------------------- /runtime.asm: -------------------------------------------------------------------------------- 1 | global __morestack 2 | __morestack: 3 | jmp $ 4 | 5 | global __divdi3 6 | __divdi3: 7 | jmp $ 8 | 9 | global __udivdi3 10 | __udivdi3: 11 | jmp $ 12 | 13 | global __mulodi4 14 | __mulodi4: 15 | jmp $ 16 | 17 | global __moddi3 18 | __moddi3: 19 | jmp $ 20 | 21 | global __umoddi3 22 | __umoddi3: 23 | jmp $ 24 | 25 | global fmod 26 | fmod: 27 | jmp $ 28 | 29 | global fmodf 30 | fmodf: 31 | jmp $ 32 | 33 | global floorf 34 | floorf: 35 | jmp $ 36 | 37 | global ceilf 38 | ceilf: 39 | jmp $ 40 | 41 | global roundf 42 | roundf: 43 | jmp $ 44 | 45 | global truncf 46 | truncf: 47 | jmp $ 48 | 49 | global fmaf 50 | fmaf: 51 | jmp $ 52 | 53 | global __powisf2 54 | __powisf2: 55 | jmp $ 56 | 57 | global powf 58 | powf: 59 | jmp $ 60 | 61 | global expf 62 | expf: 63 | jmp $ 64 | 65 | global exp2f 66 | exp2f: 67 | jmp $ 68 | 69 | global logf 70 | logf: 71 | jmp $ 72 | 73 | global log2f 74 | log2f: 75 | jmp $ 76 | 77 | global log10f 78 | log10f: 79 | jmp $ 80 | 81 | global floor 82 | floor: 83 | jmp $ 84 | 85 | global ceil 86 | ceil: 87 | jmp $ 88 | 89 | global round 90 | round: 91 | jmp $ 92 | 93 | global trunc 94 | trunc: 95 | jmp $ 96 | 97 | global fma 98 | fma: 99 | jmp $ 100 | 101 | global pow 102 | pow: 103 | jmp $ 104 | 105 | global __powidf2 106 | __powidf2: 107 | jmp $ 108 | 109 | global exp 110 | exp: 111 | jmp $ 112 | 113 | global exp2 114 | exp2: 115 | jmp $ 116 | 117 | global log 118 | log: 119 | jmp $ 120 | 121 | global log2 122 | log2: 123 | jmp $ 124 | 125 | global log10 126 | log10: 127 | jmp $ 128 | 129 | global fdimf 130 | fdimf: 131 | jmp $ 132 | 133 | global fdim 134 | fdim: 135 | jmp $ 136 | 137 | global __fixunssfdi 138 | __fixunssfdi: 139 | jmp $ 140 | 141 | global __fixunsdfdi 142 | __fixunsdfdi: 143 | jmp $ 144 | --------------------------------------------------------------------------------