ゼロからのOS自作入門(その4)osbook_day03c の続き。
natsutan.hatenablog.com
4日目はUEFIアプリからグラフィックスの情報をカーネルに渡します。今、UEFIアプリがC、カーネルをRustで書いているので、CとRustの間で構造体のやりとりが必要です。
std::os::raw を使う
gihyo.jp
実践Rust入門を見ると、#[repr(C)]とstd::os::rawのやり方が紹介されています。
本を見ながら、こんな感じで書いてみました。
use std::os::raw::c_int;
use std::os::raw::c_uint;
use std::os::raw::c_uchar;
#[repr(C)]
struct FrameBufferConfig {
frame_buffer : *mut c_uchar,
pixels_per_scan_line : c_int,
horizontal_reslution: c_uint,
vertical_resolution: c_uint,
pixel_format : PixelFormat
}
実際にやってみるとエラーがでます。
error[E0433]: failed to resolve: use of undeclared crate or module `std`
--> src/main.rs:7:5
|
7 | use std::os::raw::c_int;
| ^^^ use of undeclared crate or module `std`
#![no_std] を設定しているので、stdから始まるクレートが使えないようです。
困っていたらTwitterで的確なアドバイスをいただきました。いつもありがとうございます。
ctyを使う
使い方はとても簡単で、cty::から使いたい型をuseするだけ。
use cty::{uint32_t, c_uchar};
#[derive(Debug, Copy, Clone)]
#[repr(C)]
pub struct FrameBufferConfig {
frame_buffer : *mut c_uchar,
pixels_per_scan_line : uint32_t,
horizontal_reslution: uint32_t,
vertical_resolution: uint32_t,
pixel_format : PixelFormat
}
#[no_mangle]
pub extern "C" fn KernelMain(frame_buffer_config: *mut FrameBufferConfig) -> ! {
let fb_buffer_config = unsafe {*frame_buffer_config};
こんな記述でUEFI側を変更すること無く構造体の受け渡しが出来ました。
C言語側の構造体定義はこうなっています。
struct FrameBufferConfig {
uint8_t *frame_buffer;
uint32_t pixels_per_scan_line;
uint32_t horizontal_reslution;
uint32_t vertical_resolution;
enum PixelFormat pixel_format;
};
C言語側もint等を使わずにビット幅を指定しているので、上手く渡せているようです。
これでUEFIからもらったグラフィックスの情報を使って、座標を指定して色を塗ることが出来るようになりました。
全ソース
カーネル側の全ソースです。四日目分はまだ作業中。
#![no_std]
#![no_main]
#![feature(asm)]
#![feature(abi_efiapi)]
use cty::{uint32_t, c_uchar};
extern crate rlibc;
extern crate panic_halt;
#[derive(Debug, Copy, Clone)]
#[repr(C)]
enum PixelFormat {
KPixelRGBResv8bitPerColor,
KPixelBGRResv8BitPerColor
}
#[derive(Debug, Copy, Clone)]
#[repr(C)]
pub struct FrameBufferConfig {
frame_buffer : *mut c_uchar,
pixels_per_scan_line : uint32_t,
horizontal_reslution: uint32_t,
vertical_resolution: uint32_t,
pixel_format : PixelFormat
}
#[derive(Debug, Copy, Clone)]
struct PixelColor {
r : u8,
g : u8,
b : u8
}
fn pixel_offset(x:u32, y:u32, config: &FrameBufferConfig) -> u32 {
4 * (config.pixels_per_scan_line * y + x)
}
fn write(x:u32, y:u32, pixel:PixelColor, config: &FrameBufferConfig) {
let offset = pixel_offset(x, y, config);
unsafe {
*(config.frame_buffer).offset(offset as isize) = pixel.r;
*(config.frame_buffer).offset(offset as isize + 1) = pixel.g;
*(config.frame_buffer).offset(offset as isize + 2) = pixel.b;
}
}
#[no_mangle]
pub extern "C" fn KernelMain(frame_buffer_config: *mut FrameBufferConfig) -> ! {
let fb_buffer_config = unsafe {*frame_buffer_config};
let white = PixelColor{r:255, b:255, g:255};
for y in 0..fb_buffer_config.vertical_resolution {
for x in 0..fb_buffer_config.horizontal_reslution {
write(x, y, white, &fb_buffer_config);
}
}
let green = PixelColor{r:0, g:255, b:0};
for y in 0..200 {
for x in 0..200 {
write(x, y, green, &fb_buffer_config);
}
}
loop {
unsafe {
asm!("hlt")
}
}
}