Compare commits

...

7 Commits

Author SHA1 Message Date
FineFindus
8b7a66e2b7 Merge 5c3adee95b into 6d20ba47fa 2024-02-28 11:27:36 -08:00
Philipp Oppermann
6d20ba47fa Merge pull request #1298 from acyanbird/format
Format for two post
2024-02-28 19:03:48 +01:00
acyanbird
a3bbd5ab55 update
wrong code branch
2024-02-28 17:39:58 +00:00
acyanbird
8e6c4caffc update 2024-02-13 19:32:41 +00:00
FineFindus
5c3adee95b feat(epub): use poper file name 2023-08-05 22:16:13 +02:00
FineFindus
fc8c87bee5 feat(epub): add cover image 2023-08-05 22:05:04 +02:00
FineFindus
e1c58bba97 feat: add script to generate epub 2023-08-05 14:38:08 +02:00
5 changed files with 38 additions and 8 deletions

View File

@@ -69,7 +69,7 @@ x86 架构支持两种固件标准: **BIOS**[Basic Input/Output System](htt
## 最小内核 ## 最小内核
现在我们已经明白电脑是如何启动的那也是时候编写我们自己的内核了。我们的小目标是创建一个内核的磁盘映像它能够在启动时向屏幕输出一行“Hello World!”;我们的工作将基于上一章构建的[独立式可执行程序][freestanding Rust binary]。 现在我们已经明白电脑是如何启动的那也是时候编写我们自己的内核了。我们的小目标是创建一个内核的磁盘映像它能够在启动时向屏幕输出一行“Hello World!”;我们的工作将基于上一章构建的[独立式可执行程序][freestanding-rust-binary]。
如果读者还有印象的话,在上一章,我们使用 `cargo` 构建了一个独立的二进制程序;但这个程序依然基于特定的操作系统平台:因平台而异,我们需要定义不同名称的函数,且使用不同的编译指令。这是因为在默认情况下,`cargo` 会为特定的**宿主系统**host system构建源码比如为你正在运行的系统构建源码。这并不是我们想要的因为我们的内核不应该基于另一个操作系统——我们想要编写的就是这个操作系统。确切地说我们想要的是编译为一个特定的**目标系统**target system 如果读者还有印象的话,在上一章,我们使用 `cargo` 构建了一个独立的二进制程序;但这个程序依然基于特定的操作系统平台:因平台而异,我们需要定义不同名称的函数,且使用不同的编译指令。这是因为在默认情况下,`cargo` 会为特定的**宿主系统**host system构建源码比如为你正在运行的系统构建源码。这并不是我们想要的因为我们的内核不应该基于另一个操作系统——我们想要编写的就是这个操作系统。确切地说我们想要的是编译为一个特定的**目标系统**target system

View File

@@ -18,7 +18,7 @@ translation_contributors = ["liuyuran"]
<!-- more --> <!-- more -->
这个系列的 blog 在[GitHub]上开放开发,如果你有任何问题,请在这里开一个 issue 来讨论。当然你也可以在[底部][at the bottom]留言。你可以在[`post-08`][post branch]找到这篇文章的完整源码。 这个系列的 blog 在[GitHub]上开放开发,如果你有任何问题,请在这里开一个 issue 来讨论。当然你也可以在[底部][at the bottom]留言。你可以在[`post-09`][post branch]找到这篇文章的完整源码。
[GitHub]: https://github.com/phil-opp/blog_os [GitHub]: https://github.com/phil-opp/blog_os
[at the bottom]: #comments [at the bottom]: #comments
@@ -555,9 +555,9 @@ fn translate_addr_inner(addr: VirtAddr, physical_memory_offset: VirtAddr)
我们没有重复使用`active_level_4_table`函数,而是再次从`CR3`寄存器读取4级帧。我们这样做是因为它简化了这个原型的实现。别担心我们一会儿就会创建一个更好的解决方案。 我们没有重复使用`active_level_4_table`函数,而是再次从`CR3`寄存器读取4级帧。我们这样做是因为它简化了这个原型的实现。别担心我们一会儿就会创建一个更好的解决方案。
`VirtAddr`结构已经提供了计算四级页面表索引的方法。我们将这些索引存储在一个小数组中,因为它允许我们使用`for`循环遍历页表。在循环之外,我们记住了最后访问的`frame',以便以后计算物理地址。`frame`在迭代时指向页表框架在最后一次迭代后指向映射的框架也就是在跟随第1级条目之后。 `VirtAddr`结构已经提供了计算四级页面表索引的方法。我们将这些索引存储在一个小数组中,因为它允许我们使用`for`循环遍历页表。在循环之外,我们记住了最后访问的`frame`,以便以后计算物理地址。`frame`在迭代时指向页表框架在最后一次迭代后指向映射的框架也就是在跟随第1级条目之后。
在这个循环中,我们再次使用`physical_memory_offset`将帧转换为页表引用。然后我们读取当前页表的条目,并使用[`PageTableEntry::frame`]函数来检索映射的框架。如果该条目没有映射到一个框架,我们返回`None'。如果该条目映射了一个巨大的2&nbsp;MiB或1&nbsp;GiB页面我们就暂时慌了。 在这个循环中,我们再次使用`physical_memory_offset`将帧转换为页表引用。然后我们读取当前页表的条目,并使用[`PageTableEntry::frame`]函数来检索映射的框架。如果该条目没有映射到一个框架,我们返回`None`。如果该条目映射了一个巨大的2&nbsp;MiB或1&nbsp;GiB页面我们就暂时慌了。
[`PageTableEntry::frame`]: https://docs.rs/x86_64/0.14.2/x86_64/structures/paging/page_table/struct.PageTableEntry.html#method.frame [`PageTableEntry::frame`]: https://docs.rs/x86_64/0.14.2/x86_64/structures/paging/page_table/struct.PageTableEntry.html#method.frame
@@ -648,7 +648,7 @@ unsafe fn active_level_4_table(physical_memory_offset: VirtAddr)
{} {}
``` ```
该函数接受 "physical_memory_offset "作为参数,并返回一个新的 "OffsetPageTable "实例,该实例具有 "静态 "寿命。这意味着该实例在我们内核的整个运行时间内保持有效。在函数体中,我们首先调用 "active_level_4_table "函数来获取4级页表的可变引用。然后我们用这个引用调用[`OffsetPageTable::new`] 函数。作为第二个参数,`new`函数希望得到物理内存映射开始的虚拟地址,该地址在`physical_memory_offset'变量中给出。 该函数接受 "physical_memory_offset "作为参数,并返回一个新的 "OffsetPageTable "实例,该实例具有 "静态 "寿命。这意味着该实例在我们内核的整个运行时间内保持有效。在函数体中,我们首先调用 "active_level_4_table "函数来获取4级页表的可变引用。然后我们用这个引用调用[`OffsetPageTable::new`] 函数。作为第二个参数,`new`函数希望得到物理内存映射开始的虚拟地址,该地址在`physical_memory_offset`变量中给出。
[`OffsetPageTable::new`]: https://docs.rs/x86_64/0.14.2/x86_64/structures/paging/mapper/struct.OffsetPageTable.html#method.new [`OffsetPageTable::new`]: https://docs.rs/x86_64/0.14.2/x86_64/structures/paging/mapper/struct.OffsetPageTable.html#method.new
@@ -896,7 +896,7 @@ impl BootInfoFrameAllocator {
#### 一个 `usable_frames` 方法 #### 一个 `usable_frames` 方法
在我们实现`FrameAllocator'特性之前,我们添加一个辅助方法,将内存映射转换为可用帧的迭代器。 在我们实现`FrameAllocator`特性之前,我们添加一个辅助方法,将内存映射转换为可用帧的迭代器。
```rust ```rust
// in src/memory.rs // in src/memory.rs

BIN
scripts/cover.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 66 KiB

30
scripts/create-book.sh Executable file
View File

@@ -0,0 +1,30 @@
#!/bin/bash
# create working dir
rm -r book/
mkdir book/
# copy data to working dir
cat ../blog/content/edition-2/posts/*/index.md > book/book.md
find ../blog/content/edition-2/posts ! -name "*.md" -exec cp -t book/ {} +
# remove zola metadata
sed -i '/^+++/,/^+++/d' book/book.md
# remove br in table in 06, pandoc handles the layout
sed -i '/<br>/d' book/book.md
# details/summary breaks epub layout
sed -i '/^<details>/d' book/book.md
sed -i '/^<\/details>/d' book/book.md
sed -i '/^<summary>/d' book/book.md
# special fix for linking to different folder
sed -i 's|../paging-introduction/||g' book/book.md
# go to work dir and create epub
cd book/
pandoc book.md -o "Writing an OS in Rust.epub" --metadata cover-image="../cover.png" --metadata title="Writing an OS in Rust" --metadata author="Philipp Oppermann" --metadata description="This blog series creates a small operating system in the Rust programming language. Each post is a small tutorial and includes all needed code, so you can follow along if you like. The source code is also available in the corresponding Github repository."
#clean up
cd ..
mv "book/Writing an OS in Rust.epub" .
rm -rf book/