「30日でできる!OS自作入門」
■ このスレッドは過去ログ倉庫に格納されています
プログラミングの基礎からはじめて、
30日後にはウィンドウシステムを有する32bitマルチタスクOSを
フルスクラッチで作り上げるという入門書。
ビギナーでも無理なく作成できるようPCの仕組み・アセンブラ・Cの解説から始まり、
試行錯誤を繰り返しながらアルゴリズムを学びつつ、
たのしく自由な雰囲気でOSをゼロから構築していくという、
他に類を見ない手法による、
趣味と実用と学習を兼ね備えたOS作成の入門書です。 チラシの裏:
4日目終了
C言語をアセンブリに翻訳したものを提示されるたびに(。・ρ・。)ヘーと思う。
ポインタの本質が分かった気がした。そうか、それで不正な型とかいわれていたのか!と思った。
配列の記述もそういう風に翻訳されてたんだ〜と思った。
ただ、なんかPCが不調で再起動してから(OS作りではパレットの設定を始めたあたりから)
make run で haribote.imgの書き出しに失敗することがあるようになった。
何回かやり直せばうまくいくけど…、なんでなのかよくわからない。
それから、これ第5刷なんですけど、P90〜91のnaskfunc.nasで
ソースの9行目 io_stihlt は _io_stihlt かな〜と思った。
ソースの _io_out16: のあたりで MOV EAX,[ESP+8] は MOV AX,[ESP+8] ではないかなー
と思った(16bitだし)。が、こっちはなんとなく自信なし。(アセンブリ経験浅過ぎなんで) >>247
> P90〜91のnaskfunc.nasでソースの9行目 io_stihlt は _io_stihlt かな〜と思った。
ソースの _io_out16: のあたりで MOV EAX,[ESP+8] は MOV AX,[ESP+8] ではないかなー
チラシの裏に書いておくだけじゃ、モッタイない(死語)
こっちにも書いて問い合わせてみたら、いいやん。
ttp://hrb.osask.jp/wiki/index.php?bugs ◆teNezgnnCoにとっては、小さな一歩だが。
人類にとっては、偉大な一歩なのだ。
”なーんちゃったりして ”
「書き込みが的を得ていたみたいで、
K氏より回答があったみたいじゃん」
まずは、オメデトー。 >>250
おー本当ですね〜。
MOV EAX,[ESP+8] はこっちの方がいいからなのか〜。
なるほどなー。勉強になるなぁ〜。 三日目〜十日目終了。
いちいちコードを吟味する暇はねぇんだよ。 5日目完了
まぁやったことっていうと、文字・マウスポインタを書いて
GDT/IDTについてちょこっと知ったくらいですかね。
引き続き6日目へいきます。 11日目〜12日目終了。
さすがの俺様もペースが落ちてきたぜ。 6日目終了
分割コンパイル、Makefile整理、ヘッダファイル使用、PIC初期化、割り込み処理が完了
9日目突入〜
基本的には1章読んでは、エミュで実行してみるという流れで
ほぼ読むだけで進めてるのに、全然終わる気配が無いw
はやく改造したりして遊びたいYO だんだん飽きてきた…
少しずつ着実に進めるのが正解だろうな いつの日にか必ず再開する予定なので
それまで保守ヨロシコ 反骨精神で帰ってきた(`・ω・´)
まずはPCは起動せずに、本だけ通読してみます 金土日は部活なので進めれませんでした。
しかーし。
今日から再開ですよ。 <チラシの裏>
68日目
テストカキコ
</チラシの裏>
<チラシの裏>
69日目
調子に乗ってHDDに書き込みしたら、大変なことになった
</チラシの裏> <chiraU>
OS自作が面白くてFF3どころじゃないやい
</chiraU> これでしょ。DSリメイク版のFF3
ttp://www.famitsu.com/topics/2006/06/02/601,1149223096,54260,0,0.html
当然それ
最新PCで動く自作OSよりも
遅いCPUの携帯ゲーム機のほうが描画がすごいのが悲しい それを言ったら、
昔のCPU
Z80を使ったアーケドゲーム機に最新のPCゲームは及ばないよ。 PS3が売れたらパソコンが売れなくなりそうで、それが楽しみ。 みんな、ガンバレ。
日本の、OS自作の夜明けは近い! 平均して一日一ページくらいのペースの今日この頃ですが
みなさま如何お過ごしでしょうか ∧_∧
( ´∀`) <チラ裏を独り占め
/, つ
(_(_, )
しし' 〃∩ ∧_∧
⊂⌒( ・ω・) ふむふむ、チラチラ解消か…
`ヽ_っ⌒/⌒c
⌒ ⌒
ただいまの進捗率 31% -‐-
__ 〃 ヽ
ヽ\ ノノノ)ヘ)、!〉 / ̄ ̄ ̄ ̄
(0_)リ (┃┃〈リ | はわわ〜
レVlト " lフ/ n <
l^ヾヽ!v‐' 犯 | 次はいよいよマルチタスクだモナ…もとい、ですよー
ヽ `'´ >ァ'l|´ \____
〉-イ'´ ||
進捗41%までアップ 本の課題に挑戦した人たち
本当に30日でOSが出来上がるのかを試してみるBlog
ttp://d.hatena.ne.jp/hariboteOS/
『30日でできる!OS自作入門』Linux環境でチャレンジ!
ttp://homepage2.nifty.com/hanpen/index2.html
[HariboteOS][本]
ttp://d.hatena.ne.jp/papamitra/searchdiary?of=15&word=%2a%5bHariboteOS%5d
OS製作やOS/プログラミングに関する話題を収集するWiki
osdev
ttp://wiki.osdev.info/index.php OS Wiki
ttp://community.osdev.info/
30日でできる! OS自作入門」のサポートページ
ttp://hrb.osask.jp/ うっしっし
コードの部分を全く見ずに文字だけ読んだら大分進んだぞ
進捗およそ90% >>295
それでいいの?
なんか目的が、OSが自作できるようになることから、
ただ早く読み終わることに成り下がっているんじゃないかと、心配だよ。 >>296
なんでもいいから一旦読み終えてしまいたい(;´Д`)…
フルカラーにして壁紙つけたりしてささやかな俺様OSを作りたいのに
読み終えないと、最終ソースから改造できないし
まともに読むのはもう飽きちゃったから仕方ないんだYO なるほどそういうことかー。
最終ソースからの改造が目的なら、
改造の過程で必要なところは復習できそうだから、
その読み方でもいいかもしれないですね。 ∧__∧
( ´∀`) <100%達成したよ!
( O┬O
≡◎-ヽJ┴◎
だが、真の戦いはこれからだ!
結局2週目読み直すはめになりそう(苦ワライ osの本で検索しても見つけられずにいたが(無意識にスルーしていた?)、
最近知った良さそうな本の紹介
APIで学ぶWindows徹底理解
http://www.amazon.co.jp/exec/obidos/ASIN/4822228266 なんか良さげですね
丁度サービスコールの役割がいまいち理解できなくて
お手本が見たかったところでした 形から入るならこんなもの買わないで、はじめて読むシリーズとタネ本、汗本を全巻揃えろよな
はじめて読む本も、「30日でできる!OS…」本も、持ってるけど
「30日でできる!OS…」本のほうがためになったなぁ。 >>304
はじめて読むシリーズは
MASMと8080と486は持ってる罠
タネ本と汗本って何ですか? >>307
駱駝とかと同じで表紙のイラストかとオモッタ
タネンバウムはOS博士なのね
ググったら9千円くらいの本があったけど、そんなの要らね HDDがあるのに使えない。使わない。 ってのはイライラするOSだね。 >>310
MINIXの本なら読んで損はしないよ。
マルチポストになるけども、どうしても分からないのでご教授お願いします。
向こうだと、書きにくいので。
分からないところは、p208のsheet_slide関数でのマウスの移動です。
シートが出てくるまでは移動前のマウスカーソルの有った範囲を塗りつぶして、
新しいマウスカーソルを書いていました。
harib07cのsheet_slide関数では、どのタイミングで以前有ったマウスカーソルが塗り潰されるのでしょうか?
sheet_refreshsub(ctl, vx0, vy0, vx0 + sht->bxsize, vy0 + sht->bysize)で
1、sht_backの移動前のマウスカーソルがある場所だけを塗りつぶす。
2、移動前のマウスカーソルを書く。
sheet_refreshsub(ctl, old_vx0, old_vy0, old_vx0 + sht->bxsize, old_vy0 + sht->bysize);で、
3、sht_backの移動後のマウスカーソルのある範囲だけを塗りつぶす。
4、移動後のマウスカーソルを書く。
の順になると思うのですが、移動前の書き換えられる範囲から外れたマウスはなぜ
画面に残らないのでしょうか。
シートと言う仕組みを使っても結局はVRAMにマウスカーソルを重ね書きしているわけで、
例えば(152,78)からマウスカーソルが(100,100)に移動した場合(152,78)に
以前のマウスカーソルが残るような気がするのですが。
(152,78)から(168,94)を塗りつぶす→(152,78)から(168,94)にマウス書く。
(100,100)から(116,116)を塗りつぶす→(100,100)から(116,116)にマウス書く。
これでは、(152,78)から(168,94)にマウスが残りそうなのですけれども。
>>315
sheet_refreshsub関数を2回呼ぶ前に、以下でシート階層上は、マウスカーソールは、論理的に移動している、ということを頭にいれてソースを読み直すとよいと思う。
sht->vx0 = vx0;
sht->vy0 = vy0;
移動前と移動後のマウスカーソルの矩形イメージが重ならないなら、
sheet_refreshsub(ctl, old_vx0, old_vy0, old_vx0 + sht->bxsize, old_vy0 + sht->bysize);で、
1、sht_backのイメージで移動前のマウスカーソルがある場所だけを塗りつぶす。
sheet_refreshsub(ctl, vx0, vy0, vx0 + sht->bxsize, vy0 + sht->bysize);で
2、sht_backのイメージで移動後のマウスカーソルのある範囲だけを塗りつぶす。
3、移動後のマウスカーソルを書く。
になると思うけど。 >>316
エ、エスパー?
>sheet_refreshsub関数を2回呼ぶ前に、
>以下でシート階層上は、マウスカーソールは、
>論理的に移動している、ということを頭にいれてソースを読み直すとよいと思う。
>sht->vx0 = vx0;
>sht->vy0 = vy0;
ズバリ自分が勘違いしていたところです。
そりゃ、{2、移動前のマウスカーソルを書く。}なんてことが起こるはずだよ。
こんなことで紙とペンもって一日中考えていたとは・・・・
いい経験になりました。ご助言有難うございます。
もしよければこっちでも質問してよいですかね?
むこうのwikiは使いづらいので。 あの、すごく低レベルな質問で申し訳ないんですが・・・
harib08h、sheet_refreshmap関数からの疑問点です。
sht = ctl->sheets[h];
sid = sht - ctl->sheets0; /* 番地を引き算してそれを下じき番号として利用 */
という代入文なのですが、普通の変数に番地を代入する事はOKなのでしょうか?
p77にもありますが、「C言語は普通の数値とメモリ番地は根本的に違うのだ
という考え方で設計されていまして〜」とあり、
番地変数に普通の数字を代入するときはその数値がメモリの番地だと分かるように
キャストしてあげなければいけませんでした。
今回もキャストのようなことはしなくて良いのかなと思ったので。 >>318
http://www.st.rim.or.jp/~phinloda/cqa/cqa3.html#Q16
ある一次元座標上の座標位置A,Bを引き算して出てくる値は、位置Aを原点とする座標から見れば、位置に違いないけど、今使っている座標から見れば、位置の意味がなくなって、
位置Aと位置Bの距離になるでしょ。同じように
コンピュータが今使ってるアドレス空間上の番地A,Bを引き算して出てくる値は、コンピュータが想定しているアドレス空間上の番地の意味はなくなって、番地A,Bのデータ型のサイズでスケールされた番地A,B間の距離(符号つき整数型)になる。
>>319
ほぇ〜。回答有り難うございます。
ポインタに代入されているアドレスが引き算されるんじゃなくて、添え字の引き算の結果になるんですね。
例えば
sht = ctl->sheets[2];
とすると、
sid = sht - ctl->sheets0;
は
sid = ctl->sheets[2]-ctl->sheets0;
となってsidは2が代入されるわけですね。
でも、その場合
sid = ctl->sheets[2]-ctl->sheets0[0];
じゃないとおかしくなるんじゃ無いんでしょうか。
ctl->sheets0の場合、「配列名は配列の先頭要素のアドレス」と本に書いてあったので、
やっぱりポインタに代入されているアドレスが引き算されるのではないのでしょうか? >>320
>ポインタに代入されているアドレスが引き算されるんじゃなくて、添え字の引き算の結果になるんですね。
何でそういう二者択一になるの?
リンク先で言っているのは、ポインタ同士の引き算は、
ふたつのポインタが、同じ配列上のいずれかの要素を指していて、
ポインタの指す型が、要素の型と一致すれば、
ポインタに対応する要素の添字の引き算と結果的に同じになると言ってるんですけど。
ポインタの引き算は、アドレスを引き算して、ポインタの指しているデータ型のサイズで割るんだから
同じになるでしょ。
>例えば
>sht = ctl->sheets[2];
>とすると、
>sid = sht - ctl->sheets0;
>は
>sid = ctl->sheets[2]-ctl->sheets0;
>となってsidは2が代入されるわけですね。
いいえ。可能的には、符号つき整数の全範囲の値のいずれか。
プログラムが正しく動いていると仮定すれば、 0からSHEETS_MAXの範囲の整数のいずれかの値です。
多分、ctl->sheets[2] の添字が2で、ctl->sheets0が最初の要素を指しているいて、添字が0だから
2マイナス0は2と考えているんだろうと思うけど、ctl->sheets配列とctl->sheets0配列は、要素の型も
存在する場所も異なる、まったく別の配列だから添字を引き算しても意味がないでしょ。
実際は、ctl->sheets[2]は、ctl->sheets0配列の要素のどれかを指しているから、まあ添字の引き算で考えるなら、ctl->sheets0配列の要素のどれかの添字マイナス0と考えないと。
わかったぁ!
メモリって言うのは道路なんだ!
ポインタって言うのは、道路の上の標識みたいな物なんだ。
今まで「ポインタって言うのはメモリのアドレス(特殊な数値)」とだけ念じてプログラムを読んできたけれど、
それじゃ理解が不十分で、こうやってイメージしながらプログラムを読むことが大事なんだ!
>>319さん
すいません、リンク先だけ見てました。
>コンピュータが今使ってるアドレス空間上の番地A,Bを引き算して出てくる値は、
>コンピュータが想定しているアドレス空間上の番地の意味はなくなって、
>番地A,Bのデータ型のサイズでスケールされた番地A,B間の距離(符号つき整数型)になる。
勉強になりました!
>>320,321さん。
詳しい解説有り難うございます。
つまり
int型メモリ番地0x00000003-int型メモリ番地0x00000000を行った場合
答えは番地0x00000003になる(←今までの自分の誤解していた点。メモリ番地は数値だから引き算できて当然と思っていた)。
実際はそうではなくて
0x00000003はメモリ番地の意味が無くなってint型だから1になるわけですね。
>>323
水を差すようだけどあまり考え込まない方がいいと思うよ。
これだ!って確実に理解できるイメージがないから、
結局使いながら使い方を覚えるしかなくてみんな苦労するんだよ。
> メモリって言うのは道路なんだ!
> ポインタって言うのは、道路の上の標識みたいな物なんだ。
たとえに突っ込むのも野暮だと思うけど、
メモリは家でポインタは住所の方が近い。
int a[3];
printf("%d\n", &a[3] - &a[0]);
これの結果は3になる。
家と住所のたとえでいえば、
a[0] a[1] a[2] a[3]
と並んでいて、
3は0の3軒隣ということ。 >>324
うぉー、ご助言感謝です。
>int a[3];
>printf("%d\n", &a[3] - &a[0]);
>これの結果は3になる。
>家と住所のたとえでいえば、
>a[0] a[1] a[2] a[3]
>と並んでいて、
>3は0の3軒隣ということ
OKです。
つまり、さっきの例でいくと、
(a[3]のアドレス-a[0]のアドレス)/int=3と言うわけですね。
プログラムの勉強をしていると数学が大事と言うことが分かったので、
オイラーの贈り物という本を買って今クロネコで届きました。
プログラムの勉強をするともれなく数学の勉強も一緒にできるなんて、プログラムは便利な学問だなぁ。
>>323
> 今まで「ポインタって言うのはメモリのアドレス(特殊な数値)」とだけ念じてプログラムを読んできたけれど、
> それじゃ理解が不十分で、こうやってイメージしながらプログラムを読むことが大事なんだ!
イメージが間違っていると変な癖が付いたりするから、
たとえとか持ち出さないでケースバイケースで使い方を覚える方が良いと思うよ。
ポインタはある程度経験を積まないと見えてこないから難しい。
> int型メモリ番地0x00000003-int型メモリ番地0x00000000を行った場合
> 答えは番地0x00000003になる(←今までの自分の誤解していた点。メモリ番地は数値だから引き算できて当然と思っていた)。
> 実際はそうではなくて
> 0x00000003はメモリ番地の意味が無くなってint型だから1になるわけですね。
配列の添字とアドレスがごっちゃになってないかな?
int a[3];
printf("%d,%d,%d\n", &a[3], &a[0], &a[3] - &a[0]);
こうやるとアドレスの値を見ることができる。
実行するとたとえばこんな結果になる。
2280668,2280656,3
※最初の2つはOSによって数字が違うので注意
この場合、a[3]の3が添字で、2280668がアドレス。
a[3]とa[0]のアドレスを単純に引き算すると12になる。
これがなぜ3になるかというと、intが1つにつき4バイト必要だから、
12÷4=3でintが3つ分という意味で3となる。 >>325
> (a[3]のアドレス-a[0]のアドレス)/int=3と言うわけですね。
ここではintじゃなくて「intのサイズ」と言う方が良い。
C言語の書き方ではsizeof(int)。
ちなみに全部をC言語で書くとこうなる。
(((char*)&a[3])-((char*)&a[0])/sizeof(int)
> プログラムの勉強をしていると数学が大事と言うことが分かったので、
> オイラーの贈り物という本を買って今クロネコで届きました。
>
> プログラムの勉強をするともれなく数学の勉強も一緒にできるなんて、プログラムは便利な学問だなぁ。
数学力をプログラムで鍛えるなら3Dがお勧め。
人類の至宝とまで言われるオイラーの等式e^(i*pi)=-1とか普通に使うよ。 >>326,327
本当に親切な解説有り難うございます。
ところで、結局「30日でできる!OS自作入門」を読み切るにはどの程度のC言語の知識が必要なんでしょうか?
今回自分が躓いたようなことは、自分が参考にしている本「やさしいC 第二版 高橋麻奈 著」(コレしか持ってない)
には書いてありませんでした。
「30日でできる!OS自作入門」のオビには「どんなプログラミング言語でも良いので、
簡単なプログラムなら書いたことあるよ位のセンスがあれば、それでOK」
とあるので、プログラム書いたこと無いけどセンター試験でBASICの勉強したからイイかなぁと思って購入したんですけど。
10日目までの内容は、アセンブラも含めてほぼ理解している自信はあります。
ただ、ソースコードを読んで疑問に思う→インターネットで調べる→理解して本に書き込む
を繰り返した結果10日目なのに本がボロボロになってしまって・・・
これ以上本の内容が難しくなると、やさしいCじゃもう対処できそうにないし
今の自分のレベルで次は何という参考書を買えばよいのでしょうか?
C言語の本がたくさんありすぎて迷ってしまいます。
>>328
内容を全部理解しようと力みすぎ。
細かい所は気にしないでざっと進めた方がいいよ。
完全に理解するのははっきり言って無理。
C言語で書きながら頭の中でアセンブリに翻訳できるくらいの実力が必要。
そんなレベルをいきなり目指すのは
掛け算九九もできないのに微分積分に手を出すようなこと。
プログラミングは理屈じゃなくて年季だから、
本を必死に調べるよりもあれこれ改造したりして経験を積む方が良い。
たとえばC言語のポインタは数学的ではない。
必要な算数の知識は四則演算だけで小学校低学年レベル。
だけど難しいのは理解に経験が必要な類の知識だから。 >>328
C言語の本のお薦めは「プログラミング言語C ANSI規格準拠」
B.W. カーニハン (著), D.M. リッチー (著), 石田 晴久 (翻訳)
¥ 2,940 (税込) >>330
これは値段も手頃だし147x210x20(mm)とコンパクトでいいよ。翻訳が硬いのが
難だけど、安いからしかたないね。 >>329,330,331
有難うございます。
お勧めされた本、凄く有名みたいですね。
amazonから1000円のクーポンが送られてきたので買ってみます。
本当に有難うございました! 凄くくだらないことなんですが、質問です。
p240の
struct TIMER *timer_alloc(void)
{
int i;
for (i = 0; i < MAX_TIMER; i++) {
if (timerctl.timer[i].flags == 0) {
timerctl.timer[i].flags = TIMER_FLAGS_ALLOC;
return &timerctl.timer[i];
}
}
return 0; /* 見つからなかった */
}
という関数で戻り値の型が、struct TIMER型のポインタなのは、
戻り値が構造体timerctlのメンバ(struct TIMER型の)timerのアドレスだからという理解でOKですよね?
周りにプログラミングをしている人が居ないので、とても疑心暗鬼になってしまって申し訳ないです。 それと、もうひとつイマイチ理解に苦しむものが・・・
p248の
timer_settime関数で一番最初のタイマ(timer,1000)を登録する場合なのですが、
for (i = 0; i < timerctl.using; i++) {
if (timerctl.timers[i]->timeout >= timer->timeout) {
break;
}
}
timerctl.using++;
の時点で変数は、i = 0 ,using = 1が代入されていますよね。
/* うしろをずらす */
for (j = timerctl.using; j > i; j--) {
timerctl.timers[j] = timerctl.timers[j - 1];
}
/* あいたすきまに入れる */
この↑の処理で
どこのメモリ番地が代入されているか分からないポインタ (timerctl.timers[1]に
どこのメモリ番地が代入されているか分からないポインタ(timerctl.timers[0]が代入される
という処理が行われるという理解で良いのでしょうか?
timerctl.timers[i] = timer;
↑この時点でポインタに代入していますよね? >>333
さいですな。
>>334
そうなるんでないかい。
変な所を見に行くとか心配なら、timerctl.usingの役目も
考えてあげてください。
アルゴリズムを解説している本を一冊読んだ方がよいと思いますです。
>>335
合ってましたか。
値を代入していないポインタの演算が初めて出てきたので、
解釈があっているかなと心配になって質問してみました。
有難うございます。 >>336
>値を代入していないポインタの演算
こんな処理はあり得ない。無意味。
本持ってないので未確認だけど、
配列がグローバルならNULL初期化されているので、
値が代入されていないわけではない。
それ以外に考えられることとして、
文字列みたいにNULL終端の配列なら
1つ後ろまでずらすということも考えられる。
後は誰か本持ってる人お願い。 >>337
なるほど、サンクスです。
ポインタもグローバル変数だったら、
普通のグローバル変数が0で初期化されるのと同じようにNULLで
初期化されるわけですね。
勉強になりました!
intelのマニュアルでCPU勉強したり英語のサイトでBIOS勉強したり
していた俺を君達はほんの数週間でこえていく('A`)
この本おそろしい ■ このスレッドは過去ログ倉庫に格納されています