5
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

ZigでOSを作るシリーズ

Part1 基本 Part2 ブート Part3 割り込み Part4 メモリ Part5 プロセス Part6 FS
✅ Done ✅ Done ✅ Done 👈 Now - -

はじめに

前回は割り込み処理を実装した。

今回はメモリ管理!物理メモリアロケータ、仮想メモリ管理、そしてZigのアロケータインターフェースを使った動的メモリ確保を実現する。

メモリ管理はOSの中でも特に面白い部分なんだよね。ここがしっかりできれば、だいたいのことはできるようになるよ。

メモリ管理の全体像

┌─────────────────────────────────────────────────────────────────┐
│                      メモリ管理の階層構造                        │
├─────────────────────────────────────────────────────────────────┤
│                                                                  │
│  ┌───────────────────────────────────────────────────────────┐  │
│  │          Application / Kernel Code                        │  │
│  └────────────────────────┬──────────────────────────────────┘  │
│                           │                                      │
│                           ↓                                      │
│  ┌───────────────────────────────────────────────────────────┐  │
│  │            Zig Allocator Interface                        │  │
│  │        (std.mem.Allocator compatible)                     │  │
│  └────────────────────────┬──────────────────────────────────┘  │
│                           │                                      │
│                           ↓                                      │
│  ┌───────────────────────────────────────────────────────────┐  │
│  │          Virtual Memory Manager (VMM)                     │  │
│  │             Page Table Management                         │  │
│  └────────────────────────┬──────────────────────────────────┘  │
│                           │                                      │
│                           ↓                                      │
│  ┌───────────────────────────────────────────────────────────┐  │
│  │        Physical Memory Allocator (PMM)                    │  │
│  │            Bitmap / Buddy Allocator                       │  │
│  └────────────────────────┬──────────────────────────────────┘  │
│                           │                                      │
│                           ↓                                      │
│  ┌───────────────────────────────────────────────────────────┐  │
│  │              Physical Memory (RAM)                        │  │
│  └───────────────────────────────────────────────────────────┘  │
│                                                                  │
└─────────────────────────────────────────────────────────────────┘

物理メモリアロケータ(Bitmap)

まずは単純なビットマップアロケータから作っていくよ。

// pmm.zig - Physical Memory Manager
const std = @import("std");

const PAGE_SIZE: usize = 4096;
const MAX_MEMORY: usize = 4 * 1024 * 1024 * 1024;  // 4GB
const BITMAP_SIZE: usize = MAX_MEMORY / PAGE_SIZE / 8;

var bitmap: [BITMAP_SIZE]u8 = [_]u8{0xFF} ** BITMAP_SIZE;  // 全て使用中で初期化
var total_memory: usize = 0;
var used_memory: usize = 0;

pub fn init(mmap_addr: u64, mmap_length: u64) void {
    // メモリマップを解析して利用可能な領域を記録
    var entry_ptr: [*]const MmapEntry = @ptrFromInt(@as(usize, @truncate(mmap_addr)));
    const end_ptr = @as(usize, @truncate(mmap_addr + mmap_length));

    while (@intFromPtr(entry_ptr) < end_ptr) {
        const entry = entry_ptr[0];

        if (entry.type == 1) {  // Available
            const base = alignUp(entry.base_addr, PAGE_SIZE);
            const end = alignDown(entry.base_addr + entry.length, PAGE_SIZE);

            if (end > base) {
                markRegionFree(base, end - base);
                total_memory += end - base;
            }
        }

        entry_ptr = @ptrFromInt(@intFromPtr(entry_ptr) + entry.size + 4);
    }

    // カーネル領域を予約(1MB - 4MB)
    markRegionUsed(0x100000, 3 * 1024 * 1024);
}

const MmapEntry = extern struct {
    size: u32,
    base_addr: u64,
    length: u64,
    type: u32,
};

fn markRegionFree(base: u64, length: u64) void {
    const start_page = @as(usize, @truncate(base / PAGE_SIZE));
    const page_count = @as(usize, @truncate(length / PAGE_SIZE));

    for (start_page..start_page + page_count) |page| {
        clearBit(page);
    }
}

fn markRegionUsed(base: u64, length: u64) void {
    const start_page = @as(usize, @truncate(base / PAGE_SIZE));
    const page_count = @as(usize, @truncate(length / PAGE_SIZE));

    for (start_page..start_page + page_count) |page| {
        setBit(page);
    }
    used_memory += length;
}

fn setBit(page: usize) void {
    bitmap[page / 8] |= @as(u8, 1) << @truncate(page % 8);
}

fn clearBit(page: usize) void {
    bitmap[page / 8] &= ~(@as(u8, 1) << @truncate(page % 8));
}

fn testBit(page: usize) bool {
    return (bitmap[page / 8] & (@as(u8, 1) << @truncate(page % 8))) != 0;
}

// 単一ページを割り当て
pub fn allocatePage() ?u64 {
    for (0..BITMAP_SIZE * 8) |page| {
        if (!testBit(page)) {
            setBit(page);
            used_memory += PAGE_SIZE;
            return @as(u64, page) * PAGE_SIZE;
        }
    }
    return null;
}

// 連続した複数ページを割り当て
pub fn allocatePages(count: usize) ?u64 {
    var consecutive: usize = 0;
    var start_page: usize = 0;

    for (0..BITMAP_SIZE * 8) |page| {
        if (!testBit(page)) {
            if (consecutive == 0) {
                start_page = page;
            }
            consecutive += 1;

            if (consecutive == count) {
                // 見つかった!全部使用中にする
                for (start_page..start_page + count) |p| {
                    setBit(p);
                }
                used_memory += count * PAGE_SIZE;
                return @as(u64, start_page) * PAGE_SIZE;
            }
        } else {
            consecutive = 0;
        }
    }
    return null;
}

// ページを解放
pub fn freePage(addr: u64) void {
    const page = @as(usize, @truncate(addr / PAGE_SIZE));
    if (testBit(page)) {
        clearBit(page);
        used_memory -= PAGE_SIZE;
    }
}

pub fn freePages(addr: u64, count: usize) void {
    for (0..count) |i| {
        freePage(addr + i * PAGE_SIZE);
    }
}

pub fn getTotalMemory() usize {
    return total_memory;
}

pub fn getUsedMemory() usize {
    return used_memory;
}

pub fn getFreeMemory() usize {
    return total_memory - used_memory;
}

fn alignUp(addr: u64, alignment: u64) u64 {
    return (addr + alignment - 1) & ~(alignment - 1);
}

fn alignDown(addr: u64, alignment: u64) u64 {
    return addr & ~(alignment - 1);
}

仮想メモリマネージャ

ページテーブルを管理して、仮想アドレスと物理アドレスをマッピングするよ。

// vmm.zig - Virtual Memory Manager
const pmm = @import("pmm.zig");

const PAGE_SIZE: usize = 4096;

// ページテーブルエントリのフラグ
const PAGE_PRESENT: u64 = 1 << 0;
const PAGE_WRITABLE: u64 = 1 << 1;
const PAGE_USER: u64 = 1 << 2;
const PAGE_WRITE_THROUGH: u64 = 1 << 3;
const PAGE_CACHE_DISABLE: u64 = 1 << 4;
const PAGE_ACCESSED: u64 = 1 << 5;
const PAGE_DIRTY: u64 = 1 << 6;
const PAGE_HUGE: u64 = 1 << 7;
const PAGE_GLOBAL: u64 = 1 << 8;
const PAGE_NO_EXECUTE: u64 = 1 << 63;

const PageTable = *align(PAGE_SIZE) [512]u64;

var kernel_pml4: PageTable = undefined;

pub fn init() void {
    // カーネル用のPML4を作成
    const pml4_phys = pmm.allocatePage() orelse unreachable;
    kernel_pml4 = @ptrFromInt(@as(usize, @truncate(pml4_phys)));

    // ゼロクリア
    for (kernel_pml4) |*entry| {
        entry.* = 0;
    }

    // Identity mapping(最初の4GB)
    identityMap(0, 4 * 1024 * 1024 * 1024);

    // PML4をCR3に設定
    loadPageTable(pml4_phys);
}

fn identityMap(start: u64, size: u64) void {
    var addr = start;
    while (addr < start + size) : (addr += PAGE_SIZE) {
        mapPage(addr, addr, PAGE_PRESENT | PAGE_WRITABLE);
    }
}

pub fn mapPage(virt: u64, phys: u64, flags: u64) void {
    const pml4_idx = (virt >> 39) & 0x1FF;
    const pdpt_idx = (virt >> 30) & 0x1FF;
    const pd_idx = (virt >> 21) & 0x1FF;
    const pt_idx = (virt >> 12) & 0x1FF;

    // PML4 → PDPT
    if (kernel_pml4[pml4_idx] & PAGE_PRESENT == 0) {
        const pdpt_phys = pmm.allocatePage() orelse return;
        kernel_pml4[pml4_idx] = pdpt_phys | PAGE_PRESENT | PAGE_WRITABLE;
        zeroPage(pdpt_phys);
    }

    const pdpt: PageTable = @ptrFromInt(@as(usize, @truncate(kernel_pml4[pml4_idx] & 0x000FFFFFFFFFF000)));

    // PDPT → PD
    if (pdpt[pdpt_idx] & PAGE_PRESENT == 0) {
        const pd_phys = pmm.allocatePage() orelse return;
        pdpt[pdpt_idx] = pd_phys | PAGE_PRESENT | PAGE_WRITABLE;
        zeroPage(pd_phys);
    }

    const pd: PageTable = @ptrFromInt(@as(usize, @truncate(pdpt[pdpt_idx] & 0x000FFFFFFFFFF000)));

    // PD → PT
    if (pd[pd_idx] & PAGE_PRESENT == 0) {
        const pt_phys = pmm.allocatePage() orelse return;
        pd[pd_idx] = pt_phys | PAGE_PRESENT | PAGE_WRITABLE;
        zeroPage(pt_phys);
    }

    const pt: PageTable = @ptrFromInt(@as(usize, @truncate(pd[pd_idx] & 0x000FFFFFFFFFF000)));

    // PT → Physical Page
    pt[pt_idx] = phys | flags;

    // TLBをフラッシュ
    invlpg(virt);
}

pub fn unmapPage(virt: u64) void {
    const pml4_idx = (virt >> 39) & 0x1FF;
    const pdpt_idx = (virt >> 30) & 0x1FF;
    const pd_idx = (virt >> 21) & 0x1FF;
    const pt_idx = (virt >> 12) & 0x1FF;

    if (kernel_pml4[pml4_idx] & PAGE_PRESENT == 0) return;
    const pdpt: PageTable = @ptrFromInt(@as(usize, @truncate(kernel_pml4[pml4_idx] & 0x000FFFFFFFFFF000)));

    if (pdpt[pdpt_idx] & PAGE_PRESENT == 0) return;
    const pd: PageTable = @ptrFromInt(@as(usize, @truncate(pdpt[pdpt_idx] & 0x000FFFFFFFFFF000)));

    if (pd[pd_idx] & PAGE_PRESENT == 0) return;
    const pt: PageTable = @ptrFromInt(@as(usize, @truncate(pd[pd_idx] & 0x000FFFFFFFFFF000)));

    pt[pt_idx] = 0;
    invlpg(virt);
}

pub fn translateAddress(virt: u64) ?u64 {
    const pml4_idx = (virt >> 39) & 0x1FF;
    const pdpt_idx = (virt >> 30) & 0x1FF;
    const pd_idx = (virt >> 21) & 0x1FF;
    const pt_idx = (virt >> 12) & 0x1FF;
    const offset = virt & 0xFFF;

    if (kernel_pml4[pml4_idx] & PAGE_PRESENT == 0) return null;
    const pdpt: PageTable = @ptrFromInt(@as(usize, @truncate(kernel_pml4[pml4_idx] & 0x000FFFFFFFFFF000)));

    if (pdpt[pdpt_idx] & PAGE_PRESENT == 0) return null;
    const pd: PageTable = @ptrFromInt(@as(usize, @truncate(pdpt[pdpt_idx] & 0x000FFFFFFFFFF000)));

    if (pd[pd_idx] & PAGE_PRESENT == 0) return null;
    const pt: PageTable = @ptrFromInt(@as(usize, @truncate(pd[pd_idx] & 0x000FFFFFFFFFF000)));

    if (pt[pt_idx] & PAGE_PRESENT == 0) return null;
    return (pt[pt_idx] & 0x000FFFFFFFFFF000) + offset;
}

fn zeroPage(phys: u64) void {
    const ptr: [*]u8 = @ptrFromInt(@as(usize, @truncate(phys)));
    for (0..PAGE_SIZE) |i| {
        ptr[i] = 0;
    }
}

fn loadPageTable(pml4_phys: u64) void {
    asm volatile ("mov %[pml4], %%cr3"
        :
        : [pml4] "r" (pml4_phys),
    );
}

fn invlpg(virt: u64) void {
    asm volatile ("invlpg (%[virt])"
        :
        : [virt] "r" (virt),
        : "memory"
    );
}

ヒープアロケータ

Zigのアロケータインターフェースに対応したヒープを実装。

// heap.zig - Kernel Heap Allocator
const std = @import("std");
const pmm = @import("pmm.zig");
const vmm = @import("vmm.zig");

const PAGE_SIZE: usize = 4096;
const HEAP_START: usize = 0xFFFF_8000_0000_0000;  // カーネルヒープ領域
const HEAP_INITIAL_SIZE: usize = 16 * 1024 * 1024;  // 16MB

// フリーリストのブロックヘッダ
const BlockHeader = struct {
    size: usize,
    next: ?*BlockHeader,
    is_free: bool,
};

var heap_start: usize = HEAP_START;
var heap_end: usize = HEAP_START;
var free_list: ?*BlockHeader = null;

pub fn init() void {
    // 初期ヒープ領域をマップ
    expandHeap(HEAP_INITIAL_SIZE);
}

fn expandHeap(size: usize) void {
    const pages = (size + PAGE_SIZE - 1) / PAGE_SIZE;

    for (0..pages) |_| {
        const phys = pmm.allocatePage() orelse return;
        vmm.mapPage(heap_end, phys, 0x03);  // Present | Writable
        heap_end += PAGE_SIZE;
    }

    // 新しい空き領域をフリーリストに追加
    const new_block: *BlockHeader = @ptrFromInt(heap_end - size);
    new_block.* = .{
        .size = size - @sizeOf(BlockHeader),
        .next = free_list,
        .is_free = true,
    };
    free_list = new_block;
}

// First-fit アロケーション
fn findFreeBlock(size: usize) ?*BlockHeader {
    var current = free_list;

    while (current) |block| {
        if (block.is_free and block.size >= size) {
            return block;
        }
        current = block.next;
    }
    return null;
}

pub fn alloc(size: usize) ?[*]u8 {
    const aligned_size = alignUp(size, 16);
    const total_size = aligned_size + @sizeOf(BlockHeader);

    // フリーリストから探す
    if (findFreeBlock(aligned_size)) |block| {
        // ブロックを分割できるかチェック
        if (block.size > total_size + 64) {
            // 分割
            const new_block: *BlockHeader = @ptrFromInt(@intFromPtr(block) + total_size);
            new_block.* = .{
                .size = block.size - total_size,
                .next = block.next,
                .is_free = true,
            };
            block.size = aligned_size;
            block.next = new_block;
        }

        block.is_free = false;
        return @ptrFromInt(@intFromPtr(block) + @sizeOf(BlockHeader));
    }

    // 新しいページを割り当て
    expandHeap(alignUp(total_size, PAGE_SIZE));
    return alloc(size);  // 再試行
}

pub fn free(ptr: [*]u8) void {
    const header: *BlockHeader = @ptrFromInt(@intFromPtr(ptr) - @sizeOf(BlockHeader));
    header.is_free = true;

    // 隣接する空きブロックと結合(簡略化版)
    coalesceFreeBlocks();
}

fn coalesceFreeBlocks() void {
    var current = free_list;

    while (current) |block| {
        if (block.next) |next| {
            if (block.is_free and next.is_free) {
                // 結合
                block.size += next.size + @sizeOf(BlockHeader);
                block.next = next.next;
                continue;  // もう一度同じブロックをチェック
            }
        }
        current = block.next;
    }
}

fn alignUp(value: usize, alignment: usize) usize {
    return (value + alignment - 1) & ~(alignment - 1);
}

// Zig std.mem.Allocator インターフェース
pub const kernel_allocator = std.mem.Allocator{
    .ptr = undefined,
    .vtable = &.{
        .alloc = zigAlloc,
        .resize = zigResize,
        .free = zigFree,
    },
};

fn zigAlloc(_: *anyopaque, len: usize, _: u8, _: usize) ?[*]u8 {
    return alloc(len);
}

fn zigResize(_: *anyopaque, _: []u8, _: u8, _: usize, _: usize) bool {
    // リサイズは未実装
    return false;
}

fn zigFree(_: *anyopaque, buf: []u8, _: u8, _: usize) void {
    free(buf.ptr);
}

バディアロケータ(高度版)

効率的なメモリ管理のためのバディシステム。

// buddy.zig - Buddy Allocator
const std = @import("std");
const pmm = @import("pmm.zig");

const PAGE_SIZE: usize = 4096;
const MIN_ORDER: u5 = 0;   // 4KB
const MAX_ORDER: u5 = 10;  // 4MB

const FreeList = struct {
    head: ?*BuddyBlock,
};

const BuddyBlock = struct {
    next: ?*BuddyBlock,
    order: u5,
};

var free_lists: [MAX_ORDER + 1]FreeList = [_]FreeList{.{ .head = null }} ** (MAX_ORDER + 1);
var base_addr: usize = 0;
var total_pages: usize = 0;

pub fn init(start: usize, size: usize) void {
    base_addr = start;
    total_pages = size / PAGE_SIZE;

    // 最大サイズのブロックとして追加
    var remaining = total_pages;
    var current = start;

    while (remaining > 0) {
        const order = findLargestOrder(remaining);
        const block: *BuddyBlock = @ptrFromInt(current);
        block.* = .{
            .next = free_lists[order].head,
            .order = order,
        };
        free_lists[order].head = block;

        const block_pages = @as(usize, 1) << order;
        current += block_pages * PAGE_SIZE;
        remaining -= block_pages;
    }
}

fn findLargestOrder(pages: usize) u5 {
    var order: u5 = MAX_ORDER;
    while (order > MIN_ORDER) : (order -= 1) {
        if ((@as(usize, 1) << order) <= pages) {
            return order;
        }
    }
    return MIN_ORDER;
}

pub fn allocate(size: usize) ?[*]u8 {
    // 必要なオーダーを計算
    const pages = (size + PAGE_SIZE - 1) / PAGE_SIZE;
    var order: u5 = MIN_ORDER;
    while ((@as(usize, 1) << order) < pages and order < MAX_ORDER) {
        order += 1;
    }

    return allocateOrder(order);
}

fn allocateOrder(order: u5) ?[*]u8 {
    // このオーダーのフリーリストから取得
    if (free_lists[order].head) |block| {
        free_lists[order].head = block.next;
        return @ptrCast(block);
    }

    // より大きなブロックを分割
    if (order < MAX_ORDER) {
        if (allocateOrder(order + 1)) |larger_ptr| {
            const larger: usize = @intFromPtr(larger_ptr);

            // 半分をフリーリストに戻す
            const buddy_addr = larger + ((@as(usize, 1) << order) * PAGE_SIZE);
            const buddy: *BuddyBlock = @ptrFromInt(buddy_addr);
            buddy.* = .{
                .next = free_lists[order].head,
                .order = order,
            };
            free_lists[order].head = buddy;

            return @ptrFromInt(larger);
        }
    }

    return null;
}

pub fn deallocate(ptr: [*]u8, size: usize) void {
    const pages = (size + PAGE_SIZE - 1) / PAGE_SIZE;
    var order: u5 = MIN_ORDER;
    while ((@as(usize, 1) << order) < pages and order < MAX_ORDER) {
        order += 1;
    }

    freeOrder(@intFromPtr(ptr), order);
}

fn freeOrder(addr: usize, order: u5) void {
    // バディを探す
    const buddy_addr = addr ^ ((@as(usize, 1) << order) * PAGE_SIZE);

    // バディがフリーリストにあるかチェック
    var prev: ?*?*BuddyBlock = null;
    var current = free_lists[order].head;

    while (current) |block| {
        if (@intFromPtr(block) == buddy_addr) {
            // バディを見つけた!結合する
            if (prev) |p| {
                p.* = block.next;
            } else {
                free_lists[order].head = block.next;
            }

            // 結合して一つ上のオーダーへ
            const merged_addr = @min(addr, buddy_addr);
            if (order < MAX_ORDER) {
                freeOrder(merged_addr, order + 1);
            } else {
                // 最大オーダーに達した
                const merged: *BuddyBlock = @ptrFromInt(merged_addr);
                merged.* = .{
                    .next = free_lists[order].head,
                    .order = order,
                };
                free_lists[order].head = merged;
            }
            return;
        }

        prev = &block.next;
        current = block.next;
    }

    // バディが見つからない - そのまま追加
    const block: *BuddyBlock = @ptrFromInt(addr);
    block.* = .{
        .next = free_lists[order].head,
        .order = order,
    };
    free_lists[order].head = block;
}

pub fn getFragmentation() f32 {
    var total_free: usize = 0;
    var largest_free: usize = 0;

    for (free_lists, 0..) |list, order| {
        var current = list.head;
        while (current) |block| {
            const size = (@as(usize, 1) << @truncate(order)) * PAGE_SIZE;
            total_free += size;
            if (size > largest_free) {
                largest_free = size;
            }
            current = block.next;
        }
    }

    if (total_free == 0) return 0;
    return 1.0 - @as(f32, @floatFromInt(largest_free)) / @as(f32, @floatFromInt(total_free));
}

使用例:動的配列

// main.zig
const std = @import("std");
const heap = @import("heap.zig");
const vga = @import("vga.zig");

pub fn dynamicArrayDemo() void {
    const allocator = heap.kernel_allocator;

    // 動的配列を作成
    var list = std.ArrayList(u32).init(allocator);
    defer list.deinit();

    // 要素を追加
    list.append(10) catch {};
    list.append(20) catch {};
    list.append(30) catch {};

    vga.print("Dynamic Array: ");
    for (list.items) |item| {
        printNumber(item);
        vga.print(" ");
    }
    vga.print("\n");

    // HashMap
    var map = std.AutoHashMap([]const u8, u32).init(allocator);
    defer map.deinit();

    map.put("one", 1) catch {};
    map.put("two", 2) catch {};
    map.put("three", 3) catch {};

    if (map.get("two")) |value| {
        vga.print("map['two'] = ");
        printNumber(value);
        vga.print("\n");
    }
}

fn printNumber(n: u32) void {
    var buf: [10]u8 = undefined;
    var i: usize = buf.len;
    var num = n;

    if (num == 0) {
        vga.putChar('0');
        return;
    }

    while (num > 0) {
        i -= 1;
        buf[i] = @truncate('0' + (num % 10));
        num /= 10;
    }

    for (buf[i..]) |c| {
        vga.putChar(c);
    }
}

メモリ情報表示

// memory_info.zig
const vga = @import("vga.zig");
const pmm = @import("pmm.zig");

pub fn printMemoryInfo() void {
    vga.print("\n=== Memory Information ===\n");

    const total = pmm.getTotalMemory();
    const used = pmm.getUsedMemory();
    const free = pmm.getFreeMemory();

    vga.print("Total: ");
    printSize(total);
    vga.print("\n");

    vga.print("Used:  ");
    printSize(used);
    vga.print("\n");

    vga.print("Free:  ");
    printSize(free);
    vga.print("\n");

    // 使用率バー
    vga.print("\nUsage: [");
    const bar_width = 40;
    const used_bars = (used * bar_width) / total;

    for (0..bar_width) |i| {
        if (i < used_bars) {
            vga.putChar('#');
        } else {
            vga.putChar('-');
        }
    }
    vga.print("] ");

    printNumber((used * 100) / total);
    vga.print("%\n");
}

fn printSize(bytes: usize) void {
    if (bytes >= 1024 * 1024 * 1024) {
        printNumber(bytes / (1024 * 1024 * 1024));
        vga.print(" GB");
    } else if (bytes >= 1024 * 1024) {
        printNumber(bytes / (1024 * 1024));
        vga.print(" MB");
    } else if (bytes >= 1024) {
        printNumber(bytes / 1024);
        vga.print(" KB");
    } else {
        printNumber(bytes);
        vga.print(" B");
    }
}

fn printNumber(n: usize) void {
    var buf: [20]u8 = undefined;
    var i: usize = buf.len;
    var num = n;

    if (num == 0) {
        vga.putChar('0');
        return;
    }

    while (num > 0) {
        i -= 1;
        buf[i] = @truncate('0' + (num % 10));
        num /= 10;
    }

    for (buf[i..]) |c| {
        vga.putChar(c);
    }
}

まとめ

今回実装したこと:

コンポーネント 説明
PMM(Bitmap) 物理ページの管理
VMM ページテーブル操作、仮想メモリマッピング
ヒープアロケータ First-fit方式の動的メモリ確保
バディアロケータ 効率的なメモリ管理
Zigインターフェース std.mem.Allocator互換
┌─────────────────────────────────────────────────────────────┐
│                    メモリレイアウト                          │
├─────────────────────────────────────────────────────────────┤
│  0x0000_0000 ┌──────────────────────────────────┐           │
│              │        Reserved (1MB)            │           │
│  0x0010_0000 ├──────────────────────────────────┤           │
│              │         Kernel Code              │           │
│  0x0040_0000 ├──────────────────────────────────┤           │
│              │      Physical Page Pool          │           │
│              │        (PMM managed)             │           │
│              └──────────────────────────────────┘           │
│                                                             │
│  Virtual Address Space:                                     │
│  0xFFFF_8000_0000_0000 ┌────────────────────────┐           │
│                        │     Kernel Heap        │           │
│                        │    (16MB initial)      │           │
│                        └────────────────────────┘           │
└─────────────────────────────────────────────────────────────┘

次回はプロセス管理を実装するよ。タスクスイッチとスケジューリングで、マルチタスクが動くようになるよ!

この記事が役に立ったら、いいね・ストックしてもらえると嬉しいです!

5
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
5
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?