「30日でできる!OS自作入門」をRustで。9日目

Posted on June 20, 2019 , Tags: OS自作入門, OS, Rust

「30日でできる!OS自作入門 」のC言語の部分をできるだけRustですすめてみる。今回は9日目の内容。

メモリサイズの測定

今回の目標はメモリ管理となる。
まずはメモリサイズの測定をする。
C言語の実装を参考に、memory.rsという新しいファイルを作成し、以下のように実装した。

本体となる測定関数(上の例ではmemtest_main)は、本ではアセンブリ言語で実装されていたが、今回はvolatileクレートを使い、コンパイル時の最適化を抑制した上で、Rustで実装することにした。

以下のようにして最大メモリ数を表示してみる。

メモリサイズを表示

本と同様に32MBになるように qemu-system-i386 -m 32 -fda haribote.img でQEMUを起動するようにした。

メモリサイズ

上図の通り、32MBがちゃんと測定できた。

メモリ管理をする

次に、メモリ管理を実装していく。本の通り、freeされているメモリを保持するデータ構造をつくる。
実装が長くなってしまったものの、一応全て載せておく。

// memory.rs
const MEMMAN_FREES: u32 = 4090; // 約32KB
pub const MEMMAN_ADDR: u32 = 0x003c0000;

#[derive(Debug, Clone, Copy, PartialEq)]
struct FreeInfo {
    addr: u32,
    size: u32,
}

#[derive(Clone, Copy)]
pub struct MemMan {
    frees: u32,
    maxfrees: u32,
    lostsize: u32,
    losts: u32,
    free: [FreeInfo; MEMMAN_FREES as usize],
}

impl MemMan {
    pub fn new() -> MemMan {
        MemMan {
            frees: 0,
            maxfrees: 0,
            lostsize: 0,
            losts: 0,
            free: [FreeInfo { addr: 0, size: 0 }; MEMMAN_FREES as usize],
        }
    }

    pub fn total(&self) -> u32 {
        let mut t = 0;
        for i in 0..self.frees {
            t += self.free[i as usize].size;
        }
        t
    }

    pub fn alloc(&mut self, size: u32) -> Result<u32, &'static str> {
        for i in 0..self.frees {
            let i = i as usize;
            if self.free[i].size >= size {
                let a = self.free[i].addr;
                self.free[i].addr += size;
                self.free[i].size -= size;
                if self.free[i].size == 0 {
                    self.frees -= 1;
                    self.free[i] = self.free[i + 1]
                }
                return Ok(a);
            }
        }
        Err("CANNOT ALLOCATE MEMORY")
    }

    pub fn free(&mut self, addr: u32, size: u32) -> Result<(), &'static str> {
        let mut idx: usize = 0;
        // addrの順に並ぶように、insertすべきindexを決める
        for i in 0..self.frees {
            let i = i as usize;
            if self.free[i].addr > addr {
                idx = i;
                break;
            }
        }
        if idx > 0 {
            if self.free[idx - 1].addr + self.free[idx - 1].size == addr {
                self.free[idx - 1].size += size;
                if idx < self.frees as usize {
                    if addr + size == self.free[idx].addr {
                        self.free[idx - 1].size += self.free[idx].size;
                    }
                    self.frees -= 1;
                    for i in idx..(self.frees as usize) {
                        self.free[i] = self.free[i + 1];
                    }
                }
                return Ok(());
            }
        }
        if idx < self.frees as usize {
            if addr + size == self.free[idx].addr {
                self.free[idx].addr = addr;
                self.free[idx].size += size;
                return Ok(());
            }
        }
        if self.frees < MEMMAN_FREES {
            let mut j = self.frees as usize;
            while j > idx {
                self.free[j] = self.free[j - 1];
                j -= 1;
            }
            self.frees += 1;
            if self.maxfrees < self.frees {
                self.maxfrees = self.frees;
            }
            self.free[idx].addr = addr;
            self.free[idx].size = size;
            return Ok(());
        }
        self.losts += 1;
        self.lostsize += size;
        Err("CANNOT FREE MEMORY")
    }
}

以下のように、freeした結果を表示する。

free結果

実行してみると以下の通り、正しく29304KBが表示される。

free結果

9日目は以上となる。ここまでの内容のコードはyoshitsugu/hariboteos_in_rustのday9としてタグを打ってある。