From a131cb0a88b0d5339683e05f0a2e1a8bf8f03e05 Mon Sep 17 00:00:00 2001 From: Sandro-Alessio Gierens Date: Mon, 30 Dec 2024 15:33:00 +0100 Subject: [PATCH 01/17] fix(src/kernel/page_allocator): correct allocate function name typo Signed-off-by: Sandro-Alessio Gierens --- src/kernel/page_allocator.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/kernel/page_allocator.md b/src/kernel/page_allocator.md index efd6954..6933f66 100644 --- a/src/kernel/page_allocator.md +++ b/src/kernel/page_allocator.md @@ -61,7 +61,7 @@ const PageAllocator = @import("mem/PageAllocator.zig").PageAllocator; // <= 冗 `Allocator` 経由で呼ばれたこれらの関数は、第1引数 `ctx` に `Allocator.ptr` が渡されます。 これはアロケータインスタンスであるため、共通の `Allocator` 経由で呼ばれても各アロケータの内部実装を呼び出すことができます。 つまりここでやるべきことは、`PageAllocator.zig` にページアロケータの内部実装を定義した上で、 -`allocater()` / `free()` / `resize()` の 3API を提供することです。 +`allocate()` / `free()` / `resize()` の 3API を提供することです。 この3つさえ実装すれば、残りの細々としたユーティリティ関数は `Allocator` が提供してくれます。 ## Bitmap From 76a5ddcda0016ae6568f52f2d359e8d6ea1ea310 Mon Sep 17 00:00:00 2001 From: Sandro-Alessio Gierens Date: Mon, 30 Dec 2024 15:33:22 +0100 Subject: [PATCH 02/17] fix(src/kernel/general_allocator): correct allocate function name typo Signed-off-by: Sandro-Alessio Gierens --- src/kernel/general_allocator.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/kernel/general_allocator.md b/src/kernel/general_allocator.md index f9297c4..1cec97f 100644 --- a/src/kernel/general_allocator.md +++ b/src/kernel/general_allocator.md @@ -183,7 +183,7 @@ Bin から chunk を取得したり返却する処理が実装できたため、 `PageAllocator` の場合と異なり、`BinAllocator` はページサイズ以下の領域を確保する可能性があります。 よって、 `BinAllocator` 要求されたアラインを考慮する必要があります。 -要求されるアラインは、`allocater()`の第3引数に渡されます: +要求されるアラインは、`allocate()`の第3引数に渡されます: ```ymir/mem/BinAllocator.zig fn allocate(ctx: *anyopaque, n: usize, log2_align: u8, _: usize) ?[*]u8 { From f3262d550653493aaa468bad671ff7274465bae7 Mon Sep 17 00:00:00 2001 From: Sandro-Alessio Gierens Date: Mon, 30 Dec 2024 15:42:20 +0100 Subject: [PATCH 03/17] fix(src/kernel/page_allocator): remove trailing _ from map param Signed-off-by: Sandro-Alessio Gierens --- src/kernel/page_allocator.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/kernel/page_allocator.md b/src/kernel/page_allocator.md index 6933f66..b070964 100644 --- a/src/kernel/page_allocator.md +++ b/src/kernel/page_allocator.md @@ -74,7 +74,7 @@ Ymir の `PageAllocator` では、利用できる(割当可能な)ページを `PageAllocator` では初期化時にこのメモリマップを受取り、メモリを探査して利用可能なページをビットマップに記録していきます: ```ymir/mem/PageAllocator.zig -pub fn init(self: *Self, map_: MemoryMap) void { +pub fn init(self: *Self, map: MemoryMap) void { var avail_end: Phys = 0; var desc_iter = MemoryDescriptorIterator.new(map); From 0535e890c21f35843fdbb755848c75e2fe7b2cd3 Mon Sep 17 00:00:00 2001 From: Sandro-Alessio Gierens Date: Mon, 30 Dec 2024 16:06:42 +0100 Subject: [PATCH 04/17] fix(src/kernel/page_allocator): add missing bytes_per_frame definition Signed-off-by: Sandro-Alessio Gierens --- src/kernel/page_allocator.md | 1 + 1 file changed, 1 insertion(+) diff --git a/src/kernel/page_allocator.md b/src/kernel/page_allocator.md index b070964..b4f4950 100644 --- a/src/kernel/page_allocator.md +++ b/src/kernel/page_allocator.md @@ -153,6 +153,7 @@ const BitMap = [num_maplines]MapLineType; ```ymir/mem/PageAllocator.zig const FrameId = u64; +const bytes_per_frame = 4 * kib; inline fn phys2frame(phys: Phys) FrameId { return phys / bytes_per_frame; From 2396ad2326cfaefe2a3bf4e341f99af1d278dd6d Mon Sep 17 00:00:00 2001 From: Sandro-Alessio Gierens Date: Mon, 30 Dec 2024 19:22:06 +0100 Subject: [PATCH 05/17] fix(src/kernel/page_allocator): correct allocPages name typo Signed-off-by: Sandro-Alessio Gierens --- src/kernel/page_allocator.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/kernel/page_allocator.md b/src/kernel/page_allocator.md index b4f4950..e596ca6 100644 --- a/src/kernel/page_allocator.md +++ b/src/kernel/page_allocator.md @@ -425,7 +425,7 @@ pub const page_allocator = Allocator{ `page_allocator_instance` は `PageAllocator` の唯一のインスタンスです。 基本的にこちらのインスタンスは直接触ることはありません。 -唯一使う必要があるのは、先ほどの `allocaPages()` を呼び出す場合のみです。 +唯一使う必要があるのは、先ほどの `allocPages()` を呼び出す場合のみです。 というか、このインスタンスは直接触らせたくないので本当は `pub` 指定したくありません。 `PageAllocator` という型自体も同様です。 しかし、`Allocator.alignedAlloc()` がページサイズ以上のアラインを許容しないため致し方ありません[^align]。 From b4650f817f9580da26cb18483962e47c83f22630 Mon Sep 17 00:00:00 2001 From: Sandro-Alessio Gierens Date: Mon, 30 Dec 2024 19:55:14 +0100 Subject: [PATCH 06/17] fix(src/kernel/page_allocator): complete listings in create allocator Signed-off-by: Sandro-Alessio Gierens --- src/kernel/page_allocator.md | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/src/kernel/page_allocator.md b/src/kernel/page_allocator.md index e596ca6..eccbdad 100644 --- a/src/kernel/page_allocator.md +++ b/src/kernel/page_allocator.md @@ -414,6 +414,15 @@ pub fn allocPages(self: *PageAllocator, num_pages: usize, align_size: usize) ?[] 以上で準備が整いました。 Ymir で利用できる `Allocator` を作成しましょう: +```ymir/mem/PageAllocator.zig +pub fn newUninit() Self { + return Self{ + .frame_end = undefined, + .bitmap = undefined, + }; +} +``` + ```ymir/mem.zig pub const PageAllocator = @import("mem/PageAllocator.zig"); pub var page_allocator_instance = PageAllocator.newUninit(); @@ -421,6 +430,10 @@ pub const page_allocator = Allocator{ .ptr = &page_allocator_instance, .vtable = &PageAllocator.vtable, }; + +pub fn initPageAllocator(map: MemoryMap) void { + page_allocator_instance.init(map); +} ``` `page_allocator_instance` は `PageAllocator` の唯一のインスタンスです。 @@ -436,10 +449,14 @@ pub const page_allocator = Allocator{ 利用時には以下のようにして `Allocator` として利用します (内部実装を気にする必要がありません): -```zig +```ymir/main.zig +mem.initPageAllocator(boot_info.memory_map); +log.info("Initialized page allocator", .{}); const page_allocator = ymir.mem.page_allocator; + const array = try page_allocator.alloc(u32, 4); log.debug("Memory allocated @ {X:0>16}", .{@intFromPtr(array.ptr)}); +page_allocator.free(array); ``` ## まとめ From 4cce83a363dbf60a2c9ff179b032a53158347945 Mon Sep 17 00:00:00 2001 From: Sandro-Alessio Gierens Date: Mon, 30 Dec 2024 20:44:55 +0100 Subject: [PATCH 07/17] fix(src/kernel/paging): correct num_table_entries value typo Signed-off-by: Sandro-Alessio Gierens --- src/kernel/paging.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/kernel/paging.md b/src/kernel/paging.md index efec85f..b34abd4 100644 --- a/src/kernel/paging.md +++ b/src/kernel/paging.md @@ -85,7 +85,7 @@ fn allocatePage(allocator: Allocator) PageError![*]align(page_size_4k) u8 { ```ymir/arch/x86/page.zig pub fn reconstruct(allocator: Allocator) PageError!void { const lv4tbl_ptr: [*]Lv4Entry = @ptrCast(try allocatePage(allocator)); - const lv4tbl = lv4tbl_ptr[0..num_table_entries]; // 256 + const lv4tbl = lv4tbl_ptr[0..num_table_entries]; // 512 @memset(lv4tbl, std.mem.zeroes(Lv4Entry)); ... } @@ -93,7 +93,7 @@ pub fn reconstruct(allocator: Allocator) PageError!void { まず最初に新しい Lv4 ページテーブルを確保します。 `allocatePage()` が返す領域は [many-item pointer](https://ziglang.org/documentation/master/#Pointers) であるため、 -テーブルあたりのエントリ数 256 でスライスを作っています。 +テーブルあたりのエントリ数 512 でスライスを作っています。 作成したページテーブルはとりあえず全部ゼロ埋めしておきます。 ゼロ埋めすることでエントリの `present` フィールドが 0 になるため、何もマップしない状態になります。 念の為以下にページテーブルエントリの構造を再掲しておきます: From 5251d80278be92f0d79b8e53509cb4ae044a1865 Mon Sep 17 00:00:00 2001 From: Sandro-Alessio Gierens Date: Mon, 30 Dec 2024 23:15:13 +0100 Subject: [PATCH 08/17] fix(src/kernel/paging): add more lines to final reconstruct listing At the moment it's not necessarily obvious where this code goes. Signed-off-by: Sandro-Alessio Gierens --- src/kernel/paging.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/kernel/paging.md b/src/kernel/paging.md index b34abd4..0eb86c6 100644 --- a/src/kernel/paging.md +++ b/src/kernel/paging.md @@ -245,10 +245,12 @@ fn cloneLevel1Table(lv1_table: []Lv1Entry, allocator: Allocator) PageError![]Lv1 Lv4 ページテーブルのアドレスは CR3 レジスタに書き込むことで変更できます。 ```ymir/arch/x86/page.zig +pub fn reconstruct(allocator: Allocator) PageError!void { ... + const cr3 = @intFromPtr(lv4tbl) & ~@as(u64, 0xFFF); am.loadCr3(cr3); - ... +} ``` CR3 へ書き込みを行うと、TLB の前エントリがフラッシュされ古いエントリが無効になります。 From b6f150eaf31d2bbd3e29e256aa8cbe953ff406e4 Mon Sep 17 00:00:00 2001 From: Sandro-Alessio Gierens Date: Mon, 30 Dec 2024 23:18:17 +0100 Subject: [PATCH 09/17] fix(src/kernel/paging): correct 3-rd typo Signed-off-by: Sandro-Alessio Gierens --- src/kernel/paging.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/kernel/paging.md b/src/kernel/paging.md index 0eb86c6..3d57343 100644 --- a/src/kernel/paging.md +++ b/src/kernel/paging.md @@ -265,7 +265,7 @@ CR3 へ書き込みを行うと、TLB の前エントリがフラッシュされ 本シリーズの Ymir では [PCID: Process Context Identifiers](https://en.wikipedia.org/wiki/Translation_lookaside_buffer#PCID) は使わないため,この表のフォーマットに従います[^pcid]。 表中の `M` は物理アドレスのサイズであり、おそらく最近の Core シリーズでは `46` になるのではないかと思います。 -3-th / 4-th bit は Lv4 テーブルにアクセスする際のキャッシュタイプを決定する要因の1つになります。 +3-rd / 4-th bit は Lv4 テーブルにアクセスする際のキャッシュタイプを決定する要因の1つになります。 今回は特にこのあたりは気にせず、どちらも `0` としています。 ## 仮想-物理アドレス変換 From 95d004776e54b72ab9755ccd76b4c17e2347ef32 Mon Sep 17 00:00:00 2001 From: Sandro-Alessio Gierens Date: Mon, 30 Dec 2024 23:29:46 +0100 Subject: [PATCH 10/17] fix(src/kernel/paging): correct addr typo in phys2virt Signed-off-by: Sandro-Alessio Gierens --- src/kernel/paging.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/kernel/paging.md b/src/kernel/paging.md index 3d57343..3c4eb2f 100644 --- a/src/kernel/paging.md +++ b/src/kernel/paging.md @@ -306,7 +306,7 @@ pub fn virt2phys(addr: u64) Phys { pub fn phys2virt(addr: u64) Virt { return if (!mapping_reconstructed) b: { // UEFI's page table. - break :b value; + break :b addr; } else b: { // Direct map region. break :b addr + ymir.direct_map_base; From f0c4d36c06238166dce49d299b7b891e1ea3d48e Mon Sep 17 00:00:00 2001 From: Sandro-Alessio Gierens Date: Thu, 2 Jan 2025 01:08:34 +0100 Subject: [PATCH 11/17] fix(src/kernel/paging): add flushTlbSingle function Signed-off-by: Sandro-Alessio Gierens --- src/kernel/paging.md | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/src/kernel/paging.md b/src/kernel/paging.md index 3c4eb2f..3af0598 100644 --- a/src/kernel/paging.md +++ b/src/kernel/paging.md @@ -388,6 +388,19 @@ pub fn changeMap4k(virt: Virt, attr: PageAttribute) PageError!void { ただし、Surtr はカーネルのロードで 4KiB だけを使うため、この関数の前提は満たされます。 途中で存在しない (`present == false`) ページエントリが見つかった場合には gracefull にエラーを返すようにしています。 +特定の TLB エントリをフラッシュするヘルパー関数は、INVLPG 命令を使用します: + +```surtr/arch/x86/asm.zig +pub inline fn flushTlbSingle(virt: u64) void { + asm volatile ( + \\invlpg (%[virt]) + : + : [virt] "r" (virt), + : "memory" + ); +} +``` + 続いて、カーネルのロード部分を修正します: ```surtr/boot.zig From 936574f9d679fdcbe20883d74f94430c2671c660 Mon Sep 17 00:00:00 2001 From: Sandro-Alessio Gierens Date: Sat, 11 Jan 2025 21:51:11 +0100 Subject: [PATCH 12/17] fix(src/kernel/general_allocator): add newUninit, correct mem.zig path Signed-off-by: Sandro-Alessio Gierens --- src/kernel/general_allocator.md | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/kernel/general_allocator.md b/src/kernel/general_allocator.md index 1cec97f..89bfaf9 100644 --- a/src/kernel/general_allocator.md +++ b/src/kernel/general_allocator.md @@ -255,6 +255,15 @@ fn resize(_: *anyopaque, _: []u8, _: u8, _: usize, _: usize) bool { `BinAllocator` をインスタンス化して利用可能な状態にします: ```ymir/mem/BinAllocator.zig +pub fn newUninit() Self { + return Self{ + .page_allocator = undefined, + .list_heads = undefined, + }; +} +``` + +```ymir/mem.zig pub const general_allocator = Allocator{ .ptr = &bin_allocator_instance, .vtable = &BinAllocator.vtable, From 62cabc8634598c2059a963b7007a82407f9a9672 Mon Sep 17 00:00:00 2001 From: Sandro-Alessio Gierens Date: Sun, 12 Jan 2025 00:33:34 +0100 Subject: [PATCH 13/17] fix(src/kernel/pic): replace redundant relax definition by asm import Signed-off-by: Sandro-Alessio Gierens --- src/kernel/pic.md | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/kernel/pic.md b/src/kernel/pic.md index 2ae144e..4fbca5f 100644 --- a/src/kernel/pic.md +++ b/src/kernel/pic.md @@ -232,6 +232,8 @@ const Ocw = union(ocw) { 続いて、これらの CW を PIC に対して発行するためのヘルパー関数を定義します: ```ymir/arch/x86/pic.zig +const am = @import("asm.zig"); + fn issue(cw: anytype, port: u16) void { const T = @TypeOf(cw); if (T != Icw and T != Ocw) { @@ -242,10 +244,6 @@ fn issue(cw: anytype, port: u16) void { } am.relax(); } - -pub fn relax() void { - asm volatile ("rep; nop"); -} ``` `issue()` は `Icw` か `Ocw` のみを受け付けることを保証しています。 From be51991ba5659dd8cfee7c47fdf2b3e15d5be5eb Mon Sep 17 00:00:00 2001 From: Sandro-Alessio Gierens Date: Sun, 12 Jan 2025 13:33:14 +0100 Subject: [PATCH 14/17] fix(src/kernel/pic): add listing of interrupts.zig Signed-off-by: Sandro-Alessio Gierens --- src/kernel/pic.md | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/kernel/pic.md b/src/kernel/pic.md index 4fbca5f..4d54226 100644 --- a/src/kernel/pic.md +++ b/src/kernel/pic.md @@ -489,6 +489,18 @@ pub fn enableInterrupt(port: Ports) void { } ``` +`idefs` は、`interrupts.zig` のインポートであり、次のようになります。 + +```ymir/interrupts.zig +const arch = @import("ymir").arch; + +pub const user_intr_base = arch.intr.num_system_exceptions; + +pub const pic_timer = 0 + user_intr_base; +... +pub const pic_serial1 = 4 + user_intr_base; +``` + なお、IER の 1-th bit をクリアしているのは無限割り込みを防ぐためです。 Tx-empty は、シリアル出力しようとしたデータが実際に送信され、出力バッファに他のデータを書き込める状態になった時に発生します。 しかし、割り込みハンドラの中でさらにシリアルログ出力をしており、これがまた Tx-empty を発生させます。 From ef8e1a144c4fd2566cfd0ffc87bb4fb1ee007d7d Mon Sep 17 00:00:00 2001 From: Sandro-Alessio Gierens Date: Sat, 18 Jan 2025 13:51:59 +0100 Subject: [PATCH 15/17] fix(src/kernel/pic): correct introduction of interrupts.zig Signed-off-by: Sandro-Alessio Gierens --- src/kernel/pic.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/kernel/pic.md b/src/kernel/pic.md index 4d54226..49b47c0 100644 --- a/src/kernel/pic.md +++ b/src/kernel/pic.md @@ -489,7 +489,7 @@ pub fn enableInterrupt(port: Ports) void { } ``` -`idefs` は、`interrupts.zig` のインポートであり、次のようになります。 +`idefs` は、`interrupts.zig` のインポートです: ```ymir/interrupts.zig const arch = @import("ymir").arch; From 6d2b1905f209116b0df2c472937febd191bf526c Mon Sep 17 00:00:00 2001 From: Sandro-Alessio Gierens Date: Sat, 11 Jan 2025 20:24:07 +0100 Subject: [PATCH 16/17] fix(src/kernel/panic): correct typo in panic builtin call Signed-off-by: Sandro-Alessio Gierens --- src/kernel/panic.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/kernel/panic.md b/src/kernel/panic.md index 6ab063a..bdb9a2c 100644 --- a/src/kernel/panic.md +++ b/src/kernel/panic.md @@ -117,7 +117,7 @@ pub const panic = ymir.panic.panic_fn; `ReleaseFast` レベルだと最適化が結構強く働くため、関数がインライン化されてスタックトレースが出力できない場合があります: ```ymir/main.tmp.zig -panic("fugafuga"); +@panic("fugafuga"); ``` 出力は以下のようになります: From ea1b726bdac3c5af48107fc527e1a82eeccaf6e9 Mon Sep 17 00:00:00 2001 From: Sandro-Alessio Gierens Date: Sat, 18 Jan 2025 13:57:32 +0100 Subject: [PATCH 17/17] fix(src/kernel/panic): add missing export of panic as panic_fn Signed-off-by: Sandro-Alessio Gierens --- src/kernel/panic.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/kernel/panic.md b/src/kernel/panic.md index bdb9a2c..bf9f59c 100644 --- a/src/kernel/panic.md +++ b/src/kernel/panic.md @@ -88,6 +88,8 @@ pub fn endlessHalt() noreturn { Zig にはスタックトレースを取得するためのユーティリティ構造体である `StackIterator` があるため今回はこれを使います: ```ymir/panic.zig +pub const panic_fn = panic; + fn panic(msg: []const u8, _: ?*builtin.StackTrace, _: ?usize) noreturn { ... var it = std.debug.StackIterator.init(@returnAddress(), null);