├── .cargo └── config.toml ├── .gitignore ├── .gitmodules ├── .travis.yml ├── Cargo.toml ├── LICENSE ├── Makefile ├── README.md ├── arch └── x86 │ ├── asm │ ├── gdt.asm │ ├── idt.asm │ ├── multiboot.asm │ └── runtime.asm │ ├── cpu │ ├── features.rs │ ├── gdt.rs │ ├── idt.rs │ ├── mod.rs │ ├── pic.rs │ └── timer.rs │ ├── io │ └── mod.rs │ ├── keyboard │ └── mod.rs │ ├── mmu │ └── mod.rs │ └── vga │ └── mod.rs ├── bin └── .gitkeep ├── kernel ├── interrupts │ ├── keyboard.rs │ ├── mod.rs │ └── timer.rs ├── keyboard.rs ├── main.rs └── stdio.rs ├── kernel_x86.rs └── link.ld /.cargo/config.toml: -------------------------------------------------------------------------------- 1 | [build] 2 | target = "i686-unknown-linux-gnu" 3 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.o 2 | bin/kernel.bin 3 | Cargo.lock 4 | 5 | /target 6 | **/*.rs.bk 7 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "rlibc"] 2 | path = rlibc 3 | url = https://github.com/alexcrichton/rlibc.git 4 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: rust 2 | 3 | rust: 4 | - nightly 5 | 6 | notifications: 7 | email: 8 | on_success: never 9 | on_failure: always 10 | 11 | sudo: false 12 | 13 | addons: 14 | apt: 15 | packages: 16 | - nasm 17 | - qemu-kvm 18 | 19 | install: 20 | - rustup target add i686-unknown-linux-gnu 21 | 22 | script: 23 | - make 24 | - "{ sleep 10; echo q; } | qemu-system-x86_64 -kernel bin/kernel.bin -monitor stdio -display none" 25 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "element76" 3 | version = "0.1.0" 4 | authors = ["Mathijs van de Nes "] 5 | edition = "2018" 6 | 7 | [lib] 8 | name = "kernel" 9 | path = "kernel_x86.rs" 10 | crate-type = ["staticlib"] 11 | 12 | [dependencies.compiler_builtins] 13 | version = "0.1" 14 | features = ["mem"] 15 | 16 | [profile.dev] 17 | panic = "abort" 18 | # the compiler_builtins crate requires at least some optimizations 19 | opt-level = 1 20 | 21 | [profile.release] 22 | panic = "abort" 23 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2014 Mathijs van de Nes 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | RUSTC?=rustc -g 2 | CARGO?=cargo 3 | NASM?=nasm 4 | LD?=ld 5 | 6 | ARCH_DEPENDENCIES=$(wildcard arch/x86/*/*.rs) 7 | KERNEL_DEPENDENCIES=$(wildcard kernel/*.rs) $(wildcard kernel/*/*.rs) 8 | RUST_DEPENDENCIES=$(ARCH_DEPENDENCIES) $(KERNEL_DEPENDENCIES) 9 | ASSEMBLIES=$(patsubst %.asm, %.o, $(wildcard arch/x86/asm/*.asm)) 10 | TARGET=i686-unknown-linux-gnu 11 | RUSTLIB=target/i686-unknown-linux-gnu/debug/libkernel.a 12 | BINARY=bin/kernel.bin 13 | RUSTC_OPTIONS=--target $(TARGET) -C panic=abort 14 | 15 | all: $(BINARY) 16 | 17 | .PHONY: run 18 | run: $(BINARY) 19 | qemu-system-i386 -kernel $< 20 | 21 | .PHONY: clean 22 | clean: 23 | cargo clean 24 | $(RM) $(BINARY) *.o $(ASSEMBLIES) 25 | 26 | $(ASSEMBLIES): %.o : %.asm 27 | $(NASM) -f elf32 -o $@ $< 28 | 29 | $(RUSTLIB): kernel_x86.rs $(RUST_DEPENDENCIES) 30 | cargo build 31 | 32 | $(BINARY): $(ASSEMBLIES) $(RUSTLIB) 33 | $(LD) -m elf_i386 -T link.ld -o $@ $^ 34 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | element76 2 | ========= 3 | 4 | [![Build Status](https://travis-ci.org/mvdnes/element76.png?branch=master)](https://travis-ci.org/mvdnes/element76) 5 | 6 | An operating system written in Rust 7 | 8 | Build instructions 9 | ------------------ 10 | 11 | Setup rust nightly and install i686 target: 12 | 13 | rustup override nightly 14 | rustup target add i686-unknown-linux-gnu 15 | 16 | Compile: 17 | 18 | - `make` 19 | 20 | Run: 21 | 22 | - `make run` 23 | -------------------------------------------------------------------------------- /arch/x86/asm/gdt.asm: -------------------------------------------------------------------------------- 1 | ; Thanks to http://www.jamesmolloy.co.uk/tutorial_html/4.-The%20GDT%20and%20IDT.html 2 | 3 | global gdt_flush 4 | 5 | gdt_flush: 6 | mov eax, [esp+4] ; Get the pointer to the GDT, passed as a parameter. 7 | lgdt [eax] ; Load the new GDT pointer 8 | 9 | mov ax, 0x10 ; 0x10 is the offset in the GDT to our data segment 10 | mov ds, ax ; Load all data segment selectors 11 | mov es, ax 12 | mov fs, ax 13 | mov gs, ax 14 | mov ss, ax 15 | jmp 0x08:.flush ; 0x08 is the offset to our code segment: Far jump! 16 | .flush: 17 | ret 18 | -------------------------------------------------------------------------------- /arch/x86/asm/idt.asm: -------------------------------------------------------------------------------- 1 | %macro ISR_NOERRCODE 1 ; define a macro, taking one parameter 2 | [GLOBAL isr%1] ; %1 accesses the first parameter. 3 | isr%1: 4 | cli 5 | push byte 0 6 | push byte %1 7 | jmp isr_common_stub 8 | %endmacro 9 | 10 | %macro ISR_ERRCODE 1 11 | [GLOBAL isr%1] 12 | isr%1: 13 | cli 14 | push byte %1 15 | jmp isr_common_stub 16 | %endmacro 17 | 18 | %macro IRQ 2 19 | global irq%1 20 | irq%1: 21 | cli 22 | push byte 0 23 | push byte %2 24 | jmp isr_common_stub 25 | %endmacro 26 | 27 | ISR_NOERRCODE 0 28 | ISR_NOERRCODE 1 29 | ISR_NOERRCODE 2 30 | ISR_NOERRCODE 3 31 | ISR_NOERRCODE 4 32 | ISR_NOERRCODE 5 33 | ISR_NOERRCODE 6 34 | ISR_NOERRCODE 7 35 | ISR_ERRCODE 8 36 | ISR_NOERRCODE 9 37 | ISR_ERRCODE 10 38 | ISR_ERRCODE 11 39 | ISR_ERRCODE 12 40 | ISR_ERRCODE 13 41 | ISR_ERRCODE 14 42 | ISR_NOERRCODE 15 43 | ISR_NOERRCODE 16 44 | ISR_NOERRCODE 17 45 | ISR_NOERRCODE 18 46 | ISR_NOERRCODE 19 47 | ISR_NOERRCODE 20 48 | ISR_NOERRCODE 21 49 | ISR_NOERRCODE 22 50 | ISR_NOERRCODE 23 51 | ISR_NOERRCODE 24 52 | ISR_NOERRCODE 25 53 | ISR_NOERRCODE 26 54 | ISR_NOERRCODE 27 55 | ISR_NOERRCODE 28 56 | ISR_NOERRCODE 29 57 | ISR_NOERRCODE 30 58 | ISR_NOERRCODE 31 59 | 60 | IRQ 0, 32 61 | IRQ 1, 33 62 | IRQ 2, 34 63 | IRQ 3, 35 64 | IRQ 4, 36 65 | IRQ 5, 37 66 | IRQ 6, 38 67 | IRQ 7, 39 68 | IRQ 8, 40 69 | IRQ 9, 41 70 | IRQ 10, 42 71 | IRQ 11, 43 72 | IRQ 12, 44 73 | IRQ 13, 45 74 | IRQ 14, 46 75 | IRQ 15, 47 76 | 77 | global idt_flush ; Allows the C code to call idt_flush(). 78 | 79 | idt_flush: 80 | mov eax, [esp+4] ; Get the pointer to the IDT, passed as a parameter. 81 | lidt [eax] ; Load the IDT pointer. 82 | ret 83 | 84 | extern isr_handler 85 | 86 | ; This is our common ISR stub. It saves the processor state, sets 87 | ; up for kernel mode segments, calls the C-level fault handler, 88 | ; and finally restores the stack frame. 89 | isr_common_stub: 90 | pushad ; Pushes edi,esi,ebp,esp,ebx,edx,ecx,eax 91 | 92 | mov ax, ds ; Lower 16-bits of eax = ds. 93 | push eax ; save the data segment descriptor 94 | 95 | mov ax, 0x10 ; load the kernel data segment descriptor 96 | mov ds, ax 97 | mov es, ax 98 | mov fs, ax 99 | mov gs, ax 100 | 101 | mov eax, esp 102 | sub esp, 512 103 | and esp, -16 104 | fxsave [esp] 105 | push eax 106 | 107 | call isr_handler 108 | 109 | pop eax 110 | fxrstor [esp] 111 | mov esp, eax 112 | 113 | pop eax ; reload the original data segment descriptor 114 | mov ds, ax 115 | mov es, ax 116 | mov fs, ax 117 | mov gs, ax 118 | 119 | popad ; Pops edi,esi,ebp... 120 | add esp, 8 ; Cleans up the pushed error code and pushed ISR number 121 | sti 122 | iret ; pops 5 things at once: CS, EIP, EFLAGS, SS, and ESP 123 | -------------------------------------------------------------------------------- /arch/x86/asm/multiboot.asm: -------------------------------------------------------------------------------- 1 | ;;init.asm 2 | use32 3 | 4 | section .multiboot 5 | ;multiboot spec 6 | align 4 7 | dd 0x1BADB002 ;magic 8 | dd 0x00 ;flags 9 | dd - (0x1BADB002 + 0x00) ;checksum. m+f+c should be zero 10 | -------------------------------------------------------------------------------- /arch/x86/asm/runtime.asm: -------------------------------------------------------------------------------- 1 | global __morestack 2 | 3 | __morestack: 4 | cli 5 | hlt 6 | jmp __morestack 7 | 8 | ; Allocate a 16KiB stack 9 | section .bootstrap_stack 10 | align 4 11 | stack_bottom: 12 | times 16384 db 0 13 | stack_top: 14 | 15 | extern entry 16 | 17 | ; Entry point 18 | section .text 19 | global start 20 | start: 21 | cli 22 | ; Set up the stack 23 | mov esp, stack_top 24 | ; Make everything play nice with segmented stacks - see __morestack below 25 | mov [gs:0x30], dword 0 26 | call entry 27 | jmp hang 28 | 29 | global abort 30 | abort: 31 | jmp hang 32 | 33 | hang: 34 | cli 35 | hlt 36 | jmp hang 37 | -------------------------------------------------------------------------------- /arch/x86/cpu/features.rs: -------------------------------------------------------------------------------- 1 | pub fn enable_sse() { 2 | unsafe { 3 | core::arch::asm!( 4 | "mov eax, cr0", 5 | "and ax, 0xFFFB", 6 | "or ax, 0x2", 7 | "mov cr0, eax", 8 | "mov eax, cr4", 9 | "or ax, (3 << 9)", 10 | "mov cr4, eax", 11 | out("eax") _, 12 | ); 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /arch/x86/cpu/gdt.rs: -------------------------------------------------------------------------------- 1 | /* 2 | * This file contains code for the Global Descriptor Table 3 | * 4 | * See: http://www.jamesmolloy.co.uk/tutorial_html/4.-The%20GDT%20and%20IDT.html 5 | */ 6 | 7 | const GDT_COUNT: usize = 5; 8 | static mut GDT_ENTRIES: [GDTEntry; GDT_COUNT] = [GDTEntry { limit_low: 0, base_low: 0, base_middle: 0, access: 0, granularity: 0, base_high: 0 }; GDT_COUNT]; 9 | static mut GDT_PTR: GDTPointer = GDTPointer { limit: 0, base: 0 }; 10 | 11 | #[repr(packed)] 12 | struct GDTEntry 13 | { 14 | limit_low: u16, 15 | base_low: u16, 16 | base_middle: u8, 17 | access: u8, 18 | granularity: u8, 19 | base_high: u8 20 | } 21 | 22 | impl Copy for GDTEntry {} 23 | impl Clone for GDTEntry { fn clone(&self) -> Self { *self } } 24 | 25 | #[repr(packed)] 26 | struct GDTPointer 27 | { 28 | limit: u16, 29 | base: usize 30 | } 31 | 32 | pub fn init_gdt() 33 | { 34 | unsafe 35 | { 36 | GDT_PTR.limit = (::core::mem::size_of::() * GDT_COUNT - 1) as u16; 37 | GDT_PTR.base = core::ptr::addr_of_mut!(GDT_ENTRIES) as *const [GDTEntry; GDT_COUNT] as usize; 38 | 39 | gdt_set_gate(0, 0, 0, 0, 0); 40 | gdt_set_gate(1, 0, 0xFFFFFFFF, 0x9A, 0xCF); 41 | gdt_set_gate(2, 0, 0xFFFFFFFF, 0x92, 0xCF); 42 | gdt_set_gate(3, 0, 0xFFFFFFFF, 0xFA, 0xCF); 43 | gdt_set_gate(4, 0, 0xFFFFFFFF, 0xF2, 0xCF); 44 | 45 | gdt_flush(core::ptr::addr_of_mut!(GDT_PTR) as *const GDTPointer as u32); 46 | }; 47 | } 48 | 49 | unsafe fn gdt_set_gate(n: usize, base: usize, limit: usize, access: u8, gran: u8) 50 | { 51 | GDT_ENTRIES[n].base_low = (base & 0xFFFF) as u16; 52 | GDT_ENTRIES[n].base_middle = ((base >> 16) & 0xFF) as u8; 53 | GDT_ENTRIES[n].base_high = ((base >> 24) & 0xFF) as u8; 54 | 55 | GDT_ENTRIES[n].limit_low = (limit & 0xFFFF) as u16; 56 | GDT_ENTRIES[n].granularity = ((limit >> 16) & 0x0F) as u8; 57 | 58 | GDT_ENTRIES[n].granularity |= gran & 0xF0; 59 | GDT_ENTRIES[n].access = access; 60 | } 61 | 62 | extern "C" 63 | { 64 | fn gdt_flush(pointer: u32); 65 | } 66 | -------------------------------------------------------------------------------- /arch/x86/cpu/idt.rs: -------------------------------------------------------------------------------- 1 | /* 2 | * This file contains code for the Interrupt Descriptor Table 3 | * 4 | * See: http://www.jamesmolloy.co.uk/tutorial_html/4.-The%20GDT%20and%20IDT.html 5 | */ 6 | 7 | const IDT_COUNT: usize = 256; 8 | static mut IDT_ENTRIES: [IDTEntry; IDT_COUNT] = [IDTEntry { base_low: 0, selector: 0, zero: 0, flags: 0, base_high: 0 }; IDT_COUNT]; 9 | static mut IDT_PTR: IDTPointer = IDTPointer { limit: 0, base: 0 }; 10 | 11 | #[repr(packed)] 12 | struct IDTEntry 13 | { 14 | base_low: u16, 15 | selector: u16, 16 | zero: u8, 17 | flags: u8, 18 | base_high: u16 19 | } 20 | 21 | impl Copy for IDTEntry {} 22 | impl Clone for IDTEntry { fn clone(&self) -> Self { *self } } 23 | 24 | #[repr(packed)] 25 | struct IDTPointer 26 | { 27 | limit: u16, 28 | base: usize 29 | } 30 | 31 | pub fn init_idt() 32 | { 33 | unsafe 34 | { 35 | IDT_PTR.limit = (::core::mem::size_of::() * IDT_COUNT - 1) as u16; 36 | IDT_PTR.base = core::ptr::addr_of_mut!(IDT_ENTRIES) as *const [IDTEntry; IDT_COUNT] as usize; 37 | 38 | idt_set_gate( 0, isr0 as usize, 0x08, 0x8E); 39 | idt_set_gate( 1, isr1 as usize, 0x08, 0x8E); 40 | idt_set_gate( 2, isr2 as usize, 0x08, 0x8E); 41 | idt_set_gate( 3, isr3 as usize, 0x08, 0x8E); 42 | idt_set_gate( 4, isr4 as usize, 0x08, 0x8E); 43 | idt_set_gate( 5, isr5 as usize, 0x08, 0x8E); 44 | idt_set_gate( 6, isr6 as usize, 0x08, 0x8E); 45 | idt_set_gate( 7, isr7 as usize, 0x08, 0x8E); 46 | idt_set_gate( 8, isr8 as usize, 0x08, 0x8E); 47 | idt_set_gate( 9, isr9 as usize, 0x08, 0x8E); 48 | idt_set_gate(10, isr10 as usize, 0x08, 0x8E); 49 | idt_set_gate(11, isr11 as usize, 0x08, 0x8E); 50 | idt_set_gate(12, isr12 as usize, 0x08, 0x8E); 51 | idt_set_gate(13, isr13 as usize, 0x08, 0x8E); 52 | idt_set_gate(14, isr14 as usize, 0x08, 0x8E); 53 | idt_set_gate(15, isr15 as usize, 0x08, 0x8E); 54 | idt_set_gate(16, isr16 as usize, 0x08, 0x8E); 55 | idt_set_gate(17, isr17 as usize, 0x08, 0x8E); 56 | idt_set_gate(18, isr18 as usize, 0x08, 0x8E); 57 | idt_set_gate(19, isr19 as usize, 0x08, 0x8E); 58 | idt_set_gate(20, isr20 as usize, 0x08, 0x8E); 59 | idt_set_gate(21, isr21 as usize, 0x08, 0x8E); 60 | idt_set_gate(22, isr22 as usize, 0x08, 0x8E); 61 | idt_set_gate(23, isr23 as usize, 0x08, 0x8E); 62 | idt_set_gate(24, isr24 as usize, 0x08, 0x8E); 63 | idt_set_gate(25, isr25 as usize, 0x08, 0x8E); 64 | idt_set_gate(26, isr26 as usize, 0x08, 0x8E); 65 | idt_set_gate(27, isr27 as usize, 0x08, 0x8E); 66 | idt_set_gate(28, isr28 as usize, 0x08, 0x8E); 67 | idt_set_gate(29, isr29 as usize, 0x08, 0x8E); 68 | idt_set_gate(30, isr30 as usize, 0x08, 0x8E); 69 | idt_set_gate(31, isr31 as usize, 0x08, 0x8E); 70 | idt_set_gate(32, irq0 as usize, 0x08, 0x8E); 71 | idt_set_gate(33, irq1 as usize, 0x08, 0x8E); 72 | idt_set_gate(34, irq2 as usize, 0x08, 0x8E); 73 | idt_set_gate(35, irq3 as usize, 0x08, 0x8E); 74 | idt_set_gate(36, irq4 as usize, 0x08, 0x8E); 75 | idt_set_gate(37, irq5 as usize, 0x08, 0x8E); 76 | idt_set_gate(38, irq6 as usize, 0x08, 0x8E); 77 | idt_set_gate(39, irq7 as usize, 0x08, 0x8E); 78 | idt_set_gate(40, irq8 as usize, 0x08, 0x8E); 79 | idt_set_gate(41, irq9 as usize, 0x08, 0x8E); 80 | idt_set_gate(42, irq10 as usize, 0x08, 0x8E); 81 | idt_set_gate(43, irq11 as usize, 0x08, 0x8E); 82 | idt_set_gate(44, irq12 as usize, 0x08, 0x8E); 83 | idt_set_gate(45, irq13 as usize, 0x08, 0x8E); 84 | idt_set_gate(46, irq14 as usize, 0x08, 0x8E); 85 | idt_set_gate(47, irq15 as usize, 0x08, 0x8E); 86 | 87 | idt_flush(core::ptr::addr_of_mut!(IDT_PTR) as *const IDTPointer as u32); 88 | } 89 | } 90 | 91 | unsafe fn idt_set_gate(n: usize, base: usize, sel: u16, flags: u8) 92 | { 93 | IDT_ENTRIES[n].base_low = (base & 0xFFFF) as u16; 94 | IDT_ENTRIES[n].base_high = ((base >> 16) & 0xFFFF) as u16; 95 | 96 | IDT_ENTRIES[n].selector = sel; 97 | IDT_ENTRIES[n].zero = 0; 98 | IDT_ENTRIES[n].flags = (flags & 0b11100000) | 0b01110; 99 | } 100 | 101 | extern "C" 102 | { 103 | fn idt_flush(pointer: u32); 104 | fn isr0 (); 105 | fn isr1 (); 106 | fn isr2 (); 107 | fn isr3 (); 108 | fn isr4 (); 109 | fn isr5 (); 110 | fn isr6 (); 111 | fn isr7 (); 112 | fn isr8 (); 113 | fn isr9 (); 114 | fn isr10(); 115 | fn isr11(); 116 | fn isr12(); 117 | fn isr13(); 118 | fn isr14(); 119 | fn isr15(); 120 | fn isr16(); 121 | fn isr17(); 122 | fn isr18(); 123 | fn isr19(); 124 | fn isr20(); 125 | fn isr21(); 126 | fn isr22(); 127 | fn isr23(); 128 | fn isr24(); 129 | fn isr25(); 130 | fn isr26(); 131 | fn isr27(); 132 | fn isr28(); 133 | fn isr29(); 134 | fn isr30(); 135 | fn isr31(); 136 | fn irq0 (); 137 | fn irq1 (); 138 | fn irq2 (); 139 | fn irq3 (); 140 | fn irq4 (); 141 | fn irq5 (); 142 | fn irq6 (); 143 | fn irq7 (); 144 | fn irq8 (); 145 | fn irq9 (); 146 | fn irq10(); 147 | fn irq11(); 148 | fn irq12(); 149 | fn irq13(); 150 | fn irq14(); 151 | fn irq15(); 152 | } 153 | -------------------------------------------------------------------------------- /arch/x86/cpu/mod.rs: -------------------------------------------------------------------------------- 1 | use crate::kernel; 2 | use core::arch::asm; 3 | 4 | mod gdt; 5 | mod idt; 6 | mod pic; 7 | mod timer; 8 | mod features; 9 | 10 | static IRQ_OFFSET: u8 = 0x20; 11 | 12 | #[repr(C)] 13 | pub struct InterruptArguments { 14 | _ds: u32, _edi: u32, _esi: u32, _ebp: u32, _esp: u32, _ebx: u32, _edx: u32, _ecx: u32, _eax: u32, 15 | interrupt_number: u32, 16 | error_code: u32, 17 | _eip: u32, _cs: u32, _eflags: u32, _useresp: u32, _ss: u32, 18 | } 19 | 20 | #[repr(C)] 21 | pub struct SSEData { 22 | data: [u8; 512], 23 | } 24 | 25 | impl Copy for InterruptArguments {} 26 | impl Clone for InterruptArguments { fn clone(&self) -> Self { *self } } 27 | 28 | pub fn idle() 29 | { 30 | unsafe 31 | { 32 | asm!("hlt"); 33 | } 34 | } 35 | 36 | pub fn halt() -> ! 37 | { 38 | loop 39 | { 40 | unsafe 41 | { 42 | asm!( 43 | "cli", 44 | "hlt", 45 | ); 46 | } 47 | } 48 | } 49 | 50 | pub fn request_int3() 51 | { 52 | unsafe 53 | { 54 | asm!("int 0x03"); 55 | } 56 | pic::disable_irq(0); 57 | } 58 | 59 | pub fn setup() 60 | { 61 | features::enable_sse(); 62 | gdt::init_gdt(); 63 | pic::remap_pic(IRQ_OFFSET); 64 | idt::init_idt(); 65 | timer::set_interval(50); 66 | } 67 | 68 | #[no_mangle] 69 | pub extern "C" fn isr_handler(args: &InterruptArguments, _fpu_sse_data: SSEData) 70 | { 71 | kernel::interrupts::handle_interrupt(args.interrupt_number, args.error_code); 72 | 73 | // Ack IRQ 74 | if args.interrupt_number >= (IRQ_OFFSET as u32) 75 | { 76 | pic::acknowledge_irq(args.interrupt_number as u8 - IRQ_OFFSET); 77 | } 78 | } 79 | 80 | pub fn enable_interrupts() 81 | { 82 | pic::enable_irq(0); 83 | pic::enable_irq(1); 84 | unsafe 85 | { 86 | asm!("sti"); 87 | } 88 | } 89 | -------------------------------------------------------------------------------- /arch/x86/cpu/pic.rs: -------------------------------------------------------------------------------- 1 | use crate::platform::io; 2 | 3 | static PIC1: u16 = 0x20; 4 | static PIC1_DATA: u16 = 0x21; 5 | static PIC2: u16 = 0xA0; 6 | static PIC2_DATA: u16 = 0xA1; 7 | 8 | static IRQ_ACK: u8 = 0x20; 9 | static ICW1: u8 = 0x11; 10 | static ICW4: u8 = 0x01; 11 | 12 | pub fn remap_pic(offset: u8) 13 | { 14 | unsafe 15 | { 16 | // Initialize 17 | io::outport(PIC1, ICW1); 18 | io::io_wait(); 19 | io::outport(PIC2, ICW1); 20 | io::io_wait(); 21 | 22 | // Set offset 23 | io::outport(PIC1_DATA, offset); 24 | io::io_wait(); 25 | io::outport(PIC2_DATA, offset + 8); 26 | io::io_wait(); 27 | 28 | // Connect Master to slave 29 | io::outport(PIC1_DATA, 4); 30 | io::io_wait(); 31 | io::outport(PIC2_DATA, 2); 32 | io::io_wait(); 33 | 34 | // Finalize 35 | io::outport(PIC1_DATA, ICW4); 36 | io::io_wait(); 37 | io::outport(PIC2_DATA, ICW4); 38 | io::io_wait(); 39 | 40 | // Disable all interrupts 41 | io::outport(PIC1_DATA, 0xFF); 42 | io::outport(PIC2_DATA, 0xFF); 43 | } 44 | } 45 | 46 | pub fn enable_irq(irq: u32) 47 | { 48 | let (port, line) = if irq < 8 49 | { 50 | (PIC1_DATA, irq) 51 | } 52 | else 53 | { 54 | (PIC2_DATA, irq - 8) 55 | }; 56 | 57 | unsafe 58 | { 59 | let value = io::inport(port) & !(1 << line); 60 | io::outport(port, value); 61 | } 62 | } 63 | 64 | pub fn disable_irq(irq: u32) 65 | { 66 | let (port, line) = if irq < 8 67 | { 68 | (PIC1_DATA, irq) 69 | } 70 | else 71 | { 72 | (PIC2_DATA, irq - 8) 73 | }; 74 | 75 | unsafe 76 | { 77 | let value = io::inport(port) | (1 << line); 78 | io::outport(port, value); 79 | } 80 | } 81 | 82 | pub fn acknowledge_irq(irq: u8) 83 | { 84 | if irq >= 8 85 | { 86 | unsafe { io::outport(PIC2, IRQ_ACK); } 87 | } 88 | unsafe { io::outport(PIC1, IRQ_ACK); } 89 | } 90 | -------------------------------------------------------------------------------- /arch/x86/cpu/timer.rs: -------------------------------------------------------------------------------- 1 | use crate::platform::io; 2 | 3 | static TIMER_COMMAND: u16 = 0x43; 4 | static TIMER_CHANNEL0: u16 = 0x40; 5 | 6 | pub fn set_interval(frequency: u32) 7 | { 8 | let divisor = 1193180 / frequency; 9 | let l = divisor as u8; 10 | let h = (divisor >> 8) as u8; 11 | unsafe 12 | { 13 | io::outport(TIMER_COMMAND, 0x36); // 0x36 tells timer to repeat 14 | io::outport(TIMER_CHANNEL0, l); 15 | io::outport(TIMER_CHANNEL0, h); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /arch/x86/io/mod.rs: -------------------------------------------------------------------------------- 1 | use ::core::arch::asm; 2 | 3 | pub unsafe fn outport(address: u16, value: u8) 4 | { 5 | asm!( 6 | "out dx, al", 7 | in("al") value, 8 | in("dx") address, 9 | ); 10 | } 11 | 12 | pub unsafe fn inport(address: u16) -> u8 13 | { 14 | let result; 15 | asm!( 16 | "in al, dx", 17 | in("dx") address, 18 | out("al") result, 19 | ); 20 | result 21 | } 22 | 23 | pub fn io_wait() 24 | { 25 | unsafe { outport(0x80, 0); }; 26 | } 27 | -------------------------------------------------------------------------------- /arch/x86/keyboard/mod.rs: -------------------------------------------------------------------------------- 1 | use crate::platform; 2 | 3 | pub enum ArchKeyboardAction 4 | { 5 | Down(u8), 6 | Up(u8) 7 | } 8 | 9 | impl Copy for ArchKeyboardAction {} 10 | impl Clone for ArchKeyboardAction { fn clone(&self) -> Self { *self } } 11 | 12 | pub fn get_key() -> ArchKeyboardAction 13 | { 14 | let raw = unsafe { platform::io::inport(0x60) }; 15 | let key = raw & 0x7F; 16 | match raw & 0x80 17 | { 18 | 0 => ArchKeyboardAction::Down(key), 19 | _ => ArchKeyboardAction::Up(key), 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /arch/x86/mmu/mod.rs: -------------------------------------------------------------------------------- 1 | extern "C" 2 | { 3 | static end: u32; 4 | } 5 | 6 | static mut PLACEMENT_ADDRESS: u32 = 0; 7 | 8 | pub fn setup() 9 | { 10 | unsafe 11 | { 12 | PLACEMENT_ADDRESS = end; 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /arch/x86/vga/mod.rs: -------------------------------------------------------------------------------- 1 | use crate::platform::io; 2 | 3 | pub enum Color { 4 | Black = 0, 5 | Blue = 1, 6 | Green = 2, 7 | Cyan = 3, 8 | Red = 4, 9 | Pink = 5, 10 | Brown = 6, 11 | LightGray = 7, 12 | DarkGray = 8, 13 | LightBlue = 9, 14 | LightGreen = 10, 15 | LightCyan = 11, 16 | LightRed = 12, 17 | LightPink = 13, 18 | Yellow = 14, 19 | White = 15, 20 | } 21 | 22 | impl Copy for Color {} 23 | impl Clone for Color { fn clone(&self) -> Self { *self } } 24 | 25 | pub static ROWS: u32 = 25; 26 | pub static COLS: u32 = 80; 27 | 28 | pub fn putc(xpos: u32, ypos: u32, value: u8) 29 | { 30 | if xpos >= COLS || ypos >= ROWS { return } 31 | unsafe 32 | { 33 | *((0xb8000 + ypos * COLS * 2 + xpos * 2) as *mut u8) = value; 34 | } 35 | } 36 | 37 | pub fn setfg(xpos: u32, ypos: u32, value: Color) 38 | { 39 | if xpos >= COLS || ypos >= ROWS { return } 40 | unsafe 41 | { 42 | let ptr = (0xb8000 + ypos * COLS * 2 + xpos * 2 + 1) as *mut u8; 43 | *ptr = (*ptr & 0xF0) | (value as u8 & 0x0F); 44 | } 45 | } 46 | 47 | pub fn setbg(xpos: u32, ypos: u32, value: Color) 48 | { 49 | if xpos >= COLS || ypos >= ROWS { return } 50 | unsafe 51 | { 52 | let ptr = (0xb8000 + ypos * COLS * 2 + xpos * 2 + 1) as *mut u8; 53 | *ptr = (*ptr & 0x0F) | (((value as u8) << 4) & 0x70); 54 | } 55 | } 56 | 57 | pub fn move_cursor(xpos: u32, ypos: u32) 58 | { 59 | if xpos >= COLS || ypos >= COLS { return }; 60 | let pos = ypos * COLS + xpos; 61 | unsafe 62 | { 63 | io::outport(0x3D4, 14); 64 | io::outport(0x3D5, (pos >> 8) as u8); 65 | io::outport(0x3D4, 15); 66 | io::outport(0x3D5, pos as u8); 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /bin/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mvdnes/element76/610f8c802adadf37adba22c53cc4762e7ee3a1c9/bin/.gitkeep -------------------------------------------------------------------------------- /kernel/interrupts/keyboard.rs: -------------------------------------------------------------------------------- 1 | use crate::kernel::stdio::StdioWriter; 2 | use crate::kernel::keyboard::*; 3 | use crate::platform::vga::Color; 4 | use crate::{kernel, platform}; 5 | 6 | static mut SHIFT: u32 = 0; 7 | static mut IRQPRINTER: StdioWriter = StdioWriter{ xpos: 0, ypos: 4, fg: Color::Yellow, bg: Color::LightRed }; 8 | 9 | pub fn keyboard_irq() 10 | { 11 | let mut printer = unsafe { IRQPRINTER }; 12 | match kernel::keyboard::get_key() 13 | { 14 | KeyboardAction::KeyUp(KeyboardKey::Escape) => { platform::cpu::request_int3(); }, 15 | KeyboardAction::KeyUp(KeyboardKey::Shift) => unsafe { SHIFT -= 1; }, 16 | KeyboardAction::KeyDown(key) => match key 17 | { 18 | KeyboardKey::Printable(c, d) => { printer.print_char(if unsafe {SHIFT == 0} {c} else {d}); }, 19 | KeyboardKey::Backspace => { printer.backspace(); }, 20 | KeyboardKey::Return => { printer.crlf(); }, 21 | KeyboardKey::Shift => unsafe { SHIFT += 1; }, 22 | KeyboardKey::Tab => { printer.tab(); }, 23 | KeyboardKey::Unknown(c) => { printer.print_hex(c as u32, 8); printer.print_char(' '); }, 24 | _ => {}, 25 | }, 26 | _ => {}, 27 | }; 28 | unsafe { IRQPRINTER = printer; }; 29 | } 30 | -------------------------------------------------------------------------------- /kernel/interrupts/mod.rs: -------------------------------------------------------------------------------- 1 | use crate::kernel::stdio::StdioWriter; 2 | use crate::platform::vga::Color; 3 | 4 | mod timer; 5 | mod keyboard; 6 | 7 | pub fn handle_interrupt(interrupt_number: u32, error_code: u32) 8 | { 9 | match interrupt_number 10 | { 11 | 0x20 => timer::handle_irq(), 12 | 0x21 => keyboard::keyboard_irq(), 13 | _ => unknown_irq(interrupt_number, error_code), 14 | }; 15 | } 16 | 17 | fn unknown_irq(interrupt_number: u32, error_code: u32) 18 | { 19 | let mut printer = StdioWriter::new(); 20 | printer.fg = Color::White; 21 | printer.bg = Color::Black; 22 | printer.go_to(10, 5); 23 | printer.print_screen("Interrupt received"); 24 | printer.fg = Color::Black; 25 | printer.bg = Color::White; 26 | printer.go_to(10, 6); 27 | printer.print_hex(interrupt_number, 32); 28 | printer.go_to(10, 7); 29 | printer.print_bin(error_code, 32); 30 | } 31 | -------------------------------------------------------------------------------- /kernel/interrupts/timer.rs: -------------------------------------------------------------------------------- 1 | use crate::kernel::stdio::StdioWriter; 2 | use crate::platform::vga::Color; 3 | 4 | static mut TICK: u32 = 48; 5 | 6 | pub fn handle_irq() 7 | { 8 | let mut printer = StdioWriter { xpos: 0, ypos: 10, fg: Color::White, bg: Color::Black }; 9 | let mytick = unsafe 10 | { 11 | TICK = (TICK + 1) % 50; 12 | TICK 13 | }; 14 | if mytick % 25 == 0 15 | { 16 | printer.print_screen(if mytick < 25 { "tick" } else { "tock" }); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /kernel/keyboard.rs: -------------------------------------------------------------------------------- 1 | use crate::platform::keyboard; 2 | use crate::platform::keyboard::ArchKeyboardAction; 3 | 4 | pub enum KeyboardKey 5 | { 6 | Printable(char, char), 7 | Return, 8 | Backspace, 9 | Shift, 10 | Escape, 11 | Tab, 12 | Unknown(u8) 13 | } 14 | 15 | pub enum KeyboardAction 16 | { 17 | KeyUp(KeyboardKey), 18 | KeyDown(KeyboardKey), 19 | } 20 | 21 | pub fn get_key() -> KeyboardAction 22 | { 23 | match keyboard::get_key() 24 | { 25 | ArchKeyboardAction::Down(code) => KeyboardAction::KeyDown(parse_keycode(code)), 26 | ArchKeyboardAction::Up(code) => KeyboardAction::KeyUp(parse_keycode(code)), 27 | } 28 | } 29 | 30 | fn parse_keycode(code: u8) -> KeyboardKey 31 | { 32 | match code 33 | { 34 | 1 => KeyboardKey::Escape, 35 | 2 => KeyboardKey::Printable('1', '!'), 36 | 3 => KeyboardKey::Printable('2', '@'), 37 | 4 => KeyboardKey::Printable('3', '#'), 38 | 5 => KeyboardKey::Printable('4', '$'), 39 | 6 => KeyboardKey::Printable('5', '%'), 40 | 7 => KeyboardKey::Printable('6', '^'), 41 | 8 => KeyboardKey::Printable('7', '&'), 42 | 9 => KeyboardKey::Printable('8', '*'), 43 | 10 => KeyboardKey::Printable('9', '('), 44 | 11 => KeyboardKey::Printable('0', ')'), 45 | 12 => KeyboardKey::Printable('-', '_'), 46 | 13 => KeyboardKey::Printable('=', '+'), 47 | 14 => KeyboardKey::Backspace, 48 | 15 => KeyboardKey::Tab, 49 | 16 => KeyboardKey::Printable('q', 'Q'), 50 | 17 => KeyboardKey::Printable('w', 'W'), 51 | 18 => KeyboardKey::Printable('e', 'E'), 52 | 19 => KeyboardKey::Printable('r', 'R'), 53 | 20 => KeyboardKey::Printable('t', 'T'), 54 | 21 => KeyboardKey::Printable('y', 'Y'), 55 | 22 => KeyboardKey::Printable('u', 'U'), 56 | 23 => KeyboardKey::Printable('i', 'I'), 57 | 24 => KeyboardKey::Printable('o', 'O'), 58 | 25 => KeyboardKey::Printable('p', 'P'), 59 | 26 => KeyboardKey::Printable('[', '{'), 60 | 27 => KeyboardKey::Printable(']', '}'), 61 | 28 => KeyboardKey::Return, 62 | 30 => KeyboardKey::Printable('a', 'A'), 63 | 31 => KeyboardKey::Printable('s', 'S'), 64 | 32 => KeyboardKey::Printable('d', 'D'), 65 | 33 => KeyboardKey::Printable('f', 'F'), 66 | 34 => KeyboardKey::Printable('g', 'G'), 67 | 35 => KeyboardKey::Printable('h', 'H'), 68 | 36 => KeyboardKey::Printable('j', 'J'), 69 | 37 => KeyboardKey::Printable('k', 'K'), 70 | 38 => KeyboardKey::Printable('l', 'L'), 71 | 39 => KeyboardKey::Printable(';', ':'), 72 | 40 => KeyboardKey::Printable('\'', '"'), 73 | 41 => KeyboardKey::Printable('`', '~'), 74 | 42 => KeyboardKey::Shift, 75 | 43 => KeyboardKey::Printable('\\', '|'), 76 | 44 => KeyboardKey::Printable('z', 'Z'), 77 | 45 => KeyboardKey::Printable('x', 'X'), 78 | 46 => KeyboardKey::Printable('c', 'C'), 79 | 47 => KeyboardKey::Printable('v', 'V'), 80 | 48 => KeyboardKey::Printable('b', 'B'), 81 | 49 => KeyboardKey::Printable('n', 'N'), 82 | 50 => KeyboardKey::Printable('m', 'M'), 83 | 51 => KeyboardKey::Printable(',', '<'), 84 | 52 => KeyboardKey::Printable('.', '>'), 85 | 53 => KeyboardKey::Printable('/', '?'), 86 | 54 => KeyboardKey::Shift, 87 | 55 => KeyboardKey::Printable('*', '*'), 88 | 57 => KeyboardKey::Printable(' ', ' '), 89 | 71 => KeyboardKey::Printable('7', '7'), 90 | 72 => KeyboardKey::Printable('8', '8'), 91 | 73 => KeyboardKey::Printable('9', '9'), 92 | 74 => KeyboardKey::Printable('-', '-'), 93 | 75 => KeyboardKey::Printable('4', '4'), 94 | 76 => KeyboardKey::Printable('5', '5'), 95 | 77 => KeyboardKey::Printable('6', '6'), 96 | 78 => KeyboardKey::Printable('+', '+'), 97 | 79 => KeyboardKey::Printable('1', '1'), 98 | 80 => KeyboardKey::Printable('2', '2'), 99 | 81 => KeyboardKey::Printable('3', '3'), 100 | 82 => KeyboardKey::Printable('0', '0'), 101 | 83 => KeyboardKey::Printable('.', '.'), 102 | c => KeyboardKey::Unknown(c), 103 | } 104 | } 105 | -------------------------------------------------------------------------------- /kernel/main.rs: -------------------------------------------------------------------------------- 1 | use crate::platform::vga::Color; 2 | use crate::kernel::stdio::StdioWriter; 3 | use crate::platform; 4 | use core::fmt::Write; 5 | use core::panic::PanicInfo; 6 | 7 | #[no_mangle] 8 | pub fn entry() -> ! 9 | { 10 | platform::cpu::setup(); 11 | platform::mmu::setup(); 12 | platform::cpu::enable_interrupts(); 13 | main(); 14 | loop { platform::cpu::idle(); } 15 | } 16 | 17 | fn main() 18 | { 19 | let mut printer = StdioWriter::new(); 20 | printer.bg = Color::Red; 21 | printer.fg = Color::Yellow; 22 | printer.clear_screen(); 23 | printer.fg = Color::White; 24 | printer.go_to(3, 3); 25 | printer.print_screen("Hello, World!"); 26 | } 27 | 28 | #[panic_handler] 29 | #[no_mangle] 30 | pub fn panic(info: &PanicInfo) -> ! 31 | { 32 | let mut printer = StdioWriter::new(); 33 | printer.bg = Color::Black; 34 | printer.fg = Color::Red; 35 | 36 | printer.print_screen("RUST FAIL"); 37 | printer.crlf(); 38 | 39 | if let Some(location) = info.location() { 40 | let _ = writeln!(printer, "Panic in '{}' at line {}", location.file(), location.line()); 41 | } 42 | else { 43 | let _ = writeln!(printer, "Panic at unknown location"); 44 | } 45 | let _ = write!(printer, "{}", info.message()); 46 | 47 | platform::cpu::halt(); 48 | } 49 | -------------------------------------------------------------------------------- /kernel/stdio.rs: -------------------------------------------------------------------------------- 1 | use crate::platform::vga::{Color, COLS, ROWS}; 2 | use crate::platform::vga; 3 | 4 | pub struct StdioWriter 5 | { 6 | pub xpos: u32, 7 | pub ypos: u32, 8 | pub fg: Color, 9 | pub bg: Color 10 | } 11 | 12 | impl Copy for StdioWriter {} 13 | impl Clone for StdioWriter { fn clone(&self) -> Self { *self } } 14 | 15 | impl StdioWriter 16 | { 17 | pub fn new() -> StdioWriter 18 | { 19 | StdioWriter 20 | { 21 | xpos: 0, 22 | ypos: 0, 23 | fg: Color::White, 24 | bg: Color::Black 25 | } 26 | } 27 | 28 | pub fn clear_screen(&mut self) 29 | { 30 | for y in 0u32 .. ROWS 31 | { 32 | for x in 0u32 .. COLS 33 | { 34 | vga::putc(x, y, 0); 35 | vga::setfg(x, y, self.fg); 36 | vga::setbg(x, y, self.bg); 37 | } 38 | } 39 | self.go_to(0, 0); 40 | } 41 | 42 | pub fn go_to(&mut self, x: u32, y: u32) 43 | { 44 | self.move_coords(x, y); 45 | self.set_cursor(); 46 | } 47 | 48 | pub fn backspace(&mut self) 49 | { 50 | self.go_left(); 51 | self.raw_print_char(' ' as u8); 52 | self.set_cursor(); 53 | } 54 | 55 | pub fn tab(&mut self) 56 | { 57 | let x = self.xpos; 58 | for _ in 0 .. 4 - (x % 4) 59 | { 60 | self.raw_print_char(' ' as u8); 61 | self.go_right(); 62 | } 63 | self.set_cursor(); 64 | } 65 | 66 | pub fn crlf(&mut self) 67 | { 68 | self.xpos = 0; 69 | self.ypos = if self.ypos == ROWS - 1 { 0 } else { self.ypos + 1 }; 70 | self.set_cursor(); 71 | } 72 | 73 | fn go_right(&mut self) 74 | { 75 | if self.xpos == COLS - 1 76 | { 77 | self.xpos = 0; 78 | self.ypos = (self.ypos + ROWS + 1) % ROWS; 79 | } 80 | else 81 | { 82 | self.xpos += 1; 83 | } 84 | } 85 | 86 | fn go_left(&mut self) 87 | { 88 | if self.xpos == 0 89 | { 90 | self.xpos = COLS - 1; 91 | self.ypos = (self.ypos + ROWS - 1) % ROWS; 92 | } 93 | else 94 | { 95 | self.xpos -= 1; 96 | } 97 | } 98 | 99 | fn move_coords(&mut self, x: u32, y: u32) 100 | { 101 | let mut newx = x; 102 | let mut newy = y; 103 | if newx >= COLS { newx = 0; newy += 1; } 104 | if newy >= ROWS { newy = 0; } 105 | self.xpos = newx; 106 | self.ypos = newy; 107 | } 108 | 109 | fn set_cursor(&self) 110 | { 111 | vga::move_cursor(self.xpos, self.ypos); 112 | } 113 | 114 | pub fn print_bin(&mut self, v: u32, sz: u32) 115 | { 116 | self.print_screen("0b"); 117 | 118 | let mut i = (sz - 1) as i32; 119 | while i >= 0 120 | { 121 | let c = match (v >> (i as u32)) & 0x1 122 | { 123 | 0 => '0', 124 | _ => '1', 125 | } as u8; 126 | self.raw_print_char(c); 127 | self.go_right(); 128 | i -= 1; 129 | } 130 | self.set_cursor(); 131 | } 132 | 133 | pub fn print_hex(&mut self, v: u32, sz: u32) 134 | { 135 | self.print_screen("0x"); 136 | 137 | let mut i = (sz - 4) as i32; 138 | while i >= 0 139 | { 140 | let c = match (v >> (i as u32)) & 0xF 141 | { 142 | c if c <= 9 => c + '0' as u32, 143 | c => c - 10 + 'A' as u32, 144 | } as u8; 145 | self.raw_print_char(c); 146 | self.go_right(); 147 | i -= 4; 148 | } 149 | self.set_cursor(); 150 | } 151 | 152 | pub fn print_char(&mut self, value: char) 153 | { 154 | self.raw_print_char(value as u8); 155 | self.go_right(); 156 | self.set_cursor(); 157 | } 158 | 159 | fn raw_print_char(&self, value: u8) 160 | { 161 | vga::putc(self.xpos, self.ypos, value); 162 | vga::setfg(self.xpos, self.ypos, self.fg); 163 | vga::setbg(self.xpos, self.ypos, self.bg); 164 | } 165 | 166 | pub fn print_screen(&mut self, value: &str) 167 | { 168 | for c in value.bytes() 169 | { 170 | self.raw_print_char(c); 171 | self.go_right(); 172 | } 173 | self.set_cursor(); 174 | } 175 | } 176 | 177 | impl ::core::fmt::Write for StdioWriter 178 | { 179 | fn write_str(&mut self, s: &str) -> ::core::fmt::Result 180 | { 181 | for b in s.bytes() 182 | { 183 | if b == b'\n' { 184 | self.xpos = 0; 185 | self.ypos = if self.ypos == ROWS - 1 { 0 } else { self.ypos + 1 }; 186 | } 187 | else { 188 | self.raw_print_char(b); 189 | self.go_right(); 190 | } 191 | } 192 | self.set_cursor(); 193 | Ok(()) 194 | } 195 | } 196 | -------------------------------------------------------------------------------- /kernel_x86.rs: -------------------------------------------------------------------------------- 1 | #![no_std] 2 | 3 | #![allow(internal_features)] 4 | #![feature(lang_items)] 5 | 6 | #[path = "arch/x86/"] 7 | pub mod platform { 8 | pub mod vga; 9 | pub mod cpu; 10 | pub mod mmu; 11 | mod io; 12 | pub mod keyboard; 13 | } 14 | 15 | pub mod kernel { 16 | pub mod main; 17 | pub mod interrupts; 18 | mod stdio; 19 | mod keyboard; 20 | } 21 | 22 | #[no_mangle] 23 | pub extern "C" fn _Unwind_Resume() -> ! { 24 | loop {} 25 | } 26 | 27 | #[lang = "eh_personality"] 28 | #[no_mangle] 29 | pub extern "C" fn eh_personality() {} 30 | -------------------------------------------------------------------------------- /link.ld: -------------------------------------------------------------------------------- 1 | /* 2 | * link.ld 3 | */ 4 | OUTPUT_FORMAT(elf32-i386) 5 | ENTRY(start) 6 | SECTIONS 7 | { 8 | . = 0x100000; 9 | .text : 10 | { 11 | *(.multiboot) 12 | *(.bootstrap_stack) 13 | *(.text) 14 | . = ALIGN(4096); 15 | KEEP(*(.multiboot)) 16 | } 17 | .data : 18 | { 19 | *(.data) 20 | . = ALIGN(4096); 21 | } 22 | .bss : 23 | { 24 | *(.bss) 25 | . = ALIGN(4096); 26 | } 27 | end = .; 28 | } 29 | --------------------------------------------------------------------------------