From 2629945c72ccbf0b8888792ef44e04bff29c8277 Mon Sep 17 00:00:00 2001 From: Philipp Oppermann Date: Fri, 2 Feb 2018 13:27:46 +0100 Subject: [PATCH] Delete code from first edition --- Cargo.toml | 18 +- Makefile | 82 --------- Xargo.toml | 2 - libs/bump_allocator/.gitignore | 2 - src/arch/x86_64/boot.asm | 202 ---------------------- src/arch/x86_64/grub.cfg | 16 -- src/arch/x86_64/linker.ld | 64 ------- src/arch/x86_64/long_mode_init.asm | 34 ---- src/arch/x86_64/multiboot_header.asm | 24 --- src/interrupts/gdt.rs | 95 ---------- src/interrupts/mod.rs | 120 ------------- src/lib.rs | 112 ------------ src/memory/area_frame_allocator.rs | 104 ----------- src/memory/mod.rs | 154 ----------------- src/memory/paging/entry.rs | 78 --------- src/memory/paging/mapper.rs | 125 -------------- src/memory/paging/mod.rs | 248 --------------------------- src/memory/paging/table.rs | 136 --------------- src/memory/paging/temporary_page.rs | 91 ---------- src/memory/stack_allocator.rs | 81 --------- src/vga_buffer.rs | 150 ---------------- 21 files changed, 1 insertion(+), 1937 deletions(-) delete mode 100644 Makefile delete mode 100644 Xargo.toml delete mode 100644 libs/bump_allocator/.gitignore delete mode 100644 src/arch/x86_64/boot.asm delete mode 100644 src/arch/x86_64/grub.cfg delete mode 100644 src/arch/x86_64/linker.ld delete mode 100644 src/arch/x86_64/long_mode_init.asm delete mode 100644 src/arch/x86_64/multiboot_header.asm delete mode 100644 src/interrupts/gdt.rs delete mode 100644 src/interrupts/mod.rs delete mode 100644 src/lib.rs delete mode 100644 src/memory/area_frame_allocator.rs delete mode 100644 src/memory/mod.rs delete mode 100644 src/memory/paging/entry.rs delete mode 100644 src/memory/paging/mapper.rs delete mode 100644 src/memory/paging/mod.rs delete mode 100644 src/memory/paging/table.rs delete mode 100644 src/memory/paging/temporary_page.rs delete mode 100644 src/memory/stack_allocator.rs delete mode 100644 src/vga_buffer.rs diff --git a/Cargo.toml b/Cargo.toml index 74109d7e..dcd35135 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,22 +1,6 @@ [package] authors = ["Philipp Oppermann "] name = "blog_os" -version = "0.1.0" +version = "0.2.0" [dependencies] -bit_field = "0.7.0" -bitflags = "0.9.1" -multiboot2 = "0.1.0" -once = "0.3.2" -rlibc = "1.0" -spin = "0.4.5" -volatile = "0.1.0" -x86_64 = "0.1.2" -linked_list_allocator = "0.4.2" - -[dependencies.lazy_static] -features = ["spin_no_std"] -version = "0.2.1" - -[lib] -crate-type = ["staticlib"] diff --git a/Makefile b/Makefile deleted file mode 100644 index 31b5e12c..00000000 --- a/Makefile +++ /dev/null @@ -1,82 +0,0 @@ -# Copyright 2016 Philipp Oppermann. See the README.md -# file at the top-level directory of this distribution. -# -# Licensed under the Apache License, Version 2.0 or the MIT license -# , at your -# option. This file may not be copied, modified, or distributed -# except according to those terms. - -arch ?= x86_64 -target ?= $(arch)-blog_os -kernel := build/kernel-$(arch).bin -iso := build/os-$(arch).iso - -rust_os := target/$(target)/debug/libblog_os.a -linker_script := src/arch/$(arch)/linker.ld -grub_cfg := src/arch/$(arch)/grub.cfg -assembly_source_files := $(wildcard src/arch/$(arch)/*.asm) -assembly_object_files := $(patsubst src/arch/$(arch)/%.asm, \ - build/arch/$(arch)/%.o, $(assembly_source_files)) - -# used by docker_* targets -docker_image ?= blog_os -tag ?= 0.1 -docker_cargo_volume ?= blogos-$(shell id -u)-$(shell id -g)-cargo -docker_rustup_volume ?= blogos-$(shell id -u)-$(shell id -g)-rustup -docker_args ?= -e LOCAL_UID=$(shell id -u) -e LOCAL_GID=$(shell id -g) -v $(docker_cargo_volume):/usr/local/cargo -v $(docker_rustup_volume):/usr/local/rustup -v $(shell pwd):$(shell pwd) -w $(shell pwd) -docker_clean_args ?= $(docker_cargo_volume) $(docker_rustup_volume) - -.PHONY: all clean run debug iso cargo gdb - -all: $(kernel) - -clean: - @cargo clean - @rm -rf build - -run: $(iso) - @qemu-system-x86_64 -cdrom $(iso) -s - -debug: $(iso) - @qemu-system-x86_64 -cdrom $(iso) -s -S - -# docker_* targets - -docker_build: - @docker build docker/ -t $(docker_image):$(tag) - -docker_iso: - @docker run --rm $(docker_args) $(docker_image):$(tag) make iso - -docker_run: docker_iso - @qemu-system-x86_64 -cdrom $(iso) -s - -docker_interactive: - @docker run -it --rm $(docker_args) $(docker_image):$(tag) - -docker_clean: - @docker volume rm $(docker_clean_args) - -gdb: - @rust-os-gdb/bin/rust-gdb "build/kernel-x86_64.bin" -ex "target remote :1234" - -iso: $(iso) - -$(iso): $(kernel) $(grub_cfg) - @mkdir -p build/isofiles/boot/grub - @cp $(kernel) build/isofiles/boot/kernel.bin - @cp $(grub_cfg) build/isofiles/boot/grub - @grub-mkrescue -o $(iso) build/isofiles 2> /dev/null - @rm -r build/isofiles - -$(kernel): cargo $(rust_os) $(assembly_object_files) $(linker_script) - @ld -n --gc-sections -T $(linker_script) -o $(kernel) $(assembly_object_files) $(rust_os) - -cargo: - @RUST_TARGET_PATH="$(shell pwd)" xargo build --target $(target) - -# compile assembly files -build/arch/$(arch)/%.o: src/arch/$(arch)/%.asm - @mkdir -p $(shell dirname $@) - @nasm -felf64 $< -o $@ diff --git a/Xargo.toml b/Xargo.toml deleted file mode 100644 index 73f2a1d2..00000000 --- a/Xargo.toml +++ /dev/null @@ -1,2 +0,0 @@ -[target.x86_64-blog_os.dependencies] -alloc = {} diff --git a/libs/bump_allocator/.gitignore b/libs/bump_allocator/.gitignore deleted file mode 100644 index 49d4fed9..00000000 --- a/libs/bump_allocator/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -# Generated by Cargo -/target/ diff --git a/src/arch/x86_64/boot.asm b/src/arch/x86_64/boot.asm deleted file mode 100644 index 0fcffc79..00000000 --- a/src/arch/x86_64/boot.asm +++ /dev/null @@ -1,202 +0,0 @@ -; Copyright 2016 Philipp Oppermann. See the README.md -; file at the top-level directory of this distribution. -; -; Licensed under the Apache License, Version 2.0 or the MIT license -; , at your -; option. This file may not be copied, modified, or distributed -; except according to those terms. - -global start -extern long_mode_start - -section .text -bits 32 -start: - mov esp, stack_top - ; Move Multiboot info pointer to edi to pass it to the kernel. We must not - ; modify the `edi` register until the kernel it called. - mov edi, ebx - - call check_multiboot - call check_cpuid - call check_long_mode - - call set_up_page_tables - call enable_paging - call set_up_SSE - - ; load the 64-bit GDT - lgdt [gdt64.pointer] - - jmp gdt64.code:long_mode_start - -set_up_page_tables: - ; recursive map P4 - mov eax, p4_table - or eax, 0b11 ; present + writable - mov [p4_table + 511 * 8], eax - - ; map first P4 entry to P3 table - mov eax, p3_table - or eax, 0b11 ; present + writable - mov [p4_table], eax - - ; map first P3 entry to P2 table - mov eax, p2_table - or eax, 0b11 ; present + writable - mov [p3_table], eax - - ; map each P2 entry to a huge 2MiB page - mov ecx, 0 ; counter variable -.map_p2_table: - ; map ecx-th P2 entry to a huge page that starts at address (2MiB * ecx) - mov eax, 0x200000 ; 2MiB - mul ecx ; start address of ecx-th page - or eax, 0b10000011 ; present + writable + huge - mov [p2_table + ecx * 8], eax ; map ecx-th entry - - inc ecx ; increase counter - cmp ecx, 512 ; if counter == 512, the whole P2 table is mapped - jne .map_p2_table ; else map the next entry - - ret - -enable_paging: - ; load P4 to cr3 register (cpu uses this to access the P4 table) - mov eax, p4_table - mov cr3, eax - - ; enable PAE-flag in cr4 (Physical Address Extension) - mov eax, cr4 - or eax, 1 << 5 - mov cr4, eax - - ; set the long mode bit in the EFER MSR (model specific register) - mov ecx, 0xC0000080 - rdmsr - or eax, 1 << 8 - wrmsr - - ; enable paging in the cr0 register - mov eax, cr0 - or eax, 1 << 31 - mov cr0, eax - - ret - -; Prints `ERR: ` and the given error code to screen and hangs. -; parameter: error code (in ascii) in al -error: - mov dword [0xb8000], 0x4f524f45 - mov dword [0xb8004], 0x4f3a4f52 - mov dword [0xb8008], 0x4f204f20 - mov byte [0xb800a], al - hlt - -; Throw error 0 if eax doesn't contain the Multiboot 2 magic value (0x36d76289). -check_multiboot: - cmp eax, 0x36d76289 - jne .no_multiboot - ret -.no_multiboot: - mov al, "0" - jmp error - -; Throw error 1 if the CPU doesn't support the CPUID command. -check_cpuid: - ; Check if CPUID is supported by attempting to flip the ID bit (bit 21) in - ; the FLAGS register. If we can flip it, CPUID is available. - - ; Copy FLAGS in to EAX via stack - pushfd - pop eax - - ; Copy to ECX as well for comparing later on - mov ecx, eax - - ; Flip the ID bit - xor eax, 1 << 21 - - ; Copy EAX to FLAGS via the stack - push eax - popfd - - ; Copy FLAGS back to EAX (with the flipped bit if CPUID is supported) - pushfd - pop eax - - ; Restore FLAGS from the old version stored in ECX (i.e. flipping the ID bit - ; back if it was ever flipped). - push ecx - popfd - - ; Compare EAX and ECX. If they are equal then that means the bit wasn't - ; flipped, and CPUID isn't supported. - cmp eax, ecx - je .no_cpuid - ret -.no_cpuid: - mov al, "1" - jmp error - -; Throw error 2 if the CPU doesn't support Long Mode. -check_long_mode: - ; test if extended processor info in available - mov eax, 0x80000000 ; implicit argument for cpuid - cpuid ; get highest supported argument - cmp eax, 0x80000001 ; it needs to be at least 0x80000001 - jb .no_long_mode ; if it's less, the CPU is too old for long mode - - ; use extended info to test if long mode is available - mov eax, 0x80000001 ; argument for extended processor info - cpuid ; returns various feature bits in ecx and edx - test edx, 1 << 29 ; test if the LM-bit is set in the D-register - jz .no_long_mode ; If it's not set, there is no long mode - ret -.no_long_mode: - mov al, "2" - jmp error - -; Check for SSE and enable it. If it's not supported throw error "a". -set_up_SSE: - ; check for SSE - mov eax, 0x1 - cpuid - test edx, 1<<25 - jz .no_SSE - - ; enable SSE - mov eax, cr0 - and ax, 0xFFFB ; clear coprocessor emulation CR0.EM - or ax, 0x2 ; set coprocessor monitoring CR0.MP - mov cr0, eax - mov eax, cr4 - or ax, 3 << 9 ; set CR4.OSFXSR and CR4.OSXMMEXCPT at the same time - mov cr4, eax - - ret -.no_SSE: - mov al, "a" - jmp error - -section .bss -align 4096 -p4_table: - resb 4096 -p3_table: - resb 4096 -p2_table: - resb 4096 -stack_bottom: - resb 4096 * 4 -stack_top: - -section .rodata -gdt64: - dq 0 ; zero entry -.code: equ $ - gdt64 ; new - dq (1<<44) | (1<<47) | (1<<43) | (1<<53) ; code segment -.pointer: - dw $ - gdt64 - 1 - dq gdt64 diff --git a/src/arch/x86_64/grub.cfg b/src/arch/x86_64/grub.cfg deleted file mode 100644 index dbe53c10..00000000 --- a/src/arch/x86_64/grub.cfg +++ /dev/null @@ -1,16 +0,0 @@ -# Copyright 2016 Philipp Oppermann. See the README.md -# file at the top-level directory of this distribution. -# -# Licensed under the Apache License, Version 2.0 or the MIT license -# , at your -# option. This file may not be copied, modified, or distributed -# except according to those terms. - -set timeout=0 -set default=0 - -menuentry "my os" { - multiboot2 /boot/kernel.bin - boot -} diff --git a/src/arch/x86_64/linker.ld b/src/arch/x86_64/linker.ld deleted file mode 100644 index 62f8f266..00000000 --- a/src/arch/x86_64/linker.ld +++ /dev/null @@ -1,64 +0,0 @@ -/* -Copyright 2016 Philipp Oppermann. See the README.md -file at the top-level directory of this distribution. - -Licensed under the Apache License, Version 2.0 or the MIT license -, at your -option. This file may not be copied, modified, or distributed -except according to those terms. -*/ - -ENTRY(start) - -SECTIONS { - . = 1M; - - .rodata : - { - /* ensure that the multiboot header is at the beginning */ - KEEP(*(.multiboot_header)) - *(.rodata .rodata.*) - . = ALIGN(4K); - } - - .text : - { - *(.text .text.*) - . = ALIGN(4K); - } - - .data : - { - *(.data .data.*) - . = ALIGN(4K); - } - - .bss : - { - *(.bss .bss.*) - . = ALIGN(4K); - } - - .got : - { - *(.got) - . = ALIGN(4K); - } - - .got.plt : - { - *(.got.plt) - . = ALIGN(4K); - } - - .data.rel.ro : ALIGN(4K) { - *(.data.rel.ro.local*) *(.data.rel.ro .data.rel.ro.*) - . = ALIGN(4K); - } - - .gcc_except_table : ALIGN(4K) { - *(.gcc_except_table) - . = ALIGN(4K); - } -} diff --git a/src/arch/x86_64/long_mode_init.asm b/src/arch/x86_64/long_mode_init.asm deleted file mode 100644 index 79b4c025..00000000 --- a/src/arch/x86_64/long_mode_init.asm +++ /dev/null @@ -1,34 +0,0 @@ -; Copyright 2016 Philipp Oppermann. See the README.md -; file at the top-level directory of this distribution. -; -; Licensed under the Apache License, Version 2.0 or the MIT license -; , at your -; option. This file may not be copied, modified, or distributed -; except according to those terms. - -global long_mode_start -extern rust_main - -section .text -bits 64 -long_mode_start: - ; load 0 into all data segment registers - mov ax, 0 - mov ss, ax - mov ds, ax - mov es, ax - mov fs, ax - mov gs, ax - - ; call rust main (with multiboot pointer in rdi) - call rust_main -.os_returned: - ; rust main returned, print `OS returned!` - mov rax, 0x4f724f204f534f4f - mov [0xb8000], rax - mov rax, 0x4f724f754f744f65 - mov [0xb8008], rax - mov rax, 0x4f214f644f654f6e - mov [0xb8010], rax - hlt diff --git a/src/arch/x86_64/multiboot_header.asm b/src/arch/x86_64/multiboot_header.asm deleted file mode 100644 index 0b3f83bb..00000000 --- a/src/arch/x86_64/multiboot_header.asm +++ /dev/null @@ -1,24 +0,0 @@ -; Copyright 2016 Philipp Oppermann. See the README.md -; file at the top-level directory of this distribution. -; -; Licensed under the Apache License, Version 2.0 or the MIT license -; , at your -; option. This file may not be copied, modified, or distributed -; except according to those terms. - -section .multiboot_header -header_start: - dd 0xe85250d6 ; magic number (multiboot 2) - dd 0 ; architecture 0 (protected mode i386) - dd header_end - header_start ; header length - ; checksum - dd 0x100000000 - (0xe85250d6 + 0 + (header_end - header_start)) - - ; insert optional multiboot tags here - - ; required end tag - dw 0 ; type - dw 0 ; flags - dd 8 ; size -header_end: diff --git a/src/interrupts/gdt.rs b/src/interrupts/gdt.rs deleted file mode 100644 index 5ea28e31..00000000 --- a/src/interrupts/gdt.rs +++ /dev/null @@ -1,95 +0,0 @@ -use x86_64::structures::tss::TaskStateSegment; -use x86_64::structures::gdt::SegmentSelector; -use x86_64::PrivilegeLevel; - -pub struct Gdt { - table: [u64; 8], - next_free: usize, -} - -impl Gdt { - pub fn new() -> Gdt { - Gdt { - table: [0; 8], - next_free: 1, - } - } - - pub fn add_entry(&mut self, entry: Descriptor) -> SegmentSelector { - let index = match entry { - Descriptor::UserSegment(value) => self.push(value), - Descriptor::SystemSegment(value_low, value_high) => { - let index = self.push(value_low); - self.push(value_high); - index - } - }; - SegmentSelector::new(index as u16, PrivilegeLevel::Ring0) - } - - fn push(&mut self, value: u64) -> usize { - if self.next_free < self.table.len() { - let index = self.next_free; - self.table[index] = value; - self.next_free += 1; - index - } else { - panic!("GDT full"); - } - } - - pub fn load(&'static self) { - use x86_64::instructions::tables::{DescriptorTablePointer, lgdt}; - use core::mem::size_of; - - let ptr = DescriptorTablePointer { - base: self.table.as_ptr() as u64, - limit: (self.table.len() * size_of::() - 1) as u16, - }; - - unsafe { lgdt(&ptr) }; - } -} - -pub enum Descriptor { - UserSegment(u64), - SystemSegment(u64, u64), -} - -impl Descriptor { - pub fn kernel_code_segment() -> Descriptor { - let flags = USER_SEGMENT | PRESENT | EXECUTABLE | LONG_MODE; - Descriptor::UserSegment(flags.bits()) - } - - pub fn tss_segment(tss: &'static TaskStateSegment) -> Descriptor { - use core::mem::size_of; - use bit_field::BitField; - - let ptr = tss as *const _ as u64; - - let mut low = PRESENT.bits(); - // base - low.set_bits(16..40, ptr.get_bits(0..24)); - low.set_bits(56..64, ptr.get_bits(24..32)); - // limit (the `-1` in needed since the bound is inclusive) - low.set_bits(0..16, (size_of::() - 1) as u64); - // type (0b1001 = available 64-bit tss) - low.set_bits(40..44, 0b1001); - - let mut high = 0; - high.set_bits(0..32, ptr.get_bits(32..64)); - - Descriptor::SystemSegment(low, high) - } -} - -bitflags! { - struct DescriptorFlags: u64 { - const CONFORMING = 1 << 42; - const EXECUTABLE = 1 << 43; - const USER_SEGMENT = 1 << 44; - const PRESENT = 1 << 47; - const LONG_MODE = 1 << 53; - } -} diff --git a/src/interrupts/mod.rs b/src/interrupts/mod.rs deleted file mode 100644 index c4da624a..00000000 --- a/src/interrupts/mod.rs +++ /dev/null @@ -1,120 +0,0 @@ -// Copyright 2016 Philipp Oppermann. See the README.md -// file at the top-level directory of this distribution. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -use memory::MemoryController; -use x86_64::structures::tss::TaskStateSegment; -use x86_64::structures::idt::{Idt, ExceptionStackFrame, PageFaultErrorCode}; -use spin::Once; - -mod gdt; - -const DOUBLE_FAULT_IST_INDEX: usize = 0; - -lazy_static! { - static ref IDT: Idt = { - let mut idt = Idt::new(); - - idt.divide_by_zero.set_handler_fn(divide_by_zero_handler); - idt.breakpoint.set_handler_fn(breakpoint_handler); - idt.invalid_opcode.set_handler_fn(invalid_opcode_handler); - idt.page_fault.set_handler_fn(page_fault_handler); - - unsafe { - idt.double_fault.set_handler_fn(double_fault_handler) - .set_stack_index(DOUBLE_FAULT_IST_INDEX as u16); - } - - idt - }; -} - -static TSS: Once = Once::new(); -static GDT: Once = Once::new(); - -pub fn init(memory_controller: &mut MemoryController) { - use x86_64::structures::gdt::SegmentSelector; - use x86_64::instructions::segmentation::set_cs; - use x86_64::instructions::tables::load_tss; - use x86_64::VirtualAddress; - - let double_fault_stack = memory_controller - .alloc_stack(1) - .expect("could not allocate double fault stack"); - - let tss = TSS.call_once(|| { - let mut tss = TaskStateSegment::new(); - tss.interrupt_stack_table[DOUBLE_FAULT_IST_INDEX] = - VirtualAddress(double_fault_stack.top()); - tss - }); - - let mut code_selector = SegmentSelector(0); - let mut tss_selector = SegmentSelector(0); - let gdt = GDT.call_once(|| { - let mut gdt = gdt::Gdt::new(); - code_selector = gdt.add_entry(gdt::Descriptor::kernel_code_segment()); - tss_selector = gdt.add_entry(gdt::Descriptor::tss_segment(&tss)); - gdt - }); - gdt.load(); - - unsafe { - // reload code segment register - set_cs(code_selector); - // load TSS - load_tss(tss_selector); - } - - IDT.load(); -} - -extern "x86-interrupt" fn divide_by_zero_handler(stack_frame: &mut ExceptionStackFrame) { - println!("\nEXCEPTION: DIVIDE BY ZERO\n{:#?}", stack_frame); - loop {} -} - -extern "x86-interrupt" fn breakpoint_handler(stack_frame: &mut ExceptionStackFrame) { - println!( - "\nEXCEPTION: BREAKPOINT at {:#x}\n{:#?}", - stack_frame.instruction_pointer, - stack_frame - ); -} - -extern "x86-interrupt" fn invalid_opcode_handler(stack_frame: &mut ExceptionStackFrame) { - println!( - "\nEXCEPTION: INVALID OPCODE at {:#x}\n{:#?}", - stack_frame.instruction_pointer, - stack_frame - ); - loop {} -} - -extern "x86-interrupt" fn page_fault_handler( - stack_frame: &mut ExceptionStackFrame, - error_code: PageFaultErrorCode, -) { - use x86_64::registers::control_regs; - println!( - "\nEXCEPTION: PAGE FAULT while accessing {:#x}\nerror code: \ - {:?}\n{:#?}", - control_regs::cr2(), - error_code, - stack_frame - ); - loop {} -} - -extern "x86-interrupt" fn double_fault_handler( - stack_frame: &mut ExceptionStackFrame, - _error_code: u64, -) { - println!("\nEXCEPTION: DOUBLE FAULT\n{:#?}", stack_frame); - loop {} -} diff --git a/src/lib.rs b/src/lib.rs deleted file mode 100644 index ef14939f..00000000 --- a/src/lib.rs +++ /dev/null @@ -1,112 +0,0 @@ -// Copyright 2016 Philipp Oppermann. See the README.md -// file at the top-level directory of this distribution. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -#![feature(lang_items)] -#![feature(const_fn, unique)] -#![feature(alloc)] -#![feature(asm)] -#![feature(naked_functions)] -#![feature(abi_x86_interrupt)] -#![feature(const_unique_new, const_atomic_usize_new)] -#![feature(allocator_api)] -#![feature(global_allocator)] -#![no_std] - -#[macro_use] -extern crate alloc; -extern crate rlibc; -extern crate volatile; -extern crate spin; -extern crate multiboot2; -#[macro_use] -extern crate bitflags; -extern crate x86_64; -#[macro_use] -extern crate once; -extern crate linked_list_allocator; -#[macro_use] -extern crate lazy_static; -extern crate bit_field; -#[macro_use] -mod vga_buffer; -mod memory; -mod interrupts; - -#[no_mangle] -pub extern "C" fn rust_main(multiboot_information_address: usize) { - // ATTENTION: we have a very small stack and no guard page - vga_buffer::clear_screen(); - println!("Hello World{}", "!"); - - let boot_info = unsafe { multiboot2::load(multiboot_information_address) }; - enable_nxe_bit(); - enable_write_protect_bit(); - - // set up guard page and map the heap pages - let mut memory_controller = memory::init(boot_info); - - unsafe { - HEAP_ALLOCATOR.lock().init(HEAP_START, HEAP_SIZE); - } - - // initialize our IDT - interrupts::init(&mut memory_controller); - - fn stack_overflow() { - stack_overflow(); // for each recursion, the return address is pushed - } - - // trigger a stack overflow - stack_overflow(); - - - println!("It did not crash!"); - loop {} -} - -fn enable_nxe_bit() { - use x86_64::registers::msr::{IA32_EFER, rdmsr, wrmsr}; - - let nxe_bit = 1 << 11; - unsafe { - let efer = rdmsr(IA32_EFER); - wrmsr(IA32_EFER, efer | nxe_bit); - } -} - -fn enable_write_protect_bit() { - use x86_64::registers::control_regs::{cr0, cr0_write, Cr0}; - - unsafe { cr0_write(cr0() | Cr0::WRITE_PROTECT) }; -} - -#[cfg(not(test))] -#[lang = "eh_personality"] -#[no_mangle] -pub extern "C" fn eh_personality() {} - -#[cfg(not(test))] -#[lang = "panic_fmt"] -#[no_mangle] -pub extern "C" fn panic_fmt(fmt: core::fmt::Arguments, file: &'static str, line: u32) -> ! { - println!("\n\nPANIC in {} at line {}:", file, line); - println!(" {}", fmt); - loop {} -} - -#[no_mangle] -pub extern "C" fn _Unwind_Resume() -> ! { loop {} } - -use linked_list_allocator::LockedHeap; - -pub const HEAP_START: usize = 0o_000_001_000_000_0000; -pub const HEAP_SIZE: usize = 100 * 1024; // 100 KiB - -#[global_allocator] -static HEAP_ALLOCATOR: LockedHeap = LockedHeap::empty(); diff --git a/src/memory/area_frame_allocator.rs b/src/memory/area_frame_allocator.rs deleted file mode 100644 index 2afa3130..00000000 --- a/src/memory/area_frame_allocator.rs +++ /dev/null @@ -1,104 +0,0 @@ -// Copyright 2016 Philipp Oppermann. See the README.md -// file at the top-level directory of this distribution. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -use memory::{Frame, FrameAllocator}; -use multiboot2::{MemoryAreaIter, MemoryArea}; - -/// A frame allocator that uses the memory areas from the multiboot information structure as -/// source. The {kernel, multiboot}_{start, end} fields are used to avoid returning memory that is -/// already in use. -/// -/// `kernel_end` and `multiboot_end` are _inclusive_ bounds. -pub struct AreaFrameAllocator { - next_free_frame: Frame, - current_area: Option<&'static MemoryArea>, - areas: MemoryAreaIter, - kernel_start: Frame, - kernel_end: Frame, - multiboot_start: Frame, - multiboot_end: Frame, -} - -impl AreaFrameAllocator { - pub fn new( - kernel_start: usize, - kernel_end: usize, - multiboot_start: usize, - multiboot_end: usize, - memory_areas: MemoryAreaIter, - ) -> AreaFrameAllocator { - let mut allocator = AreaFrameAllocator { - next_free_frame: Frame::containing_address(0), - current_area: None, - areas: memory_areas, - kernel_start: Frame::containing_address(kernel_start), - kernel_end: Frame::containing_address(kernel_end), - multiboot_start: Frame::containing_address(multiboot_start), - multiboot_end: Frame::containing_address(multiboot_end), - }; - allocator.choose_next_area(); - allocator - } - - fn choose_next_area(&mut self) { - self.current_area = self.areas - .clone() - .filter(|area| { - let address = area.base_addr + area.length - 1; - Frame::containing_address(address as usize) >= self.next_free_frame - }) - .min_by_key(|area| area.base_addr); - - if let Some(area) = self.current_area { - let start_frame = Frame::containing_address(area.base_addr as usize); - if self.next_free_frame < start_frame { - self.next_free_frame = start_frame; - } - } - } -} - -impl FrameAllocator for AreaFrameAllocator { - fn allocate_frame(&mut self) -> Option { - if let Some(area) = self.current_area { - // "clone" the frame to return it if it's free. Frame doesn't - // implement Clone, but we can construct an identical frame. - let frame = Frame { number: self.next_free_frame.number }; - - // the last frame of the current area - let current_area_last_frame = { - let address = area.base_addr + area.length - 1; - Frame::containing_address(address as usize) - }; - - if frame > current_area_last_frame { - // all frames of current area are used, switch to next area - self.choose_next_area(); - } else if frame >= self.kernel_start && frame <= self.kernel_end { - // `frame` is used by the kernel - self.next_free_frame = Frame { number: self.kernel_end.number + 1 }; - } else if frame >= self.multiboot_start && frame <= self.multiboot_end { - // `frame` is used by the multiboot information structure - self.next_free_frame = Frame { number: self.multiboot_end.number + 1 }; - } else { - // frame is unused, increment `next_free_frame` and return it - self.next_free_frame.number += 1; - return Some(frame); - } - // `frame` was not valid, try it again with the updated `next_free_frame` - self.allocate_frame() - } else { - None // no free frames left - } - } - - fn deallocate_frame(&mut self, _frame: Frame) { - unimplemented!() - } -} diff --git a/src/memory/mod.rs b/src/memory/mod.rs deleted file mode 100644 index fc1a7dce..00000000 --- a/src/memory/mod.rs +++ /dev/null @@ -1,154 +0,0 @@ -// Copyright 2016 Philipp Oppermann. See the README.md -// file at the top-level directory of this distribution. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -pub use self::area_frame_allocator::AreaFrameAllocator; -pub use self::paging::remap_the_kernel; -pub use self::stack_allocator::Stack; -use self::paging::PhysicalAddress; -use multiboot2::BootInformation; - -mod area_frame_allocator; -pub mod heap_allocator; -mod paging; -mod stack_allocator; - -pub const PAGE_SIZE: usize = 4096; - -pub fn init(boot_info: &BootInformation) -> MemoryController { - assert_has_not_been_called!("memory::init must be called only once"); - - let memory_map_tag = boot_info.memory_map_tag().expect("Memory map tag required"); - let elf_sections_tag = boot_info - .elf_sections_tag() - .expect("Elf sections tag required"); - - let kernel_start = elf_sections_tag - .sections() - .filter(|s| s.is_allocated()) - .map(|s| s.addr) - .min() - .unwrap(); - let kernel_end = elf_sections_tag - .sections() - .filter(|s| s.is_allocated()) - .map(|s| s.addr + s.size) - .max() - .unwrap(); - - println!( - "kernel start: {:#x}, kernel end: {:#x}", - kernel_start, - kernel_end - ); - println!( - "multiboot start: {:#x}, multiboot end: {:#x}", - boot_info.start_address(), - boot_info.end_address() - ); - - let mut frame_allocator = AreaFrameAllocator::new( - kernel_start as usize, - kernel_end as usize, - boot_info.start_address(), - boot_info.end_address(), - memory_map_tag.memory_areas(), - ); - - let mut active_table = paging::remap_the_kernel(&mut frame_allocator, boot_info); - - use self::paging::Page; - use super::{HEAP_START, HEAP_SIZE}; - - let heap_start_page = Page::containing_address(HEAP_START); - let heap_end_page = Page::containing_address(HEAP_START + HEAP_SIZE - 1); - - for page in Page::range_inclusive(heap_start_page, heap_end_page) { - active_table.map(page, paging::WRITABLE, &mut frame_allocator); - } - - let stack_allocator = { - let stack_alloc_start = heap_end_page + 1; - let stack_alloc_end = stack_alloc_start + 100; - let stack_alloc_range = Page::range_inclusive(stack_alloc_start, stack_alloc_end); - stack_allocator::StackAllocator::new(stack_alloc_range) - }; - - MemoryController { - active_table: active_table, - frame_allocator: frame_allocator, - stack_allocator: stack_allocator, - } -} - -pub struct MemoryController { - active_table: paging::ActivePageTable, - frame_allocator: AreaFrameAllocator, - stack_allocator: stack_allocator::StackAllocator, -} - -impl MemoryController { - pub fn alloc_stack(&mut self, size_in_pages: usize) -> Option { - let &mut MemoryController { - ref mut active_table, - ref mut frame_allocator, - ref mut stack_allocator, - } = self; - stack_allocator.alloc_stack(active_table, frame_allocator, size_in_pages) - } -} - -#[derive(Debug, PartialEq, Eq, PartialOrd, Ord)] -pub struct Frame { - number: usize, -} - -impl Frame { - fn containing_address(address: usize) -> Frame { - Frame { number: address / PAGE_SIZE } - } - - fn start_address(&self) -> PhysicalAddress { - self.number * PAGE_SIZE - } - - fn clone(&self) -> Frame { - Frame { number: self.number } - } - - fn range_inclusive(start: Frame, end: Frame) -> FrameIter { - FrameIter { - start: start, - end: end, - } - } -} - -struct FrameIter { - start: Frame, - end: Frame, -} - -impl Iterator for FrameIter { - type Item = Frame; - - fn next(&mut self) -> Option { - if self.start <= self.end { - let frame = self.start.clone(); - self.start.number += 1; - Some(frame) - } else { - None - } - } -} - -pub trait FrameAllocator { - fn allocate_frame(&mut self) -> Option; - fn deallocate_frame(&mut self, frame: Frame); -} diff --git a/src/memory/paging/entry.rs b/src/memory/paging/entry.rs deleted file mode 100644 index 5afbcd75..00000000 --- a/src/memory/paging/entry.rs +++ /dev/null @@ -1,78 +0,0 @@ -// Copyright 2016 Philipp Oppermann. See the README.md -// file at the top-level directory of this distribution. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -use memory::Frame; -use multiboot2::ElfSection; - -pub struct Entry(u64); - -impl Entry { - pub fn is_unused(&self) -> bool { - self.0 == 0 - } - - pub fn set_unused(&mut self) { - self.0 = 0; - } - - pub fn flags(&self) -> EntryFlags { - EntryFlags::from_bits_truncate(self.0) - } - - pub fn pointed_frame(&self) -> Option { - if self.flags().contains(PRESENT) { - Some(Frame::containing_address( - self.0 as usize & 0x000fffff_fffff000, - )) - } else { - None - } - } - - pub fn set(&mut self, frame: Frame, flags: EntryFlags) { - assert!(frame.start_address() & !0x000fffff_fffff000 == 0); - self.0 = (frame.start_address() as u64) | flags.bits(); - } -} - -bitflags! { - pub struct EntryFlags: u64 { - const PRESENT = 1 << 0; - const WRITABLE = 1 << 1; - const USER_ACCESSIBLE = 1 << 2; - const WRITE_THROUGH = 1 << 3; - const NO_CACHE = 1 << 4; - const ACCESSED = 1 << 5; - const DIRTY = 1 << 6; - const HUGE_PAGE = 1 << 7; - const GLOBAL = 1 << 8; - const NO_EXECUTE = 1 << 63; - } -} - -impl EntryFlags { - pub fn from_elf_section_flags(section: &ElfSection) -> EntryFlags { - use multiboot2::{ELF_SECTION_ALLOCATED, ELF_SECTION_WRITABLE, ELF_SECTION_EXECUTABLE}; - - let mut flags = EntryFlags::empty(); - - if section.flags().contains(ELF_SECTION_ALLOCATED) { - // section is loaded to memory - flags = flags | PRESENT; - } - if section.flags().contains(ELF_SECTION_WRITABLE) { - flags = flags | WRITABLE; - } - if !section.flags().contains(ELF_SECTION_EXECUTABLE) { - flags = flags | NO_EXECUTE; - } - - flags - } -} diff --git a/src/memory/paging/mapper.rs b/src/memory/paging/mapper.rs deleted file mode 100644 index c46a87cd..00000000 --- a/src/memory/paging/mapper.rs +++ /dev/null @@ -1,125 +0,0 @@ -// Copyright 2016 Philipp Oppermann. See the README.md -// file at the top-level directory of this distribution. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -use super::{VirtualAddress, PhysicalAddress, Page, ENTRY_COUNT}; -use super::entry::*; -use super::table::{self, Table, Level4}; -use memory::{PAGE_SIZE, Frame, FrameAllocator}; -use core::ptr::Unique; - -pub struct Mapper { - p4: Unique>, -} - -impl Mapper { - pub unsafe fn new() -> Mapper { - Mapper { p4: Unique::new_unchecked(table::P4) } - } - - pub fn p4(&self) -> &Table { - unsafe { self.p4.as_ref() } - } - - pub fn p4_mut(&mut self) -> &mut Table { - unsafe { self.p4.as_mut() } - } - - pub fn translate(&self, virtual_address: VirtualAddress) -> Option { - let offset = virtual_address % PAGE_SIZE; - self.translate_page(Page::containing_address(virtual_address)) - .map(|frame| frame.number * PAGE_SIZE + offset) - } - - pub fn translate_page(&self, page: Page) -> Option { - let p3 = self.p4().next_table(page.p4_index()); - - let huge_page = || { - p3.and_then(|p3| { - let p3_entry = &p3[page.p3_index()]; - // 1GiB page? - if let Some(start_frame) = p3_entry.pointed_frame() { - if p3_entry.flags().contains(HUGE_PAGE) { - // address must be 1GiB aligned - assert!(start_frame.number % (ENTRY_COUNT * ENTRY_COUNT) == 0); - return Some(Frame { - number: start_frame.number + page.p2_index() * ENTRY_COUNT + - page.p1_index(), - }); - } - } - if let Some(p2) = p3.next_table(page.p3_index()) { - let p2_entry = &p2[page.p2_index()]; - // 2MiB page? - if let Some(start_frame) = p2_entry.pointed_frame() { - if p2_entry.flags().contains(HUGE_PAGE) { - // address must be 2MiB aligned - assert!(start_frame.number % ENTRY_COUNT == 0); - return Some(Frame { number: start_frame.number + page.p1_index() }); - } - } - } - None - }) - }; - - p3.and_then(|p3| p3.next_table(page.p3_index())) - .and_then(|p2| p2.next_table(page.p2_index())) - .and_then(|p1| p1[page.p1_index()].pointed_frame()) - .or_else(huge_page) - } - - pub fn map_to(&mut self, page: Page, frame: Frame, flags: EntryFlags, allocator: &mut A) - where - A: FrameAllocator, - { - let mut p3 = self.p4_mut().next_table_create(page.p4_index(), allocator); - let mut p2 = p3.next_table_create(page.p3_index(), allocator); - let mut p1 = p2.next_table_create(page.p2_index(), allocator); - - assert!(p1[page.p1_index()].is_unused()); - p1[page.p1_index()].set(frame, flags | PRESENT); - } - - pub fn map(&mut self, page: Page, flags: EntryFlags, allocator: &mut A) - where - A: FrameAllocator, - { - let frame = allocator.allocate_frame().expect("out of memory"); - self.map_to(page, frame, flags, allocator) - } - - pub fn identity_map(&mut self, frame: Frame, flags: EntryFlags, allocator: &mut A) - where - A: FrameAllocator, - { - let page = Page::containing_address(frame.start_address()); - self.map_to(page, frame, flags, allocator) - } - - pub fn unmap(&mut self, page: Page, allocator: &mut A) - where - A: FrameAllocator, - { - use x86_64::VirtualAddress; - use x86_64::instructions::tlb; - - assert!(self.translate(page.start_address()).is_some()); - - let p1 = self.p4_mut() - .next_table_mut(page.p4_index()) - .and_then(|p3| p3.next_table_mut(page.p3_index())) - .and_then(|p2| p2.next_table_mut(page.p2_index())) - .expect("mapping code does not support huge pages"); - let frame = p1[page.p1_index()].pointed_frame().unwrap(); - p1[page.p1_index()].set_unused(); - tlb::flush(VirtualAddress(page.start_address())); - // TODO free p(1,2,3) table if empty - // allocator.deallocate_frame(frame); - } -} diff --git a/src/memory/paging/mod.rs b/src/memory/paging/mod.rs deleted file mode 100644 index 91358528..00000000 --- a/src/memory/paging/mod.rs +++ /dev/null @@ -1,248 +0,0 @@ -// Copyright 2016 Philipp Oppermann. See the README.md -// file at the top-level directory of this distribution. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -pub use self::entry::*; -use memory::{PAGE_SIZE, Frame, FrameAllocator}; -use self::temporary_page::TemporaryPage; -pub use self::mapper::Mapper; -use core::ops::{Add, Deref, DerefMut}; -use multiboot2::BootInformation; - -mod entry; -mod table; -mod temporary_page; -mod mapper; - -const ENTRY_COUNT: usize = 512; - -pub type PhysicalAddress = usize; -pub type VirtualAddress = usize; - -#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)] -pub struct Page { - number: usize, -} - -impl Page { - pub fn containing_address(address: VirtualAddress) -> Page { - assert!( - address < 0x0000_8000_0000_0000 || address >= 0xffff_8000_0000_0000, - "invalid address: 0x{:x}", - address - ); - Page { number: address / PAGE_SIZE } - } - - pub fn start_address(&self) -> usize { - self.number * PAGE_SIZE - } - - fn p4_index(&self) -> usize { - (self.number >> 27) & 0o777 - } - fn p3_index(&self) -> usize { - (self.number >> 18) & 0o777 - } - fn p2_index(&self) -> usize { - (self.number >> 9) & 0o777 - } - fn p1_index(&self) -> usize { - (self.number >> 0) & 0o777 - } - - pub fn range_inclusive(start: Page, end: Page) -> PageIter { - PageIter { - start: start, - end: end, - } - } -} - -impl Add for Page { - type Output = Page; - - fn add(self, rhs: usize) -> Page { - Page { number: self.number + rhs } - } -} - -#[derive(Clone)] -pub struct PageIter { - start: Page, - end: Page, -} - -impl Iterator for PageIter { - type Item = Page; - - fn next(&mut self) -> Option { - if self.start <= self.end { - let page = self.start; - self.start.number += 1; - Some(page) - } else { - None - } - } -} - -pub struct ActivePageTable { - mapper: Mapper, -} - -impl Deref for ActivePageTable { - type Target = Mapper; - - fn deref(&self) -> &Mapper { - &self.mapper - } -} - -impl DerefMut for ActivePageTable { - fn deref_mut(&mut self) -> &mut Mapper { - &mut self.mapper - } -} - -impl ActivePageTable { - unsafe fn new() -> ActivePageTable { - ActivePageTable { mapper: Mapper::new() } - } - - pub fn with( - &mut self, - table: &mut InactivePageTable, - temporary_page: &mut temporary_page::TemporaryPage, // new - f: F, - ) where - F: FnOnce(&mut Mapper), - { - use x86_64::registers::control_regs; - use x86_64::instructions::tlb; - - { - let backup = Frame::containing_address(control_regs::cr3().0 as usize); - - // map temporary_page to current p4 table - let p4_table = temporary_page.map_table_frame(backup.clone(), self); - - // overwrite recursive mapping - self.p4_mut()[511].set(table.p4_frame.clone(), PRESENT | WRITABLE); - tlb::flush_all(); - - // execute f in the new context - f(self); - - // restore recursive mapping to original p4 table - p4_table[511].set(backup, PRESENT | WRITABLE); - tlb::flush_all(); - } - - temporary_page.unmap(self); - } - - pub fn switch(&mut self, new_table: InactivePageTable) -> InactivePageTable { - use x86_64::PhysicalAddress; - use x86_64::registers::control_regs; - - let old_table = InactivePageTable { - p4_frame: Frame::containing_address(control_regs::cr3().0 as usize), - }; - unsafe { - control_regs::cr3_write(PhysicalAddress(new_table.p4_frame.start_address() as u64)); - } - old_table - } -} - -pub struct InactivePageTable { - p4_frame: Frame, -} - -impl InactivePageTable { - pub fn new( - frame: Frame, - active_table: &mut ActivePageTable, - temporary_page: &mut TemporaryPage, - ) -> InactivePageTable { - { - let table = temporary_page.map_table_frame(frame.clone(), active_table); - table.zero(); - table[511].set(frame.clone(), PRESENT | WRITABLE); - } - temporary_page.unmap(active_table); - - InactivePageTable { p4_frame: frame } - } -} - -pub fn remap_the_kernel(allocator: &mut A, boot_info: &BootInformation) -> ActivePageTable -where - A: FrameAllocator, -{ - let mut temporary_page = TemporaryPage::new(Page { number: 0xcafebabe }, allocator); - - let mut active_table = unsafe { ActivePageTable::new() }; - let mut new_table = { - let frame = allocator.allocate_frame().expect("no more frames"); - InactivePageTable::new(frame, &mut active_table, &mut temporary_page) - }; - - active_table.with(&mut new_table, &mut temporary_page, |mapper| { - let elf_sections_tag = boot_info - .elf_sections_tag() - .expect("Memory map tag required"); - - // identity map the allocated kernel sections - for section in elf_sections_tag.sections() { - if !section.is_allocated() { - // section is not loaded to memory - continue; - } - - assert!( - section.addr as usize % PAGE_SIZE == 0, - "sections need to be page aligned" - ); - println!( - "mapping section at addr: {:#x}, size: {:#x}", - section.addr, - section.size - ); - - let flags = EntryFlags::from_elf_section_flags(section); - - let start_frame = Frame::containing_address(section.start_address()); - let end_frame = Frame::containing_address(section.end_address() - 1); - for frame in Frame::range_inclusive(start_frame, end_frame) { - mapper.identity_map(frame, flags, allocator); - } - } - - // identity map the VGA text buffer - let vga_buffer_frame = Frame::containing_address(0xb8000); - mapper.identity_map(vga_buffer_frame, WRITABLE, allocator); - - // identity map the multiboot info structure - let multiboot_start = Frame::containing_address(boot_info.start_address()); - let multiboot_end = Frame::containing_address(boot_info.end_address() - 1); - for frame in Frame::range_inclusive(multiboot_start, multiboot_end) { - mapper.identity_map(frame, PRESENT, allocator); - } - }); - - let old_table = active_table.switch(new_table); - println!("NEW TABLE!!!"); - - let old_p4_page = Page::containing_address(old_table.p4_frame.start_address()); - active_table.unmap(old_p4_page, allocator); - println!("guard page at {:#x}", old_p4_page.start_address()); - - active_table -} diff --git a/src/memory/paging/table.rs b/src/memory/paging/table.rs deleted file mode 100644 index f94afc42..00000000 --- a/src/memory/paging/table.rs +++ /dev/null @@ -1,136 +0,0 @@ -// Copyright 2016 Philipp Oppermann. See the README.md -// file at the top-level directory of this distribution. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -use memory::paging::entry::*; -use memory::paging::ENTRY_COUNT; -use memory::FrameAllocator; -use core::ops::{Index, IndexMut}; -use core::marker::PhantomData; - -pub const P4: *mut Table = 0xffffffff_fffff000 as *mut _; - -pub struct Table { - entries: [Entry; ENTRY_COUNT], - level: PhantomData, -} - -impl Table -where - L: TableLevel, -{ - pub fn zero(&mut self) { - for entry in self.entries.iter_mut() { - entry.set_unused(); - } - } -} - -/* - * Addresses are expected to be canonical (bits 48-63 must be the same as bit 47), otherwise the - * CPU will #GP when we ask it to translate it. - */ -fn make_address_canonical(address : usize) -> usize { - let sign_extension = 0o177777_000_000_000_000_0000 * ((address >> 47) & 0b1); - (address & ((1 << 48) - 1)) | sign_extension -} - -impl Table -where - L: HierarchicalLevel, -{ - fn next_table_address(&self, index: usize) -> Option { - let entry_flags = self[index].flags(); - if entry_flags.contains(PRESENT) && !entry_flags.contains(HUGE_PAGE) { - let table_address = self as *const _ as usize; - Some(make_address_canonical((table_address << 9) | (index << 12))) - } else { - None - } - } - - pub fn next_table(&self, index: usize) -> Option<&Table> { - self.next_table_address(index) - .map(|address| unsafe { &*(address as *const _) }) - } - - pub fn next_table_mut(&mut self, index: usize) -> Option<&mut Table> { - self.next_table_address(index) - .map(|address| unsafe { &mut *(address as *mut _) }) - } - - pub fn next_table_create( - &mut self, - index: usize, - allocator: &mut A, - ) -> &mut Table - where - A: FrameAllocator, - { - if self.next_table(index).is_none() { - assert!( - !self.entries[index].flags().contains(HUGE_PAGE), - "mapping code does not support huge pages" - ); - let frame = allocator.allocate_frame().expect("no frames available"); - self.entries[index].set(frame, PRESENT | WRITABLE); - self.next_table_mut(index).unwrap().zero(); - } - self.next_table_mut(index).unwrap() - } -} - -impl Index for Table -where - L: TableLevel, -{ - type Output = Entry; - - fn index(&self, index: usize) -> &Entry { - &self.entries[index] - } -} - -impl IndexMut for Table -where - L: TableLevel, -{ - fn index_mut(&mut self, index: usize) -> &mut Entry { - &mut self.entries[index] - } -} - -pub trait TableLevel {} - -pub enum Level4 {} -#[allow(dead_code)] -pub enum Level3 {} -#[allow(dead_code)] -pub enum Level2 {} -pub enum Level1 {} - -impl TableLevel for Level4 {} -impl TableLevel for Level3 {} -impl TableLevel for Level2 {} -impl TableLevel for Level1 {} - -pub trait HierarchicalLevel: TableLevel { - type NextLevel: TableLevel; -} - -impl HierarchicalLevel for Level4 { - type NextLevel = Level3; -} - -impl HierarchicalLevel for Level3 { - type NextLevel = Level2; -} - -impl HierarchicalLevel for Level2 { - type NextLevel = Level1; -} diff --git a/src/memory/paging/temporary_page.rs b/src/memory/paging/temporary_page.rs deleted file mode 100644 index e404b183..00000000 --- a/src/memory/paging/temporary_page.rs +++ /dev/null @@ -1,91 +0,0 @@ -// Copyright 2016 Philipp Oppermann. See the README.md -// file at the top-level directory of this distribution. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -use super::{Page, ActivePageTable, VirtualAddress}; -use super::table::{Table, Level1}; -use memory::{Frame, FrameAllocator}; - -pub struct TemporaryPage { - page: Page, - allocator: TinyAllocator, -} - -impl TemporaryPage { - pub fn new(page: Page, allocator: &mut A) -> TemporaryPage - where - A: FrameAllocator, - { - TemporaryPage { - page: page, - allocator: TinyAllocator::new(allocator), - } - } - - /// Maps the temporary page to the given frame in the active table. - /// Returns the start address of the temporary page. - pub fn map(&mut self, frame: Frame, active_table: &mut ActivePageTable) -> VirtualAddress { - use super::entry::WRITABLE; - - assert!( - active_table.translate_page(self.page).is_none(), - "temporary page is already mapped" - ); - active_table.map_to(self.page, frame, WRITABLE, &mut self.allocator); - self.page.start_address() - } - - /// Maps the temporary page to the given page table frame in the active table. - /// Returns a reference to the now mapped table. - pub fn map_table_frame( - &mut self, - frame: Frame, - active_table: &mut ActivePageTable, - ) -> &mut Table { - unsafe { &mut *(self.map(frame, active_table) as *mut Table) } - } - - /// Unmaps the temporary page in the active table. - pub fn unmap(&mut self, active_table: &mut ActivePageTable) { - active_table.unmap(self.page, &mut self.allocator) - } -} - -struct TinyAllocator([Option; 3]); - -impl TinyAllocator { - fn new(allocator: &mut A) -> TinyAllocator - where - A: FrameAllocator, - { - let mut f = || allocator.allocate_frame(); - let frames = [f(), f(), f()]; - TinyAllocator(frames) - } -} - -impl FrameAllocator for TinyAllocator { - fn allocate_frame(&mut self) -> Option { - for frame_option in &mut self.0 { - if frame_option.is_some() { - return frame_option.take(); - } - } - None - } - - fn deallocate_frame(&mut self, frame: Frame) { - for frame_option in &mut self.0 { - if frame_option.is_none() { - *frame_option = Some(frame); - return; - } - } - panic!("Tiny allocator can hold only 3 frames."); - } -} diff --git a/src/memory/stack_allocator.rs b/src/memory/stack_allocator.rs deleted file mode 100644 index e69fcabf..00000000 --- a/src/memory/stack_allocator.rs +++ /dev/null @@ -1,81 +0,0 @@ -use memory::paging::{self, Page, PageIter, ActivePageTable}; -use memory::{PAGE_SIZE, FrameAllocator}; - -pub struct StackAllocator { - range: PageIter, -} - -impl StackAllocator { - pub fn new(page_range: PageIter) -> StackAllocator { - StackAllocator { range: page_range } - } -} - -impl StackAllocator { - pub fn alloc_stack( - &mut self, - active_table: &mut ActivePageTable, - frame_allocator: &mut FA, - size_in_pages: usize, - ) -> Option { - if size_in_pages == 0 { - return None; /* a zero sized stack makes no sense */ - } - - // clone the range, since we only want to change it on success - let mut range = self.range.clone(); - - // try to allocate the stack pages and a guard page - let guard_page = range.next(); - let stack_start = range.next(); - let stack_end = if size_in_pages == 1 { - stack_start - } else { - // choose the (size_in_pages-2)th element, since index - // starts at 0 and we already allocated the start page - range.nth(size_in_pages - 2) - }; - - match (guard_page, stack_start, stack_end) { - (Some(_), Some(start), Some(end)) => { - // success! write back updated range - self.range = range; - - // map stack pages to physical frames - for page in Page::range_inclusive(start, end) { - active_table.map(page, paging::WRITABLE, frame_allocator); - } - - // create a new stack - let top_of_stack = end.start_address() + PAGE_SIZE; - Some(Stack::new(top_of_stack, start.start_address())) - } - _ => None, /* not enough pages */ - } - } -} - -#[derive(Debug)] -pub struct Stack { - top: usize, - bottom: usize, -} - -impl Stack { - fn new(top: usize, bottom: usize) -> Stack { - assert!(top > bottom); - Stack { - top: top, - bottom: bottom, - } - } - - pub fn top(&self) -> usize { - self.top - } - - #[allow(dead_code)] - pub fn bottom(&self) -> usize { - self.bottom - } -} diff --git a/src/vga_buffer.rs b/src/vga_buffer.rs deleted file mode 100644 index f3374940..00000000 --- a/src/vga_buffer.rs +++ /dev/null @@ -1,150 +0,0 @@ -// Copyright 2016 Philipp Oppermann. See the README.md -// file at the top-level directory of this distribution. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -use core::ptr::Unique; -use core::fmt; -use spin::Mutex; -use volatile::Volatile; - -const BUFFER_HEIGHT: usize = 25; -const BUFFER_WIDTH: usize = 80; - -pub static WRITER: Mutex = Mutex::new(Writer { - column_position: 0, - color_code: ColorCode::new(Color::LightGreen, Color::Black), - buffer: unsafe { Unique::new_unchecked(0xb8000 as *mut _) }, -}); - -macro_rules! println { - ($fmt:expr) => (print!(concat!($fmt, "\n"))); - ($fmt:expr, $($arg:tt)*) => (print!(concat!($fmt, "\n"), $($arg)*)); -} - -macro_rules! print { - ($($arg:tt)*) => ({ - $crate::vga_buffer::print(format_args!($($arg)*)); - }); -} - -pub fn print(args: fmt::Arguments) { - use core::fmt::Write; - WRITER.lock().write_fmt(args).unwrap(); -} - -pub fn clear_screen() { - for _ in 0..BUFFER_HEIGHT { - println!(""); - } -} - -#[allow(dead_code)] -#[derive(Debug, Clone, Copy)] -#[repr(u8)] -pub enum Color { - Black = 0, - Blue = 1, - Green = 2, - Cyan = 3, - Red = 4, - Magenta = 5, - Brown = 6, - LightGray = 7, - DarkGray = 8, - LightBlue = 9, - LightGreen = 10, - LightCyan = 11, - LightRed = 12, - Pink = 13, - Yellow = 14, - White = 15, -} - -pub struct Writer { - column_position: usize, - color_code: ColorCode, - buffer: Unique, -} - -impl Writer { - pub fn write_byte(&mut self, byte: u8) { - match byte { - b'\n' => self.new_line(), - byte => { - if self.column_position >= BUFFER_WIDTH { - self.new_line(); - } - let row = BUFFER_HEIGHT - 1; - let col = self.column_position; - - let color_code = self.color_code; - - self.buffer().chars[row][col].write(ScreenChar { - ascii_character: byte, - color_code: color_code, - }); - self.column_position += 1; - } - } - } - - fn buffer(&mut self) -> &mut Buffer { - unsafe { self.buffer.as_mut() } - } - - fn new_line(&mut self) { - for row in 1..BUFFER_HEIGHT { - for col in 0..BUFFER_WIDTH { - let buffer = self.buffer(); - let character = buffer.chars[row][col].read(); - buffer.chars[row - 1][col].write(character); - } - } - self.clear_row(BUFFER_HEIGHT - 1); - self.column_position = 0; - } - - fn clear_row(&mut self, row: usize) { - let blank = ScreenChar { - ascii_character: b' ', - color_code: self.color_code, - }; - for col in 0..BUFFER_WIDTH { - self.buffer().chars[row][col].write(blank); - } - } -} - -impl fmt::Write for Writer { - fn write_str(&mut self, s: &str) -> ::core::fmt::Result { - for byte in s.bytes() { - self.write_byte(byte) - } - Ok(()) - } -} - -#[derive(Debug, Clone, Copy)] -struct ColorCode(u8); - -impl ColorCode { - const fn new(foreground: Color, background: Color) -> ColorCode { - ColorCode((background as u8) << 4 | (foreground as u8)) - } -} - -#[derive(Debug, Clone, Copy)] -#[repr(C)] -struct ScreenChar { - ascii_character: u8, - color_code: ColorCode, -} - -struct Buffer { - chars: [[Volatile; BUFFER_WIDTH]; BUFFER_HEIGHT], -}