30日でできるOS自作入門【18日目】
概要
これはMozyの1人アドベントカレンダー 2018 の18日目の記事です。
書こうとした経緯は、こちら
今日の内容
- 色番号の設定を追記した
今日やったこと
- OSらしく画面を描くために色番号の設定を作成した
bootpack.c
void io_hlt(void); void io_cli(void); void io_out8(int port, int data); int io_load_eflags(void); void io_store_eflags(int eflags); /* 実は同じソースファイルに書いてあっても、定義する前に使うのなら、 やっぱり宣言しておかないといけない。 */ void init_palette(void); void set_palette(int start, int end, unsigned char *rgb); void HariMain(void) { int i; /* iは、32ビットの整数型 */ char *p; /* pは、BYTE [...]用の番地 */ init_palette(); /* パレット設定 */ p = (char *) 0xa0000; /* 番地を代入 */ for (i = 0; i <= 0xffff; i++) { p[i] = i & 0x0f; } for (;;) { io_hlt(); } } void init_palette(void) { static unsigned char table_rgb[16 * 3] = { 0x00, 0x00, 0x00, /* 0:黒 */ 0xff, 0x00, 0x00, /* 1:明るい赤 */ 0x00, 0xff, 0x00, /* 2:明るい緑 */ 0xff, 0xff, 0x00, /* 3:明るい黄色 */ 0x00, 0x00, 0xff, /* 4:明るい青 */ 0xff, 0x00, 0xff, /* 5:明るい紫 */ 0x00, 0xff, 0xff, /* 6:明るい水色 */ 0xff, 0xff, 0xff, /* 7:白 */ 0xc6, 0xc6, 0xc6, /* 8:明るい灰色 */ 0x84, 0x00, 0x00, /* 9:暗い赤 */ 0x00, 0x84, 0x00, /* 10:暗い緑 */ 0x84, 0x84, 0x00, /* 11:暗い黄色 */ 0x00, 0x00, 0x84, /* 12:暗い青 */ 0x84, 0x00, 0x84, /* 13:暗い紫 */ 0x00, 0x84, 0x84, /* 14:暗い水色 */ 0x84, 0x84, 0x84 /* 15:暗い灰色 */ }; set_palette(0, 15, table_rgb); return; /* static char 命令は、データにしか使えないけどDB命令相当 */ } void set_palette(int start, int end, unsigned char *rgb) { int i, eflags; eflags = io_load_eflags(); /* 割り込み許可フラグの値を記録する */ io_cli(); /* 許可フラグを0にして割り込み禁止にする */ io_out8(0x03c8, start); for (i = start; i <= end; i++) { io_out8(0x03c9, rgb[0] / 4); io_out8(0x03c9, rgb[1] / 4); io_out8(0x03c9, rgb[2] / 4); rgb += 3; } io_store_eflags(eflags); /* 割り込み許可フラグを元に戻す */ return; }
init_palette部分
単にtable_rgbを宣言しているだけ。
char a[3];
は a: RESB 3
と相当する。知ったことに書いたが、初期値の保証はそれぞれで違う
こんな感じに、代入しなきゃ行けない値がたくさんある場合は、アセンブラでいうと、RESB命令だったら毎回記述が必要となるので、DB命令を使うよね。
C言語でそれと同じ意味のものとして宣言時に static
をつけるってのがある
set_palette部分
基本的にはio_out8関数をなんども呼び出しているだけの処理。
io_out8はこの後にアセンブラで書く事になるが、装置番号で指定した装置にデータを送る関数のようだ。
OSが動くためには、サウンドカードとかキーボードとかそういうデバイスに対して電気信号のINとOUTを行う必要があって、こういう命令はC言語にはないため、アセンブラで自作しなければならないって事だ。
ハマりポイント
記述量が多かったのでtypoに一瞬はまった。
知ったこと
【ブログのタネ】【技術書】O'Reilly Safari Books Onlineを契約してみた 【読み放題】
この記事は、write-blog-every-week Advent Calendar 2018の17日目の記事です。
この記事では、ブログを定期的に書き続けるためのタネになっているO'Reilly Safari Books Online というサービスを紹介してみたいと思います。(タネはあるが、書くネタがなかった
経緯
最近、オライリー本などの技術書をHumbel Bundleなどでセット買って読んでいた。
そこで、以下のようなサービスがあることを知って居ても立っても居られず契約をしてみた。
O'Reilly Japan - Safari Books Online
Safariは、200社以上の大手出版社から発行される書籍、ビデオトレーニング、オライリーカンファレンスのフルコンパイルを提供しているデジタルライブラリーサービスです。ビジネス、テクノロジー、デザイン分野の最新情報がいち早く入手できます。
実際の画面はこんな感じ。(最近の本を表示したところ)
アレクサのスキルを作るための書籍とかマニアックですねぇ。
どれぐらいコンテンツがあるのか
設定画面から言語設定ができるのですが、以下のような内訳になっています。英語だけで4万7千冊以上! 2018/12/17現在
English (47,334 titles)
チュートリアル講座もある
料金は?
月33ドル、年間で333ドル 安くはないけど高くもない、ちょうどいい感じです。勉強のモチベーションが上がる!
まとめ
エンジニアなら契約して損はないぞ! ここら辺でもっと詳細に解説しています。
時間ギリギリになってしまったのでこんな感じで尻すぼみですが締めたいと思います!!
30日でできるOS自作入門【17日目】
概要
これはMozyの1人アドベントカレンダー 2018 の17日目の記事です。
書こうとした経緯は、こちら
今日の内容
- ポインタをどんどん応用していく
今日やったこと
- プログラムをどんどん書き換えていく
ポインタの知識を応用すると、こんな感じに書き換えもできるし
bootpack.c
p = (char *) 0xa0000; /* 番地を代入 */ for (i = 0; i <= 0xffff; i++) { *(p + i) = i & 0x0f; }
こんな感じにもできるな
p = (char *) 0xa0000; /* 番地を代入 */ for (i = 0; i <= 0xffff; i++) { p[i] = i & 0x0f; }
p[i]
って記述は別にpって配列のi番目って意味じゃないことはこうやってアセンブラぽく進めると理解できるよね。
p[i]
は *(p + i)
と同じ意味になるので別に省略する書き方なだけでそれ以上でも以下でもないのだ。
p[0]
が *p
と同じって考えると理解しやすいかもね。
あと、足し算はもちろん順序を変えても問題ないので、p[i]
はi[p]
と同じになります。
こうなると、p[i]
は pという配列のi番目って表現が使えないのはわかりますよねぇ。経験が長いエンジニアでも間違えて理解しているところな気がするここら辺。
ハマりポイント
特になし。
知ったこと
30日でできるOS自作入門【16日目】
概要
これはMozyの1人アドベントカレンダー 2018 の16日目の記事です。
書こうとした経緯は、こちら
今日の内容
- ポインタに挑戦
今日やったこと
- 機能書いたプログラムをポインタを使って書き直す
bootpack.c
void io_hlt(void); void HariMain(void) { int i; /* iは32ビットの整数 */ char *p; /* pという変数は、BYTE [...]用の番地 */ for (i = 0xa0000; i <= 0xaffff; i++) { p = i; /* 番地を代入 */ *p = i & 0x0f; /* これで write_mem8(i, i & 0x0f); の代わりになる */ } for (;;) { io_hlt(); } }
ただし、warningが出ているな。
bootpack.c: In function `HariMain': bootpack.c:10: warning: assignment makes pointer from integer without a cast
なるほど。キャストが足りないのね。
p = (char *) i;
てな感じにして解決!
ハマりポイント
久々にポインタの概念が出てきたので、一応、少しググって思い出していた。
こうやって急に問われた時に正確な概念が返せないといけないねぇ。
p = (char *) i;
と
*p = i & 0x0f
の違いを説明してみよう。
これらのpをECXだとして、アセンブラぽくしてみると
MOV ECX, i
MOV BYTE [ECX], (i & 0x0f)
てな感じになるよね
こうすると違いがすごく明確で、ECXっていう「レジスタ」への書き込みなのか
それとも、ECX番地の「メモリ」への代入なのかとなる。
そもそも書き込む素子ですら違うのでめっちゃ明確に違うものとわかる。
これがC言語だと p なのか *p なのかの一文字で変わってしまうのよね。
知ったこと
そう言えば、char、short、intがそれぞれ1、2、4バイトの変数って知っていたけれども、AL、AX、EAXと対応する感じなんだなぁ。
こうやって既存のCを知っている状態でもっと低レベルを知ると納得できる部分がどんどん出てきていいですねぇ。
30日でできるOS自作入門【15日目】
概要
これはMozyの1人アドベントカレンダー 2018 の15日目の記事です。
書こうとした経緯は、こちら
今日の内容
- bootpack.cを改造して、模様をかけるようにした
今日やったこと
bootpack.c
void io_hlt(void); void write_mem8(int addr, int data); void HariMain(void) { int i; for (i = 0xa0000; i <= 0xaffff; i++) { write_mem8(i, 15); /* MOV BYTE [i],15 */ } for (;;) { io_hlt(); } }
試しに、write_mem8(i, 14)
としてみたところ
うーん確かに変わっている。数字によって変わるってことね。
しかし面白くないので、模様をかけるようにするぞ。
write_mem8の部分を以下のように変更した。
bootpack.c
for (i = 0xa0000; i <= 0xaffff; i++) { write_mem8(i, i & 0x0f); }
&
はAND演算子のことで、このように番地の値に0x0fをANDすると、番地の下位4bitだけが、そのまま残って、他のビットは全て0となる。こうなると書き込まれる値が、
00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 00 01 02....
てな感じに繰り返されるので
ハマりポイント
特になかったぞ。順調だ。説明が丁寧な本っていいね。
知ったこと
なるほど。こうやって直接VRAMを扱うことで表示を作れたりするのね。
bit演算を考えてグラフィックを作るのも面白いなと思った。
これでどうにかドラえもんとか描けないなかなぁ。
30日でできるOS自作入門【14日目】【祝2週間】
概要
これはMozyの1人アドベントカレンダー 2018 の14日目の記事です。
書こうとした経緯は、こちら
今日の内容
- C言語からメモリの書き込みたいぞ
今日やったこと
- C言語と画面表示の練習
昨日は、画面を真っ黒にすることはできたが、やっぱり何か絵を描いてみたいよね。
そのためには、VRAMになにかを書き込めば良い。そのためには、メモリの番地を直接指定して書き込む必要があるので、そういう関数を作ってしまおう。ということになった
nascfunc.nasに追記
_write_mem8: ; void write_mem8( int, addr, int data ); MOV ECX, [ESP+4] ; [ESP+4]にaddrが入っているのでそれをECXに読み込む MOV AL, [ESP+8] ; [ESP+8]にdataが入っているのでそれをALに読み込む MOV [ECX], AL RET
これは write_mem8(0x1234, 0x56) のように使う。
動作としては MOV BYTE [0x1234], 0x56
をやらせたいということ。
ハマりポイント
特になかった。順調だが、進度は亀のように遅い笑
知ったこと
なるほど。言われてみればVRAMにデータを書き込めば表示は出るよな。
普段はVRAMとか意識せずにGUIなどを使っているのだなぁと思った。
2週間を迎えて
継続はできているぞ! 内容は薄い日もあるけど継続は力なり。このまま完遂まで行ってみよう!
30日でできるOS自作入門【13日目】
概要
これはMozyの1人アドベントカレンダー 2018 の13日目の記事です。
書こうとした経緯は、こちら
今日の内容
- とにかくHLTしたいぞ
今日やったこと
- HLTする関数を作った
nackfun.nas
; naskfunc ; TAB=4 [FORMAT "WCOFF"] ; オブジェクトファイルを作るためのモード [BITS 32] ; オブジェクトファイルのための情報 [FILE "naskfunc.nas"] GLOBAL _io_hlt ; このプログラムに含まれる関数 ; 以下が実際の関数 [SECTION .text] ; オブジェクトファイルはこれを書いてからプログラムを書くらしい _io_hlt: ; void io_hlt(void); HLT RET
bootpack.c
void io_hlt(void); void HariMain(void) { fin: io_hlt(); /* これでnaskfunc.nasの io_hltが実行される*/ goto fin; }
ハマりポイント
特になし〜。順調だが、寒くて体調が悪くなってきた