mirror of
https://github.com/phil-opp/blog_os.git
synced 2025-12-16 14:27:49 +00:00
Compare commits
116 Commits
post-06
...
code-heap-
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
1eb8f0f2c7 | ||
|
|
398ca5357c | ||
|
|
4acf12bb69 | ||
|
|
6f25c34d46 | ||
|
|
23e45b5b13 | ||
|
|
161d5fe7be | ||
|
|
9bf4ea7341 | ||
|
|
a1bf5651fc | ||
|
|
763228c859 | ||
|
|
770af27d75 | ||
|
|
3e59283c19 | ||
|
|
6146ccba2d | ||
|
|
b0e1527a95 | ||
|
|
cb4410c84e | ||
|
|
98b5976656 | ||
|
|
9335386928 | ||
|
|
7c30d62f33 | ||
|
|
61683bccda | ||
|
|
e1ec5159b8 | ||
|
|
7b7d19592f | ||
|
|
e387c0b6b8 | ||
|
|
d5abc119f3 | ||
|
|
59da6e5620 | ||
|
|
ef1cc0ed4f | ||
|
|
90f0caec1a | ||
|
|
7198a4d110 | ||
|
|
5c0fb63f33 | ||
|
|
6ffcb2cf1a | ||
|
|
1c72107cb1 | ||
|
|
036a8e7608 | ||
|
|
3b960751f4 | ||
|
|
0ff6334026 | ||
|
|
10c4d0509d | ||
|
|
57998ea4f8 | ||
|
|
f05aaeb0ac | ||
|
|
78a30984bc | ||
|
|
09dd68a1a2 | ||
|
|
81e4eec055 | ||
|
|
ef9a629ddc | ||
|
|
18d8d311cb | ||
|
|
7b61da94a0 | ||
|
|
d974cf5200 | ||
|
|
94447af25a | ||
|
|
a7f487f206 | ||
|
|
36d6c6d0e9 | ||
|
|
76d3715eef | ||
|
|
babf9d8cce | ||
|
|
ff49104764 | ||
|
|
bda1b8929c | ||
|
|
09ff2e01b1 | ||
|
|
03e43da9f9 | ||
|
|
58e171cce7 | ||
|
|
901a1630eb | ||
|
|
e696d65b60 | ||
|
|
ef09418cbf | ||
|
|
28f37da07d | ||
|
|
ebf626061f | ||
|
|
4c9352d898 | ||
|
|
a41a007039 | ||
|
|
c3d023ad40 | ||
|
|
f3cf5b51de | ||
|
|
26be4cb84d | ||
|
|
0a10b3e784 | ||
|
|
9617680e45 | ||
|
|
8f18fb4282 | ||
|
|
e0f66a8196 | ||
|
|
ba54fd2503 | ||
|
|
6b9d275c2d | ||
|
|
e5dfbd4b23 | ||
|
|
4e6ce8d16e | ||
|
|
519f47286c | ||
|
|
5ad2962389 | ||
|
|
82e6c4b066 | ||
|
|
d564dc208f | ||
|
|
a56e22b6fc | ||
|
|
67f536d7c6 | ||
|
|
741224411b | ||
|
|
818417d119 | ||
|
|
f272785861 | ||
|
|
5d807ee622 | ||
|
|
90c3cdf0f3 | ||
|
|
2bc233b2f6 | ||
|
|
0df629df47 | ||
|
|
cca85de5ed | ||
|
|
1da81c6f84 | ||
|
|
42d89c1030 | ||
|
|
051b23f577 | ||
|
|
97e884e6a3 | ||
|
|
954c0bcfbb | ||
|
|
bd1f5345da | ||
|
|
662faa8dd0 | ||
|
|
f2bc2d33f0 | ||
|
|
38a121a887 | ||
|
|
8b380f0692 | ||
|
|
f23ee04161 | ||
|
|
2031a8dc81 | ||
|
|
b184f7d996 | ||
|
|
7c07a67bf5 | ||
|
|
ec2da4bebd | ||
|
|
abaf5bd862 | ||
|
|
b7005b766f | ||
|
|
91ca04e8c2 | ||
|
|
ada45c6e52 | ||
|
|
207a466707 | ||
|
|
a954c02fbe | ||
|
|
895991fee3 | ||
|
|
25796110f3 | ||
|
|
1d153d694e | ||
|
|
c2e4e8c96f | ||
|
|
599a643d97 | ||
|
|
5efcecc2f2 | ||
|
|
1a39774ead | ||
|
|
1ea8cf6ed1 | ||
|
|
4060ac558c | ||
|
|
28a11e47bc | ||
|
|
6504bed810 |
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)",
|
"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)",
|
"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)",
|
"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)",
|
"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)",
|
"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)",
|
"volatile 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
@@ -56,6 +58,11 @@ name = "cc"
|
|||||||
version = "1.0.30"
|
version = "1.0.30"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
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]]
|
[[package]]
|
||||||
name = "fixedvec"
|
name = "fixedvec"
|
||||||
version = "0.2.3"
|
version = "0.2.3"
|
||||||
@@ -114,6 +121,19 @@ name = "os_bootinfo"
|
|||||||
version = "0.2.1"
|
version = "0.2.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
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]]
|
[[package]]
|
||||||
name = "pulldown-cmark"
|
name = "pulldown-cmark"
|
||||||
version = "0.0.3"
|
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 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 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 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 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 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"
|
"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 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 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 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 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 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"
|
"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"
|
edition = "2018"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
bootloader = "0.4.0"
|
bootloader = { version = "0.4.0", features = ["map_physical_memory"]}
|
||||||
volatile = "0.2.3"
|
volatile = "0.2.3"
|
||||||
spin = "0.4.9"
|
spin = "0.4.9"
|
||||||
uart_16550 = "0.1.0"
|
uart_16550 = "0.1.0"
|
||||||
x86_64 = "0.5.2"
|
x86_64 = "0.5.2"
|
||||||
|
pic8259_simple = "0.1.1"
|
||||||
|
pc-keyboard = "0.3.1"
|
||||||
|
|
||||||
[dependencies.lazy_static]
|
[dependencies.lazy_static]
|
||||||
version = "1.0"
|
version = "1.0"
|
||||||
|
|||||||
@@ -1,10 +1,10 @@
|
|||||||
# Blog OS (Double Faults)
|
# 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 [Double Faults][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/double-fault-exceptions/
|
[post]: https://os.phil-opp.com/paging-implementation/
|
||||||
|
|
||||||
**Check out the [master branch](https://github.com/phil-opp/blog_os) for more information.**
|
**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_std)]
|
||||||
#![cfg_attr(not(test), no_main)] // disable all Rust-level entry points
|
#![cfg_attr(not(test), no_main)] // disable all Rust-level entry points
|
||||||
#![cfg_attr(test, allow(unused_imports))]
|
#![cfg_attr(test, allow(unused_imports))]
|
||||||
|
#![feature(alloc_error_handler)]
|
||||||
|
|
||||||
|
use blog_os::memory::allocator::DummyAllocator;
|
||||||
use blog_os::{exit_qemu, serial_println};
|
use blog_os::{exit_qemu, serial_println};
|
||||||
|
use core::alloc::Layout;
|
||||||
use core::panic::PanicInfo;
|
use core::panic::PanicInfo;
|
||||||
|
|
||||||
/// This function is the entry point, since the linker looks for a function
|
/// This function is the entry point, since the linker looks for a function
|
||||||
@@ -31,3 +34,11 @@ fn panic(info: &PanicInfo) -> ! {
|
|||||||
}
|
}
|
||||||
loop {}
|
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]
|
#![no_std]
|
||||||
#![cfg_attr(not(test), no_main)]
|
#![cfg_attr(not(test), no_main)]
|
||||||
#![cfg_attr(test, allow(dead_code, unused_macros, unused_imports))]
|
#![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 blog_os::{exit_qemu, serial_println};
|
||||||
|
use core::alloc::Layout;
|
||||||
use core::panic::PanicInfo;
|
use core::panic::PanicInfo;
|
||||||
|
|
||||||
#[cfg(not(test))]
|
#[cfg(not(test))]
|
||||||
@@ -32,3 +35,11 @@ fn panic(info: &PanicInfo) -> ! {
|
|||||||
}
|
}
|
||||||
loop {}
|
loop {}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[global_allocator]
|
||||||
|
static ALLOCATOR: DummyAllocator = DummyAllocator;
|
||||||
|
|
||||||
|
#[alloc_error_handler]
|
||||||
|
fn out_of_memory(layout: Layout) -> ! {
|
||||||
|
panic!("out of memory: allocation for {:?} failed", layout);
|
||||||
|
}
|
||||||
|
|||||||
@@ -2,8 +2,11 @@
|
|||||||
#![no_std]
|
#![no_std]
|
||||||
#![cfg_attr(not(test), no_main)]
|
#![cfg_attr(not(test), no_main)]
|
||||||
#![cfg_attr(test, allow(dead_code, unused_macros, unused_imports))]
|
#![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 blog_os::{exit_qemu, serial_println};
|
||||||
|
use core::alloc::Layout;
|
||||||
use core::panic::PanicInfo;
|
use core::panic::PanicInfo;
|
||||||
use lazy_static::lazy_static;
|
use lazy_static::lazy_static;
|
||||||
|
|
||||||
@@ -45,6 +48,14 @@ fn panic(info: &PanicInfo) -> ! {
|
|||||||
loop {}
|
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};
|
use x86_64::structures::idt::{InterruptDescriptorTable, InterruptStackFrame};
|
||||||
|
|
||||||
lazy_static! {
|
lazy_static! {
|
||||||
|
|||||||
@@ -1,8 +1,11 @@
|
|||||||
#![cfg_attr(not(test), no_std)]
|
#![cfg_attr(not(test), no_std)]
|
||||||
#![cfg_attr(not(test), no_main)]
|
#![cfg_attr(not(test), no_main)]
|
||||||
#![cfg_attr(test, allow(unused_imports))]
|
#![cfg_attr(test, allow(unused_imports))]
|
||||||
|
#![feature(alloc_error_handler)]
|
||||||
|
|
||||||
|
use blog_os::memory::allocator::DummyAllocator;
|
||||||
use blog_os::{exit_qemu, serial_println};
|
use blog_os::{exit_qemu, serial_println};
|
||||||
|
use core::alloc::Layout;
|
||||||
use core::panic::PanicInfo;
|
use core::panic::PanicInfo;
|
||||||
|
|
||||||
#[cfg(not(test))]
|
#[cfg(not(test))]
|
||||||
@@ -21,3 +24,11 @@ fn panic(_info: &PanicInfo) -> ! {
|
|||||||
}
|
}
|
||||||
loop {}
|
loop {}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[global_allocator]
|
||||||
|
static ALLOCATOR: DummyAllocator = DummyAllocator;
|
||||||
|
|
||||||
|
#[alloc_error_handler]
|
||||||
|
fn out_of_memory(layout: Layout) -> ! {
|
||||||
|
panic!("out of memory: allocation for {:?} failed", layout);
|
||||||
|
}
|
||||||
|
|||||||
@@ -4,19 +4,47 @@
|
|||||||
// problem we skip compilation of this module on Windows.
|
// problem we skip compilation of this module on Windows.
|
||||||
#![cfg(not(windows))]
|
#![cfg(not(windows))]
|
||||||
|
|
||||||
use crate::{gdt, println};
|
use crate::{gdt, hlt_loop, print, println};
|
||||||
use lazy_static::lazy_static;
|
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! {
|
lazy_static! {
|
||||||
static ref IDT: InterruptDescriptorTable = {
|
static ref IDT: InterruptDescriptorTable = {
|
||||||
let mut idt = InterruptDescriptorTable::new();
|
let mut idt = InterruptDescriptorTable::new();
|
||||||
idt.breakpoint.set_handler_fn(breakpoint_handler);
|
idt.breakpoint.set_handler_fn(breakpoint_handler);
|
||||||
|
idt.page_fault.set_handler_fn(page_fault_handler);
|
||||||
unsafe {
|
unsafe {
|
||||||
idt.double_fault
|
idt.double_fault
|
||||||
.set_handler_fn(double_fault_handler)
|
.set_handler_fn(double_fault_handler)
|
||||||
.set_stack_index(gdt::DOUBLE_FAULT_IST_INDEX);
|
.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
|
idt
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@@ -29,10 +57,60 @@ extern "x86-interrupt" fn breakpoint_handler(stack_frame: &mut InterruptStackFra
|
|||||||
println!("EXCEPTION: BREAKPOINT\n{:#?}", stack_frame);
|
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(
|
extern "x86-interrupt" fn double_fault_handler(
|
||||||
stack_frame: &mut InterruptStackFrame,
|
stack_frame: &mut InterruptStackFrame,
|
||||||
_error_code: u64,
|
_error_code: u64,
|
||||||
) {
|
) {
|
||||||
println!("EXCEPTION: DOUBLE FAULT\n{:#?}", stack_frame);
|
println!("EXCEPTION: DOUBLE FAULT\n{:#?}", stack_frame);
|
||||||
loop {}
|
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());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
11
src/lib.rs
11
src/lib.rs
@@ -1,8 +1,13 @@
|
|||||||
#![cfg_attr(not(test), no_std)]
|
#![cfg_attr(not(test), no_std)]
|
||||||
#![feature(abi_x86_interrupt)]
|
#![feature(abi_x86_interrupt)]
|
||||||
|
#![feature(alloc)]
|
||||||
|
#![feature(const_fn)]
|
||||||
|
|
||||||
|
extern crate alloc;
|
||||||
|
|
||||||
pub mod gdt;
|
pub mod gdt;
|
||||||
pub mod interrupts;
|
pub mod interrupts;
|
||||||
|
pub mod memory;
|
||||||
pub mod serial;
|
pub mod serial;
|
||||||
pub mod vga_buffer;
|
pub mod vga_buffer;
|
||||||
|
|
||||||
@@ -12,3 +17,9 @@ pub unsafe fn exit_qemu() {
|
|||||||
let mut port = Port::<u32>::new(0xf4);
|
let mut port = Port::<u32>::new(0xf4);
|
||||||
port.write(0);
|
port.write(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn hlt_loop() -> ! {
|
||||||
|
loop {
|
||||||
|
x86_64::instructions::hlt();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
61
src/main.rs
61
src/main.rs
@@ -1,27 +1,56 @@
|
|||||||
#![cfg_attr(not(test), no_std)]
|
#![cfg_attr(not(test), no_std)]
|
||||||
#![cfg_attr(not(test), no_main)]
|
#![cfg_attr(not(test), no_main)]
|
||||||
#![cfg_attr(test, allow(unused_imports))]
|
#![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;
|
use core::panic::PanicInfo;
|
||||||
|
|
||||||
|
entry_point!(kernel_main);
|
||||||
|
|
||||||
#[cfg(not(test))]
|
#[cfg(not(test))]
|
||||||
#[no_mangle]
|
fn kernel_main(boot_info: &'static BootInfo) -> ! {
|
||||||
pub extern "C" fn _start() -> ! {
|
use blog_os::interrupts::PICS;
|
||||||
|
use blog_os::memory;
|
||||||
|
use x86_64::{structures::paging::Page, VirtAddr};
|
||||||
|
|
||||||
println!("Hello World{}", "!");
|
println!("Hello World{}", "!");
|
||||||
|
|
||||||
blog_os::gdt::init();
|
blog_os::gdt::init();
|
||||||
blog_os::interrupts::init_idt();
|
blog_os::interrupts::init_idt();
|
||||||
|
unsafe { PICS.lock().initialize() };
|
||||||
|
x86_64::instructions::interrupts::enable();
|
||||||
|
|
||||||
fn stack_overflow() {
|
let mut mapper = unsafe { memory::init(boot_info.physical_memory_offset) };
|
||||||
stack_overflow(); // for each recursion, the return address is pushed
|
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());
|
||||||
// trigger a stack overflow
|
println!("with vec of size {}: {}", x.len(), x.iter().sum::<i32>());
|
||||||
stack_overflow();
|
println!("with formular: {}", 999 * 1000 / 2);
|
||||||
|
|
||||||
println!("It did not crash!");
|
println!("It did not crash!");
|
||||||
loop {}
|
blog_os::hlt_loop();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// This function is called on panic.
|
/// This function is called on panic.
|
||||||
@@ -29,5 +58,17 @@ pub extern "C" fn _start() -> ! {
|
|||||||
#[panic_handler]
|
#[panic_handler]
|
||||||
fn panic(info: &PanicInfo) -> ! {
|
fn panic(info: &PanicInfo) -> ! {
|
||||||
println!("{}", info);
|
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)]
|
#[doc(hidden)]
|
||||||
pub fn _print(args: ::core::fmt::Arguments) {
|
pub fn _print(args: ::core::fmt::Arguments) {
|
||||||
use core::fmt::Write;
|
use core::fmt::Write;
|
||||||
SERIAL1
|
use x86_64::instructions::interrupts;
|
||||||
.lock()
|
|
||||||
.write_fmt(args)
|
interrupts::without_interrupts(|| {
|
||||||
.expect("Printing to serial failed");
|
SERIAL1
|
||||||
|
.lock()
|
||||||
|
.write_fmt(args)
|
||||||
|
.expect("Printing to serial failed");
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Prints to the host through the serial interface.
|
/// Prints to the host through the serial interface.
|
||||||
|
|||||||
@@ -163,11 +163,16 @@ macro_rules! println {
|
|||||||
($($arg:tt)*) => ($crate::print!("{}\n", format_args!($($arg)*)));
|
($($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)]
|
#[doc(hidden)]
|
||||||
pub fn _print(args: fmt::Arguments) {
|
pub fn _print(args: fmt::Arguments) {
|
||||||
use core::fmt::Write;
|
use core::fmt::Write;
|
||||||
WRITER.lock().write_fmt(args).unwrap();
|
use x86_64::instructions::interrupts;
|
||||||
|
|
||||||
|
interrupts::without_interrupts(|| {
|
||||||
|
WRITER.lock().write_fmt(args).unwrap();
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
|
|||||||
Reference in New Issue
Block a user