From eb7303a07f38673e75855df622a74f1bdb3be32a Mon Sep 17 00:00:00 2001 From: Calvin Lee Date: Tue, 27 Jun 2017 15:38:50 -0700 Subject: [PATCH] Fix compilation and generally improve things This project hasn't had a commit in awhile, so this is more of a messy sweep-up job than anything else. Months of negligence on a "nightly" versioned project leads to several compilation failures, which have now been fixed. These include the merging of `collections` and `alloc` crates. The change of the `Unique` struct. And a new target option has been added, which made cross cross compilation fail. There have been also several general improvements. These include the new use of the `x86_64` crate, instead of x86, which simplifies code (but also requires a quite larger stack). This enables interrupt handling to be greatly simplified when paired with the new "x86-interrupt" abi. Also there is a small change to printing that allows for waiting for the writer to flush. This is very useful for color switching. Finally there have been a few minor changes, including changing the name of the ugly `(ARCH)-unknown-none-gnu` to `(ARCH)-ESALP`. And a small .gdbinit file has been added which should simplify debugging with qemu. Many of these changes are better shown my themselves in Blog-OS. Please see phil-opp/blog_os#289 phil-opp/blog_os#325 and phil-opp/blog_os#333 for more details. --- .gdbinit | 12 +++ Cargo.toml | 15 +--- Makefile | 2 +- Xargo.toml | 2 + libs/hole_list_allocator/src/lib.rs | 1 - src/arch/x86_64/boot.asm | 2 +- src/arch/x86_64/interrupts.asm | 79 ----------------- src/interrupts/idt.rs | 129 ---------------------------- src/interrupts/mod.rs | 122 +++++++------------------- src/lib.rs | 16 ++-- src/memory/paging/mapper.rs | 11 ++- src/memory/paging/mod.rs | 20 ++--- src/memory/stack_frame_allocator.rs | 8 +- src/vga_buffer.rs | 16 +++- x86_64-ESALP.json | 12 +++ x86_64-unknown-none-gnu.json | 17 ---- 16 files changed, 99 insertions(+), 365 deletions(-) create mode 100644 .gdbinit create mode 100644 Xargo.toml delete mode 100644 src/arch/x86_64/interrupts.asm delete mode 100644 src/interrupts/idt.rs create mode 100644 x86_64-ESALP.json delete mode 100644 x86_64-unknown-none-gnu.json diff --git a/.gdbinit b/.gdbinit new file mode 100644 index 0000000..550e8be --- /dev/null +++ b/.gdbinit @@ -0,0 +1,12 @@ +file ./build/kernel-x86_64.bin +target remote localhost:1234 +set architecture i386:x86-64 +set disassembly-flavor intel + +display /i $pc + +define longfix + disconnect + set architecture i386:x86-64:intel + target remote localhost:1234 +end diff --git a/Cargo.toml b/Cargo.toml index 1d7fa1a..27c4e8e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -10,6 +10,7 @@ once = "0.3.2" rlibc = "0.1.4" spin = "0.4.4" multiboot2 = "0.3.0" +x86_64 = "0.1.2" [dependencies.hole_list_allocator] path = "libs/hole_list_allocator" @@ -21,19 +22,5 @@ version = "0.2.1" [dependencies.log_buffer] git = "https://github.com/ESALP/rust-log_buffer" -[dependencies.x86] -default-features = false -version = "0.7.1" - [lib] crate-type = ["staticlib"] - -[profile] - -[profile.dev] -panic = "abort" - -[profile.release] -panic = "abort" - -[workspace] diff --git a/Makefile b/Makefile index a6bd6c7..9e63f42 100644 --- a/Makefile +++ b/Makefile @@ -9,7 +9,7 @@ arch ?= x86_64 name ?= ESALP -target ?= $(arch)-unknown-none-gnu +target ?= $(arch)-ESALP rust_os := target/$(target)/debug/lib$(name).a kernel := build/kernel-$(arch).bin iso := build/os-$(arch).iso diff --git a/Xargo.toml b/Xargo.toml new file mode 100644 index 0000000..38d2619 --- /dev/null +++ b/Xargo.toml @@ -0,0 +1,2 @@ +[target.x86_64-ESALP.dependencies] +alloc = {} diff --git a/libs/hole_list_allocator/src/lib.rs b/libs/hole_list_allocator/src/lib.rs index 7354b05..b45f3e1 100644 --- a/libs/hole_list_allocator/src/lib.rs +++ b/libs/hole_list_allocator/src/lib.rs @@ -17,7 +17,6 @@ use spin::Mutex; use linked_list_allocator::Heap; -#[macro_use] extern crate lazy_static; extern crate linked_list_allocator; extern crate spin; diff --git a/src/arch/x86_64/boot.asm b/src/arch/x86_64/boot.asm index 97753bf..cb1f878 100644 --- a/src/arch/x86_64/boot.asm +++ b/src/arch/x86_64/boot.asm @@ -351,5 +351,5 @@ kernel_table: ; undefined behavior. align 16 stack_bottom: - resb 4096 * 2 + resb 4096 * 6 stack_top: diff --git a/src/arch/x86_64/interrupts.asm b/src/arch/x86_64/interrupts.asm deleted file mode 100644 index b27a308..0000000 --- a/src/arch/x86_64/interrupts.asm +++ /dev/null @@ -1,79 +0,0 @@ -; Copyright 2016 Phillip Oppermann, Calvin Lee and JJ Garzella. -; See the README.md file at the top-level directory of this -; distribution. -; -; Licensed under the MIT license , at your option. -; This file may not be copied, modified, or distributed -; except according to those terms. - -extern rust_irq_handler - -section .text -bits 64 -%macro pushall 0 - ; Save registers which are normally supposed to - ; be saved by the caller. I _think_ this list - ; is correct, but don't quote me on that. I'm - ; probably forgetting something vital. - push rax - push rcx - push rdx - push rsi - push rdi - push r8 - push r9 - push r10 - push r11 -%endmacro -%macro popall 0 - pop r11 - pop r10 - pop r9 - pop r8 - pop rdi - pop rsi - pop rdx - pop rcx - pop rax -%endmacro - -%macro isr 1 -global isr%1 -isr%1: - pushall - mov rdi, rsp - add rdi, 72 ; Account for the pushed registers - mov rsi, %1 - call irq_common - popall - add rsp, 8 ; Pop the error code - iretq -%endmacro - -%macro isr_noerr 1 -global isr%1 -isr%1: - push qword 0 ; Push faux error code - pushall - mov rdi, rsp - add rdi, 72 ; Account for the pushed registers - mov rsi, %1 - call irq_common - popall - add rsp, 8 ; Pop the error code - iretq -%endmacro - -isr_noerr 0 - -isr_noerr 3 -isr 13 -isr 14 -isr_noerr 32 -isr_noerr 33 - - -irq_common: - call rust_irq_handler - ret diff --git a/src/interrupts/idt.rs b/src/interrupts/idt.rs deleted file mode 100644 index 457ffc3..0000000 --- a/src/interrupts/idt.rs +++ /dev/null @@ -1,129 +0,0 @@ -// Copyright 2016 Phillip Oppermann, Calvin Lee and JJ Garzella. -// See the README.md file at the top-level directory of this -// distribution. -// -// Licensed under the MIT license , at your option. -// This file may not be copied, modified, or distributed -// except according to those terms. - -use x86::segmentation::{self, SegmentSelector}; -use bit_field::BitField; - -/// The type of an assempbly interrupt service routine -pub type HandlerFunc = unsafe extern "C" fn(); - -/// The Interrupt Descriptor table -pub struct Idt([Entry; 40]); - -impl Idt { - /// Creates a new Idt, each entry is unused - pub fn new() -> Idt { - Idt([Entry::missing(); 40]) - } - - /// Sets a certain entry as present and initializes it with a certain handler - pub fn set_handler(&mut self, entry: u8, handler: HandlerFunc) -> &mut EntryOptions { - self.0[entry as usize] = Entry::new(segmentation::cs(), handler); - &mut self.0[entry as usize].options - } - - /// Loads the given IDT into the CPU - /// - /// # Safety - /// The IDT must be valid, if it is not undefined behaviour will most likely - /// occur. Also `self` must live for the duration of the kernel, a lifetime of - /// `'static` ensures this. - pub unsafe fn load(&'static self) { - use x86::dtables::{DescriptorTablePointer, lidt}; - use core::mem::size_of; - - let ptr = DescriptorTablePointer { - base: self as *const _ as u64, - limit: (size_of::() - 1) as u16, - }; - lidt(&ptr) - } -} - -/// An Interrupt Descriptor Table entry type -#[derive(Debug, Clone, Copy)] -#[repr(C, packed)] -pub struct Entry { - /// The lowest 16 bits of the isr pointer - pointer_low: u16, - gdt_selector: SegmentSelector, - /// A bitfield of options for the entry - options: EntryOptions, - /// The middle 16 bits of the isr pointer - pointer_middle: u16, - /// The high 32 bits of the isr pointer - pointer_high: u32, - reserved: u32, -} - -impl Entry { - /// Creates a new Entry given a `HandlerFunc` - fn new(gdt_selector: SegmentSelector, handler: HandlerFunc) -> Self { - let pointer = handler as usize; - Entry { - gdt_selector: gdt_selector, - pointer_low: pointer as u16, - pointer_middle: (pointer >> 16) as u16, - pointer_high: (pointer >> 32) as u32, - options: EntryOptions::new(), - reserved: 0, - } - } - - /// Returns an uninitialized Entry - fn missing() -> Self { - Entry { - gdt_selector: SegmentSelector::new(0), - pointer_low: 0, - pointer_middle: 0, - pointer_high: 0, - options: EntryOptions::minimal(), - reserved: 0, - } - } -} - -/// A representation of the `Options` field of an `Entry` -#[derive(Debug, Clone, Copy)] -pub struct EntryOptions(BitField); - -impl EntryOptions { - /// Returns options with 'must be one' bits set - fn minimal() -> Self { - let mut options = BitField::new(0); - options.set_range(9..12, 0b111); // 'must be one' bits - EntryOptions(options) - } - - /// Returns a option with `present` and `disable_interrupts` set - fn new() -> Self { - let mut options = Self::minimal(); - options.set_present(true); - options.disable_interrupts(true); - options - } - - /// Sets the `present` bit - pub fn set_present(&mut self, present: bool) { - self.0.set_bit(15, present); - } - - /// Disables interrupts for the `Entry` - pub fn disable_interrupts(&mut self, disable: bool) { - self.0.set_bit(8, !disable); - } - - pub fn set_privilege_level(&mut self, dpl: u16) { - self.0.set_range(13..15, dpl); - } - - pub fn set_stack_index(&mut self, index: u16) { - self.0.set_range(0..3, index); - } -} diff --git a/src/interrupts/mod.rs b/src/interrupts/mod.rs index 90511da..2f460b7 100644 --- a/src/interrupts/mod.rs +++ b/src/interrupts/mod.rs @@ -9,10 +9,11 @@ #![allow(dead_code)] -use core::fmt; - use spin::Mutex; +use x86_64::structures::idt::Idt; +use x86_64::structures::idt::{ExceptionStackFrame, PageFaultErrorCode}; + use self::pic::ChainedPICs; pub use self::keyboard::KEYBOARD; use vga_buffer; @@ -23,17 +24,9 @@ mod keyboard; mod cpuio; /// The programmable interrupt controller mod pic; -/// The Interrupt Descriptor Table -mod idt; extern "C" { - fn isr0(); - fn isr3(); - fn isr13(); - fn isr14(); - fn isr32(); - fn isr33(); - /// Function that contains the `sti` instruction + /// Enable interrupts fn sti(); /// The kernel exit point fn KEXIT(); @@ -41,19 +34,20 @@ extern "C" { lazy_static! { /// This is the Interrupt Descriptor Table that contains handlers for all - /// interrupt vectors that we support. Each handler is set in its lazy_static - /// definition and is not modified again. - // TODO Use const functions for initial handlers - static ref IDT: idt::Idt = { - let mut idt = idt::Idt::new(); + /// interrupt vectors that we support. Each handler is set in its initialization + /// and is not modified again. + static ref IDT: Idt = { + let mut idt = Idt::new(); // Initialize handlers - idt.set_handler(0x0, isr0 ); - idt.set_handler(0x3, isr3 ); - idt.set_handler(0xD, isr13); - idt.set_handler(0xE, isr14); - idt.set_handler(0x20,isr32); - idt.set_handler(0x21,isr33); + idt.divide_by_zero.set_handler_fn(de_handler); + idt.breakpoint.set_handler_fn(breakpoint_handler); + idt.general_protection_fault.set_handler_fn(gp_handler); + idt.page_fault.set_handler_fn(pf_handler); + // PIC handlers + idt[0x20].set_handler_fn(kb_handler); + idt[0x21].set_handler_fn(timer_handler); + idt }; } @@ -62,8 +56,8 @@ lazy_static! { pub static PIC: Mutex = Mutex::new(unsafe { ChainedPICs::new(0x20, 0x28) }); pub fn init() { + IDT.load(); unsafe { - IDT.load(); { let mut pic = PIC.lock(); pic.initialize(); @@ -72,41 +66,6 @@ pub fn init() { } } -/// A struct that represents what the CPU pushes to the stack when an isr is -/// called. -#[repr(C)] -pub struct ExceptionStackFrame { - error_code: u64, - instruction_pointer: u64, - code_segment: u64, - cpu_flags: u64, - stack_pointer: u64, - stack_segment: u64, -} - -impl fmt::Debug for ExceptionStackFrame { - /// Pretty printing for the `ExceptionStackFrame` struct. - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, - r#" -ExceptionStackFrame {{ - Instruction Pointer: 0x{:04x}:{:0al$x}, - Stack Pointer: 0x{:04x}:{:0al$x}, - Flags: 0b{:0fl$b}, - Error Code: 0b{:0fl$b}, -}}"#, - self.code_segment, - self.instruction_pointer, - self.stack_segment, - self.stack_pointer, - self.cpu_flags, - self.error_code, - // TODO maybe adjust this dynamically? - al = 16, - fl = 16) - } -} - // Exceptions: // | Name | Vector # | Type | Mnemonic | Error Code? | // | ----------------------------- | ---------- | ----------- | ---------- | ------------- | @@ -138,54 +97,31 @@ ExceptionStackFrame {{ // | FPU Error Interrupt | 25 (0x18) | Interrupt | #FERR | No | // | ----------------------------- | ---------- | ----------- | ---------- | ------------- | -/// All assembly interrupt service routines call this function with their interrupt -/// vector number. -#[no_mangle] -pub extern "C" fn rust_irq_handler(stack_frame: *const ExceptionStackFrame, isr_number: usize) { - match isr_number { - 0x0 => rust_de_handler(stack_frame), - 0x3 => breakpoint_handler(stack_frame), - 0xD => rust_gp_handler(stack_frame), - 0xE => rust_pf_handler(stack_frame), - 0x20 => rust_timer_handler(), - 0x21 => rust_kb_handler(), - _ => unreachable!(), - } -} - /// Divide by zero handler -extern "C" fn rust_de_handler(stack_frame: *const ExceptionStackFrame) { - unsafe { - panic!("EXCEPTION DIVIDE BY ZERO\n{:#?}", *stack_frame); - } +extern "x86-interrupt" fn de_handler(stack_frame: &mut ExceptionStackFrame) { + panic!("EXCEPTION DIVIDE BY ZERO\n{:#?}", stack_frame); } -extern "C" fn breakpoint_handler(stack_frame: *const ExceptionStackFrame) { - unsafe { - println!("Breakpoint at {:#?}\n{:#?}", - (*stack_frame).instruction_pointer, - *stack_frame); - } +extern "x86-interrupt" fn breakpoint_handler(stack_frame: &mut ExceptionStackFrame) { + println!("Breakpoint at {:#?}\n{:#?}", + (stack_frame).instruction_pointer, + stack_frame); } /// General protection fault handler -extern "C" fn rust_gp_handler(stack_frame: *const ExceptionStackFrame) { - unsafe { - panic!("EXCEPTION GENERAL PROTECTION FAULT\n{:#?}", *stack_frame); - } +extern "x86-interrupt" fn gp_handler(stack_frame: &mut ExceptionStackFrame, error_code: u64) { + panic!("EXCEPTION GENERAL PROTECTION FAULT\nerror_code: {}\n{:#?}\n", error_code, stack_frame); } /// Protection fault handler -extern "C" fn rust_pf_handler(stack_frame: *const ExceptionStackFrame) { - unsafe { - panic!("EXCEPTION PAGE FAULT\n{:#?}", *stack_frame); - } +extern "x86-interrupt" fn pf_handler(stack_frame: &mut ExceptionStackFrame, error_code: PageFaultErrorCode) { + panic!("EXCEPTION PAGE FAULT\nerror_code: {:?}\n{:#?}", error_code, stack_frame); } /// Timer handler /// /// This function flushes the log buffer whenever a timer interrupt happends -extern "C" fn rust_timer_handler() { +extern "x86-interrupt" fn timer_handler(_: &mut ExceptionStackFrame) { // Print to the screen vga_buffer::flush_screen(); unsafe { @@ -197,7 +133,7 @@ extern "C" fn rust_timer_handler() { /// /// This function pages the `Keyboard` port to get the key that was pressed, it then /// prints the associated byte to the screen and saves the state of the keyboard. -extern "C" fn rust_kb_handler() { +extern "x86-interrupt" fn kb_handler(_: &mut ExceptionStackFrame) { let mut kb = KEYBOARD.lock(); match kb.port.read() { // If the key was just pressed, diff --git a/src/lib.rs b/src/lib.rs index b6418ca..b0aed59 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -7,12 +7,14 @@ // This file may not be copied, modified, or distributed // except according to those terms. +#![allow(non_snake_case)] + #![feature(lang_items)] -#![feature(alloc, collections)] +#![feature(alloc)] #![feature(const_fn, unique)] #![feature(associated_type_defaults)] #![feature(asm)] -#![feature(relaxed_adts)] +#![feature(abi_x86_interrupt)] #![no_std] // crates.io crates @@ -21,8 +23,7 @@ extern crate rlibc; extern crate spin; /// Abstraction of the multiboot2 info structure extern crate multiboot2; -#[macro_use] -extern crate x86; +extern crate x86_64; extern crate bit_field; #[macro_use] extern crate bitflags; @@ -39,10 +40,8 @@ extern crate log_buffer; // Features involving allocation /// Heap allocator for rust code extern crate hole_list_allocator; -extern crate alloc; /// Higher-level data structures that use the heap -#[macro_use] -extern crate collections; +extern crate alloc; #[macro_use] /// Abstraction of the VGA text buffer @@ -104,8 +103,9 @@ pub extern "C" fn _Unwind_Resume() -> ! { #[lang = "eh_personality"] extern "C" fn eh_personality() {} /// Runs during a `panic!()` +#[no_mangle] #[lang = "panic_fmt"] -extern "C" fn panic_fmt(args: ::core::fmt::Arguments, file: &'static str, line: u32) -> ! { +pub extern "C" fn panic_fmt(args: ::core::fmt::Arguments, file: &'static str, line: u32) -> ! { vga_buffer::change_color(vga_buffer::Color::Red, vga_buffer::Color::Black); println!("\n\nPANIC at {}:{}", file, line); println!("\t{}", args); diff --git a/src/memory/paging/mapper.rs b/src/memory/paging/mapper.rs index 958daf7..413638f 100644 --- a/src/memory/paging/mapper.rs +++ b/src/memory/paging/mapper.rs @@ -31,12 +31,12 @@ impl Mapper { /// Returns a reference to the level 4 page table. pub fn p4(&self) -> &Table { - unsafe { self.p4.get() } + unsafe { self.p4.as_ref() } } /// Returns a mutable reference to the level 4 page table. pub fn p4_mut(&mut self) -> &mut Table { - unsafe { self.p4.get_mut() } + unsafe { self.p4.as_mut() } } /// Translates a virtual to the corresponding physical @@ -138,10 +138,9 @@ impl Mapper { // Even after we update this value in memory, // it is still cached in the TLB in the CPU. - // Use ::x86 crate to flush it. - unsafe { - ::x86::tlb::flush(page.start_address()); - } + use x86_64::VirtualAddress; + use x86_64::instructions::tlb; + 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 index b1e2baa..1ebeba1 100644 --- a/src/memory/paging/mod.rs +++ b/src/memory/paging/mod.rs @@ -167,29 +167,26 @@ impl ActivePageTable { f: F) where F: FnOnce(&mut Mapper) { - use x86::{tlb, controlregs}; - let flush_tlb = || unsafe { tlb::flush_all() }; + use x86_64::registers::control_regs; + use x86_64::instructions::tlb; { // Save table - let backup = Frame::containing_address(// Safe iff the processor is in ring 0 - // during execution. If it's not there - // are bigger problems. - unsafe { controlregs::cr3() } as usize); + let backup = Frame::containing_address(control_regs::cr3().0 as usize); // Map temporary_page to the current table let p4_table = temporary_page.map_table_frame(backup.clone(), self); // Overwrite recursive mapping self.p4_mut()[510].set(table.p4_frame.clone(), PRESENT | WRITABLE); - flush_tlb(); + tlb::flush_all(); // Execute the closure in the new context f(self); // Restore recursive mapping p4_table[510].set(backup, PRESENT | WRITABLE); - flush_tlb(); + tlb::flush_all(); } temporary_page.unmap(self); @@ -198,14 +195,15 @@ impl ActivePageTable { /// Activates the `InactivePageTable` given. /// Returns the previous ActivePageTable pub fn switch(&mut self, new_table: InactivePageTable) -> InactivePageTable { - use x86::controlregs; + use x86_64::PhysicalAddress; + use x86_64::registers::control_regs; let old_table = InactivePageTable { - p4_frame: Frame::containing_address(unsafe { controlregs::cr3() } as usize), + p4_frame: Frame::containing_address(control_regs::cr3().0 as usize), }; unsafe { - controlregs::cr3_write(new_table.p4_frame.start_address() as u64); + control_regs::cr3_write(PhysicalAddress(new_table.p4_frame.start_address() as u64)); } old_table } diff --git a/src/memory/stack_frame_allocator.rs b/src/memory/stack_frame_allocator.rs index ecba06d..d24e0dc 100644 --- a/src/memory/stack_frame_allocator.rs +++ b/src/memory/stack_frame_allocator.rs @@ -62,7 +62,7 @@ impl FrameAllocator for StackFrameAllocator { // If we have no more frames on the current page, attempt // to return the frame that is used for the stack let stack_page = Page::containing_address(unsafe { - self.stack_base.offset(self.offset) as *const _ as VirtualAddress + self.stack_base.as_ptr().offset(self.offset) as *const _ as VirtualAddress }); if let Some(frame) = ACTIVE_TABLE.lock().translate_page(stack_page) { @@ -90,7 +90,7 @@ impl FrameAllocator for StackFrameAllocator { // not using any pages it shouldn't. Just pop one off and // return it. self.offset -= 1; - let frame = unsafe { ::core::ptr::read(self.stack_base.offset(self.offset)) }; + let frame = unsafe { ::core::ptr::read(self.stack_base.as_ptr().offset(self.offset)) }; Some(frame) } @@ -109,7 +109,7 @@ impl FrameAllocator for StackFrameAllocator { /// called. fn deallocate_frame(&mut self, frame: Frame) { let stack_page = Page::containing_address(unsafe { - self.stack_base.offset(self.offset) as *const _ as VirtualAddress + self.stack_base.as_ptr().offset(self.offset) as *const _ as VirtualAddress }); if self.offset % 512 == 0 && None == ACTIVE_TABLE.lock() .translate_page(stack_page) @@ -129,7 +129,7 @@ impl FrameAllocator for StackFrameAllocator { } else { // Just push a frame on the stack. unsafe { - *self.stack_base.offset(self.offset) = frame; + *self.stack_base.as_ptr().offset(self.offset) = frame; } self.offset += 1; } diff --git a/src/vga_buffer.rs b/src/vga_buffer.rs index 3370eb5..9a33360 100644 --- a/src/vga_buffer.rs +++ b/src/vga_buffer.rs @@ -12,6 +12,7 @@ use core::ptr::Unique; use spin::Mutex; use log_buffer::LogBuffer; +use core::sync::atomic::{AtomicBool, Ordering}; use core::sync::atomic::{ATOMIC_BOOL_INIT, ATOMIC_USIZE_INIT}; use core::cell::UnsafeCell; use core::convert::AsMut; @@ -21,6 +22,8 @@ const BUFFER_HEIGHT: usize = 25; /// The number of columns in the VGA text buffer const BUFFER_WIDTH: usize = 80; +static WAIT_FLUSH: AtomicBool = ATOMIC_BOOL_INIT; + /// All writing to the VGA text buffer _must_ go through this /// struct. static WRITER: Mutex = Mutex::new(Writer { @@ -83,12 +86,23 @@ pub fn flush_screen() { // TODO these operations have to be atomic together WRITER.lock().write_str(WRITE_BUF.extract()); WRITE_BUF.clear(); + + WAIT_FLUSH.store(false, Ordering::Relaxed); +} + +fn wait_flush() { + WAIT_FLUSH.store(true, Ordering::Relaxed); + + while WAIT_FLUSH.load(Ordering::Relaxed) { + unsafe { asm!("pause"); } + } } /// Changes the color of the `WRITER` struct. This may produce /// unpredictable behaviour if `bg` has the bright bit (bit 3) /// set. pub fn change_color(fg: Color, bg: Color) { + wait_flush(); WRITER.lock().color(fg, bg); } @@ -169,7 +183,7 @@ impl Writer { /// Gets a reference to the buffer fn buffer(&mut self) -> &mut Buffer { - unsafe { self.buffer.get_mut() } + unsafe { self.buffer.as_mut() } } /// Moves the position to the next line, similar to printing diff --git a/x86_64-ESALP.json b/x86_64-ESALP.json new file mode 100644 index 0000000..037c2d9 --- /dev/null +++ b/x86_64-ESALP.json @@ -0,0 +1,12 @@ +{ + "llvm-target": "x86_64-unknown-none", + "target-endian": "little", + "target-pointer-width": "64", + "linker-flavor": "gcc", + "os": "none", + "arch": "x86_64", + "data-layout": "e-m:e-i64:64-f80:128-n8:16:32:64-S128", + "features": "-mmx,-sse,-sse2,+soft-float", + "disable-redzone": true, + "panic": "abort" +} diff --git a/x86_64-unknown-none-gnu.json b/x86_64-unknown-none-gnu.json deleted file mode 100644 index fd419a5..0000000 --- a/x86_64-unknown-none-gnu.json +++ /dev/null @@ -1,17 +0,0 @@ -{ - "llvm-target": "x86_64-unknown-none-gnu", - "target-endian": "little", - "target-pointer-width": "64", - "os": "none", - "arch": "x86_64", - "data-layout": "e-m:e-i64:64-f80:128-n8:16:32:64-S128", - "pre-link-args": [ "-m64" ], - "cpu": "x86-64", - "features": "-mmx,-sse,-sse2,-sse3,-ssse3,-sse4.1,-sse4.2,-3dnow,-3dnowa,-avx,-avx2,-fxsr,+soft-float", - "allow-asm": true, - "disable-redzone": true, - "eliminate-frame-pointer": true, - "linker-is-gnu": true, - "no-compiler-rt": true, - "archive-format": "gnu" -}