mirror of
https://github.com/phil-opp/blog_os.git
synced 2025-12-16 14:27:49 +00:00
Compare commits
146 Commits
0b61e748fb
...
code-heap-
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
1eb8f0f2c7 | ||
|
|
398ca5357c | ||
|
|
4acf12bb69 | ||
|
|
6f25c34d46 | ||
|
|
23e45b5b13 | ||
|
|
701823742e | ||
|
|
161d5fe7be | ||
|
|
9bf4ea7341 | ||
|
|
a1bf5651fc | ||
|
|
763228c859 | ||
|
|
770af27d75 | ||
|
|
3e59283c19 | ||
|
|
6146ccba2d | ||
|
|
b0e1527a95 | ||
|
|
cb4410c84e | ||
|
|
98b5976656 | ||
|
|
9335386928 | ||
|
|
7c30d62f33 | ||
|
|
61683bccda | ||
|
|
e1ec5159b8 | ||
|
|
7b7d19592f | ||
|
|
e387c0b6b8 | ||
|
|
d5abc119f3 | ||
|
|
59da6e5620 | ||
|
|
ef1cc0ed4f | ||
|
|
90f0caec1a | ||
|
|
7198a4d110 | ||
|
|
5c0fb63f33 | ||
|
|
6ffcb2cf1a | ||
|
|
1c72107cb1 | ||
|
|
b533bf6596 | ||
|
|
036a8e7608 | ||
|
|
3b960751f4 | ||
|
|
0ff6334026 | ||
|
|
1ed76411f7 | ||
|
|
10c4d0509d | ||
|
|
57998ea4f8 | ||
|
|
f05aaeb0ac | ||
|
|
78a30984bc | ||
|
|
09dd68a1a2 | ||
|
|
81e4eec055 | ||
|
|
8e5b6a3e3f | ||
|
|
be0ed3a54d | ||
|
|
ef9a629ddc | ||
|
|
18d8d311cb | ||
|
|
7b61da94a0 | ||
|
|
d974cf5200 | ||
|
|
f5b6094521 | ||
|
|
94447af25a | ||
|
|
a7f487f206 | ||
|
|
36d6c6d0e9 | ||
|
|
76d3715eef | ||
|
|
babf9d8cce | ||
|
|
ff49104764 | ||
|
|
bda1b8929c | ||
|
|
38bd9a65b6 | ||
|
|
09ff2e01b1 | ||
|
|
03e43da9f9 | ||
|
|
58e171cce7 | ||
|
|
b3e94470e4 | ||
|
|
901a1630eb | ||
|
|
e696d65b60 | ||
|
|
ef09418cbf | ||
|
|
7b01e9c862 | ||
|
|
28f37da07d | ||
|
|
ebf626061f | ||
|
|
4c9352d898 | ||
|
|
5452e0f455 | ||
|
|
a41a007039 | ||
|
|
c3d023ad40 | ||
|
|
f3cf5b51de | ||
|
|
202902f30d | ||
|
|
26be4cb84d | ||
|
|
0a10b3e784 | ||
|
|
9617680e45 | ||
|
|
3bb30fd1e8 | ||
|
|
8f18fb4282 | ||
|
|
e0f66a8196 | ||
|
|
ba54fd2503 | ||
|
|
41e36b4afa | ||
|
|
6b9d275c2d | ||
|
|
e5dfbd4b23 | ||
|
|
4e6ce8d16e | ||
|
|
519f47286c | ||
|
|
f76ec1ae32 | ||
|
|
5ad2962389 | ||
|
|
82e6c4b066 | ||
|
|
d564dc208f | ||
|
|
efe92e5004 | ||
|
|
a56e22b6fc | ||
|
|
67f536d7c6 | ||
|
|
741224411b | ||
|
|
818417d119 | ||
|
|
f272785861 | ||
|
|
5d807ee622 | ||
|
|
90c3cdf0f3 | ||
|
|
2bc233b2f6 | ||
|
|
0df629df47 | ||
|
|
cca85de5ed | ||
|
|
1da81c6f84 | ||
|
|
42d89c1030 | ||
|
|
233943310c | ||
|
|
ef6d69f82b | ||
|
|
051b23f577 | ||
|
|
97e884e6a3 | ||
|
|
954c0bcfbb | ||
|
|
637b517f47 | ||
|
|
bd1f5345da | ||
|
|
662faa8dd0 | ||
|
|
5802c97938 | ||
|
|
f2bc2d33f0 | ||
|
|
38a121a887 | ||
|
|
8b380f0692 | ||
|
|
f23ee04161 | ||
|
|
2031a8dc81 | ||
|
|
29ee6b15dd | ||
|
|
b184f7d996 | ||
|
|
7c07a67bf5 | ||
|
|
ec2da4bebd | ||
|
|
90ad333e90 | ||
|
|
afe8dc3dcf | ||
|
|
8bb0187f35 | ||
|
|
abaf5bd862 | ||
|
|
b7005b766f | ||
|
|
91ca04e8c2 | ||
|
|
ada45c6e52 | ||
|
|
207a466707 | ||
|
|
a954c02fbe | ||
|
|
895991fee3 | ||
|
|
25796110f3 | ||
|
|
1d153d694e | ||
|
|
c2e4e8c96f | ||
|
|
599a643d97 | ||
|
|
5efcecc2f2 | ||
|
|
1a39774ead | ||
|
|
1ea8cf6ed1 | ||
|
|
4060ac558c | ||
|
|
28a11e47bc | ||
|
|
6504bed810 | ||
|
|
d8edfccca4 | ||
|
|
ff25a7d86c | ||
|
|
b5202e26a1 | ||
|
|
ea1b031fd3 | ||
|
|
db4e879c34 | ||
|
|
7fd29c9cbe | ||
|
|
218cb9399e |
23
Cargo.lock
generated
23
Cargo.lock
generated
@@ -33,6 +33,8 @@ dependencies = [
|
||||
"array-init 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"bootloader 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"lazy_static 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"pc-keyboard 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"pic8259_simple 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"spin 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"uart_16550 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"volatile 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
@@ -56,6 +58,11 @@ name = "cc"
|
||||
version = "1.0.30"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "cpuio"
|
||||
version = "0.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "fixedvec"
|
||||
version = "0.2.3"
|
||||
@@ -114,6 +121,19 @@ name = "os_bootinfo"
|
||||
version = "0.2.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "pc-keyboard"
|
||||
version = "0.3.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "pic8259_simple"
|
||||
version = "0.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"cpuio 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pulldown-cmark"
|
||||
version = "0.0.3"
|
||||
@@ -323,6 +343,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
"checksum bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "228047a76f468627ca71776ecdebd732a3423081fcf5125585bcd7c49886ce12"
|
||||
"checksum bootloader 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a0808c55da932b82d3ababdaa0caa3f18522c5d2d06309b98f73adda849a3f03"
|
||||
"checksum cc 1.0.30 (registry+https://github.com/rust-lang/crates.io-index)" = "d01c69d08ff207f231f07196e30f84c70f1c815b04f980f8b7b01ff01f05eb92"
|
||||
"checksum cpuio 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "22b8e308ccfc5acf3b82f79c0eac444cf6114cb2ac67a230ca6c177210068daa"
|
||||
"checksum fixedvec 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "7c6c16d316ccdac21a4dd648e314e76facbbaf316e83ca137d0857a9c07419d0"
|
||||
"checksum font8x8 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)" = "b81d84c3c978af7d05d31a2198af4b9ba956d819d15d8f6d58fc150e33f8dc1f"
|
||||
"checksum fuchsia-zircon 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "2e9763c69ebaae630ba35f74888db465e49e259ba1bc0eda7d06f4a067615d82"
|
||||
@@ -332,6 +353,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
"checksum libc 0.2.48 (registry+https://github.com/rust-lang/crates.io-index)" = "e962c7641008ac010fa60a7dfdc1712449f29c44ef2d4702394aea943ee75047"
|
||||
"checksum nodrop 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)" = "2f9667ddcc6cc8a43afc9b7917599d7216aa09c463919ea32c59ed6cac8bc945"
|
||||
"checksum os_bootinfo 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "66481dbeb5e773e7bd85b63cd6042c30786f834338288c5ec4f3742673db360a"
|
||||
"checksum pc-keyboard 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "fff50ab09ba31bcebc0669f4e64c0952fae1acdca9e6e0587e68e4e8443808ac"
|
||||
"checksum pic8259_simple 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "dc64b2fd10828da8521b6cdabe0679385d7d2a3a6d4c336b819d1fa31ba35c72"
|
||||
"checksum pulldown-cmark 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "8361e81576d2e02643b04950e487ec172b687180da65c731c03cf336784e6c07"
|
||||
"checksum rand 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)" = "dee497e66d8d76bf08ce20c8d36e16f93749ab0bf89975b4f8ae5cee660c2da2"
|
||||
"checksum rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7a6fdeb83b075e8266dcc8762c22776f6877a63111121f5f8c7411e5be7eed4b"
|
||||
|
||||
@@ -5,11 +5,13 @@ authors = ["Philipp Oppermann <dev@phil-opp.com>"]
|
||||
edition = "2018"
|
||||
|
||||
[dependencies]
|
||||
bootloader = "0.4.0"
|
||||
bootloader = { version = "0.4.0", features = ["map_physical_memory"]}
|
||||
volatile = "0.2.3"
|
||||
spin = "0.4.9"
|
||||
uart_16550 = "0.1.0"
|
||||
x86_64 = "0.5.2"
|
||||
pic8259_simple = "0.1.1"
|
||||
pc-keyboard = "0.3.1"
|
||||
|
||||
[dependencies.lazy_static]
|
||||
version = "1.0"
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
# Blog OS (CPU Exceptions)
|
||||
# Blog OS (Paging Implementation)
|
||||
|
||||
[](https://travis-ci.org/phil-opp/blog_os/branches)
|
||||
[](https://travis-ci.org/phil-opp/blog_os/branches)
|
||||
|
||||
This repository contains the source code for the [CPU Exceptions][post] post of the [Writing an OS in Rust](https://os.phil-opp.com) series.
|
||||
This repository contains the source code for the [Paging Implementation][post] post of the [Writing an OS in Rust](https://os.phil-opp.com) series.
|
||||
|
||||
[post]: https://os.phil-opp.com/cpu-exceptions/
|
||||
[post]: https://os.phil-opp.com/paging-implementation/
|
||||
|
||||
**Check out the [master branch](https://github.com/phil-opp/blog_os) for more information.**
|
||||
|
||||
|
||||
@@ -1,8 +1,11 @@
|
||||
#![cfg_attr(not(test), no_std)]
|
||||
#![cfg_attr(not(test), no_main)] // disable all Rust-level entry points
|
||||
#![cfg_attr(test, allow(unused_imports))]
|
||||
#![feature(alloc_error_handler)]
|
||||
|
||||
use blog_os::memory::allocator::DummyAllocator;
|
||||
use blog_os::{exit_qemu, serial_println};
|
||||
use core::alloc::Layout;
|
||||
use core::panic::PanicInfo;
|
||||
|
||||
/// This function is the entry point, since the linker looks for a function
|
||||
@@ -31,3 +34,11 @@ fn panic(info: &PanicInfo) -> ! {
|
||||
}
|
||||
loop {}
|
||||
}
|
||||
|
||||
#[global_allocator]
|
||||
static ALLOCATOR: DummyAllocator = DummyAllocator;
|
||||
|
||||
#[alloc_error_handler]
|
||||
fn out_of_memory(layout: Layout) -> ! {
|
||||
panic!("out of memory: allocation for {:?} failed", layout);
|
||||
}
|
||||
|
||||
@@ -1,8 +1,11 @@
|
||||
#![no_std]
|
||||
#![cfg_attr(not(test), no_main)]
|
||||
#![cfg_attr(test, allow(dead_code, unused_macros, unused_imports))]
|
||||
#![feature(alloc_error_handler)]
|
||||
|
||||
use blog_os::memory::allocator::DummyAllocator;
|
||||
use blog_os::{exit_qemu, serial_println};
|
||||
use core::alloc::Layout;
|
||||
use core::panic::PanicInfo;
|
||||
|
||||
#[cfg(not(test))]
|
||||
@@ -32,3 +35,11 @@ fn panic(info: &PanicInfo) -> ! {
|
||||
}
|
||||
loop {}
|
||||
}
|
||||
|
||||
#[global_allocator]
|
||||
static ALLOCATOR: DummyAllocator = DummyAllocator;
|
||||
|
||||
#[alloc_error_handler]
|
||||
fn out_of_memory(layout: Layout) -> ! {
|
||||
panic!("out of memory: allocation for {:?} failed", layout);
|
||||
}
|
||||
|
||||
88
src/bin/test-exception-double-fault-stack-overflow.rs
Normal file
88
src/bin/test-exception-double-fault-stack-overflow.rs
Normal file
@@ -0,0 +1,88 @@
|
||||
#![feature(abi_x86_interrupt)]
|
||||
#![no_std]
|
||||
#![cfg_attr(not(test), no_main)]
|
||||
#![cfg_attr(test, allow(dead_code, unused_macros, unused_imports))]
|
||||
#![feature(alloc_error_handler)]
|
||||
|
||||
use blog_os::memory::allocator::DummyAllocator;
|
||||
use blog_os::{exit_qemu, serial_println};
|
||||
use core::alloc::Layout;
|
||||
use core::panic::PanicInfo;
|
||||
use lazy_static::lazy_static;
|
||||
|
||||
#[cfg(not(test))]
|
||||
#[no_mangle]
|
||||
#[allow(unconditional_recursion)]
|
||||
pub extern "C" fn _start() -> ! {
|
||||
blog_os::gdt::init();
|
||||
init_test_idt();
|
||||
|
||||
fn stack_overflow() {
|
||||
stack_overflow(); // for each recursion, the return address is pushed
|
||||
}
|
||||
|
||||
// trigger a stack overflow
|
||||
stack_overflow();
|
||||
|
||||
serial_println!("failed");
|
||||
serial_println!("No exception occured");
|
||||
|
||||
unsafe {
|
||||
exit_qemu();
|
||||
}
|
||||
|
||||
loop {}
|
||||
}
|
||||
|
||||
/// This function is called on panic.
|
||||
#[cfg(not(test))]
|
||||
#[panic_handler]
|
||||
fn panic(info: &PanicInfo) -> ! {
|
||||
serial_println!("failed");
|
||||
serial_println!("{}", info);
|
||||
|
||||
unsafe {
|
||||
exit_qemu();
|
||||
}
|
||||
|
||||
loop {}
|
||||
}
|
||||
|
||||
#[global_allocator]
|
||||
static ALLOCATOR: DummyAllocator = DummyAllocator;
|
||||
|
||||
#[alloc_error_handler]
|
||||
fn out_of_memory(layout: Layout) -> ! {
|
||||
panic!("out of memory: allocation for {:?} failed", layout);
|
||||
}
|
||||
|
||||
use x86_64::structures::idt::{InterruptDescriptorTable, InterruptStackFrame};
|
||||
|
||||
lazy_static! {
|
||||
static ref TEST_IDT: InterruptDescriptorTable = {
|
||||
let mut idt = InterruptDescriptorTable::new();
|
||||
unsafe {
|
||||
idt.double_fault
|
||||
.set_handler_fn(double_fault_handler)
|
||||
.set_stack_index(blog_os::gdt::DOUBLE_FAULT_IST_INDEX);
|
||||
}
|
||||
|
||||
idt
|
||||
};
|
||||
}
|
||||
|
||||
pub fn init_test_idt() {
|
||||
TEST_IDT.load();
|
||||
}
|
||||
|
||||
extern "x86-interrupt" fn double_fault_handler(
|
||||
_stack_frame: &mut InterruptStackFrame,
|
||||
_error_code: u64,
|
||||
) {
|
||||
serial_println!("ok");
|
||||
|
||||
unsafe {
|
||||
exit_qemu();
|
||||
}
|
||||
loop {}
|
||||
}
|
||||
@@ -1,8 +1,11 @@
|
||||
#![cfg_attr(not(test), no_std)]
|
||||
#![cfg_attr(not(test), no_main)]
|
||||
#![cfg_attr(test, allow(unused_imports))]
|
||||
#![feature(alloc_error_handler)]
|
||||
|
||||
use blog_os::memory::allocator::DummyAllocator;
|
||||
use blog_os::{exit_qemu, serial_println};
|
||||
use core::alloc::Layout;
|
||||
use core::panic::PanicInfo;
|
||||
|
||||
#[cfg(not(test))]
|
||||
@@ -21,3 +24,11 @@ fn panic(_info: &PanicInfo) -> ! {
|
||||
}
|
||||
loop {}
|
||||
}
|
||||
|
||||
#[global_allocator]
|
||||
static ALLOCATOR: DummyAllocator = DummyAllocator;
|
||||
|
||||
#[alloc_error_handler]
|
||||
fn out_of_memory(layout: Layout) -> ! {
|
||||
panic!("out of memory: allocation for {:?} failed", layout);
|
||||
}
|
||||
|
||||
52
src/gdt.rs
Normal file
52
src/gdt.rs
Normal file
@@ -0,0 +1,52 @@
|
||||
use lazy_static::lazy_static;
|
||||
use x86_64::structures::gdt::{Descriptor, GlobalDescriptorTable, SegmentSelector};
|
||||
use x86_64::structures::tss::TaskStateSegment;
|
||||
use x86_64::VirtAddr;
|
||||
|
||||
pub const DOUBLE_FAULT_IST_INDEX: u16 = 0;
|
||||
|
||||
lazy_static! {
|
||||
static ref TSS: TaskStateSegment = {
|
||||
let mut tss = TaskStateSegment::new();
|
||||
tss.interrupt_stack_table[DOUBLE_FAULT_IST_INDEX as usize] = {
|
||||
const STACK_SIZE: usize = 4096;
|
||||
static mut STACK: [u8; STACK_SIZE] = [0; STACK_SIZE];
|
||||
|
||||
let stack_start = VirtAddr::from_ptr(unsafe { &STACK });
|
||||
let stack_end = stack_start + STACK_SIZE;
|
||||
stack_end
|
||||
};
|
||||
tss
|
||||
};
|
||||
}
|
||||
|
||||
lazy_static! {
|
||||
static ref GDT: (GlobalDescriptorTable, Selectors) = {
|
||||
let mut gdt = GlobalDescriptorTable::new();
|
||||
let code_selector = gdt.add_entry(Descriptor::kernel_code_segment());
|
||||
let tss_selector = gdt.add_entry(Descriptor::tss_segment(&TSS));
|
||||
(
|
||||
gdt,
|
||||
Selectors {
|
||||
code_selector,
|
||||
tss_selector,
|
||||
},
|
||||
)
|
||||
};
|
||||
}
|
||||
|
||||
struct Selectors {
|
||||
code_selector: SegmentSelector,
|
||||
tss_selector: SegmentSelector,
|
||||
}
|
||||
|
||||
pub fn init() {
|
||||
use x86_64::instructions::segmentation::set_cs;
|
||||
use x86_64::instructions::tables::load_tss;
|
||||
|
||||
GDT.0.load();
|
||||
unsafe {
|
||||
set_cs(GDT.1.code_selector);
|
||||
load_tss(GDT.1.tss_selector);
|
||||
}
|
||||
}
|
||||
@@ -4,14 +4,47 @@
|
||||
// problem we skip compilation of this module on Windows.
|
||||
#![cfg(not(windows))]
|
||||
|
||||
use crate::println;
|
||||
use crate::{gdt, hlt_loop, print, println};
|
||||
use lazy_static::lazy_static;
|
||||
use x86_64::structures::idt::{InterruptDescriptorTable, InterruptStackFrame};
|
||||
use pic8259_simple::ChainedPics;
|
||||
use spin;
|
||||
use x86_64::structures::idt::{InterruptDescriptorTable, InterruptStackFrame, PageFaultErrorCode};
|
||||
|
||||
pub const PIC_1_OFFSET: u8 = 32;
|
||||
pub const PIC_2_OFFSET: u8 = PIC_1_OFFSET + 8;
|
||||
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
#[repr(u8)]
|
||||
pub enum InterruptIndex {
|
||||
Timer = PIC_1_OFFSET,
|
||||
Keyboard,
|
||||
}
|
||||
|
||||
impl InterruptIndex {
|
||||
fn as_u8(self) -> u8 {
|
||||
self as u8
|
||||
}
|
||||
|
||||
fn as_usize(self) -> usize {
|
||||
usize::from(self.as_u8())
|
||||
}
|
||||
}
|
||||
|
||||
pub static PICS: spin::Mutex<ChainedPics> =
|
||||
spin::Mutex::new(unsafe { ChainedPics::new(PIC_1_OFFSET, PIC_2_OFFSET) });
|
||||
|
||||
lazy_static! {
|
||||
static ref IDT: InterruptDescriptorTable = {
|
||||
let mut idt = InterruptDescriptorTable::new();
|
||||
idt.breakpoint.set_handler_fn(breakpoint_handler);
|
||||
idt.page_fault.set_handler_fn(page_fault_handler);
|
||||
unsafe {
|
||||
idt.double_fault
|
||||
.set_handler_fn(double_fault_handler)
|
||||
.set_stack_index(gdt::DOUBLE_FAULT_IST_INDEX);
|
||||
}
|
||||
idt[InterruptIndex::Timer.as_usize()].set_handler_fn(timer_interrupt_handler);
|
||||
idt[InterruptIndex::Keyboard.as_usize()].set_handler_fn(keyboard_interrupt_handler);
|
||||
idt
|
||||
};
|
||||
}
|
||||
@@ -23,3 +56,61 @@ pub fn init_idt() {
|
||||
extern "x86-interrupt" fn breakpoint_handler(stack_frame: &mut InterruptStackFrame) {
|
||||
println!("EXCEPTION: BREAKPOINT\n{:#?}", stack_frame);
|
||||
}
|
||||
|
||||
extern "x86-interrupt" fn page_fault_handler(
|
||||
stack_frame: &mut InterruptStackFrame,
|
||||
_error_code: PageFaultErrorCode,
|
||||
) {
|
||||
use crate::hlt_loop;
|
||||
use x86_64::registers::control::Cr2;
|
||||
|
||||
println!("EXCEPTION: PAGE FAULT");
|
||||
println!("Accessed Address: {:?}", Cr2::read());
|
||||
println!("{:#?}", stack_frame);
|
||||
hlt_loop();
|
||||
}
|
||||
|
||||
extern "x86-interrupt" fn double_fault_handler(
|
||||
stack_frame: &mut InterruptStackFrame,
|
||||
_error_code: u64,
|
||||
) {
|
||||
println!("EXCEPTION: DOUBLE FAULT\n{:#?}", stack_frame);
|
||||
hlt_loop();
|
||||
}
|
||||
|
||||
extern "x86-interrupt" fn timer_interrupt_handler(_stack_frame: &mut InterruptStackFrame) {
|
||||
print!(".");
|
||||
unsafe {
|
||||
PICS.lock()
|
||||
.notify_end_of_interrupt(InterruptIndex::Timer.as_u8());
|
||||
}
|
||||
}
|
||||
|
||||
extern "x86-interrupt" fn keyboard_interrupt_handler(_stack_frame: &mut InterruptStackFrame) {
|
||||
use pc_keyboard::{layouts, DecodedKey, Keyboard, ScancodeSet1};
|
||||
use spin::Mutex;
|
||||
use x86_64::instructions::port::Port;
|
||||
|
||||
lazy_static! {
|
||||
static ref KEYBOARD: Mutex<Keyboard<layouts::Us104Key, ScancodeSet1>> =
|
||||
Mutex::new(Keyboard::new(layouts::Us104Key, ScancodeSet1));
|
||||
}
|
||||
|
||||
let mut keyboard = KEYBOARD.lock();
|
||||
let port = Port::new(0x60);
|
||||
|
||||
let scancode: u8 = unsafe { port.read() };
|
||||
if let Ok(Some(key_event)) = keyboard.add_byte(scancode) {
|
||||
if let Some(key) = keyboard.process_keyevent(key_event) {
|
||||
match key {
|
||||
DecodedKey::Unicode(character) => print!("{}", character),
|
||||
DecodedKey::RawKey(key) => print!("{:?}", key),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
unsafe {
|
||||
PICS.lock()
|
||||
.notify_end_of_interrupt(InterruptIndex::Keyboard.as_u8());
|
||||
}
|
||||
}
|
||||
|
||||
12
src/lib.rs
12
src/lib.rs
@@ -1,7 +1,13 @@
|
||||
#![cfg_attr(not(test), no_std)]
|
||||
#![feature(abi_x86_interrupt)]
|
||||
#![feature(alloc)]
|
||||
#![feature(const_fn)]
|
||||
|
||||
extern crate alloc;
|
||||
|
||||
pub mod gdt;
|
||||
pub mod interrupts;
|
||||
pub mod memory;
|
||||
pub mod serial;
|
||||
pub mod vga_buffer;
|
||||
|
||||
@@ -11,3 +17,9 @@ pub unsafe fn exit_qemu() {
|
||||
let mut port = Port::<u32>::new(0xf4);
|
||||
port.write(0);
|
||||
}
|
||||
|
||||
pub fn hlt_loop() -> ! {
|
||||
loop {
|
||||
x86_64::instructions::hlt();
|
||||
}
|
||||
}
|
||||
|
||||
60
src/main.rs
60
src/main.rs
@@ -1,22 +1,56 @@
|
||||
#![cfg_attr(not(test), no_std)]
|
||||
#![cfg_attr(not(test), no_main)]
|
||||
#![cfg_attr(test, allow(unused_imports))]
|
||||
#![feature(alloc)]
|
||||
#![feature(alloc_error_handler)]
|
||||
|
||||
use blog_os::println;
|
||||
extern crate alloc;
|
||||
|
||||
use alloc::vec::Vec;
|
||||
use blog_os::{
|
||||
memory::allocator::{BumpAllocator, LinkedListAllocator, LockedAllocator, BucketAllocator},
|
||||
println,
|
||||
};
|
||||
use bootloader::{entry_point, BootInfo};
|
||||
use core::alloc::Layout;
|
||||
use core::panic::PanicInfo;
|
||||
|
||||
entry_point!(kernel_main);
|
||||
|
||||
#[cfg(not(test))]
|
||||
#[no_mangle]
|
||||
pub extern "C" fn _start() -> ! {
|
||||
fn kernel_main(boot_info: &'static BootInfo) -> ! {
|
||||
use blog_os::interrupts::PICS;
|
||||
use blog_os::memory;
|
||||
use x86_64::{structures::paging::Page, VirtAddr};
|
||||
|
||||
println!("Hello World{}", "!");
|
||||
|
||||
blog_os::gdt::init();
|
||||
blog_os::interrupts::init_idt();
|
||||
unsafe { PICS.lock().initialize() };
|
||||
x86_64::instructions::interrupts::enable();
|
||||
|
||||
// invoke a breakpoint exception
|
||||
x86_64::instructions::interrupts::int3();
|
||||
let mut mapper = unsafe { memory::init(boot_info.physical_memory_offset) };
|
||||
let mut frame_allocator = memory::init_frame_allocator(&boot_info.memory_map);
|
||||
|
||||
let heap_start = VirtAddr::new(HEAP_START);
|
||||
let heap_end = VirtAddr::new(HEAP_END);
|
||||
memory::map_heap(heap_start, heap_end, &mut mapper, &mut frame_allocator)
|
||||
.expect("map_heap failed");
|
||||
|
||||
ALLOCATOR.lock().underlying().add_memory(heap_start, HEAP_END - HEAP_START);
|
||||
|
||||
//let mut x = Vec::with_capacity(1000);
|
||||
let mut x = Vec::new();
|
||||
for i in 0..1000 {
|
||||
x.push(i);
|
||||
}
|
||||
println!("{:?}", *ALLOCATOR.lock());
|
||||
println!("with vec of size {}: {}", x.len(), x.iter().sum::<i32>());
|
||||
println!("with formular: {}", 999 * 1000 / 2);
|
||||
|
||||
println!("It did not crash!");
|
||||
loop {}
|
||||
blog_os::hlt_loop();
|
||||
}
|
||||
|
||||
/// This function is called on panic.
|
||||
@@ -24,5 +58,17 @@ pub extern "C" fn _start() -> ! {
|
||||
#[panic_handler]
|
||||
fn panic(info: &PanicInfo) -> ! {
|
||||
println!("{}", info);
|
||||
loop {}
|
||||
blog_os::hlt_loop();
|
||||
}
|
||||
|
||||
const HEAP_START: u64 = 0o_001_000_000_0000;
|
||||
const HEAP_END: u64 = HEAP_START + 10 * 0x1000;
|
||||
|
||||
#[global_allocator]
|
||||
static ALLOCATOR: LockedAllocator<BucketAllocator<LinkedListAllocator>> =
|
||||
LockedAllocator::new(BucketAllocator::new(LinkedListAllocator::empty()));
|
||||
|
||||
#[alloc_error_handler]
|
||||
fn out_of_memory(layout: Layout) -> ! {
|
||||
panic!("out of memory: allocation for {:?} failed", layout);
|
||||
}
|
||||
|
||||
120
src/memory.rs
Normal file
120
src/memory.rs
Normal file
@@ -0,0 +1,120 @@
|
||||
use bootloader::bootinfo::{MemoryMap, MemoryRegionType};
|
||||
use x86_64::{
|
||||
structures::paging::{
|
||||
mapper, FrameAllocator, MappedPageTable, Mapper, MapperAllSizes, Page, PageTable,
|
||||
PhysFrame, Size4KiB,
|
||||
},
|
||||
PhysAddr, VirtAddr,
|
||||
};
|
||||
|
||||
pub mod allocator;
|
||||
|
||||
/// Initialize a new MappedPageTable.
|
||||
///
|
||||
/// This function is unsafe because the caller must guarantee that the
|
||||
/// complete physical memory is mapped to virtual memory at the passed
|
||||
/// `physical_memory_offset`. Also, this function must be only called once
|
||||
/// to avoid aliasing `&mut` references (which is undefined behavior).
|
||||
pub unsafe fn init(physical_memory_offset: u64) -> impl MapperAllSizes {
|
||||
let level_4_table = active_level_4_table(physical_memory_offset);
|
||||
let phys_to_virt = move |frame: PhysFrame| -> *mut PageTable {
|
||||
let phys = frame.start_address().as_u64();
|
||||
let virt = VirtAddr::new(phys + physical_memory_offset);
|
||||
virt.as_mut_ptr()
|
||||
};
|
||||
MappedPageTable::new(level_4_table, phys_to_virt)
|
||||
}
|
||||
|
||||
/// Create a FrameAllocator from the passed memory map
|
||||
pub fn init_frame_allocator(
|
||||
memory_map: &'static MemoryMap,
|
||||
) -> BootInfoFrameAllocator<impl Iterator<Item = PhysFrame>> {
|
||||
// get usable regions from memory map
|
||||
let regions = memory_map
|
||||
.iter()
|
||||
.filter(|r| r.region_type == MemoryRegionType::Usable);
|
||||
// map each region to its address range
|
||||
let addr_ranges = regions.map(|r| r.range.start_addr()..r.range.end_addr());
|
||||
// transform to an iterator of frame start addresses
|
||||
let frame_addresses = addr_ranges.flat_map(|r| r.into_iter().step_by(4096));
|
||||
// create `PhysFrame` types from the start addresses
|
||||
let frames = frame_addresses.map(|addr| PhysFrame::containing_address(PhysAddr::new(addr)));
|
||||
|
||||
BootInfoFrameAllocator { frames }
|
||||
}
|
||||
|
||||
/// Returns a mutable reference to the active level 4 table.
|
||||
///
|
||||
/// This function is unsafe because the caller must guarantee that the
|
||||
/// complete physical memory is mapped to virtual memory at the passed
|
||||
/// `physical_memory_offset`. Also, this function must be only called once
|
||||
/// to avoid aliasing `&mut` references (which is undefined behavior).
|
||||
unsafe fn active_level_4_table(physical_memory_offset: u64) -> &'static mut PageTable {
|
||||
use x86_64::{registers::control::Cr3, VirtAddr};
|
||||
|
||||
let (level_4_table_frame, _) = Cr3::read();
|
||||
|
||||
let phys = level_4_table_frame.start_address();
|
||||
let virt = VirtAddr::new(phys.as_u64() + physical_memory_offset);
|
||||
let page_table_ptr: *mut PageTable = virt.as_mut_ptr();
|
||||
|
||||
&mut *page_table_ptr // unsafe
|
||||
}
|
||||
|
||||
pub fn map_heap(
|
||||
heap_start: VirtAddr,
|
||||
heap_end: VirtAddr,
|
||||
mapper: &mut impl Mapper<Size4KiB>,
|
||||
frame_allocator: &mut impl FrameAllocator<Size4KiB>,
|
||||
) -> Result<(), MapHeapError> {
|
||||
use x86_64::structures::paging::PageTableFlags as Flags;
|
||||
|
||||
let flags = Flags::PRESENT | Flags::WRITABLE;
|
||||
let start_page = Page::containing_address(heap_start);
|
||||
let end_page = Page::containing_address(heap_end - 1u64);
|
||||
|
||||
for page in Page::range_inclusive(start_page, end_page) {
|
||||
let frame = frame_allocator.allocate_frame();
|
||||
let frame = frame.ok_or(MapHeapError::FrameAllocationFailed)?;
|
||||
unsafe { mapper.map_to(page, frame, flags, frame_allocator)?.flush() };
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum MapHeapError {
|
||||
FrameAllocationFailed,
|
||||
MapToError(mapper::MapToError),
|
||||
}
|
||||
|
||||
impl From<mapper::MapToError> for MapHeapError {
|
||||
fn from(err: mapper::MapToError) -> Self {
|
||||
MapHeapError::MapToError(err)
|
||||
}
|
||||
}
|
||||
|
||||
/// A FrameAllocator that always returns `None`.
|
||||
pub struct EmptyFrameAllocator;
|
||||
|
||||
impl FrameAllocator<Size4KiB> for EmptyFrameAllocator {
|
||||
fn allocate_frame(&mut self) -> Option<PhysFrame> {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
pub struct BootInfoFrameAllocator<I>
|
||||
where
|
||||
I: Iterator<Item = PhysFrame>,
|
||||
{
|
||||
frames: I,
|
||||
}
|
||||
|
||||
impl<I> FrameAllocator<Size4KiB> for BootInfoFrameAllocator<I>
|
||||
where
|
||||
I: Iterator<Item = PhysFrame>,
|
||||
{
|
||||
fn allocate_frame(&mut self) -> Option<PhysFrame> {
|
||||
self.frames.next()
|
||||
}
|
||||
}
|
||||
49
src/memory/allocator.rs
Normal file
49
src/memory/allocator.rs
Normal file
@@ -0,0 +1,49 @@
|
||||
pub use bump::BumpAllocator;
|
||||
pub use dummy::DummyAllocator;
|
||||
pub use linked_list::LinkedListAllocator;
|
||||
pub use bucket::BucketAllocator;
|
||||
|
||||
use core::alloc::{GlobalAlloc, Layout};
|
||||
use spin::{Mutex, MutexGuard};
|
||||
|
||||
mod bump;
|
||||
mod dummy;
|
||||
mod linked_list;
|
||||
mod bucket;
|
||||
|
||||
pub struct LockedAllocator<T> {
|
||||
allocator: Mutex<T>,
|
||||
}
|
||||
|
||||
impl<T> LockedAllocator<T> {
|
||||
pub const fn new(allocator: T) -> Self {
|
||||
Self {
|
||||
allocator: Mutex::new(allocator),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> LockedAllocator<T> {
|
||||
pub fn lock(&self) -> MutexGuard<T> {
|
||||
self.allocator.lock()
|
||||
}
|
||||
}
|
||||
|
||||
unsafe impl<T> GlobalAlloc for LockedAllocator<T>
|
||||
where
|
||||
T: MutGlobalAlloc,
|
||||
{
|
||||
unsafe fn alloc(&self, layout: Layout) -> *mut u8 {
|
||||
self.allocator.lock().alloc(layout)
|
||||
}
|
||||
|
||||
unsafe fn dealloc(&self, ptr: *mut u8, layout: Layout) {
|
||||
self.allocator.lock().dealloc(ptr, layout)
|
||||
}
|
||||
}
|
||||
|
||||
pub trait MutGlobalAlloc {
|
||||
fn alloc(&mut self, layout: Layout) -> *mut u8;
|
||||
|
||||
fn dealloc(&mut self, ptr: *mut u8, layout: Layout);
|
||||
}
|
||||
126
src/memory/allocator/bucket.rs
Normal file
126
src/memory/allocator/bucket.rs
Normal file
@@ -0,0 +1,126 @@
|
||||
use super::MutGlobalAlloc;
|
||||
use core::alloc::Layout;
|
||||
use core::mem::size_of;
|
||||
use core::fmt::{self, Debug};
|
||||
use core::cmp;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct BucketAllocator<A> where A: MutGlobalAlloc + Debug {
|
||||
underlying: A,
|
||||
buckets: [Bucket; 10],
|
||||
}
|
||||
|
||||
impl<A> BucketAllocator<A> where A: MutGlobalAlloc + Debug {
|
||||
pub const fn new(underlying: A) -> Self {
|
||||
Self {
|
||||
underlying,
|
||||
buckets: [
|
||||
Bucket::new(size_of::<Region>()),
|
||||
Bucket::new(16),
|
||||
Bucket::new(32),
|
||||
Bucket::new(64),
|
||||
Bucket::new(128),
|
||||
Bucket::new(256),
|
||||
Bucket::new(512),
|
||||
Bucket::new(1024),
|
||||
Bucket::new(2048),
|
||||
Bucket::new(4096),
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
pub fn underlying(&mut self) -> &mut A {
|
||||
&mut self.underlying
|
||||
}
|
||||
}
|
||||
|
||||
pub struct Bucket {
|
||||
size: usize,
|
||||
head: Option<&'static mut Region>,
|
||||
}
|
||||
|
||||
impl Bucket {
|
||||
const fn new(size: usize) -> Self {
|
||||
Bucket {
|
||||
size,
|
||||
head: None,
|
||||
}
|
||||
}
|
||||
|
||||
fn layout(&self) -> Layout {
|
||||
Layout::from_size_align(self.size, self.size).unwrap()
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Debug for Bucket {
|
||||
fn fmt(&self, f: &mut fmt::Formatter)-> fmt::Result {
|
||||
let mut regions = 0;
|
||||
let mut current = &self.head;
|
||||
while let Some(region) = current {
|
||||
current = ®ion.next;
|
||||
regions += 1;
|
||||
}
|
||||
f.debug_struct("Bucket").field("size", &self.size).field("regions", ®ions).finish()
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
struct Region {
|
||||
next: Option<&'static mut Region>,
|
||||
}
|
||||
|
||||
impl Region {
|
||||
fn new() -> Self {
|
||||
Self {
|
||||
next: None,
|
||||
}
|
||||
}
|
||||
|
||||
fn as_mut_u8(&'static mut self) -> *mut u8 {
|
||||
self as *mut Region as *mut u8
|
||||
}
|
||||
|
||||
unsafe fn from_mut_u8(ptr: *mut u8) -> &'static mut Self {
|
||||
(ptr as *mut Region).write(Region::new());
|
||||
&mut *(ptr as *mut Region)
|
||||
}
|
||||
}
|
||||
|
||||
impl<A> BucketAllocator<A> where A: MutGlobalAlloc + Debug {
|
||||
fn get_bucket_index(&self, layout: &Layout) -> Option<usize> {
|
||||
let required_bucket_size = cmp::max(layout.size(), layout.align());
|
||||
match self.buckets.binary_search_by(|bucket| bucket.size.cmp(&required_bucket_size)) {
|
||||
Ok(index) => Some(index),
|
||||
Err(index) if index < self.buckets.len() => Some(index),
|
||||
Err(_) => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<A> MutGlobalAlloc for BucketAllocator<A> where A: MutGlobalAlloc + Debug {
|
||||
fn alloc(&mut self, layout: Layout) -> *mut u8 {
|
||||
if let Some(bucket_index) = self.get_bucket_index(&layout) {
|
||||
let bucket = &mut self.buckets[bucket_index];
|
||||
if let Some(head) = bucket.head.take() {
|
||||
let next = head.next.take();
|
||||
bucket.head = next;
|
||||
return head.as_mut_u8();
|
||||
} else {
|
||||
self.underlying.alloc(bucket.layout())
|
||||
}
|
||||
} else {
|
||||
self.underlying.alloc(layout)
|
||||
}
|
||||
}
|
||||
|
||||
fn dealloc(&mut self, ptr: *mut u8, layout: Layout) {
|
||||
if let Some(bucket_index) = self.get_bucket_index(&layout) {
|
||||
let bucket = &mut self.buckets[bucket_index];
|
||||
let region = unsafe {Region::from_mut_u8(ptr)};
|
||||
region.next = bucket.head.take();
|
||||
bucket.head = Some(region);
|
||||
} else {
|
||||
self.underlying.dealloc(ptr, layout);
|
||||
}
|
||||
}
|
||||
}
|
||||
38
src/memory/allocator/bump.rs
Normal file
38
src/memory/allocator/bump.rs
Normal file
@@ -0,0 +1,38 @@
|
||||
use super::MutGlobalAlloc;
|
||||
use core::alloc::Layout;
|
||||
use x86_64::align_up;
|
||||
|
||||
pub struct BumpAllocator {
|
||||
heap_start: u64,
|
||||
heap_end: u64,
|
||||
next: u64,
|
||||
}
|
||||
|
||||
impl BumpAllocator {
|
||||
pub const fn new(heap_start: u64, heap_end: u64) -> Self {
|
||||
Self {
|
||||
heap_start,
|
||||
heap_end,
|
||||
next: heap_start,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl MutGlobalAlloc for BumpAllocator {
|
||||
fn alloc(&mut self, layout: Layout) -> *mut u8 {
|
||||
let alloc_start = align_up(self.next, layout.align() as u64);
|
||||
let alloc_end = alloc_start.saturating_add(layout.size() as u64);
|
||||
|
||||
if alloc_end >= self.heap_end {
|
||||
// out of memory
|
||||
return 0 as *mut u8;
|
||||
}
|
||||
|
||||
self.next = alloc_end;
|
||||
alloc_start as *mut u8
|
||||
}
|
||||
|
||||
fn dealloc(&mut self, _ptr: *mut u8, _layout: Layout) {
|
||||
panic!("BumpAllocator::dealloc called");
|
||||
}
|
||||
}
|
||||
16
src/memory/allocator/dummy.rs
Normal file
16
src/memory/allocator/dummy.rs
Normal file
@@ -0,0 +1,16 @@
|
||||
use core::alloc::{GlobalAlloc, Layout};
|
||||
|
||||
/// A dummy allocator that panics on every `alloc` or `dealloc` call.
|
||||
pub struct DummyAllocator;
|
||||
|
||||
unsafe impl GlobalAlloc for DummyAllocator {
|
||||
/// Always panics.
|
||||
unsafe fn alloc(&self, _layout: Layout) -> *mut u8 {
|
||||
panic!("DummyAllocator::alloc called");
|
||||
}
|
||||
|
||||
/// Always panics.
|
||||
unsafe fn dealloc(&self, _ptr: *mut u8, _layout: Layout) {
|
||||
panic!("DummyAllocator::dealloc called");
|
||||
}
|
||||
}
|
||||
95
src/memory/allocator/linked_list.rs
Normal file
95
src/memory/allocator/linked_list.rs
Normal file
@@ -0,0 +1,95 @@
|
||||
use super::MutGlobalAlloc;
|
||||
use core::alloc::Layout;
|
||||
use core::mem;
|
||||
use x86_64::{align_up, VirtAddr};
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct LinkedListAllocator {
|
||||
head: Region,
|
||||
}
|
||||
|
||||
impl LinkedListAllocator {
|
||||
pub const fn empty() -> Self {
|
||||
let head = Region {
|
||||
size: 0,
|
||||
next: None,
|
||||
};
|
||||
Self { head }
|
||||
}
|
||||
|
||||
pub unsafe fn new(heap_start: VirtAddr, heap_size: u64) -> Self {
|
||||
let mut allocator = Self::empty();
|
||||
allocator.add_memory(heap_start, heap_size);
|
||||
allocator
|
||||
}
|
||||
|
||||
pub fn add_memory(&mut self, start: VirtAddr, size: u64) {
|
||||
let aligned = start.align_up(mem::size_of::<Region>() as u64);
|
||||
let mut region = Region {
|
||||
size: size - (aligned - start),
|
||||
next: None
|
||||
};
|
||||
mem::swap(&mut self.head.next, &mut region.next);
|
||||
|
||||
let region_ptr: *mut Region = aligned.as_mut_ptr();
|
||||
unsafe { region_ptr.write(region) };
|
||||
self.head.next = Some(unsafe { &mut *region_ptr });
|
||||
}
|
||||
}
|
||||
|
||||
impl MutGlobalAlloc for LinkedListAllocator {
|
||||
fn alloc(&mut self, layout: Layout) -> *mut u8 {
|
||||
let size = align_up(layout.size() as u64, mem::size_of::<Region>() as u64);
|
||||
|
||||
let mut current = &mut self.head;
|
||||
loop {
|
||||
let next = match current.next {
|
||||
Some(ref mut next) => next,
|
||||
None => break,
|
||||
};
|
||||
let next_start = VirtAddr::new(*next as *mut Region as u64);
|
||||
let next_end = next_start + next.size;
|
||||
|
||||
let alloc_start = next_start.align_up(layout.align() as u64);
|
||||
let alloc_end = alloc_start + size;
|
||||
|
||||
// check if Region large enough
|
||||
if alloc_end <= next_end {
|
||||
// remove Region from list
|
||||
let next_next = next.next.take();
|
||||
current.next = next_next;
|
||||
// insert remaining Region to list
|
||||
self.add_memory(alloc_end, next_end - alloc_end);
|
||||
// return allocated memory
|
||||
return alloc_start.as_mut_ptr();
|
||||
}
|
||||
|
||||
// continue with next element
|
||||
//
|
||||
// This is basically `current = next`, but we need a new `match` expression because
|
||||
// the compiler can't figure the lifetimes out when we use the `next` binding
|
||||
// from above.
|
||||
current = match current.next {
|
||||
Some(ref mut next) => next,
|
||||
None => unreachable!(),
|
||||
};
|
||||
}
|
||||
|
||||
// no large enough Region found
|
||||
0 as *mut u8
|
||||
}
|
||||
|
||||
fn dealloc(&mut self, ptr: *mut u8, layout: Layout) {
|
||||
let size = align_up(layout.size() as u64, mem::size_of::<Region>() as u64);
|
||||
self.add_memory(VirtAddr::new(ptr as u64), size);
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
struct Region {
|
||||
size: u64,
|
||||
next: Option<&'static mut Region>,
|
||||
}
|
||||
|
||||
|
||||
// TODO recycle alignment
|
||||
@@ -13,10 +13,14 @@ lazy_static! {
|
||||
#[doc(hidden)]
|
||||
pub fn _print(args: ::core::fmt::Arguments) {
|
||||
use core::fmt::Write;
|
||||
use x86_64::instructions::interrupts;
|
||||
|
||||
interrupts::without_interrupts(|| {
|
||||
SERIAL1
|
||||
.lock()
|
||||
.write_fmt(args)
|
||||
.expect("Printing to serial failed");
|
||||
});
|
||||
}
|
||||
|
||||
/// Prints to the host through the serial interface.
|
||||
|
||||
@@ -163,11 +163,16 @@ macro_rules! println {
|
||||
($($arg:tt)*) => ($crate::print!("{}\n", format_args!($($arg)*)));
|
||||
}
|
||||
|
||||
/// Prints the given formatted string to the VGA text buffer through the global `WRITER` instance.
|
||||
/// Prints the given formatted string to the VGA text buffer
|
||||
/// through the global `WRITER` instance.
|
||||
#[doc(hidden)]
|
||||
pub fn _print(args: fmt::Arguments) {
|
||||
use core::fmt::Write;
|
||||
use x86_64::instructions::interrupts;
|
||||
|
||||
interrupts::without_interrupts(|| {
|
||||
WRITER.lock().write_fmt(args).unwrap();
|
||||
});
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
|
||||
Reference in New Issue
Block a user