├── .gitignore ├── .gitmodules ├── LICENSE.txt ├── Makefile ├── README.md ├── arch ├── arm │ ├── .gdbinit │ ├── Makefile │ ├── boot │ │ ├── .gitignore │ │ ├── aeabi_runtime.s │ │ ├── linker.ld │ │ └── loader.s │ ├── cpu │ │ ├── interrupt.rs │ │ ├── mmu.rs │ │ └── mod.rs │ ├── drivers │ │ └── mod.rs │ ├── io │ │ └── mod.rs │ └── module.s └── x86 │ ├── .gdbinit │ ├── Makefile │ ├── boot │ ├── .gitignore │ ├── linker.ld │ └── loader.asm │ ├── cpu │ ├── exception.rs │ ├── gdt.rs │ ├── idt.rs │ ├── interrupt.rs │ ├── io.rs │ ├── mmu.rs │ ├── mod.rs │ └── tss.rs │ ├── drivers │ ├── keyboard.rs │ ├── mod.rs │ ├── pic.rs │ └── vga.rs │ ├── io │ └── mod.rs │ ├── module.asm │ └── runtime │ ├── mod.rs │ └── stack.rs └── common ├── Makefile ├── kernel ├── elf │ ├── elf32.rs │ ├── elf64.rs │ └── mod.rs ├── heap.rs ├── mm │ ├── allocator.rs │ ├── mod.rs │ └── physical.rs ├── mod.rs ├── process.rs └── util │ ├── bitv.rs │ ├── mod.rs │ └── rt.rs ├── lib.rs ├── macros.rs └── rust_core ├── bitflags.rs ├── c_types.rs ├── fail.rs ├── macros.rs ├── mod.rs └── support.rs /.gitignore: -------------------------------------------------------------------------------- 1 | config.mk 2 | 3 | # Sublime Text 4 | *.sublime-* 5 | 6 | # Upstream 7 | common/libcore 8 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pczarn/rustboot/d367cd61964235a63b40f1fcbf5ec615bd8ba2fc/.gitmodules -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | Copyright (c) 2013 Charlie Somerville 2 | Copyright (c) 2013-2014 Piotr Czarnecki 3 | 4 | MIT License 5 | 6 | Permission is hereby granted, free of charge, to any person obtaining 7 | a copy of this software and associated documentation files (the 8 | "Software"), to deal in the Software without restriction, including 9 | without limitation the rights to use, copy, modify, merge, publish, 10 | distribute, sublicense, and/or sell copies of the Software, and to 11 | permit persons to whom the Software is furnished to do so, subject to 12 | the following conditions: 13 | 14 | The above copyright notice and this permission notice shall be 15 | included in all copies or substantial portions of the Software. 16 | 17 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 18 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 19 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 20 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 21 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 22 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 23 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 24 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | -include ./config.mk 2 | 3 | arch ?= x86 4 | 5 | # can make the compiler fail. Disable for now 6 | DEBUG ?= 7 | 8 | RUST_ROOT ?= /usr 9 | LLVM_ROOT ?= /usr 10 | GCC_PREFIX ?= /usr/bin/ 11 | SHELL ?= /bin/bash 12 | 13 | export DEBUG 14 | 15 | export RUST_ROOT 16 | export LLVM_ROOT 17 | export GCC_PREFIX 18 | 19 | all: 20 | @$(MAKE) all -C arch/$(arch)/ SHELL=$(SHELL) 21 | 22 | %: 23 | @$(MAKE) $* -C arch/$(arch)/ SHELL=$(SHELL) 24 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | rustboot 2 | ================================================================================ 3 | A small kernel with basic functionality written in Rust. Currently only parts 4 | of memory management and the keyboard driver are any interesting. 5 | 6 | Pictures 7 | -------------------------------------------------------------------------------- 8 | 9 | It paints the screen bright red and then displays some information. You can 10 | write. That's it: 11 | 12 | ![][x86_run] 13 | 14 | ![][arm_dbg] 15 | 16 | Setup 17 | -------------------------------------------------------------------------------- 18 | 19 | You need a few things to run rustboot: 20 | 21 | 1. [Rust's `master` branch][rm] 22 | 2. qemu 23 | 3. On x86 24 | * clang 25 | * nasm 26 | 4. On ARM 27 | * binutils for arm-none-eabi 28 | * gcc cross-compiler 29 | 5. Optionally for debugging 30 | * gdb 31 | * tmux 32 | 33 | Clone this repository. 34 | 35 | ```bash 36 | $ git clone https://github.com/pczarn/rustboot.git 37 | $ cd rustboot 38 | ``` 39 | 40 | To get edge Rust going, grab it from git: 41 | 42 | ```bash 43 | $ git clone https://github.com/mozilla/rust 44 | $ cd rust 45 | $ ./configure --target=i686-unknown-linux-gnu 46 | $ make && make install 47 | ``` 48 | 49 | You can considerably minimize build time: 50 | ```bash 51 | $ ./configure --target=i686-unknown-linux-gnu --llvm-root=/usr 52 | $ make rustc-stage1 53 | ``` 54 | Then use the `rust/*/stage1/bin/rustc` binary to compile rustboot: 55 | ```bash 56 | $ echo "RUST_ROOT:=$(pwd)/x86_64-unknown-linux-gnu/stage1/bin" > rustboot/config.mk 57 | ``` 58 | 59 | ### Arch Linux 60 | 61 | Simply install all dependencies: 62 | ``` 63 | # pacman -S qemu nasm rust clang gdb tmux 64 | # yaourt -S gcc-arm-none-eabi 65 | ``` 66 | 67 | ### OSX 68 | 69 | To set things up on OSX, do this: 70 | 71 | Install `nasm` and `qemu` from homebrew: 72 | 73 | ```bash 74 | $ brew install nasm 75 | $ brew install qemu 76 | ``` 77 | 78 | Install latest binutils from [source][sw]. 79 | 80 | ```bash 81 | $ wget 'ftp://sourceware.org/pub/binutils/snapshots/binutils.tar.bz2' 82 | $ ./configure --target=i386-elf 83 | $ make && make install 84 | ``` 85 | 86 | Running it 87 | -------------------------------------------------------------------------------- 88 | 89 | To compile, simply execute `make` command. 90 | 91 | To run, use: 92 | ```bash 93 | $ make run # emulate default platform (x86) 94 | $ make arch=arm run # run on ARM 95 | $ make arch=arm debug # debug on ARM 96 | ``` 97 | 98 | [rm]: https://github.com/mozilla/rust 99 | [x86_run]: http://i.imgur.com/XW8PUlM.png 100 | [arm_dbg]: http://i.imgur.com/3cHXx2D.png 101 | [sw]: ftp://sourceware.org/pub/binutils/snapshots 102 | -------------------------------------------------------------------------------- /arch/arm/.gdbinit: -------------------------------------------------------------------------------- 1 | target remote localhost:1234 2 | symbol-file boot/kernel.elf 3 | 4 | b debug 5 | -------------------------------------------------------------------------------- /arch/arm/Makefile: -------------------------------------------------------------------------------- 1 | 2 | include ../../common/Makefile 3 | 4 | GCC_PREFIX_2 = $(GCC_PREFIX)arm-none-eabi- 5 | 6 | TARGET ?= arm-unknown-linux-gnueabi 7 | 8 | LLCFLAGS ?= -mtriple=$(TARGET) $(MAYBE_OPTIMIZE) \ 9 | -march=arm -mcpu=arm926ej-s --float-abi=hard -asm-verbose 10 | 11 | QEMU ?= qemu-system-arm 12 | 13 | OBJS ?= $(BDIR)/loader.o $(BDIR)/aeabi_runtime.o $(BDIR)/main.o 14 | LINK ?= $(BDIR)/linker.ld $(OBJS) $(BDIR)/initram.elf.embed 15 | 16 | DEP_RM ?= arch/ 17 | DEP_KEEP ?= arch/arm 18 | 19 | LD = $(GCC_PREFIX_2)ld 20 | 21 | .PHONY: all run debug 22 | 23 | all: $(BDIR)/kernel.bin 24 | @wc -c $^ 25 | 26 | %.s: %.bc 27 | $(LLC) $(LLCFLAGS) $^ -o $@ 28 | 29 | # Assemble object files. note: do not overwrite deps with -MD $*.d 30 | %.o: %.s 31 | $(AS) -g $< -o $@ 32 | 33 | # initram 34 | $(BDIR)/%.o: %.s 35 | $(AS) $< -o $@ 36 | 37 | # kernel (object) 38 | $(BDIR)/kernel.elf: $(LINK) 39 | $(LD) -o $@ -T $^ 40 | 41 | # kernel (binary image) 42 | $(BDIR)/kernel.bin: $(BDIR)/kernel.elf 43 | $(OBJCOPY) -O binary $^ $@ 44 | 45 | # running 46 | run: all 47 | $(QEMU) -M versatilepb -m 32M -nographic -kernel $(BDIR)/kernel.bin 48 | 49 | debug: $(BDIR)/kernel.elf 50 | ifeq ($(strip $(TMUX)),) 51 | tmux new-session -d -s rustboot 52 | tmux new-window -t rustboot:1 "$(QEMU) -M versatilepb -m 32M -nographic -kernel $^ -s -S" 53 | tmux split-window -t rustboot "$(GDB)" 54 | tmux a -t rustboot 55 | tmux kill-session -t rustboot 56 | else 57 | # TODO: debug in current window, can't kill panes 58 | tmux new-w "$(QEMU) -M versatilepb -m 32M -nographic -kernel $^ -s -S" 59 | tmux split-w "$(GDB); tmux kill-w" 60 | endif 61 | -------------------------------------------------------------------------------- /arch/arm/boot/.gitignore: -------------------------------------------------------------------------------- 1 | *.d 2 | 3 | main.s 4 | 5 | lib*.rlib 6 | *.bc 7 | 8 | *.elf 9 | *.o 10 | *.embed 11 | *.bin 12 | -------------------------------------------------------------------------------- /arch/arm/boot/aeabi_runtime.s: -------------------------------------------------------------------------------- 1 | //===----------------------------------------------------------------------===// 2 | // 3 | // The LLVM Compiler Infrastructure 4 | // 5 | // This file is dual licensed under the MIT and the University of Illinois Open 6 | // Source Licenses. See LICENSE.TXT for details. 7 | // 8 | //===----------------------------------------------------------------------===// 9 | 10 | .syntax unified 11 | .cpu arm926ej-s 12 | 13 | .globl __aeabi_memset 14 | __aeabi_memset: 15 | mov r3, r1 16 | mov r1, r2 17 | mov r2, r3 18 | b memset 19 | 20 | .globl __aeabi_memcpy 21 | __aeabi_memcpy: 22 | b memcpy 23 | 24 | .globl __aeabi_memmove 25 | __aeabi_memmove: 26 | b memmove 27 | 28 | .align 3 29 | .globl __aeabi_uidiv 30 | .globl __udivsi3 31 | __aeabi_uidiv: 32 | __udivsi3: 33 | # 51 "udivsi3.S" 34 | push {r7, lr} ; mov r7, sp 35 | clz r2, r0 36 | tst r1, r1 37 | clz r3, r1 38 | mov ip, #0 39 | beq .L_return 40 | mov lr, #1 41 | subs r3, r3, r2 42 | blt .L_return 43 | 44 | .L_mainLoop: 45 | # 75 "udivsi3.S" 46 | subs r2, r0, r1, lsl r3 47 | itt hs 48 | orrhs ip, ip,lr, lsl r3 49 | movhs r0, r2 50 | it ne 51 | subsne r3, r3, #1 52 | bhi .L_mainLoop 53 | 54 | 55 | 56 | subs r2, r0, r1 57 | it hs 58 | orrhs ip, #1 59 | 60 | .L_return: 61 | 62 | mov r0, ip 63 | pop {r7, pc} 64 | 65 | .align 3 66 | .globl __umodsi3 67 | __umodsi3: 68 | # 39 "umodsi3.S" 69 | clz r2, r0 70 | tst r1, r1 71 | clz r3, r1 72 | bxeq lr 73 | subs r3, r3, r2 74 | bxlt lr 75 | 76 | .L_mainLoop2: 77 | # 59 "umodsi3.S" 78 | subs r2, r0, r1, lsl r3 79 | it hs 80 | movhs r0, r2 81 | it ne 82 | subsne r3, r3, #1 83 | bhi .L_mainLoop2 84 | 85 | 86 | 87 | subs r2, r0, r1 88 | it hs 89 | movhs r0, r2 90 | bx lr 91 | 92 | .align 3 93 | .globl __aeabi_idiv 94 | __aeabi_idiv: 95 | __divsi3: 96 | # 37 "divsi3.S" 97 | push {r4, r7, lr} ; add r7, sp, #4 98 | 99 | eor r4, r0, r1 100 | 101 | eor r2, r0, r0, asr #31 102 | eor r3, r1, r1, asr #31 103 | sub r0, r2, r0, asr #31 104 | sub r1, r3, r1, asr #31 105 | 106 | bl __udivsi3 107 | 108 | eor r0, r0, r4, asr #31 109 | sub r0, r0, r4, asr #31 110 | pop {r4, r7, pc} 111 | 112 | .align 3 113 | ; .globl __modsi3 ; __modsi3: 114 | # 36 "modsi3.S" 115 | push {r4, r7, lr} ; add r7, sp, #4 116 | 117 | mov r4, r0 118 | 119 | eor r2, r0, r0, asr #31 120 | eor r3, r1, r1, asr #31 121 | sub r0, r2, r0, asr #31 122 | sub r1, r3, r1, asr #31 123 | 124 | bl __umodsi3 125 | 126 | eor r0, r0, r4, asr #31 127 | sub r0, r0, r4, asr #31 128 | pop {r4, r7, pc} 129 | 130 | // https://android.googlesource.com/platform/bionic/+/884e4f8/libc/arch-arm/bionic/memset.S 131 | /* 132 | * Copyright (C) 2008 The Android Open Source Project 133 | * All rights reserved. 134 | * 135 | * Redistribution and use in source and binary forms, with or without 136 | * modification, are permitted provided that the following conditions 137 | * are met: 138 | * * Redistributions of source code must retain the above copyright 139 | * notice, this list of conditions and the following disclaimer. 140 | * * Redistributions in binary form must reproduce the above copyright 141 | * notice, this list of conditions and the following disclaimer in 142 | * the documentation and/or other materials provided with the 143 | * distribution. 144 | * 145 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 146 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 147 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 148 | * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 149 | * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 150 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 151 | * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS 152 | * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 153 | * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 154 | * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT 155 | * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 156 | * SUCH DAMAGE. 157 | */ 158 | 159 | /* 160 | * Optimized memset() for ARM. 161 | * 162 | * memset() returns its first argument. 163 | */ 164 | memset: 165 | /* compute the offset to align the destination 166 | * offset = (4-(src&3))&3 = -src & 3 167 | */ 168 | .fnstart 169 | .save {r0, r4-r7, lr} 170 | stmfd sp!, {r0, r4-r7, lr} 171 | rsb r3, r0, #0 172 | ands r3, r3, #3 173 | cmp r3, r2 174 | movhi r3, r2 175 | 176 | /* splat r1 */ 177 | mov r1, r1, lsl #24 178 | orr r1, r1, r1, lsr #8 179 | orr r1, r1, r1, lsr #16 180 | 181 | movs r12, r3, lsl #31 182 | strcsb r1, [r0], #1 /* can't use strh (alignment unknown) */ 183 | strcsb r1, [r0], #1 184 | strmib r1, [r0], #1 185 | subs r2, r2, r3 186 | ldmlsfd sp!, {r0, r4-r7, lr} /* return */ 187 | bxls lr 188 | 189 | /* align the destination to a cache-line */ 190 | mov r12, r1 191 | mov lr, r1 192 | mov r4, r1 193 | mov r5, r1 194 | mov r6, r1 195 | mov r7, r1 196 | 197 | rsb r3, r0, #0 198 | ands r3, r3, #0x1C 199 | beq 3f 200 | cmp r3, r2 201 | andhi r3, r2, #0x1C 202 | sub r2, r2, r3 203 | 204 | /* conditionnaly writes 0 to 7 words (length in r3) */ 205 | movs r3, r3, lsl #28 206 | stmcsia r0!, {r1, lr} 207 | stmcsia r0!, {r1, lr} 208 | stmmiia r0!, {r1, lr} 209 | movs r3, r3, lsl #2 210 | strcs r1, [r0], #4 211 | 212 | 3: 213 | subs r2, r2, #32 214 | mov r3, r1 215 | bmi 2f 216 | 1: subs r2, r2, #32 217 | stmia r0!, {r1,r3,r4,r5,r6,r7,r12,lr} 218 | bhs 1b 219 | 2: add r2, r2, #32 220 | 221 | /* conditionnaly stores 0 to 31 bytes */ 222 | movs r2, r2, lsl #28 223 | stmcsia r0!, {r1,r3,r12,lr} 224 | stmmiia r0!, {r1, lr} 225 | movs r2, r2, lsl #2 226 | strcs r1, [r0], #4 227 | strmih r1, [r0], #2 228 | movs r2, r2, lsl #2 229 | strcsb r1, [r0] 230 | ldmfd sp!, {r0, r4-r7, lr} 231 | bx lr 232 | -------------------------------------------------------------------------------- /arch/arm/boot/linker.ld: -------------------------------------------------------------------------------- 1 | OUTPUT_FORMAT("elf32-littlearm", "elf32-littlearm", "elf32-littlearm") 2 | OUTPUT_ARCH(arm) 3 | ENTRY(start) 4 | 5 | SECTIONS { 6 | . = 0x10000; 7 | 8 | .text : { 9 | boot/loader.o 10 | *(.text .rodata) 11 | } 12 | 13 | .data : { *(.data) } 14 | .bss : { *(.bss) } 15 | } 16 | -------------------------------------------------------------------------------- /arch/arm/boot/loader.s: -------------------------------------------------------------------------------- 1 | .text 2 | .code 32 3 | .syntax unified 4 | .cpu arm926ej-s 5 | .fpu softvfp 6 | 7 | .global start 8 | .global abort 9 | 10 | .type start, %function 11 | 12 | start: 13 | mov sp, 0x18000 14 | bl main 15 | abort: 16 | b . 17 | -------------------------------------------------------------------------------- /arch/arm/cpu/interrupt.rs: -------------------------------------------------------------------------------- 1 | //! The vector table. 2 | 3 | use core::intrinsics::{offset, transmute, volatile_store}; 4 | 5 | use core::failure; 6 | use core::fmt; 7 | 8 | use platform::io; 9 | 10 | static VIC_INT_ENABLE: *mut u32 = (0x10140000 + 0x010) as *mut u32; 11 | static UART0_IRQ: u8 = 12; 12 | static VT: *mut u32 = 0 as *mut u32; // WARNING verify should be mutable. 13 | 14 | #[repr(u8)] 15 | pub enum Int { 16 | Reset = 0, 17 | 18 | /// In ARM mode, an undefined opcode is used as a breakpoint to break 19 | /// execution[[7]]. 20 | Undef, 21 | 22 | /// Software interrupt. 23 | SWI, 24 | PrefetchAbort, 25 | DataAbort, 26 | IRQ = 6, 27 | FIQ 28 | } 29 | 30 | fn set_word(vector: u8, instruction: u32) { 31 | unsafe { 32 | volatile_store(offset(VT, vector as int) as *mut u32, instruction); 33 | } 34 | } 35 | 36 | fn branch(rel: u32) -> u32 { 37 | // b isr ; branch instruction [1] 38 | 0xea000000 | (((rel - 8) >> 2) & 0xffffff) 39 | } 40 | 41 | /// Exception handlers can be dynamically installed[[1]] into the vector table[[2]]. 42 | /// Interrupts must be unmasked with the `VIC_INT_ENABLE`[[3]] interrupt controller register[[4]]. 43 | /// 44 | /// Enabling interrupts[[5]]. 45 | /// 46 | /// In ARM mode, an undefined opcode is used as a breakpoint to break execution[[7]]. 47 | /// 48 | /// When the exception handler has completed execution, the processor restores the state so that the program can resume. The following instructions are used to leave an exception handler[[8]]: 49 | /// 50 | /// | Exception | Return instruction | 51 | /// |-----------|--------------------| 52 | /// | UNDEF | `movs pc, lr` | 53 | /// | IRQ, FIQ | `subs pc, lr, #4` | 54 | /// 55 | /// [1]: http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.dui0056d/Caccfahd.html 56 | /// [2]: http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.dui0203j/Cihdidh2.html 57 | /// [3]: http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.ddi0273a/Cihiicbh.html 58 | /// [4]: http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.dui0225d/I1042232.html 59 | /// [5]: http://balau82.wordpress.com/2012/04/15/arm926-interrupts-in-qemu/ "ARM926 interrupts in QEMU" 60 | /// [7]: http://stackoverflow.com/questions/11345371/how-do-i-set-a-software-breakpoint-on-an-arm-processor "How do I set a software breakpoint on an ARM processor? - Stack Overflow" 61 | /// [8]: http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.ddi0222b/I3108.html "2.9.1. Exception entry and exit summary" 62 | /// [6]: https://github.com/torvalds/linux/blob/ 63 | pub struct Table; 64 | 65 | impl Table { 66 | pub fn new() -> Table { 67 | Table 68 | } 69 | 70 | #[allow(visible_private_types)] 71 | pub fn enable(&self, which: Int, isr: unsafe fn()) { 72 | // Installing exception handlers into the vectors directly [1] 73 | let vector: u8 = unsafe { transmute(which) }; 74 | set_word(vector, branch(isr as u32 - (vector as u32 * 4))); 75 | } 76 | 77 | pub fn load(&self) { 78 | let mut i = 0; 79 | while i < 10 { 80 | // make every handler loop indefinitely 81 | set_word(i, branch(0)); 82 | i += 1; 83 | } 84 | 85 | self.enable(Reset, unsafe { transmute(start) }); 86 | // breakpoints use an UND opcode to trigger UNDEF. [7] 87 | self.enable(Undef, debug); 88 | 89 | unsafe { 90 | // Enable IRQs [5] 91 | asm!("mov r2, sp 92 | mrs r0, cpsr // get Program Status Register 93 | bic r1, r0, #0x1F // go in IRQ mode 94 | orr r1, r1, #0x12 95 | msr cpsr, r1 96 | mov sp, 0x19000 // set IRQ stack 97 | bic r0, r0, #0x80 // Enable IRQs 98 | msr cpsr, r0 // go back in Supervisor mode 99 | mov sp, r2" 100 | ::: "r0", "r1", "r2", "cpsr"); 101 | 102 | // enable UART0 IRQ [4] 103 | *VIC_INT_ENABLE = 1 << UART0_IRQ; 104 | // enable RXIM interrupt 105 | *io::UART0_IMSC = 1 << 4; 106 | } 107 | } 108 | } 109 | 110 | extern { 111 | fn start(); 112 | } 113 | 114 | #[no_mangle] 115 | pub unsafe fn debug() { 116 | asm!("movs pc, lr") 117 | } 118 | 119 | // TODO respect destructors 120 | #[lang="begin_unwind"] 121 | unsafe extern "C" fn begin_unwind(fmt: &fmt::Arguments, file: &str, line: uint) -> ! { 122 | loop { }; 123 | } 124 | 125 | /* 126 | #[lang="fail_"] 127 | #[fixed_stack_segment] 128 | pub fn fail(expr: *u8, file: *u8, line: uint) -> ! { 129 | unsafe { zero::abort(); } 130 | } 131 | 132 | #[lang="fail_bounds_check"] 133 | #[fixed_stack_segment] 134 | pub fn fail_bounds_check(file: *u8, line: uint, index: uint, len: uint) { 135 | unsafe { zero::abort(); } 136 | } 137 | */ 138 | -------------------------------------------------------------------------------- /arch/arm/cpu/mmu.rs: -------------------------------------------------------------------------------- 1 | //! Memory management unit. 2 | 3 | use core; 4 | 5 | use kernel::mm::physical; 6 | use kernel::mm::physical::Phys; 7 | 8 | pub type Frame = [u8, ..PAGE_SIZE]; 9 | 10 | const PAGE_SIZE: uint = 0x1000; 11 | const PAGE_SIZE_LOG2: uint = 12; 12 | 13 | // kinda clever 14 | bitflags!(flags Flags: u32 { 15 | const SECTION = 0b10010, 16 | 17 | const BUFFER = 1 << 2, 18 | const CACHE = 1 << 3, 19 | const RW = 1 << 10, 20 | const CLIENT_ACCESS = 1 << 11 21 | }) 22 | 23 | #[repr(packed)] 24 | pub struct Descriptor(u32); 25 | 26 | #[repr(packed)] 27 | struct PageTableCoarse { 28 | pages: [Descriptor, ..256] 29 | } 30 | 31 | #[allow(visible_private_types)] 32 | #[repr(packed)] 33 | pub struct PageDirectory { 34 | entries: [Descriptor, ..4096] 35 | } 36 | 37 | pub static mut directory: *mut PageDirectory = 0 as *mut PageDirectory; 38 | 39 | define_reg!(CR, CRFlags: uint { 40 | CR_M = 1 << 0, // MMU enable 41 | CR_A = 1 << 1, 42 | CR_C = 1 << 2, // Data cache enable 43 | CR_W = 1 << 3, 44 | CR_P = 1 << 4, // 32-bit exception handler 45 | CR_D = 1 << 5, // 32-bit data address range 46 | CR_L = 1 << 6, // Implementation defined 47 | CR_B = 1 << 7, // Endianness 48 | CR_S = 1 << 8, 49 | CR_R = 1 << 9, 50 | CR_F = 1 << 10, // Implementation defined 51 | CR_Z = 1 << 11, // Implementation defined 52 | CR_I = 1 << 12, // Instruction cache enable 53 | CR_V = 1 << 13, 54 | CR_RR = 1 << 14, 55 | CR_L4 = 1 << 15 56 | }) 57 | 58 | // Each of the 16 domains can be either allowed full access (manager) 59 | // to a region of memory or restricted access to some pages in that region (client). 60 | bitflags!(flags DomainTypeMask: uint { 61 | const KERNEL = 0b11 << 0, 62 | const USER = 0b11 << 2, 63 | const NOACCESS = 0, 64 | const CLIENT = 0b01 * 0x55555555, 65 | const MANAGER = 0b11 * 0x55555555 66 | }) 67 | 68 | impl CR { 69 | #[inline] #[allow(dead_code)] 70 | pub fn read() -> CRFlags { 71 | unsafe { 72 | let flags; 73 | asm!(concat!("mrc p15, 0, $0, c1, c0, 0") : "=r"(flags)); 74 | CRFlags(flags) 75 | } 76 | } 77 | 78 | #[inline] #[allow(dead_code)] 79 | pub fn write(f: CRFlags) { 80 | match f { 81 | CRFlags(val) => unsafe { 82 | asm!(concat!("mcr p15, 0, $0, c1, c0, 0") :: "r"(val) :: "volatile"); 83 | } 84 | } 85 | } 86 | } 87 | 88 | pub unsafe fn init() { 89 | let dir: Phys = physical::zero_alloc_frames(4); 90 | 91 | (*dir.as_ptr()).entries[0] = Descriptor::section(0, RW); 92 | 93 | switch_directory(dir); 94 | enable_paging(); 95 | } 96 | 97 | pub fn switch_directory(dir: Phys) { 98 | // Memory protection is determined by control register c1 bits S and R, 99 | // domain access reg. c3 and per-page domain number and permission bits. 100 | let cpu_domain = KERNEL & MANAGER | USER & MANAGER; 101 | 102 | unsafe { 103 | asm!("mcr p15, 0, $0, c3, c0, 0 // load domain access register 104 | mcr p15, 0, $1, c2, c0, 0 // load page table pointer 105 | " :: "r"(cpu_domain), "r"(dir.offset()) : "ip" : "volatile"); 106 | } 107 | } 108 | 109 | fn enable_paging() { 110 | unsafe { 111 | asm!("mov ip, 0 112 | mcr p15, 0, ip, c7, c5, 0 // invalidate I & D cache 113 | mcr p15, 0, ip, c7, c10, 4 // drain write buffer 114 | mcr p15, 0, ip, c8, c7, 0 // invalidate I & D TLBs 115 | " ::: "ip" : "volatile"); 116 | 117 | CR::write(CR - (CR_A | CR_W | CR_P | CR_D | CR_R | CR_F | CR_Z | CR_V | CR_RR) 118 | | (CR_S | CR_I | CR_C | CR_M)); 119 | } 120 | } 121 | 122 | pub unsafe fn map(_: *mut u8, _: uint, _: Flags) { 123 | // TODO 124 | } 125 | 126 | impl Descriptor { 127 | fn section(base: u32, flags: Flags) -> Descriptor { 128 | // make a section descriptor 129 | Descriptor(base) | flags | SECTION 130 | } 131 | } 132 | 133 | impl_ops!(Descriptor, Flags) 134 | 135 | impl PageDirectory { 136 | pub unsafe fn map(&self, _: *mut u8, _: uint, _: Flags) { 137 | // TODO 138 | } 139 | 140 | pub unsafe fn clone(&mut self) -> Phys { 141 | Phys::at(self as *mut PageDirectory as uint) 142 | } 143 | } 144 | -------------------------------------------------------------------------------- /arch/arm/cpu/mod.rs: -------------------------------------------------------------------------------- 1 | pub mod interrupt; 2 | pub mod mmu; 3 | 4 | pub fn init() { 5 | unsafe { 6 | mmu::init(); 7 | } 8 | } 9 | 10 | pub fn info() { 11 | } 12 | -------------------------------------------------------------------------------- /arch/arm/drivers/mod.rs: -------------------------------------------------------------------------------- 1 | use core::option::{Option, None}; 2 | 3 | use super::cpu::interrupt; 4 | use super::io; 5 | use kernel; 6 | 7 | pub static mut keydown: Option = None; 8 | 9 | pub fn init() { 10 | unsafe { 11 | kernel::int_table.map(|t| { 12 | t.enable(interrupt::IRQ, keypress); 13 | }); 14 | } 15 | } 16 | 17 | #[no_mangle] 18 | pub unsafe fn keypress() { 19 | keydown.map(|f| f(*io::UART0) ); 20 | // Exception return instruction. [8] 21 | // TODO: better interrupt handler. r11 could change 22 | asm!("pop {r11, lr} 23 | subs pc, r14, #4") // pc = lr - 4 24 | } 25 | -------------------------------------------------------------------------------- /arch/arm/io/mod.rs: -------------------------------------------------------------------------------- 1 | //! UART read/write 2 | 3 | use core::intrinsics::volatile_store; 4 | 5 | pub static UART0: *mut u32 = 0x101f1000 as *mut u32; 6 | pub static UART0_IMSC: *mut u32 = (0x101f1000 + 0x038) as *mut u32; 7 | 8 | pub unsafe fn write_word(c: u32) { 9 | volatile_store(UART0, c); 10 | } 11 | 12 | pub unsafe fn write_char(c: char) { 13 | volatile_store(UART0, c as u32); 14 | } 15 | 16 | pub fn putc(c: u32) { 17 | unsafe { 18 | write_word(c); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /arch/arm/module.s: -------------------------------------------------------------------------------- 1 | .global _start 2 | 3 | .text 4 | .code 32 5 | _start: 6 | b . 7 | -------------------------------------------------------------------------------- /arch/x86/.gdbinit: -------------------------------------------------------------------------------- 1 | target remote localhost:1234 2 | symbol-file boot/kernel.elf 3 | 4 | set disassembly-flavor intel 5 | 6 | b debug 7 | c 8 | -------------------------------------------------------------------------------- /arch/x86/Makefile: -------------------------------------------------------------------------------- 1 | include ../../common/Makefile 2 | 3 | -include $(BDIR)/loader.d 4 | 5 | TARGET ?= i686-unknown-linux-gnu 6 | 7 | LDFLAGS ?= -melf_i386 --gc-sections 8 | LDFLAGS_EMBED ?= -melf_i386 9 | 10 | ASM ?= nasm 11 | ASMFLAGS ?= -g -f elf32 12 | 13 | QEMU ?= qemu-system-i386 14 | 15 | OBJS ?= $(BDIR)/loader.o $(BDIR)/main.o 16 | LINK ?= $(BDIR)/linker.ld $(OBJS) $(BDIR)/initram.elf.embed 17 | LIBS ?= 18 | 19 | SECTIONS ?= .text .data .rodata 20 | 21 | DEP_RM ?= arch/ 22 | DEP_KEEP ?= arch/i686\|arch/common 23 | 24 | 25 | .PHONY: all run debug 26 | 27 | all: $(BDIR)/floppy.img 28 | @wc -c $^ 29 | 30 | %.o: %.bc 31 | $(CC) $(CFLAGS) -c $^ -o $@ 32 | 33 | # initram 34 | $(BDIR)/%.o: %.asm 35 | $(ASM) $(ASMFLAGS) -MD $(BDIR)/$*.d -o $@ $< 36 | 37 | # Assemble loader 38 | %.o: %.asm 39 | $(ASM) $(ASMFLAGS) -MD $*.d -o $@ $< 40 | 41 | # kernel (object) 42 | $(BDIR)/kernel.elf: $(LINK) 43 | $(LD) $(LDFLAGS) -o $@ -T $^ "-(" $(LIBS) "-)" -Map=./$(BDIR)/linker.map 44 | 45 | # bootloader and kernel separately 46 | $(BDIR)/kernel.bin: $(BDIR)/kernel.elf 47 | $(OBJCOPY) -O binary $(addprefix -j ,$(SECTIONS)) $^ $@ 48 | 49 | $(BDIR)/boot.bin: $(BDIR)/kernel.elf 50 | $(OBJCOPY) -O binary -j .boot $^ $@ 51 | 52 | # join both 53 | $(BDIR)/floppy.img: $(BDIR)/boot.bin $(BDIR)/kernel.bin 54 | cat $^ > $@ 55 | 56 | # running 57 | run: all 58 | $(QEMU) -fda $(BDIR)/floppy.img 59 | 60 | debug: $(BDIR)/kernel.elf $(BDIR)/floppy.img 61 | ifeq ($(strip $(TMUX)),) 62 | tmux new-session -d -s rustboot 63 | tmux new-window -t rustboot:1 "$(QEMU) -fda $(BDIR)/floppy.img -m 32 -s -S" 64 | tmux new-window -t rustboot:2 "$(GDB)" 65 | tmux a -t rustboot 66 | tmux kill-session -t rustboot 67 | else 68 | tmux split-w "$(GDB); tmux kill-p" 69 | $(QEMU) -fda $(BDIR)/floppy.img -m 32 -s -S 70 | endif 71 | -------------------------------------------------------------------------------- /arch/x86/boot/.gitignore: -------------------------------------------------------------------------------- 1 | *.d 2 | linker.map 3 | 4 | lib*.rlib 5 | *.bc 6 | 7 | *.elf 8 | *.o 9 | *.o-* 10 | *.embed 11 | *.bin 12 | *.img 13 | -------------------------------------------------------------------------------- /arch/x86/boot/linker.ld: -------------------------------------------------------------------------------- 1 | OUTPUT_FORMAT(elf32-i386) 2 | ENTRY(start) 3 | 4 | MEMORY { 5 | boot : org = 0x7c00, l = 512 /* bootloader */ 6 | ram : org = 0x10000, l = 64K /* kernel */ 7 | } 8 | 9 | SECTIONS { 10 | .boot : { 11 | *(.boot) 12 | } >boot 13 | 14 | .text : { 15 | *(.text*) 16 | } >ram 17 | 18 | .data : { *(.data*) } >ram 19 | .rodata : { *(.rodata*) } >ram 20 | } 21 | -------------------------------------------------------------------------------- /arch/x86/boot/loader.asm: -------------------------------------------------------------------------------- 1 | global __morestack 2 | global abort 3 | global start 4 | 5 | extern main 6 | 7 | ; Assembly code in this file is used to set up the image in memory. 8 | ; The directive `use16` marks the beginning of 16-bit code[1]. Label `start` 9 | ; is defined to specify an entry point. 10 | ; 11 | ; [1]: http://www.nasm.us/doc/nasmdoc6.html#section-6.1.1 "6.1.1 USE16 & USE32: Aliases for BITS" 12 | ; [2]: http://en.wikipedia.org/wiki/INT_13H#INT_13h_AH.3D02h:_Read_Sectors_From_Drive "INT 13h AH=02h: Read Sectors From Drive" 13 | ; [3]: http://faydoc.tripod.com/cpu/cli.htm "CLI - Clear Interrupt Flag" 14 | ; [4]: http://en.wikipedia.org/wiki/Control_register#CR0 15 | ; [5]: http://www.c-jump.com/CIS77/ASM/Memory/M77_0290_segment_registers_protected.htm "Segment Registers in Protected Mode" 16 | ; [6]: http://stackoverflow.com/questions/9113310/segment-selector-in-ia-32 "Segment Selector in IA-32" 17 | 18 | section .boot 19 | use16 20 | 21 | ; entry point 22 | start: 23 | ; initialize segment registers 24 | xor ax, ax 25 | mov ds, ax 26 | mov es, ax 27 | 28 | ; BIOS interrupt 0x13 provides disk services. When given parameter ah=2, 29 | ; it reads sectors from drive[2]. 30 | ; Load Rust code into 0x10000...0x1ffff so we can jump to it later 31 | mov si, 2 ; starting with sector 67 32 | xor di, di ; and memory segment in di 33 | .loop: 34 | ; sector 67 + i*128 copied to 0x10000 + i*0x10000 35 | add di, 0x1000 ; di += 0x10000 >> 4 36 | mov es, di ; es = di (destination segment) 37 | mov ax, si ; ax = sector number 38 | mov bl, 18 39 | div bl ; ax /= 18 40 | xor bx, bx ; bx = 0 (destination = di * 16 + 0) 41 | mov dh, al 42 | mov ch, al 43 | shr ch, 1 ; ch = (si / 18) >> 1 ; cylinder & (0xff) 44 | and dh, 1 ; dh = (si / 18) & 1 ; head 45 | mov cl, ah ; cl = si % 18 ; sector | ((cylinder >> 2) & 0xc0) 46 | mov ax, 128|0x200 ; read 128 sectors (64 KiB) 47 | int 0x13 ; disk read [2] 48 | jc error 49 | add si, 128 50 | cmp di, 0x1000 ; while di != 0x3000 51 | jne .loop 52 | 53 | ; load protected mode GDT and a null IDT 54 | cli ; disable interrupts by clearing a flag [3] 55 | lgdt [gdtr] 56 | lidt [idtr] 57 | ; Register `cr0` controls the operation of the processor. General purpose 58 | ; register is used to modify its value since most instructions can't access 59 | ; control and segment registers. 60 | ; Set protected mode bit of cr0 [4] 61 | mov eax, cr0 62 | or eax, 1 63 | mov cr0, eax 64 | ; After protected mode is enabled, a far jump to 32-bit code is necessary 65 | ; to start executing 32-bit code and simultaneously load 32-bit **segment 66 | ; selector** to CS. 67 | ; far jump to load CS with 32-bit segment 1 (code) [5][6] 68 | jmp (1 << 3):protected_mode 69 | 70 | error: 71 | mov bx, ax 72 | mov si, .msg 73 | .loop: 74 | lodsb 75 | or al, al 76 | jz .done 77 | mov ah, 0x0e 78 | int 0x10 79 | jmp .loop 80 | .done: 81 | jmp $ 82 | .msg db "could not read disk", 0 83 | 84 | use32 85 | protected_mode: 86 | ; load all the other segments with 32-bit segment 2 (data) 87 | mov eax, 2 << 3 88 | mov ds, eax 89 | mov es, eax 90 | mov fs, eax 91 | mov gs, eax 92 | mov ss, eax 93 | ; set up aligned stack bottom 94 | mov esp, 0x7c00 95 | ; enable SSE instructions 96 | mov eax, cr4 97 | or eax, 512 98 | mov cr4, eax 99 | ; Temporarily store 0 as a stack upper limit. 100 | ; Rust would call morestack otherwise. 101 | ; Later, we should point gs to a small segment of local data. 102 | mov dword[gs:0x30], 0 103 | ; jump into Rust 104 | call main 105 | abort: 106 | __morestack: 107 | jmp $ 108 | 109 | gdtr: 110 | dw (gdt_end - gdt) + 1 ; size 111 | dd gdt ; offset 112 | 113 | idtr: ; null IDT register 114 | dw 0 115 | dd 0 116 | 117 | gdt: 118 | ; null entry 119 | dq 0 120 | ; code entry 121 | dw 0xffff ; limit 0:15 122 | dw 0x0000 ; base 0:15 123 | db 0x00 ; base 16:23 124 | db 0b10011010 ; access byte - code 125 | db 0x4f ; flags/(limit 16:19). flag is set to 32 bit protected mode 126 | db 0x00 ; base 24:31 127 | ; data entry 128 | dw 0xffff ; limit 0:15 129 | dw 0x0000 ; base 0:15 130 | db 0x00 ; base 16:23 131 | db 0b10010010 ; access byte - data 132 | db 0x4f ; flags/(limit 16:19). flag is set to 32 bit protected mode 133 | db 0x00 ; base 24:31 134 | gdt_end: 135 | 136 | ; half kilobyte sized sector ends with magic value 0x55 0xaa 137 | times 510-($-$$) db 0 ; fill unused space with zeros 138 | db 0x55 139 | db 0xaa 140 | -------------------------------------------------------------------------------- /arch/x86/cpu/exception.rs: -------------------------------------------------------------------------------- 1 | use core::mem::transmute; 2 | 3 | use core::fmt; 4 | 5 | use platform::io; 6 | use platform::cpu::mmu::Page; 7 | use cpu::Context; 8 | 9 | #[repr(u8)] 10 | pub enum Fault { 11 | DivideError = 0, 12 | NMI = 2, 13 | Breakpoint = 3, 14 | Overflow = 4, 15 | BoundExceeded = 5, 16 | InvalidOpcode = 6, 17 | NoMathCoprocessor = 7, 18 | DoubleFault = 8, 19 | CoprocessorSegmentOverun = 9, 20 | InvalidTss = 10, 21 | SegmentNotPresent = 11, 22 | StackSegmentFault = 12, 23 | GeneralProtection = 13, 24 | PageFault = 14, 25 | FloatingPointError = 16, 26 | AlignmentCheck = 17, 27 | MachineCheck = 18, 28 | SimdFpException = 19, 29 | } 30 | 31 | static Exceptions: &'static [&'static str] = &[ 32 | "Divide-by-zero Error", 33 | "Debug", 34 | "Non-maskable Interrupt", 35 | "Breakpoint", 36 | "Overflow", 37 | "Bound Range Exceeded", 38 | "Invalid Opcode", 39 | "Device Not Available", 40 | "Double Fault", 41 | "Coprocessor Segment Overrun", 42 | "Invalid TSS", 43 | "Segment Not Present", 44 | "Stack-Segment Fault", 45 | "General Protection Fault", 46 | "Page Fault", 47 | "Reserved", 48 | "x87 Floating-Point Exception", 49 | "Alignment Check", 50 | "Machine Check", 51 | "SIMD Floating-Point Exception", 52 | "Virtualization Exception", 53 | ]; 54 | 55 | // TODO respect destructors 56 | #[lang="begin_unwind"] 57 | unsafe extern "C" fn begin_unwind(fmt: &fmt::Arguments, file: &str, line: uint) -> ! { 58 | asm!("hlt"); 59 | loop { }; // for divergence check 60 | } 61 | 62 | #[lang = "panic_fmt"] 63 | pub extern fn rust_begin_unwind(msg: &fmt::Arguments, 64 | file: &'static str, line: uint) -> ! { 65 | unsafe { asm!("hlt"); } 66 | loop { }; // for divergence check 67 | } 68 | 69 | #[no_split_stack] 70 | #[inline(never)] 71 | unsafe fn blue_screen(stack: &Context) { 72 | io::puts("Exception "); 73 | io::puts(Exceptions[stack.int_no as uint]); 74 | asm!("hlt"); 75 | } 76 | 77 | #[no_split_stack] 78 | #[inline(never)] 79 | pub unsafe fn exception_handler() -> unsafe extern "C" fn() { 80 | asm!("jmp skip_exception_handler 81 | exception_handler_asm:" 82 | :::: "volatile", "intel"); 83 | 84 | // Points to the data on the stack 85 | let stack_ptr = Context::save(); 86 | 87 | if stack_ptr.int_no as u8 == Fault::PageFault as u8 { 88 | let cr2: uint; 89 | asm!("mov %cr2, %eax" : "={eax}"(cr2)); 90 | println!("Accessed {0:x} from {1:x}", cr2, stack_ptr.call_stack.eip); 91 | } 92 | 93 | if stack_ptr.int_no as u8 == Fault::Breakpoint as u8 { 94 | asm!("debug:" :::: "volatile") 95 | } 96 | else { 97 | blue_screen(stack_ptr); 98 | } 99 | 100 | Context::restore(); 101 | 102 | asm!("skip_exception_handler:" 103 | :::: "volatile", "intel"); 104 | 105 | extern { fn exception_handler_asm(); } 106 | exception_handler_asm 107 | } 108 | -------------------------------------------------------------------------------- /arch/x86/cpu/gdt.rs: -------------------------------------------------------------------------------- 1 | //! Global descriptor table 2 | 3 | use core::ptr::RawPtr; 4 | use core::mem::{size_of, transmute, uninitialized}; 5 | use core; 6 | 7 | use cpu::DtReg; 8 | use kernel::heap; 9 | 10 | bitflags!(flags GdtAccess: u8 { 11 | const ACCESSED = 1 << 0, 12 | const EXTEND = 1 << 1, 13 | const CONFORM = 1 << 2, 14 | const CODE = 1 << 3, 15 | const STORAGE = 1 << 4, // not TSS 16 | 17 | const DPL0 = 0 << 5, 18 | const DPL1 = 1 << 5, 19 | const DPL2 = 2 << 5, 20 | const DPL3 = 3 << 5, 21 | 22 | const PRESENT = 1 << 7, 23 | 24 | const DATA_WRITE = EXTEND.bits, 25 | const CODE_READ = CODE.bits 26 | | EXTEND.bits, 27 | const TSS = 0b1001 28 | }) 29 | 30 | bitflags!(flags GdtFlags: u8 { 31 | const SIZE_32 = 1 << 6, 32 | const PAGES = 1 << 7 33 | }) 34 | 35 | pub type GdtReg = DtReg; 36 | 37 | #[repr(packed)] 38 | pub struct GdtEntry { 39 | limit_lo: u16, 40 | base_lo: u16, 41 | base_hl: u8, 42 | access: GdtAccess, 43 | limit_hi_flags: u8, 44 | base_hh: u8 45 | } 46 | 47 | impl GdtEntry { 48 | pub fn new(base: u32, limit: u32, access: GdtAccess, flags: GdtFlags) -> GdtEntry { 49 | let (base_hh, base_hl, base_lo) = ( 50 | (base & 0xFF000000) >> 24, 51 | (base & 0x__FF0000) >> 16, 52 | (base & 0x____FFFF) 53 | ); 54 | let (limit_hi, limit_lo) = ( 55 | (limit & 0x___F0000) >> 16, 56 | (limit & 0x____FFFF) 57 | ); 58 | GdtEntry { 59 | limit_lo: limit_lo as u16, 60 | base_lo: base_lo as u16, 61 | base_hl: base_hl as u8, 62 | base_hh: base_hh as u8, 63 | access: access, 64 | limit_hi_flags: flags.bits() | limit_hi as u8 65 | } 66 | } 67 | 68 | pub fn seg(data: *mut T, access: GdtAccess, flags: GdtFlags) -> GdtEntry { 69 | assert!(size_of::() < (1u << 20)); 70 | GdtEntry::new(data as u32, size_of::() as u32, access, flags) 71 | } 72 | 73 | pub fn flat(access: GdtAccess, flags: GdtFlags) -> GdtEntry { 74 | GdtEntry::new(0, 0xFFFFF, access, flags | PAGES) 75 | } 76 | } 77 | 78 | pub struct Gdt { 79 | reg: *mut GdtReg, // WARNING verify should be mutable. 80 | table: *mut GdtEntry 81 | } 82 | 83 | impl Gdt { 84 | pub fn new() -> Gdt { 85 | unsafe { 86 | let table_ptr = heap::zero_alloc::(256); 87 | let reg_ptr: *mut GdtReg = heap::alloc(1); 88 | 89 | let reg: &mut GdtReg = transmute(reg_ptr); 90 | *reg = DtReg::new(table_ptr, 256); 91 | 92 | Gdt { reg: transmute(reg_ptr), table: table_ptr } 93 | } 94 | } 95 | 96 | pub fn enable(&self, n: uint, mut entry: GdtEntry) { 97 | unsafe { 98 | entry.access = entry.access | PRESENT; 99 | *self.table.offset(n as int) = entry; 100 | } 101 | } 102 | 103 | pub unsafe fn disable(&self, n: uint) { 104 | let entry = self.table.offset(n as int); 105 | (*entry).access = (*entry).access & !PRESENT; 106 | } 107 | 108 | pub fn load(&self, code: u16, data: u16, local: u16) { 109 | unsafe { 110 | (*self.reg).load(); 111 | asm!("mov ds, $0 112 | mov ss, $0 113 | mov fs, $1 114 | mov gs, $1" 115 | :: "r"(data), "r"(local) 116 | :: "volatile", "intel"); 117 | 118 | // A far jump updates the code segment. 119 | // Put the full address on the stack to `jmp far m16:32`. 120 | let address48: (u32, u16) = (uninitialized(), code); 121 | asm!("movl $$.flush, ($0) 122 | ljmp *($0) 123 | .flush:" 124 | :: "r"(&address48) 125 | :: "volatile"); 126 | } 127 | } 128 | } 129 | 130 | impl super::Load for GdtEntry { 131 | #[inline] 132 | unsafe fn load(reg: &super::DtReg) { 133 | asm!("lgdt [$0]" :: "r"(reg) :: "intel"); 134 | } 135 | } 136 | -------------------------------------------------------------------------------- /arch/x86/cpu/idt.rs: -------------------------------------------------------------------------------- 1 | //! Interrupt descriptor table 2 | 3 | use core; 4 | 5 | use super::DtReg; 6 | 7 | bitflags!(flags IdtFlags: u8 { 8 | const INTR_GATE = 0b1110, 9 | const TRAP_GATE = 0b1111, 10 | const PRESENT = 1 << 7 11 | }) 12 | 13 | pub type IdtReg = DtReg; 14 | 15 | #[repr(packed)] 16 | pub struct IdtEntry { 17 | addr_lo: u16, 18 | sel: u16, 19 | zero: u8, 20 | flags: IdtFlags, 21 | addr_hi: u16 22 | } 23 | 24 | impl IdtEntry { 25 | pub fn new(func: unsafe extern "C" fn(), sel: u16, flags: IdtFlags) -> IdtEntry { 26 | let addr = func as uint; 27 | let (addr_hi, addr_lo) = ( 28 | (addr & 0xFFFF0000) >> 16, 29 | (addr & 0x____FFFF) 30 | ); 31 | IdtEntry { 32 | addr_lo: addr_lo as u16, 33 | addr_hi: addr_hi as u16, 34 | sel: sel, 35 | zero: 0, 36 | flags: flags 37 | } 38 | } 39 | } 40 | 41 | impl super::Load for IdtEntry { 42 | #[inline] 43 | unsafe fn load(reg: &super::DtReg) { 44 | asm!("lidt [$0]" :: "A"(reg as *const super::DtReg) :: "intel"); 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /arch/x86/cpu/interrupt.rs: -------------------------------------------------------------------------------- 1 | //! The Interrupt Table and Isr (Interrupt Service Routine) classes. 2 | 3 | use core::mem::transmute; 4 | use core::ptr::RawPtr; 5 | 6 | use cpu::DtReg; 7 | use cpu::exception::Fault; 8 | use cpu::idt::{IdtEntry, IdtReg, INTR_GATE, PRESENT}; 9 | use platform::drivers::pic; 10 | use kernel::heap; 11 | 12 | // TODO for Rust: nested C-like enums 13 | // #[repr(u8)] 14 | pub enum Int { 15 | FaultInt(Fault) 16 | } 17 | 18 | pub struct Table { 19 | reg: &'static IdtReg, 20 | table: *mut IdtEntry, 21 | mask: u16, 22 | } 23 | 24 | impl Table { 25 | pub fn new() -> Table { 26 | unsafe { 27 | let table = heap::zero_alloc::(256); 28 | let reg = heap::alloc::(1); 29 | *(reg as *mut IdtReg) = DtReg::new(table, 256); 30 | Table { 31 | reg: transmute(reg), 32 | table: table, 33 | mask: 0xffff 34 | } 35 | } 36 | } 37 | 38 | pub unsafe fn enable_maskable(&mut self, irq: uint, isr: unsafe extern "C" fn()) { 39 | *self.table.offset(irq as int) = IdtEntry::new( 40 | isr, // interrupt service routine 41 | 1 << 3, // segment selector 42 | INTR_GATE | PRESENT // flags 43 | ); 44 | 45 | self.mask &= !(1u16 << (irq & 0b1111)); 46 | pic::mask(self.mask); 47 | } 48 | 49 | #[allow(visible_private_types)] 50 | pub unsafe fn set_isr(&mut self, val: Fault, code: bool, handler: unsafe extern "C" fn()) { 51 | *self.table.offset(val as int) = Isr::new(Int::FaultInt(val), code).idt_entry(handler); 52 | } 53 | 54 | pub unsafe fn load(&self) { 55 | self.reg.load(); 56 | pic::remap(); 57 | pic::mask(self.mask); 58 | enable(); 59 | // loop {} // faults here? 60 | } 61 | } 62 | 63 | fn enable() { 64 | unsafe { 65 | asm!("sti" :::: "volatile", "intel"); 66 | } 67 | } 68 | 69 | /// An exception is generated by the CPU to indicate incorrect code behavior[[1]]. 70 | /// To distinguish exceptions, every exception needs a different entry point[[2]]. 71 | /// For example: 72 | /// ```asm 73 | /// isr8_double_fault: 74 | /// push eax ; (smaller than push 0) or replaced by nop 75 | /// push byte 8 76 | /// jmp isr_common 77 | /// ``` 78 | /// Since inline assembly has limitations, we build these entries dynamically. 79 | /// The CPU doesn't push error code on the stack when calling some exceptions. 80 | /// In these cases, we push a dummy value to align the stack[[3]]. 81 | /// 82 | /// 1. [Exceptions - OSDev Wiki][[1]] 83 | /// 2. [piipkernel][[2]] 84 | /// 3. Dru Nelson. [Single Byte or Small x86 Opcodes][[3]] 85 | /// [1]: http://wiki.osdev.org/Exceptions "Exceptions - OSDev Wiki" 86 | /// [2]: http://www.srcf.ucam.org/piipkernel/git_repository/kernel/src/isr.asm 87 | /// [3]: http://www.xxeo.com/single-byte-or-small-x86-opcodes 88 | #[repr(packed)] 89 | pub struct Isr { 90 | push_dummy: u8, // push eax // (only for exceptions without error codes) 91 | push: u8, // push byte // save int. number 92 | value: Int, 93 | jmp: u8, // jmp rel // jump to the common handler 94 | rel: i32 95 | } 96 | 97 | impl Isr { 98 | // TODO: drop for Isr 99 | pub fn new<'a>(val: Int, code: bool) -> &'a mut Isr { 100 | let this: &mut Isr = unsafe { transmute(heap::alloc::(1)) }; 101 | *this = Isr { 102 | push_dummy: if code { 0x90 } else { 0x50 }, // [3] 103 | push: 0x6a, value: val, 104 | jmp: 0xe9, rel: -5 105 | }; 106 | this 107 | } 108 | 109 | pub unsafe fn idt_entry(&mut self, handler: unsafe extern "C" fn()) -> IdtEntry { 110 | self.rel = handler as i32 - (self as *mut Isr).offset(1) as i32; 111 | IdtEntry::new(transmute(self), 1 << 3, INTR_GATE | PRESENT) 112 | } 113 | } 114 | -------------------------------------------------------------------------------- /arch/x86/cpu/io.rs: -------------------------------------------------------------------------------- 1 | //! Low-level CPU IO: inb, outb instructions. 2 | 3 | #[inline(always)] 4 | pub fn out(port: u16, val: T) { 5 | unsafe { 6 | asm!("out $1, $0" :: "{al}"(val), "{dx}"(port) :: "intel"); 7 | } 8 | } 9 | 10 | #[inline(always)] 11 | pub fn inb(port: u16) -> u8 { 12 | let mut val: u8; 13 | unsafe { 14 | asm!("in $0, $1" : "={al}"(val) : "{dx}"(port) :: "intel"); 15 | } 16 | val 17 | } 18 | 19 | pub fn wait(port: u16, mask: u8) { 20 | while inb(port) & mask != 0 {} 21 | } 22 | -------------------------------------------------------------------------------- /arch/x86/cpu/mmu.rs: -------------------------------------------------------------------------------- 1 | //! Memory Management Unit - Translates virtual memory addresses to 2 | //! physical addresses. Memory is grouped into tabulated Pages. This module 3 | //! defines the Page(uint) and Table implementations. 4 | 5 | use core::mem::size_of; 6 | use core::ptr::copy_nonoverlapping_memory; 7 | use core::fmt; 8 | use core::prelude::*; 9 | use core; 10 | 11 | use kernel::mm::physical; 12 | use kernel::mm::physical::Phys; 13 | use util::rt; 14 | use kernel; 15 | 16 | pub type Frame = [u8, ..PAGE_SIZE]; 17 | 18 | bitflags!(flags Flags: uint { 19 | const PRESENT = 1 << 0, 20 | const RW = 1 << 1, 21 | const USER = 1 << 2, 22 | const ACCESSED = 1 << 5, 23 | const HUGE = 1 << 7 24 | }) 25 | 26 | #[repr(packed)] 27 | pub struct Page(uint); 28 | 29 | const PAGE_SIZE: uint = 0x1000; 30 | const PAGE_SIZE_LOG2: uint = 12; 31 | const ENTRIES: uint = 1024; 32 | 33 | const DIR_VADDR: uint = 0xFFFFF000; 34 | 35 | struct VMemLayout { 36 | temp1: PageDirectory, // @ 0xFF7FF000 37 | temp_tables: [PageTable, ..ENTRIES - 1], // @ 0xFF800000 38 | temp: PageDirectory, // @ 0xFFBFF000 39 | tables: [PageTable, ..ENTRIES - 1], // @ 0xFFC00000 40 | dir: PageDirectory // @ 0xFFFFF000 41 | } 42 | 43 | static VMEM: *mut VMemLayout = 0xFF7FF000u as *mut VMemLayout; 44 | 45 | // U: underlying element type 46 | #[repr(packed)] 47 | struct Table { 48 | entries: [Page, ..ENTRIES] 49 | } 50 | 51 | #[repr(packed)] 52 | struct Directory { 53 | entries: [U, ..ENTRIES] 54 | } 55 | 56 | pub type PageTable = Table; 57 | pub type PageDirectory = Table>; 58 | 59 | pub unsafe fn init() { 60 | let dir: Phys = physical::zero_alloc_frames(1); 61 | let table: Phys = physical::alloc_frames(1); 62 | 63 | (*table.as_ptr()).identity_map(0, PRESENT | RW); 64 | (*dir.as_ptr()).set_addr(0 as *mut u8, table, PRESENT | RW); 65 | 66 | // Map the directory as its own last table. 67 | // When accessing its virtual address(...) 68 | (*dir.as_ptr()).map_self(dir); 69 | 70 | kernel::int_table.map(|mut t| { 71 | use super::exception::{Fault, exception_handler}; 72 | t.set_isr(Fault::PageFault, true, exception_handler()); 73 | }); 74 | 75 | switch_directory(dir); 76 | enable_paging(); 77 | } 78 | 79 | pub fn switch_directory(dir: Phys) { 80 | use super::CR3; 81 | CR3::write(dir.as_ptr()); 82 | } 83 | 84 | fn enable_paging() { 85 | use super::{CR0, CR0_PG}; 86 | CR0::write(CR0 | CR0_PG); 87 | } 88 | 89 | pub unsafe fn map(page_ptr: *mut u8, len: uint, flags: Flags) { 90 | (*VMEM).dir.map(page_ptr, len, flags); 91 | } 92 | 93 | #[inline] 94 | fn flush_tlb(addr: T) { 95 | unsafe { 96 | asm!("invlpg [$0]" :: "r"(addr) : "memory" : "volatile", "intel") 97 | } 98 | } 99 | 100 | impl Page { 101 | fn new(addr: Phys, flags: Flags) -> Page { 102 | Page(addr.to_uint()) | flags 103 | } 104 | 105 | fn at_frame(i: uint, flags: Flags) -> Page { 106 | Page(i * PAGE_SIZE) | flags 107 | } 108 | 109 | fn physical

(&self) -> Phys

{ 110 | let &Page(p) = self; 111 | Phys::at(p & 0xFFFFF000) 112 | } 113 | 114 | fn is_present(self) -> bool { 115 | self.contains(PRESENT) 116 | } 117 | 118 | fn contains(&self, flags: Flags) -> bool { 119 | let &Page(bits) = self; 120 | (bits & flags.bits) == flags.bits 121 | } 122 | } 123 | 124 | impl core::ops::BitOr for Page { 125 | #[inline(always)] 126 | fn bitor(&self, other: &Flags) -> Page { 127 | let &Page(bits) = self; 128 | Page(bits | other.bits) 129 | } 130 | } 131 | 132 | impl fmt::Show for Page { 133 | fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { 134 | let &Page(p) = self; 135 | let page = p & 0xFFFFF000; 136 | let (p, r, u, a) = ( 137 | if self.contains(PRESENT) { 'P' } else { ' ' }, 138 | if self.contains(RW) { 'R' } else { ' ' }, 139 | if self.contains(USER) { 'U' } else { ' ' }, 140 | if self.contains(ACCESSED) { 'A' } else { ' ' } 141 | ); 142 | write!(fmt, "0x{:x}({}{}{}{})", page, p, r, u, a) 143 | } 144 | } 145 | 146 | impl Table { 147 | fn set_addr(&mut self, vaddr: *mut S, phys: Phys, flags: Flags) { 148 | // FIXME error: internal compiler error: missing default for a not explicitely provided type param 149 | self.set(vaddr as uint, Page::new(phys, flags)); 150 | flush_tlb(vaddr); 151 | } 152 | 153 | fn set(&mut self, addr: uint, page: Page) { // TODO addr: Phys 154 | // update entry, based on the underlying type (page, table) 155 | let size = size_of::() / size_of::() * PAGE_SIZE; 156 | let index = (addr / size) % ENTRIES; 157 | self.entries[index] = page; 158 | } 159 | 160 | fn get(&self, addr: uint) -> Page { 161 | let size = size_of::() / size_of::() * PAGE_SIZE; 162 | let index = (addr / size) % ENTRIES; 163 | self.entries[index] 164 | } 165 | } 166 | 167 | impl Table { 168 | fn identity_map(&mut self, start: uint, flags: Flags) { 169 | for i in range(0, ENTRIES) { 170 | self.entries[i] = Page::at_frame(start + i, flags); 171 | } 172 | } 173 | } 174 | 175 | // Can't impl on typedefs. Rust #9767 176 | impl Table> { 177 | fn fetch_table(&mut self, vptr: *mut T, flags: Flags) -> *mut PageTable { 178 | match self.get(vptr as uint) { 179 | table @ Page(_) if table.is_present() => { 180 | table.physical().as_ptr() 181 | } 182 | _ => unsafe { // allocate table 183 | let table: Phys = physical::zero_alloc_frames(1); 184 | self.set_addr(vptr, table, flags); // page fault 185 | // flush_tlb(table); 186 | table.as_ptr() 187 | } 188 | } 189 | } 190 | 191 | pub unsafe fn set_page(&mut self, vptr: *mut T, phys: Phys, flags: Flags) -> *mut T { 192 | let table = self.fetch_table(vptr, flags); 193 | (*table).set_addr(vptr, phys, flags); 194 | vptr 195 | } 196 | 197 | pub unsafe fn map_frame(&mut self, vptr: *mut u8, flags: Flags) { 198 | self.set_page(vptr, physical::alloc_frames(1), flags | PRESENT); 199 | } 200 | 201 | pub fn map(&mut self, mut page_ptr: *mut u8, len: uint, flags: Flags) { 202 | // TODO: optimize with uints? 203 | unsafe { 204 | let end = page_ptr.offset(len as int); 205 | while page_ptr < end { 206 | let frame = physical::alloc_frames(1); 207 | self.set_page(page_ptr, frame, flags | PRESENT); 208 | (*VMEM).dir.set_page(page_ptr, frame, flags | PRESENT); 209 | page_ptr = page_ptr.offset(PAGE_SIZE as int); 210 | } 211 | } 212 | } 213 | 214 | fn map_self(&mut self, this: Phys) { 215 | self.set(DIR_VADDR as uint, Page::new(this, PRESENT | RW)); 216 | } 217 | 218 | pub fn clone(&self) -> Phys { 219 | unsafe { 220 | // new directory 221 | let dir_phys: Phys = physical::zero_alloc_frames(1); 222 | 223 | let &VMemLayout { ref mut temp1, ref mut dir, .. } = &mut *VMEM; 224 | dir.set_page(temp1, dir_phys, PRESENT | RW); 225 | temp1.map_self(dir_phys); 226 | 227 | let cnt = 0xC0000000 / (ENTRIES * PAGE_SIZE); 228 | copy_nonoverlapping_memory(&mut temp1.entries[0] as *mut Page, &self.entries as *const Page, cnt); 229 | 230 | dir_phys 231 | } 232 | } 233 | } 234 | 235 | pub fn clone_directory() -> Phys { 236 | unsafe { 237 | (*VMEM).dir.clone() 238 | } 239 | } 240 | -------------------------------------------------------------------------------- /arch/x86/cpu/mod.rs: -------------------------------------------------------------------------------- 1 | use core::mem::size_of; 2 | use core::option::{Option, None, Some}; 3 | use core; 4 | 5 | use kernel::heap; 6 | use kernel; 7 | 8 | mod gdt; 9 | mod idt; 10 | mod tss; 11 | pub mod interrupt; 12 | pub mod io; 13 | mod exception; 14 | pub mod mmu; 15 | 16 | macro_rules! cpuid( 17 | ($n:expr, $s1:expr, $s2:expr, $s3:expr, $s4:expr) => ( 18 | asm!("cpuid" 19 | : "=A"($s1), 20 | "={ebx}"($s2), 21 | "={edx}"($s3), 22 | "={ecx}"($s4) 23 | : "A"($n) :: "intel"); 24 | ); 25 | ($n:expr, *$s1:expr) => ( 26 | cpuid!($n, (*$s1)[0], (*$s1)[1], (*$s1)[2], (*$s1)[3]); 27 | ); 28 | ($n:expr, $s1:expr) => ( 29 | asm!("cpuid" 30 | : "=A"($s1) 31 | : "A"($n) : "ebx", "edx", "ecx" : "intel"); 32 | ); 33 | ) 34 | 35 | bitflags!(flags Eflags: u32 { 36 | const CF = 1 << 0, 37 | const IF = 1 << 9 38 | }) 39 | 40 | impl Eflags { 41 | fn read() -> Eflags { 42 | unsafe { 43 | let mut flags: u32; 44 | asm!("pushf; pop $0;" : "=r"(flags) ::: "volatile") 45 | Eflags::from_bits_truncate(flags) 46 | } 47 | } 48 | } 49 | 50 | bitflags!(flags CR0Flags: u32 { 51 | // TODO: all flags 52 | const CR0_PG = 1 << 31 53 | }) 54 | 55 | struct CR0; 56 | 57 | // http://www.jaist.ac.jp/iscenter-new/mpc/altix/altixdata/opt/intel/vtune/doc/users_guide/mergedProjects/analyzer_ec/mergedProjects/reference_olh/mergedProjects/instructions/instruct32_hh/vc178.htm 58 | impl CR0 { 59 | #[inline] 60 | fn read() -> CR0Flags { 61 | unsafe { 62 | let flags; 63 | asm!("mov $0, cr0" : "=r"(flags) ::: "intel"); 64 | CR0Flags { bits: flags } 65 | } 66 | } 67 | 68 | #[inline] 69 | fn write(f: CR0Flags) { 70 | unsafe { 71 | asm!("mov cr0, $0" :: "r"(f.bits) :: "volatile", "intel"); 72 | } 73 | } 74 | } 75 | 76 | impl core::ops::BitOr for CR0 { 77 | #[inline(always)] 78 | fn bitor(&self, other: &CR0Flags) -> CR0Flags { 79 | CR0Flags { bits: CR0::read().bits | other.bits } 80 | } 81 | } 82 | 83 | struct CR3; 84 | 85 | // http://www.jaist.ac.jp/iscenter-new/mpc/altix/altixdata/opt/intel/vtune/doc/users_guide/mergedProjects/analyzer_ec/mergedProjects/reference_olh/mergedProjects/instructions/instruct32_hh/vc178.htm 86 | impl CR3 { 87 | #[inline] 88 | fn read() -> *mut mmu::PageDirectory { 89 | unsafe { 90 | let ptr; 91 | asm!("mov $0, cr3" : "=r"(ptr) ::: "intel"); 92 | ptr 93 | } 94 | } 95 | 96 | #[inline] 97 | fn write(ptr: *mut mmu::PageDirectory) { 98 | unsafe { 99 | asm!("mov cr3, $0" :: "r"(ptr) :: "volatile", "intel"); 100 | } 101 | } 102 | } 103 | 104 | pub trait Load { 105 | unsafe fn load(reg: &DtReg); 106 | } 107 | 108 | #[repr(packed)] 109 | struct DtReg { 110 | size: u16, 111 | addr: *mut T, 112 | } 113 | 114 | impl DtReg { 115 | pub fn new(descriptor_table: *mut T, capacity: uint) -> DtReg { 116 | DtReg { 117 | size: (capacity * size_of::()) as u16, 118 | addr: descriptor_table, 119 | } 120 | } 121 | } 122 | 123 | impl DtReg { 124 | #[inline] 125 | pub unsafe fn load(&self) { 126 | Load::load(self) 127 | } 128 | } 129 | 130 | // TODO: make push_dummy push ds? 131 | // exception info and processor state saved on stack 132 | struct Context { 133 | // Registers saved by the ISR (in reverse order) 134 | edi: u32, esi: u32, ebp: u32, esp: u32, ebx: u32, edx: u32, ecx: u32, eax: u32, 135 | ds: u32, es: u32, fs: u32, gs: u32, 136 | int_no: u32, // added by ISRs 137 | err_code: u32, // added by some exceptions 138 | call_stack: IsrCallStack 139 | } 140 | 141 | // the cpu adds these when calling the ISR 142 | struct IsrCallStack { 143 | eip: u32, cs: u32, eflags: u32, esp: u32, ss: u32 144 | } 145 | 146 | impl Context { 147 | unsafe fn save<'a>() -> &'a mut Context { 148 | let this: &mut Context; 149 | asm!("push gs 150 | push fs 151 | .byte 0x06 // push es 152 | .byte 0x1e // push ds 153 | pusha" 154 | : "={esp}"(this) ::: "volatile", "intel"); 155 | this 156 | } 157 | 158 | unsafe fn restore() { 159 | asm!("popa 160 | .byte 0x1f // pop ds 161 | .byte 0x07 // pop es 162 | pop fs 163 | pop gs 164 | add esp, 8 165 | iretd" 166 | :::: "volatile", "intel"); 167 | } 168 | } 169 | 170 | struct LocalSegment { 171 | ts: tss::TssEntry, 172 | } 173 | 174 | impl LocalSegment { 175 | // FIXME: Rust needs address spaces 176 | fn get<'a>() -> &'a mut LocalSegment { 177 | unsafe { 178 | let this: &mut LocalSegment; 179 | asm!("mov $0, dword[gs:0]" : "=r"(this) ::: "volatile", "intel") 180 | this 181 | } 182 | } 183 | } 184 | 185 | pub static mut desc_table: Option = None; 186 | 187 | pub fn init() { 188 | use cpu::gdt::{Gdt, GdtEntry, SIZE_32, STORAGE, CODE_READ, DATA_WRITE, DPL3}; 189 | 190 | let local_data = unsafe { 191 | heap::zero_alloc::(1) 192 | }; 193 | let tls = unsafe { 194 | let seg = heap::zero_alloc::(32); 195 | *seg = local_data as u32; 196 | // *(mut_offset(seg, 12)) = 0; // TODO: record stack bottom later 197 | seg 198 | }; 199 | 200 | let t = Gdt::new(); 201 | t.enable(1, GdtEntry::flat(STORAGE | CODE_READ, SIZE_32)); 202 | t.enable(2, GdtEntry::flat(STORAGE | DATA_WRITE, SIZE_32)); 203 | t.enable(3, GdtEntry::flat(STORAGE | CODE_READ | DPL3, SIZE_32)); 204 | t.enable(4, GdtEntry::flat(STORAGE | DATA_WRITE | DPL3, SIZE_32)); 205 | t.enable(5, GdtEntry::new(tls as u32, 32 * 4, STORAGE | DPL3, SIZE_32)); 206 | unsafe { 207 | t.enable(6, (*local_data).ts.gdt_entry()); 208 | } 209 | t.load(1 << 3, 2 << 3, 5 << 3); 210 | 211 | unsafe { 212 | desc_table = Some(t); 213 | 214 | kernel::int_table.map(|mut t| { 215 | use cpu::exception::{Fault, exception_handler}; 216 | t.set_isr(Fault::Breakpoint, false, exception_handler()); 217 | }); 218 | 219 | mmu::init(); 220 | } 221 | } 222 | 223 | pub fn info() { 224 | } 225 | -------------------------------------------------------------------------------- /arch/x86/cpu/tss.rs: -------------------------------------------------------------------------------- 1 | use super::gdt::{GdtEntry, GdtFlags, ACCESSED, CODE}; 2 | 3 | #[packed] 4 | pub struct TssEntry { 5 | prev_tss: u32, 6 | esp0: u32, 7 | ss0: u32, 8 | esp1: u32, 9 | ss1: u32, 10 | esp2: u32, 11 | ss2: u32, 12 | cr3: u32, 13 | eip: u32, 14 | eflags: u32, 15 | eax: u32, 16 | ecx: u32, 17 | edx: u32, 18 | ebx: u32, 19 | esp: u32, 20 | ebp: u32, 21 | esi: u32, 22 | edi: u32, 23 | es: u32, 24 | cs: u32, 25 | ss: u32, 26 | ds: u32, 27 | fs: u32, 28 | gs: u32, 29 | ldt: u32, 30 | trap: u16, 31 | iomap_base: u16 32 | } 33 | 34 | impl TssEntry { 35 | pub fn gdt_entry(&mut self) -> GdtEntry { 36 | GdtEntry::seg(self as *mut TssEntry, CODE | ACCESSED, GdtFlags::empty()) 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /arch/x86/drivers/keyboard.rs: -------------------------------------------------------------------------------- 1 | use cpu::io; 2 | use super::keydown; 3 | 4 | pub static IRQ: uint = 0x20 + 1; 5 | 6 | pub static Layout: &'static [u8] = b"\ 7 | \x00\x1B1234567890-=\x08\ 8 | \tqwertyuiop[]\n\ 9 | \x00asdfghjkl;'`\ 10 | \x00\\zxcvbnm,./\x00\ 11 | *\x00 "; 12 | 13 | static LayoutShift: &'static [u8] = b"\ 14 | \x00\x1B!@#$%^&*()_+\x08\ 15 | \tQWERTYUIOP{}\n\ 16 | \x00ASDFGHJKL:\"~\ 17 | \x00|ZXCVBNM<>?\x00\ 18 | *\x00 "; 19 | 20 | static mut shift: bool = false; 21 | static mut caps_lock: bool = false; 22 | static mut led_state: u8 = 0; 23 | 24 | fn led(state: u8) { 25 | io::wait(0x64, 2); 26 | io::out(0x60, 0xEDu8); 27 | io::wait(0x64, 2); 28 | unsafe { 29 | led_state ^= state; 30 | io::out(0x60, led_state); 31 | } 32 | } 33 | 34 | fn isalpha(c: u8) -> bool { 35 | ((c | 0x20) - 'a' as u8) < 26 36 | } 37 | 38 | #[no_split_stack] 39 | fn keypress(code: u8) { 40 | match (code & 0x7f, code & 0x80 == 0) { 41 | (0x2A, down) | (0x36, down) => unsafe { shift = down }, 42 | (0x3A, true) => unsafe { // Caps lock 43 | caps_lock = !caps_lock; 44 | led(0b100) 45 | }, 46 | (0x45, true) => led(0b010), // Number lock 47 | (0x46, true) => led(0b001), // Scroll lock 48 | (c, true) if c < 0x3A => unsafe { 49 | // handle character 50 | let mut ch = if shift { LayoutShift[c as uint] } else { Layout[c as uint] }; 51 | if ch != 0 { 52 | if caps_lock && isalpha(ch) { 53 | ch ^= 1 << 5; 54 | } 55 | keydown.map(|f| f(ch) ); 56 | } 57 | }, 58 | _ => {} 59 | } 60 | } 61 | 62 | #[no_split_stack] 63 | #[inline(never)] 64 | pub unsafe fn isr_addr() -> unsafe extern "C" fn() { 65 | asm!("jmp skip_isr_addr 66 | isr_addr_asm: 67 | push gs 68 | push fs 69 | .byte 0x06 70 | .byte 0x1e 71 | pusha" 72 | :::: "intel"); 73 | 74 | keypress(io::inb(0x60)); 75 | io::out(0x20, 0x20u8); 76 | 77 | asm!("popa 78 | .byte 0x1f // pop ds 79 | .byte 0x07 // pop es 80 | pop fs 81 | pop gs 82 | iretd 83 | skip_isr_addr:" 84 | :::: "intel"); 85 | 86 | // it must be referenced in code 87 | isr_addr_asm 88 | } 89 | 90 | extern "C" { fn isr_addr_asm(); } 91 | -------------------------------------------------------------------------------- /arch/x86/drivers/mod.rs: -------------------------------------------------------------------------------- 1 | use core::option::{Option, None}; 2 | 3 | use kernel; 4 | 5 | pub mod pic; 6 | pub mod vga; 7 | pub mod keyboard; 8 | 9 | pub static mut keydown: Option = None; 10 | 11 | pub fn init() { 12 | vga::clear_screen(vga::Color::LightRed); 13 | vga::cursor_at(0); 14 | 15 | unsafe { 16 | kernel::int_table.map(|mut t| { 17 | t.enable_maskable(keyboard::IRQ, keyboard::isr_addr()); 18 | }); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /arch/x86/drivers/pic.rs: -------------------------------------------------------------------------------- 1 | //! Programmable interrupt controller 2 | 3 | use cpu::io; 4 | 5 | pub fn remap() { 6 | io::out(0x20, 0x11u16); // WARNING verify should be u16 7 | io::out(0xA0, 0x11u16); 8 | 9 | io::out(0x21, 0x20u16); 10 | io::out(0xA1, 0x28u16); 11 | 12 | io::out(0x21, 4u16); 13 | io::out(0xA1, 2u16); 14 | 15 | io::out(0x21, 1u16); 16 | io::out(0xA1, 1u16); 17 | } 18 | 19 | pub fn enable(irq: u8) { 20 | let port: u16 = if (irq & 0b1000) == 0 { 0x21 } else { 0xa1 }; 21 | let mask: u8 = !(1u8 << (irq & 0b111) as uint); 22 | 23 | io::out(port, io::inb(port) & mask); 24 | } 25 | 26 | pub fn mask(mask: u16) { 27 | io::out(0x21, (mask & 0xFF) as u8); 28 | io::out(0xA1, ((mask >> 8) & 0xFF) as u8); 29 | } 30 | -------------------------------------------------------------------------------- /arch/x86/drivers/vga.rs: -------------------------------------------------------------------------------- 1 | use core::mem::transmute; 2 | 3 | use cpu::io; 4 | use platform::runtime::wmemset; 5 | 6 | #[repr(u8)] 7 | pub enum Color { 8 | Black = 0, 9 | Blue = 1, 10 | Green = 2, 11 | Cyan = 3, 12 | Red = 4, 13 | Pink = 5, 14 | Brown = 6, 15 | LightGray = 7, 16 | DarkGray = 8, 17 | LightBlue = 9, 18 | LightGreen = 10, 19 | LightCyan = 11, 20 | LightRed = 12, 21 | LightPink = 13, 22 | Yellow = 14, 23 | White = 15, 24 | } 25 | 26 | #[repr(packed)] 27 | struct Char { 28 | pub char: u8, 29 | attr: u8, 30 | } 31 | 32 | impl Char { 33 | #[inline] 34 | pub fn new(c: char, fg: Color, bg: Color) -> Char { 35 | Char { char: c as u8, attr: fg as u8 | (bg as u8 << 4) } 36 | } 37 | } 38 | 39 | pub const SCREEN_SIZE: uint = 80*25; 40 | type Screen = [Char, ..SCREEN_SIZE]; 41 | pub static SCREEN: *mut Screen = 0xb8000 as *mut Screen; 42 | 43 | pub fn clear_screen(bg: Color) { 44 | unsafe { 45 | wmemset(SCREEN as *mut u8, transmute(Char::new(' ', Color::Black, bg)), SCREEN_SIZE); 46 | } 47 | } 48 | 49 | pub fn cursor_at(pos: uint) { 50 | io::out(0x3D4, 15u16); // WARNING verify should be u16 51 | io::out(0x3D5, pos as u8); 52 | io::out(0x3D4, 14u16); 53 | io::out(0x3D5, (pos >> 8) as u8); 54 | } 55 | -------------------------------------------------------------------------------- /arch/x86/io/mod.rs: -------------------------------------------------------------------------------- 1 | //! Higher-level input/output interface. 2 | 3 | use core::fmt; 4 | use core::prelude::*; 5 | 6 | use super::drivers::vga; 7 | 8 | /// A format writer that writes out to the VGA screen. 9 | struct Stdout; 10 | 11 | impl Stdout { 12 | fn write_fmt(&mut self, fmt: &fmt::Arguments) { 13 | fmt::write(self, fmt); 14 | } 15 | } 16 | 17 | impl fmt::FormatWriter for Stdout { 18 | fn write(&mut self, bytes: &[u8]) -> fmt::Result { 19 | for &c in bytes.iter() { 20 | putc(c); 21 | } 22 | Ok(()) 23 | } 24 | } 25 | 26 | pub fn print_args(fmt: &fmt::Arguments) { 27 | write!(&mut Stdout, "{}", fmt); 28 | } 29 | 30 | pub fn println_args(fmt: &fmt::Arguments) { 31 | writeln!(&mut Stdout, "{}", fmt); 32 | } 33 | 34 | static mut pos: int = 0; 35 | 36 | unsafe fn seek(offset: int) { 37 | pos += offset; 38 | } 39 | 40 | unsafe fn write_char(c: char) { 41 | if c == '\x08' { 42 | if pos > 0 { 43 | if pos % 80 == 0 { 44 | while (*vga::SCREEN)[(pos-1) as uint].char == 0 { 45 | pos -= 1; 46 | } 47 | } 48 | else if pos > 0 { 49 | pos -= 1; 50 | (*vga::SCREEN)[pos as uint].char = 0; 51 | } 52 | } 53 | } 54 | else if c == '\n' { 55 | seek(80 - pos % 80); 56 | } 57 | else if c == '\t' { 58 | seek(4 - pos % 4); 59 | } 60 | else { 61 | (*vga::SCREEN)[pos as uint].char = c as u8; 62 | pos += 1; 63 | } 64 | 65 | pos %= vga::SCREEN_SIZE as int; 66 | vga::cursor_at(pos as uint); 67 | } 68 | 69 | pub fn putc(c: u8) { 70 | unsafe { 71 | write_char(c as char); 72 | } 73 | } 74 | 75 | pub fn puti(num: int) { 76 | } 77 | 78 | pub fn puts(s: &str) { 79 | for c in s.as_bytes().iter() { 80 | putc(*c); 81 | } 82 | } 83 | -------------------------------------------------------------------------------- /arch/x86/module.asm: -------------------------------------------------------------------------------- 1 | use32 2 | global _start 3 | 4 | section .text 5 | _start: 6 | jmp $ 7 | -------------------------------------------------------------------------------- /arch/x86/runtime/mod.rs: -------------------------------------------------------------------------------- 1 | use core::ptr::RawPtr; 2 | // use rust_core::c_types::c_int; 3 | 4 | mod stack; 5 | 6 | // TODO: use SSE 7 | 8 | #[inline] 9 | fn stosb(s: *mut u8, c: u8, n: uint) { 10 | unsafe { 11 | asm!("rep stosb" :: "{al}"(c), "{edi}"(s), "{ecx}"(n)) 12 | } 13 | } 14 | 15 | #[inline] 16 | fn stosd(s: *mut u8, c: u32, n: uint) { 17 | unsafe { 18 | asm!("rep stosl" :: "A"(c), "{edi}"(s), "{ecx}"(n)) 19 | } 20 | } 21 | 22 | #[inline] 23 | fn stosd8(s: *mut u8, c: u8, n: uint) { 24 | unsafe { 25 | let mut dword: u32 = c as u32; 26 | dword |= (dword << 24) | (dword << 16) | (dword << 8); 27 | asm!("rep stosl" :: "A"(dword), "{edi}"(s), "{ecx}"(n)) 28 | } 29 | } 30 | 31 | #[inline] 32 | fn stosd16(s: *mut u8, c: u16, n: uint) { 33 | unsafe { 34 | let mut dword: u32 = c as u32; 35 | dword |= dword << 16; 36 | asm!("rep stosl" :: "A"(dword), "{edi}"(s), "{ecx}"(n)) 37 | } 38 | } 39 | 40 | #[inline] 41 | fn memset_nonzero(mut s: *mut u8, c: u8, mut n: uint) { 42 | if unlikely!(n == 0) { 43 | return 44 | } 45 | if unlikely!(n == 1) { 46 | unsafe { *s = c; } 47 | return 48 | } 49 | 50 | while n > 0 { 51 | match n % 4 { 52 | 0 => { 53 | stosd8(s, c, n / 4); 54 | n = 0; 55 | } 56 | /*2 => unsafe { 57 | let mut word: u16 = c as u16; 58 | word = (word << 8) | word; 59 | asm!("rep stosw" :: "A"(word), "{edi}"(s), "{ecx}"(n / 2)) 60 | n = 0; 61 | },*/ 62 | q => { 63 | stosb(s, c, q); 64 | s = unsafe { s.offset(q as int) }; 65 | n -= q; 66 | } 67 | } 68 | } 69 | } 70 | 71 | pub fn wmemset(mut dest: *mut u8, c: u16, n: uint) { 72 | if unlikely!(n == 0) { 73 | return; 74 | } 75 | 76 | if (n % 2) == 1 { 77 | unsafe { 78 | *(dest as *mut u16) = c; 79 | dest = dest.offset(2); 80 | } 81 | } 82 | 83 | stosd16(dest, c, n >> 1); 84 | } 85 | 86 | fn dmemset(s: *mut u8, c: u32, n: uint) { 87 | if unlikely!(n == 0) { 88 | return; 89 | } 90 | 91 | stosd(s, c, n); 92 | } 93 | 94 | #[no_mangle] 95 | pub fn memset(s: *mut u8, c: i32, n: int) { 96 | memset_nonzero(s, (c & 0xFF) as u8, n as uint); 97 | } 98 | 99 | #[allow(dead_assignment)] 100 | #[no_mangle] 101 | pub fn memcpy(dest: *mut u8, src: *const u8, mut n: uint) { 102 | if unlikely!(n == 0) { 103 | return; 104 | } 105 | unsafe { 106 | if n < 12 { 107 | asm!("rep movsb" :: "{edi}"(dest), "{esi}"(src), "{ecx}"(n)) 108 | return; 109 | } 110 | 111 | let offset = (4 - (dest as uint % 4)) % 4; 112 | n -= offset; 113 | 114 | let mut pd: *mut u8; 115 | let mut ps: *const u8; 116 | asm!("rep movsb" : "={edi}"(pd), "={esi}"(ps) : "{edi}"(dest), "{esi}"(src), "{ecx}"(offset)) 117 | asm!("rep movsl" : "={edi}"(pd), "={esi}"(ps) : "{edi}"(pd), "{esi}"(ps), "{ecx}"(n >> 2)) 118 | asm!("rep movsb" :: "{edi}"(pd), "{esi}"(ps), "{ecx}"(n % 4)) 119 | } 120 | } 121 | 122 | #[no_mangle] 123 | pub fn memmove(dest: *mut u8, src: *const u8, n: uint) { 124 | unsafe { 125 | if src < dest as *const u8 { 126 | asm!("std") 127 | memcpy(dest.offset(n as int), src.offset(n as int), n); 128 | asm!("cld") 129 | } 130 | else { 131 | asm!("cld") 132 | memcpy(dest, src, n); 133 | } 134 | } 135 | } 136 | 137 | #[no_mangle] 138 | pub unsafe fn memcmp(s1: *const u8, s2: *const u8, n: uint) -> i32 { 139 | let mut i = 0; 140 | while i < n { 141 | let a = *s1.offset(i as int); 142 | let b = *s2.offset(i as int); 143 | if a != b { 144 | return (a - b) as i32 145 | } 146 | i += 1; 147 | } 148 | return 0; 149 | } 150 | -------------------------------------------------------------------------------- /arch/x86/runtime/stack.rs: -------------------------------------------------------------------------------- 1 | pub static RED_ZONE: uint = 5 * 4 * 1024; 2 | 3 | #[cfg(target_arch = "arm")] #[inline(always)] 4 | fn get_tls() -> uint { 5 | let tls_addr; 6 | asm!( 7 | "mrc p15, #0, $0, c13, c0, #3 8 | 9 | cmp $0, #0 10 | mvneq $0, #0xF000 11 | ldreq $0, [r3, #-15] 12 | 13 | add $0, $0, #4" 14 | : "=r"(tls_addr)); 15 | return tls_addr; 16 | } 17 | 18 | #[inline(always)] 19 | pub unsafe fn record_sp_limit(limit: uint) { 20 | return target_record_sp_limit(limit); 21 | 22 | // x86-64 23 | #[cfg(target_arch = "x86_64")] #[inline(always)] 24 | unsafe fn target_record_sp_limit(limit: uint) { 25 | asm!("movq $0, %fs:112" :: "r"(limit) :: "volatile") 26 | } 27 | 28 | // x86 29 | #[cfg(target_arch = "x86")] #[inline(always)] 30 | unsafe fn target_record_sp_limit(limit: uint) { 31 | asm!("movl $0, %gs:48" :: "r"(limit) :: "volatile") 32 | } 33 | 34 | #[cfg(target_arch = "arm")] #[inline(always)] 35 | unsafe fn target_record_sp_limit(limit: uint) { 36 | asm!( 37 | "str $0, [$1] 38 | mov pc, lr" 39 | :: "r"(limit), "r"(tls_addr()) :: "volatile") 40 | } 41 | } 42 | 43 | #[inline(always)] 44 | pub unsafe fn get_sp_limit() -> uint { 45 | return target_get_sp_limit(); 46 | 47 | // x86-64 48 | #[cfg(target_arch = "x86_64")] #[inline(always)] 49 | unsafe fn target_get_sp_limit() -> uint { 50 | let limit; 51 | asm!("movq %fs:112, $0" : "=r"(limit)); 52 | return limit; 53 | } 54 | 55 | // x86 56 | #[cfg(target_arch = "x86")] #[inline(always)] 57 | unsafe fn target_get_sp_limit() -> uint { 58 | let limit; 59 | asm!("movl %gs:48, $0" : "=r"(limit)); 60 | return limit; 61 | } 62 | 63 | #[cfg(target_arch = "arm")] #[inline(always)] 64 | unsafe fn target_get_sp_limit() -> uint { 65 | let limit; 66 | asm!( 67 | "ldr $0, [$1] 68 | mov pc, lr" 69 | : "=r"(limit) : "r"(tls_addr()) :: "volatile") 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /common/Makefile: -------------------------------------------------------------------------------- 1 | -include ./config.mk 2 | -include $(BDIR)/main.d 3 | 4 | # need to create new variable due to semantics of make "recursive variables" 5 | GCC_PREFIX_2 ?= $(GCC_PREFIX) 6 | 7 | # Opt level set to 2 should be enough. 8 | ifdef DEBUG 9 | MAYBE_DEBUG ?= -g 10 | endif 11 | 12 | ifndef DEBUG 13 | MAYBE_RUSTC_OPTIMIZE ?= -C opt-level=2 -C lto 14 | MAYBE_CLANG_OPTIMIZE ?= -O2 15 | endif 16 | 17 | RUSTC ?= $(RUST_ROOT)/bin/rustc 18 | RUSTCFLAGS ?= --target $(TARGET) -Z no-landing-pads $(MAYBE_RUSTC_OPTIMIZE) 19 | 20 | # CC is probably defined (as GCC) 21 | CC = $(LLVM_ROOT)/bin/clang 22 | CFLAGS ?= -ffreestanding -target $(TARGET) $(MAYBE_CLANG_OPTIMIZE) $(MAYBE_DEBUG) -fdata-sections -ffunction-sections 23 | 24 | LLC ?= $(LLVM_ROOT)/bin/llc 25 | 26 | # AS is probably defined 27 | AS = $(GCC_PREFIX_2)as 28 | LD = $(GCC_PREFIX_2)ld 29 | GDB = $(GCC_PREFIX_2)gdb 30 | OBJCOPY = $(GCC_PREFIX_2)objcopy 31 | 32 | BDIR ?= ./boot 33 | 34 | DEP_SCRIPT ?= 's~\($(DEP_KEEP)\)~\n\1~g;s~ \S*$(DEP_RM)\S*~~g;s~\n\($(DEP_KEEP)\)~\1~g' 35 | 36 | 37 | # Compile rustboot. Produce dependency info 38 | $(BDIR)/main.bc: ../../common/lib.rs 39 | $(RUSTC) $(RUSTCFLAGS) -L $(BDIR) --out-dir $(BDIR) --emit=dep-info,llvm-bc $< 40 | @sed -e $(DEP_SCRIPT) $(BDIR)/main.d > $(BDIR)/main.d.tmp 41 | @mv $(BDIR)/main.d.tmp $(BDIR)/main.d # SED to tmp file for OS X compatibility 42 | 43 | # initram 44 | 45 | $(BDIR)/initram.elf: $(BDIR)/module.o 46 | $(LD) $(LDFLAGS) -s $< -o $@ 47 | 48 | $(BDIR)/%.embed: $(BDIR)/% 49 | cd $(@D); $(LD) $(LDFLAGS_EMBED) -r -b binary -o $(@F) $( *mut Elf32_Word { 95 | unsafe { transmute(self) } 96 | } 97 | pub fn d_ptr(&mut self) -> *mut Elf32_Addr { 98 | unsafe { transmute(self) } 99 | } 100 | } 101 | pub struct Elf32_Dyn { 102 | d_tag: Elf32_Sword, 103 | d_un: Union_Unnamed1, 104 | } 105 | 106 | pub struct Elf32_Verdef { 107 | vd_version: Elf32_Half, 108 | vd_flags: Elf32_Half, 109 | vd_ndx: Elf32_Half, 110 | vd_cnt: Elf32_Half, 111 | vd_hash: Elf32_Word, 112 | vd_aux: Elf32_Word, 113 | vd_next: Elf32_Word, 114 | } 115 | 116 | pub struct Elf32_Verdaux { 117 | vda_name: Elf32_Word, 118 | vda_next: Elf32_Word, 119 | } 120 | 121 | pub struct Elf32_Verneed { 122 | vn_version: Elf32_Half, 123 | vn_cnt: Elf32_Half, 124 | vn_file: Elf32_Word, 125 | vn_aux: Elf32_Word, 126 | vn_next: Elf32_Word, 127 | } 128 | 129 | pub struct Elf32_Vernaux { 130 | vna_hash: Elf32_Word, 131 | vna_flags: Elf32_Half, 132 | vna_other: Elf32_Half, 133 | vna_name: Elf32_Word, 134 | vna_next: Elf32_Word, 135 | } 136 | 137 | pub struct AuxvValue { 138 | pub data: c_int, // or 8u? 139 | } 140 | 141 | impl AuxvValue { 142 | pub fn a_val(&mut self) -> *mut c_int { 143 | unsafe { transmute(self) } 144 | } 145 | pub fn a_ptr(&mut self) -> *mut *mut c_void { 146 | // WARN: cannot use 32 bit pointers on x86_64! 147 | unsafe { transmute(self) } 148 | } 149 | pub fn a_fcn(&mut self) -> *mut extern fn() { 150 | unsafe { transmute(self) } 151 | } 152 | } 153 | 154 | pub struct Auxv { 155 | pub a_type: AuxvType, 156 | pub a_un: AuxvValue, 157 | } 158 | 159 | /* Legal values for a_type (entry type). */ 160 | #[repr(u32)] 161 | pub enum AuxvType { 162 | AT_NULL = 0, /* End of vector */ 163 | AT_IGNORE = 1, /* Entry should be ignored */ 164 | AT_EXECFD = 2, /* File descriptor of program */ 165 | AT_PHDR = 3, /* Program headers for program */ 166 | AT_PHENT = 4, /* Size of program header entry */ 167 | AT_PHNUM = 5, /* Number of program headers */ 168 | AT_PAGESZ = 6, /* System page size */ 169 | AT_BASE = 7, /* Base address of interpreter */ 170 | AT_FLAGS = 8, /* Flags */ 171 | AT_ENTRY = 9, /* Entry point of program */ 172 | AT_NOTELF = 10, /* Program is not ELF */ 173 | AT_UID = 11, /* Real uid */ 174 | AT_EUID = 12, /* Effective uid */ 175 | AT_GID = 13, /* Real gid */ 176 | AT_EGID = 14, /* Effective gid */ 177 | AT_CLKTCK = 17, /* Frequency of times() */ 178 | 179 | /* Some more special a_type values describing the hardware. */ 180 | AT_PLATFORM = 15, /* String identifying platform. */ 181 | AT_HWCAP = 16, /* Machine-dependent hints about 182 | processor capabilities. */ 183 | 184 | /* This entry gives some information about the FPU initialization 185 | performed by the kernel. */ 186 | AT_FPUCW = 18, /* Used FPU control word. */ 187 | 188 | /* Cache block sizes. */ 189 | AT_DCACHEBSIZE = 19, /* Data cache block size. */ 190 | AT_ICACHEBSIZE = 20, /* Instruction cache block size. */ 191 | AT_UCACHEBSIZE = 21, /* Unified cache block size. */ 192 | 193 | /* A special ignored value for PPC, used by the kernel to control the 194 | interpretation of the AUXV. Must be > 16. */ 195 | AT_IGNOREPPC = 22, /* Entry should be ignored. */ 196 | 197 | AT_SECURE = 23, /* Boolean, was exec setuid-like? */ 198 | 199 | AT_BASE_PLATFORM = 24, /* String identifying real platforms.*/ 200 | 201 | AT_RANDOM = 25, /* Address of 16 random bytes. */ 202 | 203 | AT_HWCAP2 = 26, /* More machine-dependent hints about 204 | processor capabilities. */ 205 | 206 | AT_EXECFN = 31, /* Filename of executable. */ 207 | 208 | /* Pointer to the global system page used for system calls and other 209 | nice things. */ 210 | AT_SYSINFO = 32, 211 | AT_SYSINFO_EHDR = 33, 212 | 213 | /* Shapes of the caches. Bits 0-3 contains associativity; bits 4-7 contains 214 | log2 of line size; mask those to get cache size. */ 215 | AT_L1I_CACHESHAPE = 34, 216 | AT_L1D_CACHESHAPE = 35, 217 | AT_L2_CACHESHAPE = 36, 218 | AT_L3_CACHESHAPE = 37 219 | } 220 | 221 | pub struct Elf32_Nhdr { 222 | n_namesz: Elf32_Word, 223 | n_descsz: Elf32_Word, 224 | n_type: Elf32_Word, 225 | } 226 | 227 | pub struct Struct_Unnamed5 { 228 | gt_current_g_value: Elf32_Word, 229 | gt_unused: Elf32_Word, 230 | } 231 | pub struct Struct_Unnamed6 { 232 | gt_g_value: Elf32_Word, 233 | gt_bytes: Elf32_Word, 234 | } 235 | pub struct Elf32_gptab { 236 | data: [c_uchar, ..8u], 237 | } 238 | impl Elf32_gptab { 239 | pub fn gt_header(&mut self) -> *mut Struct_Unnamed5 { 240 | unsafe { transmute(self) } 241 | } 242 | pub fn gt_entry(&mut self) -> *mut Struct_Unnamed6 { 243 | unsafe { transmute(self) } 244 | } 245 | } 246 | pub struct Elf32_RegInfo { 247 | ri_gprmask: Elf32_Word, 248 | ri_cprmask: [Elf32_Word, ..4u], 249 | ri_gp_value: Elf32_Sword, 250 | } 251 | pub struct Elf_Options { 252 | kind: c_uchar, 253 | size: c_uchar, 254 | section: Elf32_Section, 255 | info: Elf32_Word, 256 | } 257 | pub struct Elf_Options_Hw { 258 | hwp_flags1: Elf32_Word, 259 | hwp_flags2: Elf32_Word, 260 | } 261 | pub struct Elf32_Lib { 262 | l_name: Elf32_Word, 263 | l_time_stamp: Elf32_Word, 264 | l_checksum: Elf32_Word, 265 | l_version: Elf32_Word, 266 | l_flags: Elf32_Word, 267 | } 268 | 269 | pub type Elf32_Conflict = Elf32_Addr; 270 | -------------------------------------------------------------------------------- /common/kernel/elf/elf64.rs: -------------------------------------------------------------------------------- 1 | use core::mem::transmute; 2 | use core::intrinsics::offset; 3 | use core::c_types::{c_ushort, c_uint, c_int, c_ulong, c_long}; 4 | 5 | use util::int::range; 6 | 7 | // rust-bindgen generated bindings 8 | pub type Elf64_Half = c_ushort; 9 | pub type Elf64_Word = c_uint; 10 | pub type Elf64_Sword = c_int; 11 | pub type Elf64_Xword = c_ulong; 12 | pub type Elf64_Sxword = c_long; 13 | pub type Elf64_Addr = c_ulong; 14 | pub type Elf64_Off = c_ulong; 15 | pub type Elf64_Section = c_ushort; 16 | pub type Elf64_Symndx = c_ulong; 17 | type c_uchar = u8; 18 | type c_void = uint; 19 | 20 | #[repr(packed)] 21 | pub struct Ehdr { 22 | e_ident: [c_uchar, ..16u], 23 | e_type: Elf64_Half, 24 | e_machine: Elf64_Half, 25 | e_version: Elf64_Word, 26 | e_entry: Elf64_Addr, 27 | e_phoff: Elf64_Off, 28 | e_shoff: Elf64_Off, 29 | e_flags: Elf64_Word, 30 | e_ehsize: Elf64_Half, 31 | e_phentsize: Elf64_Half, 32 | e_phnum: Elf64_Half, 33 | e_shentsize: Elf64_Half, 34 | e_shnum: Elf64_Half, 35 | e_shstrndx: Elf64_Half, 36 | } 37 | 38 | #[repr(packed)] 39 | pub struct Elf64_Phdr { 40 | pub p_type: super::HeaderType, 41 | pub p_flags: Elf64_Word, 42 | pub p_offset: Elf64_Off, 43 | pub p_vaddr: Elf64_Addr, 44 | pub p_paddr: Elf64_Addr, 45 | pub p_filesz: Elf64_Xword, 46 | pub p_memsz: Elf64_Xword, 47 | pub p_align: Elf64_Xword, 48 | } 49 | 50 | #[repr(packed)] 51 | pub struct Elf64_Shdr { 52 | sh_name: Elf64_Word, 53 | sh_type: Elf64_Word, 54 | sh_flags: Elf64_Xword, 55 | sh_addr: Elf64_Addr, 56 | sh_offset: Elf64_Off, 57 | sh_size: Elf64_Xword, 58 | sh_link: Elf64_Word, 59 | sh_info: Elf64_Word, 60 | sh_addralign: Elf64_Xword, 61 | sh_entsize: Elf64_Xword, 62 | } 63 | 64 | pub struct Elf64_Sym { 65 | st_name: Elf64_Word, 66 | st_info: c_uchar, 67 | st_other: c_uchar, 68 | st_shndx: Elf64_Section, 69 | st_value: Elf64_Addr, 70 | st_size: Elf64_Xword, 71 | } 72 | pub struct Elf64_Syminfo { 73 | si_boundto: Elf64_Half, 74 | si_flags: Elf64_Half, 75 | } 76 | pub struct Elf64_Rel { 77 | r_offset: Elf64_Addr, 78 | r_info: Elf64_Xword, 79 | } 80 | pub struct Elf64_Rela { 81 | r_offset: Elf64_Addr, 82 | r_info: Elf64_Xword, 83 | r_addend: Elf64_Sxword, 84 | } 85 | 86 | pub struct Union_Unnamed2 { 87 | data: [c_uchar, ..8u], 88 | } 89 | impl Union_Unnamed2 { 90 | pub fn d_val(&mut self) -> *mut Elf64_Xword { 91 | unsafe { transmute(self) } 92 | } 93 | pub fn d_ptr(&mut self) -> *mut Elf64_Addr { 94 | unsafe { transmute(self) } 95 | } 96 | } 97 | pub struct Elf64_Dyn { 98 | d_tag: Elf64_Sxword, 99 | d_un: Union_Unnamed2, 100 | } 101 | pub struct Elf64_Verdef { 102 | vd_version: Elf64_Half, 103 | vd_flags: Elf64_Half, 104 | vd_ndx: Elf64_Half, 105 | vd_cnt: Elf64_Half, 106 | vd_hash: Elf64_Word, 107 | vd_aux: Elf64_Word, 108 | vd_next: Elf64_Word, 109 | } 110 | pub struct Elf64_Verdaux { 111 | vda_name: Elf64_Word, 112 | vda_next: Elf64_Word, 113 | } 114 | pub struct Elf64_Verneed { 115 | vn_version: Elf64_Half, 116 | vn_cnt: Elf64_Half, 117 | vn_file: Elf64_Word, 118 | vn_aux: Elf64_Word, 119 | vn_next: Elf64_Word, 120 | } 121 | pub struct Elf64_Vernaux { 122 | vna_hash: Elf64_Word, 123 | vna_flags: Elf64_Half, 124 | vna_other: Elf64_Half, 125 | vna_name: Elf64_Word, 126 | vna_next: Elf64_Word, 127 | } 128 | 129 | pub struct AuxvValue { 130 | data: [c_uchar, ..8u], 131 | } 132 | 133 | impl AuxvValue { 134 | pub fn a_val(&mut self) -> *mut c_long { 135 | unsafe { transmute(self) } 136 | } 137 | pub fn a_ptr(&mut self) -> *mut *mut c_void { 138 | unsafe { transmute(self) } 139 | } 140 | pub fn a_fcn(&mut self) -> *mut extern fn() { 141 | unsafe { transmute(self) } 142 | } 143 | } 144 | 145 | pub struct Auxv { 146 | a_type: c_long, 147 | a_un: AuxvValue, 148 | } 149 | 150 | pub struct Elf64_Nhdr { 151 | n_namesz: Elf64_Word, 152 | n_descsz: Elf64_Word, 153 | n_type: Elf64_Word, 154 | } 155 | pub struct Elf64_Lib { 156 | l_name: Elf64_Word, 157 | l_time_stamp: Elf64_Word, 158 | l_checksum: Elf64_Word, 159 | l_version: Elf64_Word, 160 | l_flags: Elf64_Word, 161 | } 162 | -------------------------------------------------------------------------------- /common/kernel/elf/mod.rs: -------------------------------------------------------------------------------- 1 | use core::ptr::RawPtr; 2 | use core::ptr::{copy_nonoverlapping_memory, set_memory}; 3 | use core::mem::transmute; 4 | use core::prelude::*; 5 | use core; 6 | 7 | use kernel::process::Process; 8 | use kernel::mm; 9 | use platform::io; 10 | 11 | #[cfg(target_word_size = "32")] pub use self::elf32::{Ehdr, Phdr, Auxv, AuxvValue, AuxvType}; 12 | #[cfg(target_word_size = "64")] pub use self::elf64::{Ehdr, Phdr, Auxv, AuxvValue, AuxvType}; 13 | #[cfg(target_word_size = "32")] mod elf32; 14 | #[cfg(target_word_size = "64")] mod elf64; 15 | 16 | #[repr(u32)] 17 | enum HeaderType { 18 | PT_NULL = 0, 19 | PT_LOAD = 1, 20 | PT_DYNAMIC = 2, 21 | PT_INTERP = 3, 22 | PT_NOTE = 4, 23 | PT_SHLIB = 5, 24 | PT_PHDR = 6, 25 | PT_TLS = 7, 26 | PT_LOOS = 0x60000000, 27 | PT_GNU_EH_FRAME = 0x6474e550, 28 | PT_GNU_STACK = 0x6474e551, 29 | PT_HIOS = 0x6fffffff, 30 | PT_LOPROC = 0x70000000, 31 | PT_HIPROC = 0x7fffffff 32 | } 33 | 34 | bitflags!(flags HeaderFlags: u32 { 35 | const PT_X = 1, 36 | const PT_R = 2, 37 | const PT_W = 4 38 | }) 39 | 40 | #[repr(packed)] 41 | struct ELFIdent { 42 | ei_mag: [u8, ..4], 43 | ei_class: u8, 44 | ei_data: u8, 45 | ei_version: u8, 46 | ei_osabi: u8, 47 | ei_abiversion: u8, 48 | ei_pad: [u8, ..7] 49 | } 50 | 51 | trait EhdrT { 52 | unsafe fn spawn_process(&self) -> Process; 53 | } 54 | 55 | trait PhdrT { 56 | unsafe fn load(&self, task: &Process, buffer: *const u8); 57 | } 58 | 59 | impl EhdrT for self::Ehdr { 60 | unsafe fn spawn_process(&self) -> Process { 61 | let mut task = Process::new(); 62 | //TODO: Verify file integrity 63 | let buffer: *const u8 = transmute(self); 64 | let ph_size = self.e_phentsize as int; 65 | let ph_base = buffer.offset(self.e_phoff as int); 66 | 67 | let mut stack_flags = mm::RW; 68 | 69 | for i in range(0, self.e_phnum) { 70 | let pheader = ph_base.offset(ph_size * i as int) as *const Phdr; 71 | 72 | match (*pheader).p_type { 73 | HeaderType::PT_NULL => {} 74 | HeaderType::PT_LOAD => (*pheader).load(&task, buffer), 75 | HeaderType::PT_DYNAMIC => (*pheader).load(&task, buffer), 76 | HeaderType::PT_GNU_STACK => { 77 | if (*pheader).p_flags.contains(PT_X) { 78 | // We don't need an executable stack 79 | stack_flags = mm::Flags::empty(); 80 | } 81 | }, 82 | _ => {} 83 | } 84 | } 85 | 86 | static stack_bottom: u32 = 0xC0000000; 87 | let stack_vaddr = (stack_bottom - 0x1000) as *mut u8; 88 | task.mmap(stack_vaddr, 0x1000, stack_flags); 89 | let stack_ptr = (stack_bottom as *mut u8).offset(-(((4 + 5 + 15) & !0xF) + 8 + 4 + 4 + 4)); 90 | let argv_ptr = stack_ptr as *mut *mut u8; 91 | let envp_ptr = argv_ptr.offset(2); 92 | let auxv_ptr = argv_ptr.offset(1) as *mut Auxv; 93 | let str_ptr = (stack_bottom as *mut u8).offset(-(4 + 5)); 94 | 95 | *argv_ptr.offset(1) = transmute(0u); 96 | *envp_ptr = transmute(0u); 97 | *auxv_ptr = Auxv { a_type: AuxvType::AT_NULL, a_un: AuxvValue { data: 0 } }; 98 | 99 | let (strs, len): (*const u8, uint) = transmute("test\0"); 100 | copy_nonoverlapping_memory(str_ptr, strs, len); 101 | *argv_ptr = str_ptr; 102 | 103 | // return entry address 104 | task.esp = stack_ptr as u32; 105 | task.eip = transmute(self.e_entry); 106 | task 107 | } 108 | } 109 | 110 | impl PhdrT for self::Phdr { 111 | unsafe fn load(&self, task: &Process, buffer: *const u8) { 112 | let vaddr = self.p_vaddr as *mut u8; 113 | let mem_size = self.p_memsz as uint; 114 | let file_pos = self.p_offset as int; 115 | let file_size = self.p_filesz as uint; 116 | 117 | let flags = if self.p_flags.contains(PT_W) { 118 | mm::RW 119 | } else { 120 | mm::Flags::empty() 121 | }; 122 | 123 | task.mmap(vaddr, mem_size, flags); 124 | 125 | copy_nonoverlapping_memory(vaddr, buffer.offset(file_pos), file_size); 126 | set_memory(vaddr.offset(file_size as int), 0, mem_size - file_size); 127 | } 128 | } 129 | 130 | impl ELFIdent { 131 | unsafe fn load(&self) -> Option<&Ehdr> { 132 | // TODO: check endianness 133 | static MAGIC_STRING : &'static str = "\u007fELF"; 134 | if *(MAGIC_STRING.as_ptr() as *const u32) != transmute(self.ei_mag) { 135 | return None; 136 | } 137 | 138 | #[cfg(target_word_size = "32")] const CLASS: u8 = 1; 139 | #[cfg(target_word_size = "64")] const CLASS: u8 = 2; 140 | 141 | match self.ei_class { 142 | CLASS => return Some(transmute(self)), 143 | _ => return None 144 | } 145 | } 146 | } 147 | 148 | pub fn exec(buffer: *const u8) { 149 | unsafe { 150 | let ident: &ELFIdent = transmute(buffer); 151 | ident.load().map(|e| { e.spawn_process().enter() }); 152 | } 153 | } 154 | -------------------------------------------------------------------------------- /common/kernel/heap.rs: -------------------------------------------------------------------------------- 1 | use core::mem::size_of; 2 | use core::num::Int; 3 | use core::prelude::*; 4 | 5 | use kernel::mm::{Allocator, Alloc, BuddyAlloc}; 6 | use util::bitv; 7 | 8 | use rust_core::fail::{abort, out_of_memory}; 9 | 10 | pub static mut heap: Option = None; 11 | 12 | pub fn init() -> Alloc { 13 | let alloc = Alloc::new( 14 | BuddyAlloc::new(17, bitv::Bitv { storage: 0x100_000 as *mut u32 }), 15 | 0x110_000 as *mut u8, 16 | 0, 17 | ); 18 | unsafe { 19 | heap = Some(alloc); 20 | } 21 | alloc 22 | } 23 | 24 | #[lang = "exchange_malloc"] 25 | #[inline] 26 | pub unsafe fn malloc_raw(size: uint) -> *mut u8 { 27 | match get(heap).alloc(size) { 28 | (_, 0) => out_of_memory(), 29 | (ptr, _) => ptr 30 | } 31 | } 32 | 33 | #[no_mangle] 34 | pub unsafe extern "C" fn rust_allocate(size: uint, _align: uint) -> *mut u8 { 35 | malloc_raw(size) 36 | } 37 | 38 | #[lang = "exchange_free"] 39 | #[inline] 40 | pub unsafe fn free(ptr: *mut T) { 41 | get(heap).free(ptr as *mut u8); 42 | } 43 | 44 | #[inline] 45 | pub unsafe fn alloc(count: uint) -> *mut T { 46 | match count.checked_mul(size_of::()) { 47 | None => out_of_memory(), 48 | Some(size) => malloc_raw(size) as *mut T 49 | } 50 | } 51 | 52 | #[inline] 53 | pub unsafe fn zero_alloc(count: uint) -> *mut T { 54 | match count.checked_mul(size_of::()) { 55 | None => out_of_memory(), 56 | Some(size) => match get(heap).zero_alloc(size) { 57 | (_, 0) => out_of_memory(), 58 | (ptr, _) => ptr as *mut T 59 | } 60 | } 61 | } 62 | 63 | #[inline] 64 | pub unsafe fn realloc_raw(ptr: *mut T, count: uint) -> *mut T { 65 | match count.checked_mul(size_of::()) { 66 | None => out_of_memory(), 67 | Some(0) => { 68 | free(ptr as *mut u8); 69 | 0 as *mut T 70 | } 71 | Some(size) => match get(heap).realloc(ptr as *mut u8, size) { 72 | (_, 0) => out_of_memory(), 73 | (ptr, _) => ptr as *mut T 74 | } 75 | } 76 | } 77 | 78 | // because no .expect() from lib std 79 | fn get(opt : Option) -> T { 80 | match opt { 81 | Some(val) => val, 82 | None => abort(), 83 | } 84 | } 85 | -------------------------------------------------------------------------------- /common/kernel/mm/allocator.rs: -------------------------------------------------------------------------------- 1 | //! Mechanisms for the allocation of kernel objects. 2 | 3 | use core::ptr::RawPtr; 4 | use core::mem::transmute; 5 | use core::ptr::{set_memory, copy_memory}; 6 | use core::intrinsics::offset; 7 | use core::intrinsics::ctlz32; 8 | 9 | use util::bitv::Bitv; 10 | 11 | #[repr(u8)] 12 | enum Node { 13 | UNUSED = 0, 14 | USED = 1, 15 | SPLIT = 2, 16 | FULL = 3 17 | } 18 | 19 | /// The allocator interface. Based on an unfinished RFC. 20 | pub trait Allocator { 21 | fn alloc(&mut self, size: uint) -> (*mut u8, uint); 22 | 23 | fn zero_alloc(&mut self, s: uint) -> (*mut u8, uint) { 24 | let (ptr, size) = self.alloc(s); 25 | unsafe { set_memory(ptr, 0, size); } 26 | (ptr, size) 27 | } 28 | 29 | fn realloc(&mut self, src: *mut u8, size: uint) -> (*mut u8, uint) { 30 | self.free(src); 31 | let (ptr, sz) = self.alloc(size); 32 | unsafe { copy_memory(ptr, src as *const u8, sz); } 33 | (ptr, sz) 34 | } 35 | 36 | fn free(&mut self, ptr: *mut u8); 37 | } 38 | 39 | /// The [buddy memory allocation\[1\]][1] system is implemented with the use of a binary tree. 40 | /// It can be augmented with the use of linked lists[[2]]. 41 | /// 42 | /// 1. [Buddy memory allocation - Wikipedia](http://en.wikipedia.org/wiki/Buddy_memory_allocation) 43 | /// 2. [52.206 Operating Systems. Heap memory allocation](http://dysphoria.net/OperatingSystems1/4_allocation_buddy_system.html) 44 | /// 45 | /// [1]: http://en.wikipedia.org/wiki/Buddy_memory_allocation 46 | /// [2]: http://dysphoria.net/OperatingSystems1/4_allocation_buddy_system.html 47 | pub struct BuddyAlloc { 48 | pub order: uint, 49 | pub tree: Bitv 50 | } 51 | 52 | pub struct Alloc { 53 | pub parent: BuddyAlloc, 54 | pub base: *mut u8, 55 | pub el_size: uint 56 | } 57 | 58 | impl BuddyAlloc { 59 | pub fn new(order: uint, storage: Bitv) -> BuddyAlloc { 60 | storage.clear(1 << (order + 1)); 61 | BuddyAlloc { order: order, tree: storage } 62 | } 63 | 64 | #[inline] 65 | fn offset(&self, index: uint, level: uint) -> uint { 66 | (index + 1 - (1 << self.order >> level)) << level 67 | } 68 | 69 | fn alloc(&mut self, mut size: uint) -> (uint, uint) { 70 | if size == 0 { 71 | size = 1; 72 | } 73 | // smallest power of 2 >= size 74 | let lg2_size = 32 - unsafe { ctlz32(size as u32 - 1) } as uint; 75 | 76 | let mut index = 0; // points to current tree node 77 | let mut level = self.order; // current height 78 | 79 | loop { 80 | match (self.get(index), level == lg2_size) { 81 | (Node::UNUSED, true) => { 82 | // Found appropriate unused node 83 | self.set(index, Node::USED); // use 84 | 85 | let mut parent = index; 86 | loop { 87 | let buddy = parent - 1 + (parent & 1) * 2; 88 | match self.get(buddy) { 89 | Node::USED | Node::FULL if parent > 0 => { 90 | parent = (parent + 1) / 2 - 1; 91 | self.set(parent, Node::FULL); 92 | } 93 | _ => break 94 | } 95 | } 96 | return ( 97 | self.offset(index, level), 98 | 1 << lg2_size 99 | ); 100 | } 101 | (Node::UNUSED, false) => { 102 | // This large node is unused, split it! 103 | self.set(index, Node::SPLIT); 104 | self.set(index*2 + 1, Node::UNUSED); 105 | self.set(index*2 + 2, Node::UNUSED); 106 | index = index * 2 + 1; // left child 107 | level -= 1; 108 | } 109 | (Node::SPLIT, false) => { 110 | // Traverse children 111 | index = index * 2 + 1; // left child 112 | level -= 1; 113 | } 114 | _ => loop { 115 | // Go either right or back up 116 | if index & 1 == 1 { 117 | // right sibling 118 | index += 1; 119 | break; 120 | } 121 | 122 | // go up by one level 123 | level += 1; 124 | 125 | if index == 0 { 126 | // out of memory -- back at tree's root after traversal 127 | return (0, 0); 128 | } 129 | 130 | index = (index + 1) / 2 - 1; // parent 131 | } 132 | } 133 | } 134 | } 135 | 136 | fn free(&mut self, offset: uint) { 137 | let mut length = 1 << self.order; 138 | let mut left = 0; 139 | let mut index = 0; 140 | 141 | loop { 142 | match self.get(index) { 143 | Node::UNUSED => return, 144 | Node::USED => loop { 145 | if index == 0 { 146 | self.set(0, Node::UNUSED); 147 | return; 148 | } 149 | 150 | let buddy = index - 1 + (index & 1) * 2; 151 | match self.get(buddy) { 152 | Node::UNUSED => {} 153 | _ => { 154 | self.set(index, Node::UNUSED); 155 | loop { 156 | let parent = (index + 1) / 2 - 1; // parent 157 | match self.get(parent) { 158 | Node::FULL if index > 0 => { 159 | self.set(parent, Node::SPLIT); 160 | } 161 | _ => return 162 | } 163 | index = parent; 164 | } 165 | } 166 | } 167 | index = (index + 1) / 2 - 1; // parent 168 | }, 169 | _ => { 170 | length /= 2; 171 | if offset < left + length { 172 | index = index * 2 + 1; // left child 173 | } 174 | else { 175 | left += length; 176 | index = index * 2 + 2; // right child 177 | } 178 | } 179 | } 180 | } 181 | } 182 | 183 | fn get(&self, i: uint) -> Node { 184 | unsafe { 185 | transmute(self.tree.get(i)) 186 | } 187 | } 188 | 189 | fn set(&self, i: uint, x: Node) { 190 | self.tree.set(i, x as u8); 191 | } 192 | } 193 | 194 | impl Allocator for Alloc { 195 | fn alloc(&mut self, size: uint) -> (*mut u8, uint) { 196 | let (offset, size) = self.parent.alloc(size); 197 | unsafe { 198 | return ( 199 | self.base.offset((offset << self.el_size) as int), 200 | size << self.el_size 201 | ) 202 | } 203 | } 204 | 205 | fn free(&mut self, ptr: *mut u8) { 206 | let length = 1 << self.parent.order << self.el_size; 207 | 208 | unsafe { 209 | if ptr < self.base || ptr >= self.base.offset(length) { 210 | return; 211 | } 212 | } 213 | 214 | let offset = (ptr as uint - self.base as uint) >> self.el_size; 215 | self.parent.free(offset); 216 | } 217 | } 218 | 219 | impl Alloc { 220 | pub fn new(parent: BuddyAlloc, base: *mut u8, el_size: uint) -> Alloc { 221 | Alloc { parent: parent, base: base, el_size: el_size } 222 | } 223 | } 224 | -------------------------------------------------------------------------------- /common/kernel/mm/mod.rs: -------------------------------------------------------------------------------- 1 | //! The memory management. 2 | 3 | pub use self::allocator::{ 4 | Allocator, 5 | BuddyAlloc, 6 | Alloc, 7 | }; 8 | 9 | pub use cpu::mmu::{ 10 | Flags, 11 | Frame, 12 | PageDirectory, 13 | RW, 14 | USER 15 | }; 16 | 17 | pub mod allocator; 18 | pub mod physical; 19 | -------------------------------------------------------------------------------- /common/kernel/mm/physical.rs: -------------------------------------------------------------------------------- 1 | use core::mem::transmute; 2 | use core::ptr::RawPtr; 3 | use core::option::Option; 4 | 5 | use kernel::heap; 6 | use kernel::mm; 7 | use kernel::mm::Allocator; 8 | use cpu::mmu::Frame; 9 | use util::bitv; 10 | 11 | use rust_core::fail::abort; 12 | 13 | pub static mut frames: mm::Alloc = mm::Alloc { 14 | base: 0x200_000 as *mut u8, 15 | el_size: 12, 16 | parent: mm::BuddyAlloc { 17 | order: 13, 18 | tree: bitv::Bitv { storage: 0 as *mut u32 } 19 | } 20 | }; 21 | 22 | pub struct Phys { 23 | ptr: *mut T 24 | } 25 | 26 | impl Phys { 27 | pub fn at(offset: uint) -> Phys { 28 | Phys { ptr: offset as *mut T } 29 | } 30 | 31 | pub fn as_ptr(&self) -> *mut T { 32 | match *self { 33 | Phys { ptr: p } => p 34 | } 35 | } 36 | } 37 | 38 | impl RawPtr for Phys { 39 | fn null() -> Phys { 40 | Phys { ptr: RawPtr::null() } 41 | } 42 | 43 | fn is_null(&self) -> bool { 44 | self.ptr.is_null() 45 | } 46 | 47 | fn to_uint(&self) -> uint { 48 | self.ptr.to_uint() 49 | } 50 | 51 | unsafe fn as_ref<'a>(&self) -> Option<&'a T> { 52 | self.ptr.as_ref() 53 | } 54 | 55 | unsafe fn offset(self, n: int) -> Phys { 56 | Phys { ptr: self.ptr.offset(n) } 57 | } 58 | } 59 | 60 | pub fn init() { 61 | unsafe { 62 | frames.parent.tree.storage = heap::zero_alloc::(1024); 63 | } 64 | } 65 | 66 | pub unsafe fn alloc_frames(count: uint) -> Phys { 67 | match frames.alloc(count) { 68 | (_, 0) => abort(), 69 | (ptr, _) => Phys { ptr: ptr as *mut T } 70 | } 71 | } 72 | 73 | pub unsafe fn zero_alloc_frames(count: uint) -> Phys { 74 | match frames.zero_alloc(count) { 75 | (_, 0) => abort(), 76 | (ptr, _) => Phys { ptr: ptr as *mut T } 77 | } 78 | } 79 | 80 | #[inline] 81 | pub unsafe fn free_frames(ptr: Phys) { 82 | frames.free(ptr.to_uint() as *mut u8); 83 | } 84 | -------------------------------------------------------------------------------- /common/kernel/mod.rs: -------------------------------------------------------------------------------- 1 | use core::option::{Option, Some, None}; 2 | 3 | use platform::{cpu, io, drivers}; 4 | use cpu::interrupt; 5 | pub use cpu::interrupt::Table; 6 | 7 | pub mod util; 8 | pub mod mm; 9 | pub mod heap; 10 | mod process; 11 | #[allow(dead_code)] 12 | #[allow(non_camel_case_types)] 13 | mod elf; 14 | 15 | #[lang = "stack_exhausted"] extern fn stack_exhausted() {} 16 | #[lang = "eh_personality"] extern fn eh_personality() {} 17 | 18 | pub static mut int_table: Option = None; 19 | 20 | /// Called at the end of the bootloader. Starts in protected mode 21 | /// with the following memory layout: 22 | /// 23 | /// | Physical memory ranges | Size | Description | 24 | /// | ---------------------- | -------- | ----------- | 25 | /// | 0x0000 ... 0x7BFF | 31 KiB | Stack | 26 | /// | 0x7C00 ... 0x7DFF | 0.5 KiB | Bootloader | 27 | /// | 0x07E00 ... 0x0FFFF | 32.5 KiB | _unused_ | 28 | /// | 0x10000 ... 0x1FFFF | 64 KiB | Kernel | 29 | #[lang="start"] 30 | #[no_mangle] 31 | pub fn main() { 32 | heap::init(); 33 | mm::physical::init(); 34 | 35 | let table = interrupt::Table::new(); 36 | unsafe { 37 | table.load(); 38 | int_table = Some(table); 39 | drivers::keydown = Some(io::putc); 40 | } 41 | cpu::init(); 42 | 43 | drivers::init(); 44 | elf::exec(&_binary_initram_elf_start); 45 | extern { static _binary_initram_elf_start: u8; } 46 | } 47 | -------------------------------------------------------------------------------- /common/kernel/process.rs: -------------------------------------------------------------------------------- 1 | use core::clone::Clone; 2 | 3 | use kernel::mm::{Flags, PageDirectory}; 4 | use kernel::mm::physical; 5 | 6 | use util::rt::breakpoint; 7 | 8 | use platform::cpu::mmu; 9 | 10 | pub struct Process { 11 | pub eip: u32, 12 | pub esp: u32, 13 | pub paging: physical::Phys 14 | } 15 | 16 | impl Process { 17 | pub fn new() -> Process { 18 | Process { 19 | eip: 0, 20 | esp: 0, 21 | // paging: unsafe { physical::zero_alloc_frames(1) as *mut PageDirectory } 22 | paging: unsafe { mmu::clone_directory() } 23 | } 24 | } 25 | 26 | pub fn mmap(&self, page_ptr: *mut u8, size: uint, flags: Flags) { 27 | unsafe { 28 | (*self.paging.as_ptr()).map(page_ptr, size, flags); 29 | } 30 | } 31 | 32 | #[cfg(target_arch = "x86")] 33 | pub fn enter(&self) { 34 | unsafe { 35 | breakpoint(); 36 | // TODO need to store physical address 37 | mmu::switch_directory(self.paging); 38 | asm!("xor %eax, %eax 39 | xor %edx, %edx 40 | jmp *$0" :: "m"(self.eip), "{esp}"(self.esp) :: "volatile") 41 | } 42 | } 43 | 44 | #[cfg(target_arch = "arm")] 45 | pub fn enter(&self) {} 46 | } 47 | -------------------------------------------------------------------------------- /common/kernel/util/bitv.rs: -------------------------------------------------------------------------------- 1 | use core::ptr::{RawPtr, set_memory}; 2 | 3 | // TODO: make an actual bitmap. 4 | 5 | /// A vector of 2-bit values. 6 | pub struct Bitv { 7 | pub storage: *mut u32 8 | } 9 | 10 | impl Bitv { 11 | #[inline] 12 | pub fn get(&self, i: uint) -> u8 { 13 | let w = (i / 16) as int; 14 | let b = (i % 16) * 2; 15 | unsafe { 16 | (*self.storage.offset(w) as uint >> b) as u8 & 3 17 | } 18 | } 19 | 20 | #[inline] 21 | pub fn set(&self, i: uint, x: u8) { 22 | let w = (i / 16) as int; 23 | let b = (i % 16) * 2; 24 | unsafe { 25 | *self.storage.offset(w) = *self.storage.offset(w) & !(3 << b) | (x as u32 << b) 26 | } 27 | } 28 | 29 | #[inline] 30 | fn as_mut_ptr(&self) -> *mut u8 { 31 | self.storage as *mut u8 32 | } 33 | 34 | pub fn clear(&self, capacity: uint) { 35 | unsafe { 36 | set_memory(self.as_mut_ptr(), 0, capacity / 4); 37 | } 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /common/kernel/util/mod.rs: -------------------------------------------------------------------------------- 1 | pub mod bitv; 2 | 3 | #[cfg(target_word_size = "32")] 4 | pub mod rt; 5 | -------------------------------------------------------------------------------- /common/kernel/util/rt.rs: -------------------------------------------------------------------------------- 1 | /* rt.rs 2 | */ 3 | 4 | use core::intrinsics::{ctlz32, cttz32}; 5 | use core::mem::{transmute, size_of}; 6 | 7 | mod detail { 8 | extern { 9 | #[link_name = "llvm.debugtrap"] 10 | pub fn breakpoint(); 11 | } 12 | } 13 | 14 | #[no_mangle] 15 | pub fn breakpoint() { 16 | unsafe { detail::breakpoint() } 17 | } 18 | -------------------------------------------------------------------------------- /common/lib.rs: -------------------------------------------------------------------------------- 1 | #![crate_name = "main"] 2 | #![crate_type = "staticlib"] 3 | #![no_std] 4 | #![feature(asm, macro_rules, default_type_params, phase, globs, lang_items, intrinsics)] 5 | 6 | // The plugin phase imports compiler plugins, including regular macros. 7 | 8 | #[phase(plugin, link)] 9 | extern crate core; 10 | 11 | #[cfg(target_arch = "x86")] 12 | pub use platform::runtime::{memset, memcpy, memmove}; 13 | #[cfg(target_arch = "arm")] 14 | pub use rust_core::support::{memcpy, memmove}; 15 | 16 | pub use platform::cpu; 17 | pub use kernel::util; 18 | 19 | mod macros; 20 | 21 | mod rust_core; 22 | 23 | pub mod kernel; 24 | 25 | #[allow(dead_code)] 26 | #[cfg(target_arch = "x86")] 27 | #[path = "../arch/x86/"] 28 | mod platform { 29 | pub mod cpu; 30 | pub mod io; 31 | pub mod drivers; 32 | pub mod runtime; 33 | } 34 | 35 | #[allow(dead_code)] 36 | #[cfg(target_arch = "arm")] 37 | #[path = "../arch/arm/"] 38 | mod platform { 39 | pub mod cpu; 40 | pub mod io; 41 | pub mod drivers; 42 | } 43 | 44 | mod std { 45 | // macros refer to absolute paths 46 | pub use core::{cmp, clone}; 47 | pub use core::fmt; 48 | pub use core::option; 49 | } 50 | -------------------------------------------------------------------------------- /common/macros.rs: -------------------------------------------------------------------------------- 1 | #![macro_escape] 2 | 3 | macro_rules! define_reg ( 4 | ( 5 | $Reg:ident, $flags:ident: $T:ty { 6 | $($flag:ident $(= $v:expr)*),* 7 | } 8 | ) => ( 9 | bitflags!(flags $flags: $T { $( const $flag $(= $v)* ),* }) 10 | 11 | pub struct $Reg; 12 | 13 | impl_ops!($Reg, $flags, $flags, $Reg::read(), $flags) 14 | ) 15 | ) 16 | 17 | macro_rules! impl_ops ( 18 | ($T:ident, $RHS:ident) => ( 19 | impl core::ops::BitOr<$RHS, $T> for $T { 20 | #[inline(always)] 21 | fn bitor(&self, other: &$RHS) -> $T { 22 | match (*self, other) { 23 | ($T(p), &$RHS(f)) => $T(p | f) 24 | } 25 | } 26 | } 27 | 28 | impl core::ops::BitAnd<$RHS, $T> for $T { 29 | #[inline(always)] 30 | fn bitand(&self, other: &$RHS) -> $T { 31 | match (*self, other) { 32 | ($T(p), &$RHS(f)) => $T(p & f) 33 | } 34 | } 35 | } 36 | 37 | impl core::ops::Sub<$RHS, $T> for $T { 38 | #[inline(always)] 39 | fn sub(&self, other: &$RHS) -> $T { 40 | match (*self, other) { 41 | ($T(flags1), &$RHS(flags2)) => $T(flags1 & !flags2) 42 | } 43 | } 44 | } 45 | ); 46 | 47 | ($LHS:ident, $RHS:ident, $T:ident, $e:expr, $X:ident) => ( 48 | impl core::ops::BitOr<$RHS, $T> for $LHS { 49 | #[inline(always)] 50 | fn bitor(&self, other: &$RHS) -> $T { 51 | match ($e, other) { 52 | ($X(p), &$RHS(f)) => $T(p | f) 53 | } 54 | } 55 | } 56 | 57 | impl core::ops::BitAnd<$RHS, $T> for $LHS { 58 | #[inline(always)] 59 | fn bitand(&self, other: &$RHS) -> $T { 60 | match ($e, other) { 61 | ($X(p), &$RHS(f)) => $T(p & f) 62 | } 63 | } 64 | } 65 | 66 | impl core::ops::Sub<$RHS, $T> for $LHS { 67 | #[inline(always)] 68 | fn sub(&self, other: &$RHS) -> $T { 69 | match ($e, other) { 70 | ($X(flags1), &$RHS(flags2)) => $T(flags1 & !flags2) 71 | } 72 | } 73 | } 74 | ) 75 | ) 76 | 77 | macro_rules! print( 78 | ($($arg:tt)*) => (format_args!(::platform::io::print_args, $($arg)*)) 79 | ) 80 | 81 | macro_rules! println( 82 | ($($arg:tt)*) => (format_args!(::platform::io::println_args, $($arg)*)) 83 | ) 84 | -------------------------------------------------------------------------------- /common/rust_core/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 | #![experimental] 12 | #![macro_escape] 13 | 14 | //! A typesafe bitmask flag generator. 15 | 16 | /// The `bitflags!` macro generates a `struct` that holds a set of C-style 17 | /// bitmask flags. It is useful for creating typesafe wrappers for C APIs. 18 | /// 19 | /// The flags should only be defined for integer types, otherwise unexpected 20 | /// type errors may occur at compile time. 21 | /// 22 | /// # Example 23 | /// 24 | /// ```{.rust} 25 | /// bitflags! { 26 | /// flags Flags: u32 { 27 | /// const FLAG_A = 0x00000001, 28 | /// const FLAG_B = 0x00000010, 29 | /// const FLAG_C = 0x00000100, 30 | /// const FLAG_ABC = FLAG_A.bits 31 | /// | FLAG_B.bits 32 | /// | FLAG_C.bits, 33 | /// } 34 | /// } 35 | /// 36 | /// fn main() { 37 | /// let e1 = FLAG_A | FLAG_C; 38 | /// let e2 = FLAG_B | FLAG_C; 39 | /// assert!((e1 | e2) == FLAG_ABC); // union 40 | /// assert!((e1 & e2) == FLAG_C); // intersection 41 | /// assert!((e1 - e2) == FLAG_A); // set difference 42 | /// assert!(!e2 == FLAG_A); // set complement 43 | /// } 44 | /// ``` 45 | /// 46 | /// The generated `struct`s can also be extended with type and trait implementations: 47 | /// 48 | /// ```{.rust} 49 | /// use std::fmt; 50 | /// 51 | /// bitflags! { 52 | /// flags Flags: u32 { 53 | /// const FLAG_A = 0x00000001, 54 | /// const FLAG_B = 0x00000010, 55 | /// } 56 | /// } 57 | /// 58 | /// impl Flags { 59 | /// pub fn clear(&mut self) { 60 | /// self.bits = 0; // The `bits` field can be accessed from within the 61 | /// // same module where the `bitflags!` macro was invoked. 62 | /// } 63 | /// } 64 | /// 65 | /// impl fmt::Show for Flags { 66 | /// fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 67 | /// write!(f, "hi!") 68 | /// } 69 | /// } 70 | /// 71 | /// fn main() { 72 | /// let mut flags = FLAG_A | FLAG_B; 73 | /// flags.clear(); 74 | /// assert!(flags.is_empty()); 75 | /// assert_eq!(format!("{}", flags).as_slice(), "hi!"); 76 | /// } 77 | /// ``` 78 | /// 79 | /// # Attributes 80 | /// 81 | /// Attributes can be attached to the generated `struct` by placing them 82 | /// before the `flags` keyword. 83 | /// 84 | /// # Derived traits 85 | /// 86 | /// The `PartialEq` and `Clone` traits are automatically derived for the `struct` using 87 | /// the `deriving` attribute. Additional traits can be derived by providing an 88 | /// explicit `deriving` attribute on `flags`. 89 | /// 90 | /// # Operators 91 | /// 92 | /// The following operator traits are implemented for the generated `struct`: 93 | /// 94 | /// - `BitOr`: union 95 | /// - `BitAnd`: intersection 96 | /// - `BitXor`: toggle 97 | /// - `Sub`: set difference 98 | /// - `Not`: set complement 99 | /// 100 | /// # Methods 101 | /// 102 | /// The following methods are defined for the generated `struct`: 103 | /// 104 | /// - `empty`: an empty set of flags 105 | /// - `all`: the set of all flags 106 | /// - `bits`: the raw value of the flags currently stored 107 | /// - `is_empty`: `true` if no flags are currently stored 108 | /// - `is_all`: `true` if all flags are currently set 109 | /// - `intersects`: `true` if there are flags common to both `self` and `other` 110 | /// - `contains`: `true` all of the flags in `other` are contained within `self` 111 | /// - `insert`: inserts the specified flags in-place 112 | /// - `remove`: removes the specified flags in-place 113 | /// - `toggle`: the specified flags will be inserted if not present, and removed 114 | /// if they are. 115 | #[macro_export] 116 | macro_rules! bitflags { 117 | ($(#[$attr:meta])* flags $BitFlags:ident: $T:ty { 118 | $($(#[$Flag_attr:meta])* const $Flag:ident = $value:expr),+ 119 | }) => { 120 | #[deriving(PartialEq, Eq, Clone, PartialOrd, Ord)] 121 | $(#[$attr])* 122 | pub struct $BitFlags { 123 | bits: $T, 124 | } 125 | 126 | $($(#[$Flag_attr])* pub const $Flag: $BitFlags = $BitFlags { bits: $value };)+ 127 | 128 | impl $BitFlags { 129 | /// Returns an empty set of flags. 130 | #[inline] 131 | pub fn empty() -> $BitFlags { 132 | $BitFlags { bits: 0 } 133 | } 134 | 135 | /// Returns the set containing all flags. 136 | #[inline] 137 | pub fn all() -> $BitFlags { 138 | $BitFlags { bits: $($value)|+ } 139 | } 140 | 141 | /// Returns the raw value of the flags currently stored. 142 | #[inline] 143 | pub fn bits(&self) -> $T { 144 | self.bits 145 | } 146 | 147 | /// Convert from underlying bit representation, unless that 148 | /// representation contains bits that do not correspond to a flag. 149 | #[inline] 150 | pub fn from_bits(bits: $T) -> ::std::option::Option<$BitFlags> { 151 | if (bits & !$BitFlags::all().bits()) != 0 { 152 | ::std::option::None 153 | } else { 154 | ::std::option::Some($BitFlags { bits: bits }) 155 | } 156 | } 157 | 158 | /// Convert from underlying bit representation, dropping any bits 159 | /// that do not correspond to flags. 160 | #[inline] 161 | pub fn from_bits_truncate(bits: $T) -> $BitFlags { 162 | $BitFlags { bits: bits } & $BitFlags::all() 163 | } 164 | 165 | /// Returns `true` if no flags are currently stored. 166 | #[inline] 167 | pub fn is_empty(&self) -> bool { 168 | *self == $BitFlags::empty() 169 | } 170 | 171 | /// Returns `true` if all flags are currently set. 172 | #[inline] 173 | pub fn is_all(&self) -> bool { 174 | *self == $BitFlags::all() 175 | } 176 | 177 | /// Returns `true` if there are flags common to both `self` and `other`. 178 | #[inline] 179 | pub fn intersects(&self, other: $BitFlags) -> bool { 180 | !(*self & other).is_empty() 181 | } 182 | 183 | /// Returns `true` all of the flags in `other` are contained within `self`. 184 | #[inline] 185 | pub fn contains(&self, other: $BitFlags) -> bool { 186 | (*self & other) == other 187 | } 188 | 189 | /// Inserts the specified flags in-place. 190 | #[inline] 191 | pub fn insert(&mut self, other: $BitFlags) { 192 | self.bits |= other.bits; 193 | } 194 | 195 | /// Removes the specified flags in-place. 196 | #[inline] 197 | pub fn remove(&mut self, other: $BitFlags) { 198 | self.bits &= !other.bits; 199 | } 200 | 201 | /// Toggles the specified flags in-place. 202 | #[inline] 203 | pub fn toggle(&mut self, other: $BitFlags) { 204 | self.bits ^= other.bits; 205 | } 206 | } 207 | 208 | impl core::ops::BitOr<$BitFlags, $BitFlags> for $BitFlags { 209 | /// Returns the union of the two sets of flags. 210 | #[inline] 211 | fn bitor(&self, other: &$BitFlags) -> $BitFlags { 212 | $BitFlags { bits: self.bits | other.bits } 213 | } 214 | } 215 | 216 | impl core::ops::BitXor<$BitFlags, $BitFlags> for $BitFlags { 217 | /// Returns the left flags, but with all the right flags toggled. 218 | #[inline] 219 | fn bitxor(&self, other: &$BitFlags) -> $BitFlags { 220 | $BitFlags { bits: self.bits ^ other.bits } 221 | } 222 | } 223 | 224 | impl core::ops::BitAnd<$BitFlags, $BitFlags> for $BitFlags { 225 | /// Returns the intersection between the two sets of flags. 226 | #[inline] 227 | fn bitand(&self, other: &$BitFlags) -> $BitFlags { 228 | $BitFlags { bits: self.bits & other.bits } 229 | } 230 | } 231 | 232 | impl core::ops::Sub<$BitFlags, $BitFlags> for $BitFlags { 233 | /// Returns the set difference of the two sets of flags. 234 | #[inline] 235 | fn sub(&self, other: &$BitFlags) -> $BitFlags { 236 | $BitFlags { bits: self.bits & !other.bits } 237 | } 238 | } 239 | 240 | impl core::ops::Not<$BitFlags> for $BitFlags { 241 | /// Returns the complement of this set of flags. 242 | #[inline] 243 | fn not(&self) -> $BitFlags { 244 | $BitFlags { bits: !self.bits } & $BitFlags::all() 245 | } 246 | } 247 | }; 248 | ($(#[$attr:meta])* flags $BitFlags:ident: $T:ty { 249 | $($(#[$Flag_attr:meta])* const $Flag:ident = $value:expr),+, 250 | }) => { 251 | bitflags! { 252 | $(#[$attr])* 253 | flags $BitFlags: $T { 254 | $($(#[$Flag_attr])* const $Flag = $value),+ 255 | } 256 | } 257 | }; 258 | } 259 | -------------------------------------------------------------------------------- /common/rust_core/c_types.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 | // Supported: 12 | // - x86-linux-gnu 13 | // - x86_64-linux-gnu 14 | // - arm-linux-gnueabi 15 | 16 | #![allow(non_camel_case_types)] 17 | 18 | pub type c_short = i16; 19 | pub type c_ushort = u16; 20 | 21 | pub type c_int = i32; 22 | pub type c_uint = u32; 23 | 24 | #[cfg(target_word_size = "32")] 25 | pub type c_long = i32; 26 | #[cfg(target_word_size = "32")] 27 | pub type c_ulong = u32; 28 | 29 | #[cfg(target_word_size = "64")] 30 | pub type c_long = i64; 31 | #[cfg(target_word_size = "64")] 32 | pub type c_ulong = u64; 33 | 34 | pub type c_longlong = i64; 35 | pub type c_ulonglong = u64; 36 | 37 | pub type clockid_t = i32; 38 | 39 | pub type time_t = c_long; 40 | 41 | pub struct timespec { 42 | pub tv_sec: time_t, 43 | pub tv_nsec: c_long 44 | } 45 | 46 | pub struct pthread_t { 47 | size: c_ulong 48 | } 49 | 50 | #[cfg(target_word_size = "32")] 51 | pub struct pthread_attr_t { 52 | size: [u32, ..9] 53 | } 54 | #[cfg(target_word_size = "64")] 55 | pub struct pthread_attr_t { 56 | size: [u64, ..7] 57 | } 58 | 59 | #[cfg(target_word_size = "32")] 60 | pub struct pthread_mutex_t { 61 | size: [u32, ..6] 62 | } 63 | #[cfg(target_word_size = "64")] 64 | pub struct pthread_mutex_t { 65 | size: [u64, ..5] 66 | } 67 | 68 | pub struct pthread_mutexattr_t { 69 | size: u32 70 | } 71 | 72 | pub struct pthread_cond_t { 73 | size: [u64, ..6] 74 | } 75 | 76 | pub struct pthread_condattr_t { 77 | size: u32 78 | } 79 | -------------------------------------------------------------------------------- /common/rust_core/fail.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 | // use rust_core::c_types::c_int; // -> i32 12 | 13 | mod detail { 14 | extern { 15 | pub fn abort() -> !; 16 | pub fn breakpoint(); 17 | } 18 | } 19 | 20 | #[inline(always)] 21 | pub fn abort() -> ! { 22 | unsafe { detail::abort() } 23 | } 24 | 25 | pub fn breakpoint() { 26 | unsafe { detail::breakpoint() } 27 | } 28 | 29 | #[inline] 30 | pub fn out_of_memory() -> ! { 31 | abort() 32 | } 33 | 34 | #[cfg(debug)] 35 | #[inline(always)] 36 | pub fn assert(b: bool) { 37 | if !b { 38 | abort() 39 | } 40 | } 41 | 42 | #[cfg(not(debug))] 43 | #[inline(always)] 44 | pub fn assert(_: bool) { 45 | } 46 | 47 | pub static EINTR: i32 = 4; 48 | pub static EBUSY: i32 = 16; 49 | pub static ETIMEDOUT: i32 = 110; 50 | -------------------------------------------------------------------------------- /common/rust_core/macros.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 | #![macro_export] 12 | 13 | extern { 14 | #[link_name = "llvm.expect.i8"] 15 | pub fn u8_expect(val: u8, expected_val: u8) -> u8; 16 | } 17 | 18 | macro_rules! likely( 19 | ($val:expr) => { 20 | { 21 | let x: bool = $val; 22 | unsafe { ::rust_core::macros::u8_expect(x as u8, 1) != 0 } 23 | } 24 | } 25 | ) 26 | 27 | macro_rules! unlikely( 28 | ($val:expr) => { 29 | { 30 | let x: bool = $val; 31 | unsafe { ::rust_core::macros::u8_expect(x as u8, 0) != 0 } 32 | } 33 | } 34 | ) 35 | 36 | macro_rules! thread_local( 37 | ($name:ident, $t:ty, $init:expr) => { 38 | mod $name { 39 | #[thread_local] 40 | pub static mut VALUE: $t = $init; 41 | 42 | #[inline(always)] 43 | pub fn set(value: $t) { 44 | unsafe { 45 | VALUE = value; 46 | } 47 | } 48 | 49 | #[inline(always)] 50 | pub fn get() -> $t { 51 | unsafe { 52 | VALUE 53 | } 54 | } 55 | } 56 | } 57 | ) 58 | -------------------------------------------------------------------------------- /common/rust_core/mod.rs: -------------------------------------------------------------------------------- 1 | // bits of things mined from rust-core 2 | #![macro_escape] 3 | 4 | pub mod c_types; 5 | pub mod fail; 6 | 7 | pub mod bitflags; 8 | 9 | #[cfg(target_arch = "x86")] 10 | #[macro_escape] 11 | pub mod macros; 12 | 13 | #[cfg(target_arch = "arm")] 14 | pub mod support; 15 | -------------------------------------------------------------------------------- /common/rust_core/support.rs: -------------------------------------------------------------------------------- 1 | #![no_std] 2 | #![allow(visible_private_types)] 3 | #![allow(non_camel_case_types)] 4 | 5 | extern "rust-intrinsic" { 6 | fn offset(dst: *mut T, offset: int) -> *mut T; 7 | } 8 | 9 | extern "rust-intrinsic" { 10 | fn offset(dst: *const T, offset: int) -> *const T; 11 | } 12 | 13 | type c_int = i32; 14 | 15 | #[no_mangle] 16 | pub extern "C" fn memcpy(dest: *mut u8, src: *const u8, n: int) { 17 | unsafe { 18 | let mut i = 0; 19 | while i < n { 20 | *(offset(dest, i) as *mut u8) = *(offset(src, i)); 21 | i += 1; 22 | } 23 | } 24 | } 25 | 26 | #[no_mangle] 27 | pub extern "C" fn memmove(dest: *mut u8, src: *const u8, n: int) { 28 | unsafe { 29 | if src < dest as *const u8 { // copy from end 30 | let mut i = n; 31 | while i != 0 { 32 | i -= 1; 33 | *(offset(dest, i) as *mut u8) = *(offset(src, i)); 34 | } 35 | } else { // copy from beginning 36 | let mut i = 0; 37 | while i < n { 38 | *(offset(dest, i) as *mut u8) = *(offset(src, i)); 39 | i += 1; 40 | } 41 | } 42 | } 43 | } 44 | 45 | #[no_mangle] 46 | pub extern "C" fn memset(s: *mut u8, c: c_int, n: int) { 47 | unsafe { 48 | let mut i = 0; 49 | while i < n { 50 | *(offset(s, i) as *mut u8) = c as u8; 51 | i += 1; 52 | } 53 | } 54 | } 55 | --------------------------------------------------------------------------------