diff --git a/blog/post/2015-11-15-allocating-frames.md b/blog/post/2015-11-15-allocating-frames.md
index 294b6d7c..acbe416c 100644
--- a/blog/post/2015-11-15-allocating-frames.md
+++ b/blog/post/2015-11-15-allocating-frames.md
@@ -49,15 +49,20 @@ Instead of writing an own Multiboot module, we use the [multiboot2-elf64] crate.
[multiboot2-elf64]: https://github.com/phil-opp/multiboot2-elf64
[^fn-multiboot-crate]: All contributions are welcome! If you want to maintain it, please contact me!
-So let's add a dependency on the git repository in the `Cargo.toml`:
+So let's add a dependency on the git repository:
```toml
-...
+# in Cargo.toml
[dependencies.multiboot2]
git = "https://github.com/phil-opp/multiboot2-elf64"
```
-Now we can add `extern crate multiboot2` and use it to print available memory areas.
+```rust
+// in src/lib.rs
+extern crate multiboot2;
+```
+
+Now we can use it to print available memory areas.
### Available Memory
The boot information structure consists of various _tags_. See section 3.4 of the Multiboot specification ([PDF][multiboot specification]) for a complete list. The _memory map_ tag contains a list of all available RAM areas. Special areas such as the VGA text buffer at `0xb8000` are not available. Note that some of the available memory is already used by our kernel and by the multiboot information structure itself.
@@ -264,49 +269,64 @@ pub struct AreaFrameAllocator {
```
The `next_free_frame` field is a simple counter that is increased every time we return a frame. It's initialized to `0` and every frame below it counts as used. The `current_area` field holds the memory area that contains `next_free_frame`. If `next_free_frame` leaves this area, we will look for the next one in `areas`. When there are no areas left, all frames are used and `current_area` becomes `None`. The `{kernel, multiboot}_{start, end}` fields are used to avoid returning already used fields.
-To implement the `FrameAllocator` trait, we need to implement the `allocate_frame` and the `deallocate_frame` methods. The former looks like this:
+To implement the `FrameAllocator` trait, we need to implement the allocation and deallocation methods:
```rust
-fn allocate_frame(&mut self) -> Option {
- if let Some(area) = self.current_area {
- // "clone" the frame to return it if it's free. Frame doesn't
- // implement Clone, but we can construct an identical frame.
- let frame = Frame{ number: self.next_free_frame.number };
+impl FrameAllocator for AreaFrameAllocator {
+ fn allocate_frame(&mut self) -> Option {
+ // TODO (see below)
+ }
- // the last frame of the current area
- let current_area_last_frame = {
- let address = area.base_addr + area.length - 1;
- Frame::containing_address(address as usize)
- };
-
- if frame > current_area_last_frame {
- // all frames of current area are used, switch to next area
- self.choose_next_area();
- } else if frame >= self.kernel_start && frame <= self.kernel_end {
- // `frame` is used by the kernel
- self.next_free_frame = Frame {
- number: self.kernel_end.number + 1
- };
- } else if frame >= self.multiboot_start && frame <= self.multiboot_end {
- // `frame` is used by the multiboot information structure
- self.next_free_frame = Frame {
- number: self.multiboot_end.number + 1
- };
- } else {
- // frame is unused, increment `next_free_frame` and return it
- self.next_free_frame.number += 1;
- return Some(frame);
- }
- // `frame` was not valid, try it again with the updated `next_free_frame`
- self.allocate_frame()
- } else {
- None // no free frames left
+ fn deallocate_frame(&mut self, frame: Frame) {
+ // TODO (see below)
}
}
```
-The `choose_next_area` method isn't part of the trait and thus goes into an `impl AreaFrameAllocator` block:
+The `allocate_frame` method looks like this:
```rust
+// in `allocate_frame` in `impl FrameAllocator for AreaFrameAllocator`
+
+if let Some(area) = self.current_area {
+ // "Clone" the frame to return it if it's free. Frame doesn't
+ // implement Clone, but we can construct an identical frame.
+ let frame = Frame{ number: self.next_free_frame.number };
+
+ // the last frame of the current area
+ let current_area_last_frame = {
+ let address = area.base_addr + area.length - 1;
+ Frame::containing_address(address as usize)
+ };
+
+ if frame > current_area_last_frame {
+ // all frames of current area are used, switch to next area
+ self.choose_next_area();
+ } else if frame >= self.kernel_start && frame <= self.kernel_end {
+ // `frame` is used by the kernel
+ self.next_free_frame = Frame {
+ number: self.kernel_end.number + 1
+ };
+ } else if frame >= self.multiboot_start && frame <= self.multiboot_end {
+ // `frame` is used by the multiboot information structure
+ self.next_free_frame = Frame {
+ number: self.multiboot_end.number + 1
+ };
+ } else {
+ // frame is unused, increment `next_free_frame` and return it
+ self.next_free_frame.number += 1;
+ return Some(frame);
+ }
+ // `frame` was not valid, try it again with the updated `next_free_frame`
+ self.allocate_frame()
+} else {
+ None // no free frames left
+}
+```
+The `choose_next_area` method isn't part of the trait and thus goes into a new `impl AreaFrameAllocator` block:
+
+```rust
+// in `impl AreaFrameAllocator`
+
fn choose_next_area(&mut self) {
self.current_area = self.areas.clone().filter(|area| {
let address = area.base_addr + area.length - 1;
@@ -330,8 +350,14 @@ If the `next_free_frame` is below the new `current_area`, it needs to be updated
We don't have a data structure to store free frames, so we can't implement `deallocate_frame` reasonably. Thus we use the `unimplemented` macro, which just panics when the method is called:
```rust
-fn deallocate_frame(&mut self, _frame: Frame) {
- unimplemented!()
+impl FrameAllocator for AreaFrameAllocator {
+ fn allocate_frame(&mut self) -> Option {
+ // described above
+ }
+
+ fn deallocate_frame(&mut self, _frame: Frame) {
+ unimplemented!()
+ }
}
```
diff --git a/blog/post/2015-12-09-modifying-page-tables.md b/blog/post/2015-12-09-modifying-page-tables.md
index b6a0ee76..1d3d903e 100644
--- a/blog/post/2015-12-09-modifying-page-tables.md
+++ b/blog/post/2015-12-09-modifying-page-tables.md
@@ -101,7 +101,13 @@ features = ["no_std"]
The `no_std` feature is needed because `bitflags` depends on the standard library by default. But it has a [cargo feature] to use the core library instead. It will become the default as soon as `no_std` is stable in a stable Rust release.
[cargo feature]: http://doc.crates.io/manifest.html#the-[features]-section
-Note that you need a `#[macro_use]` above the `extern crate` definition.
+To import the macro, we need to use `#[macro_use]` above the `extern crate` definition:
+
+```rust
+// in src/lib.rs
+#[macro_use]
+extern crate bitflags;
+```
Now we can model the various flags:
diff --git a/blog/post/2016-04-11-kernel-heap.md b/blog/post/2016-04-11-kernel-heap.md
index 9f5c89b7..57f52713 100644
--- a/blog/post/2016-04-11-kernel-heap.md
+++ b/blog/post/2016-04-11-kernel-heap.md
@@ -320,7 +320,7 @@ let heap_test = Box::new(42);
When we try to compile it using `make run`, we get several linker errors about a function named `_Unwind_Resume`:
```
-target/x86_64-unknown-linux-gnu/debug/libblog_os.a(bump_allocator-947b648f2a584929.0.o):
+target/x86_64-unknown-linux-gnu/debug/libblog_os.a(bump_allocator-[…].0.o):
In function `bump_allocator::__rust_allocate':
/home/…/blog_os/libs/bump_allocator/src/lib.rs:19:
undefined reference to `_Unwind_Resume'
@@ -461,8 +461,8 @@ The crate provides an [assert_has_not_been_called!] macro (sorry for the long na
pub fn init(boot_info: &BootInformation) {
assert_has_not_been_called!("memory::init must be called only once");
- let memory_map_tag = …
- …
+ let memory_map_tag = ...
+ ...
}
```
That's it. Now our `memory::init` function can only be called once. The macro works by creating a static [AtomicBool] named `CALLED`, which is initialized to `false`. When the macro is invoked, it checks the value of `CALLED` and sets it to `true`. If the value was already `true` before, the macro panics.
@@ -481,7 +481,7 @@ pub fn remap_the_kernel(allocator: &mut A, boot_info: &BootInformation)
-> ActivePageTable // new
where A: FrameAllocator
{
- …
+ ...
println!("guard page at {:#x}", old_p4_page.start_address());
active_table // new
@@ -494,9 +494,9 @@ Now we have full page table access in the `memory::init` function. This allows u
// in src/memory/mod.rs
pub fn init(boot_info: &BootInformation) {
- …
+ ...
- let mut frame_allocator = …;
+ let mut frame_allocator = ...;
// below is the new part
@@ -520,10 +520,10 @@ The `Page::range_inclusive` function is just a copy of the `Frame::range_inclusi
// in src/memory/paging/mod.rs
#[derive(…, PartialEq, Eq, PartialOrd, Ord)]
-pub struct Page {…}
+pub struct Page {...}
impl Page {
- …
+ ...
pub fn range_inclusive(start: Page, end: Page) -> PageIter {
PageIter {
start: start,