無謀にも「ゼロからのOS自作入門」を購入し挑戦というか、少し囓ってみました。
【追記】USBメモリからの起動はできたのですが問題もありました。
失敗...電源オフ状態でUSBメモリを挿して電源オン、画像がうまく表示されない。
成功...UBUNTUが立ち上がっているときにUSBメモリを挿しておき、再起動をする
コンピュータ本体とディスプレーの信号や相性の関係と思われます。
ここに至るまでの経緯と環境について触れておきます。
1.windows11(core i5,SSD 500GB)パソコンに、WSL2とUBUNTU20.04を導入。day03あたりまでできることを確認。
2.WSL2での作業が面倒に感じ、他の環境移行を考える。
3.Dockerを使う事例を参考にしてやってみたが私にはよくわからず。
4.無料になったという「VMWare Workstation Pro」を導入し、始めてみた。環境構築もコンパイルもできたが、最後のqemuでの表示ができず、断念。
5.ジャンク品レベルのスモールサイズパソコン(core i3,SSD 120GB)を入手できたので、UBUNTU20.04をインストールし環境構築。現在に至る。
(いやいや何度もインストールやら環境構築やらしました。)
このようにして順調に行くかと思いましたが、day09bまで進んだところで、もうC++の構文について行けず。単にコンパイル、続くQEMU表示、で喜んでいてもなあ、どうしたものかと悩む。何かちょっとでも自分独自のモノを作りたい。そこで思いついたのが、マンデルブロ集合の描画。以前の投稿です。
これを移植しようと考え、day03c の main.cpp に書き加えてみました。有り難い事に、けっこう簡単に動きました(コードは後ほど示します)。
他に一つ分かった事があるので触れておきます。QEMUで実行させてみたところ速さが今ひとつ。USBメモリから起動させればもっと速いかもと、やってみました。書籍のp.30、p.34、p.35を参考にUSBメモリ起動を何度も試みるのですが、「kernel.elf」が無いと表示され起動が停止します。最後の手段。WindowsパソコンでLinuxインストール用USBメモリとして作成。その中の、EFI/BOOT/BOOTX64.EFI を置き換えることまでしてみましたが、だめでした。まあいいかと諦めかけ、いつものようにQEMU表示をしておりました。そのときターミナル上を流れる文字をぼんやり見ていて気付きました。/mnt/ つまり /dev/sdb/ の kernel.elf を読みにいってると。早速、コンパイルで作られた
~/workspace/mikanos/kernel/kernel.elf
をUSBメモリのルートにコピーして起動をかけました。表示できました、それも速いです、感動です。
ついでですが、linux起動時の「GRUB」って良いですね。USBから起動したいとき、今までスイッチオンからのF2キー連打でBIOS画面を出してましたが、GRUBのメニューから入れることを知りました。 今回もいろいろ勉強になりました。でも、私にはやっぱり「C++」は難しいです。マンデルブロ集合を描くように改造した main.cpp を示します。
/**
* @file main.cpp
*
* カーネル本体のプログラムを書いたファイル.
*/
#include <cstdint>
#include <cstddef>
#include "frame_buffer_config.hpp"
//#include <math.h>
// #@@range_begin(write_pixel)
struct PixelColor {
uint8_t r, g, b;
};
/** WritePixelは1つの点を描画します.
* @retval 0 成功
* @retval 非0 失敗
*/
int WritePixel(const FrameBufferConfig& config,
int x, int y, const PixelColor& c) {
const int pixel_position = config.pixels_per_scan_line * y + x;
if (config.pixel_format == kPixelRGBResv8BitPerColor) {
uint8_t* p = &config.frame_buffer[4 * pixel_position];
p[0] = c.r;
p[1] = c.g;
p[2] = c.b;
} else if (config.pixel_format == kPixelBGRResv8BitPerColor) {
uint8_t* p = &config.frame_buffer[4 * pixel_position];
p[0] = c.b;
p[1] = c.g;
p[2] = c.r;
} else {
return -1;
}
return 0;
}
// #@@range_end(write_pixel)
#define W 480// tft.width()
#define H 320// tft.heght()
#define X0 240//tft.width()/2
#define Y0 160//tft.height()/2
const float absZ = 4.0; // 発散判定
const uint16_t page = 20;
const uint16_t dp = 2;
// default Mandelbrot Set -----------------------------------------
// viewpW=2.4; CtoX = 0.0; CtoY = 0.0;
// repeat=200; page=1; dp=0;
// ----------------------------------------------------------------
// viewpW = 0.00024; // 10000倍に拡大
// Viewport width; Viewport Center CtoX;CtoY;
// 風景の良い場所例
// example 1
// viewpW = 0.00024; CtoX = -1.24997; CtoY = -0.00877;
// repeat=190; page=28; dp=2;
// example 2
// viewpW = 0.00024; CtoX=-1.401;CtoY=-0.000178;
// repeat=300; page=19; dp=2;
const float viewpW = 0.0012; // viewport width(window width)
const float di = viewpW / 480.0;// real/imaginary calculation step
// 1 pixel in Real and Imaginary number
const float CtoX = -1.19998; // 現在の表示(viewpW)の中心
const float CtoY = -0.15507;
uint16_t repeat = 120; // 反復上限、page進行に応じ増加させる
uint16_t k; // 反復回
float x, y, zr, zi, R, I;//複素計算変数
uint16_t C[800]; // 色配列
uint32_t now, starttime;
uint16_t pi;
int16_t j,i;
uint16_t Xi,Yj;
bool cels[W][H]; // 各セルの発散状況記憶
// #@@range_begin(call_write_pixel)
extern "C"
void KernelMain(const FrameBufferConfig& frame_buffer_config) {
for (int x = 0; x < frame_buffer_config.horizontal_resolution; ++x) {
for (int y = 0; y < frame_buffer_config.vertical_resolution; ++y) {
WritePixel(frame_buffer_config, x, y, {255, 255, 255});
}
}
for (int x = 0; x < W; ++x) {
for (int y = 0; y < H; ++y) {
WritePixel(frame_buffer_config, x, y, {0, 0, 0});
}
}
for (pi = 1; pi <= page; pi++) {// 反復数上限を増やしていく
for ( j = - Y0; j < Y0; j++) {
Yj = Y0-j-1;
y = j * di + CtoY;
for ( i = - X0; i < X0; i++) {
Xi = X0 + i;
if(cels[Xi][Yj]==false){ // 未発散のピクセル(黒)のみ計算
x = i * di + CtoX;
zr = 0.0;
zi = 0.0;
k = 0;//-1;
do {
k++;
R = zr * zr - zi * zi + x;
I = 2 * zr * zi + y;
zr = R;
zi = I;
if ( k == repeat ) break;
} while ( (zr * zr + zi * zi) < absZ );
if (k < repeat) {// 新たに発散したピクセルのみ描画
WritePixel( frame_buffer_config, Xi, Yj,
{static_cast<uint8_t>(255 -( k % 255)), // コンパイラが教えてくれた
static_cast<uint8_t>(255 - (k % 128)),
static_cast<uint8_t>(255 - (k % 64))} );
cels[Xi][Yj]=true;
}
}
}
}
repeat += dp * pi;
}
for (int x = 0; x < W; ++x) {
for (int y = H-5; y < H; ++y) {
WritePixel(frame_buffer_config, x, y, {0, 255, 255});
}
}
while (1) __asm__("hlt");
}
// #@@range_end(call_write_pixel)
最後までお付き合い頂き有難うございました。