advance/osselect
の編集
http://hrb.osask.jp/wiki/?advance/osselect
[
リロード
|
差分
|
単語検索
|
一覧
] [
編集
|
バックアップ
|
添付
]
-- 雛形とするページ --
A
Akkie
Athlon64X2
Clover
DAsoran
Falcon
FormatRule
FrontPage
Genesis
Help
I
InterWikiName
InterWikiSandBox
InterWikiテクニカル
Jormungand
K
Kebo
Kor_Lee_Hee_Rak
Leaf
Linux
Linux/wako_memo
MOIZ99
MW
MenuBar
OSC
PG_MANA
ReadersOS
RecentDeleted
SKYDASH
SandBox
Sero
Sigle
Source
Triangle_Ld.
Zxcvbnm
advance
advance/CPU
advance/FDC
advance/FPU
advance/NotHariMain
advance/QEMUVGA
advance/RTC
advance/blike
advance/cpu_reset
advance/driver
advance/driver/01
advance/driver/02
advance/families
advance/filesystem
advance/fwrite
advance/hddboot
advance/he86
advance/hints
advance/ipl
advance/kernel
advance/keycode
advance/osselect
advance/smaller1
advance/startup
advnace/smaller2
anzy
aotatsu
banbi-
bluedwarf
bo
bugs
challengers
cybozulabsyouth11
deskmanta
esb02b
faq
faq/advance
faq/asm
faq/c00-03
faq/c04-07
faq/c08-15
faq/c16-23
faq/c24-31
faq/make
faq/others
faq/qemu
guide
guide03
guide05
guide07
hikarupsp
imp_log/0000
imp_log/0001
imp_log/0002
imp_log/0003
impressions
index
k
killer_elf
kota
lea
lea/10_memory
lea/4_color
lea/idea
lea/terms
links
logs
logs/osa_hrb/comments0000
logs/osa_hrb/rumors0000
masa
members
message
mistakes
moge32
moppoi5168
notice
osdevjp
populars
prog_index
projects
q_and_a
q_and_a_2
qa_log/0000
qa_log/0001
qa_log/0002
qa_log/0003
qa_log/0004
qa_log/0005
qa_log/0006
qa_log/0007
qa_log/0008
qa_log/0009
quark
rankings
rule
sakamoto
sasaki
spc09
spcc_30min_os
tatsu
tools
tools/bim2hrb
tools/bin2obj
tools/cc1
tools/edimg
tools/gas2nask
tools/makefont
tools/nask
tools/obj2bim
tools/sjisconv
uchan
uho
updates
violations
wako
white
win64-bit
x
ytakano
ヘルプ
リックス
質問します
整形ルール
本は買ったぞ!持ってるぞ!
練習用ページ
* OSセレクタ?を作ろう! -(by [[K]], 2006.09.24) -発展課題のページ(全部読む前にここを読むのは混乱するのでおすすめじゃないです) ---- -[[「はりぼて友の会」:http://haribote.org/]]とかを覗いていると、「はりぼてOS」の兄弟OS(姉妹OS?)といえそうなものがたくさん生まれています。これらを別々のディスクにインストールして、好きなときに好きなOSを起動して遊ぶのは楽しいですが、これらのOSはみんなすごく小さいことですし、1枚のディスクにまとめられたら便利かなと思いました。 -そんなわけで、てきとーにOSセレクタ(の元?)を作ってみることにしました。 -というか、実は「はりぼてOS友の会」が[[10月のオープンソースカンファレンス:http://haribote.org/?OSC2006TokyoFall]]に出るので(おめでとう!)、その記念作品だったりします。・・・ということで、このプログラムは「はりぼて友の会」に奉げます(ライセンスは毎度のKL-01なので誰でも使えます)。 *** さてどうやって作ろうか? -景気よく「作るぞー」と意気込んではみたものの、さてどうしましょうか。OSセレクタというとまずはIPLやasmheadの部分を書き換える方法が考えられますが、これはどうやら[[Akkie]]さんがチャレンジする予定らしいので、[[K]]はやらないことにしました。 -そうなるとbootpack.hrb部分をいじるしかないわけで、コンソールにOS切り替えコマンドでもつけようかなと考えました。つまり一度は普通に「はりぼてOS」(かもしくはその兄弟OS)が起動して、そこからコマンドで他のOSに移るわけです。OS切り替えプログラムが超巨大化して、それ自身がOSになってしまった、と考えてもいいでしょう。 --「はりぼてOS」は小さいので、これでも下手なブートセレクタよりも小さかったりするのですが。 -でもこれだと切り替えコマンドがかっこ悪いとか言われそうです。それもくやしいので、切り替えAPIをつけることにしました。APIならOS切り替えアプリをかっこよくすればいいですし、それなら[[K]]がバカにされる心配もありません(笑)。 ~ ~ -仕組みはこうしました。まず、新たに.shsというファイル形式を考えます。これは「Select-bootable Haribote.Sys」の略で、「選択起動可能なharibote.sys」のつもりです。「Sister of Haribote.Sys」の略でもいいんですが(笑)。たいそうな略語ですが中身は簡単で、これはharibote.sysの中のCOLOR(#0000ff){bootpack.hrbの部分だけを取り出して}ファイル名と拡張子を変えただけです。・・・これをディスクから読み込んで、メモリ上にそれっぽく配置してJMPしてやればうまくいきそうだと考えたわけです。・・・こんなてきとーな方法でほんとにうまくいくのかな。 -なんか.shsだとWindowsの挙動がおかしいので、.bhsにしました。「select-Bootable Haribote.Sys」もしくは「Brother of Haribote.Sys」の略。 *** とにかく作ってみるよ -うまくいくかどうかを心配していても前進しないので、気の向くままに作ってみました。API番号はとりあえず30番です。 ~ ~ -console.c int *hrb_api(int edi, int esi, int ebp, int esp, int ebx, int edx, int ecx, int eax) { (中略) } else if (edx == 30) { /* EAXに.bhsへのハンドル */ fh = (struct FILEHANDLE *) reg[7]; hrb_api_osselect(fh->buf, (int *) memman_alloc_4k(memman, 512 * 1024)); } (中略) } void hrb_api_osselect(char *bhs, int *tmp) /* 主な作業内容: bootpackのコード部分をtmpのメモリにコピーする 割り込み禁止にする 0xfff8のセレクタを設定する bhsの内容を0x280000にメモしておく far-jmp 0xfff8:hrb_api_osselect_second */ { struct SEGMENT_DESCRIPTOR *gdt = (struct SEGMENT_DESCRIPTOR *) ADR_GDT; int i, *bootpack = (int *) ADR_BOTPAK; for (i = 0; i < (LIMIT_BOTPAK + 1) / 4; i++) { tmp[i] = bootpack[i]; } /* PICはまた初期化されるのでそのための準備 */ io_out8(PIC0_IMR, 0xff); /* すべて禁止 */ io_out8(PIC1_IMR, 0xff); /* すべて禁止 */ io_cli(); set_segmdesc(gdt + 8191, LIMIT_BOTPAK, (int) tmp, AR_CODE32_ER); *((int *) ADR_BOTPAK) = (int) bhs; farjmp((int) hrb_api_osselect_second, 8191 * 8); } void hrb_api_osselect_second(void) /* 主な作業内容: bhsのコードを0x280000に転送 bhsのデータもヘッダを解析して転送 asm_osselect_third(esp); → ESP=esp; farjmp(0x1b, 2 * 8); */ { char *bhs = (char *) *((int *) ADR_BOTPAK); int i, *bootpack = (int *) ADR_BOTPAK, *bhs_i = (int *) bhs; int *p, *q, datsiz; for (i = 0; i < (LIMIT_BOTPAK + 1) / 4; i++) { bootpack[i] = bhs_i[i]; } datsiz = (bhs_i[16 / 4] + 3) / 4; p = (int *) (bhs_i[20 / 4] + bhs); q = (int *) bhs_i[12 / 4]; for (i = 0; i < datsiz; i++) { q[i] = p[i]; } asm_osselect_third(bhs_i[12 / 4]); } ---- -naskfunc.nas (中略) GLOBAL _asm_osselect_third (中略) _asm_osselect_third: ; void asm_osselect_third(int esp); MOV AX,SS ; SSには8が入っているのでそれを使う MOV FS,AX MOV GS,AX MOV ESP,[ESP+4] JMP 2*8:0x0000001b ---- -bootpack.h : 以下の3行を適当な場所に書き足し void asm_osselect_third(int esp); void hrb_api_osselect(char *bhs, int *tmp); void hrb_api_osselect_second(void); *** 動作チェック用アプリ -osselect.c #include "apilib.h" void api_osselect(int i); /* これはapilib.hに書いておくべきだな */ void HariMain(void) { char s[32], *p; int i; /* コマンドライン解析 */ api_cmdline(s, 30); for (p = s; *p > ' '; p++) { } /* スペースが来るまで読み飛ばす */ for (; *p == ' '; p++) { } /* スペースを読み飛ばす */ i = api_fopen(p); if (i == 0) { api_putstr0("file open error!\n"); api_end(); } api_osselect(i); } -とりあえず >osselect hiyos.bhs のように使う。 -このサンプルをそのまま使う場合は、 STACK = 1k MALLOC = 0k で十分。 ---- -api030.nas [FORMAT "WCOFF"] [INSTRSET "i486p"] [BITS 32] [FILE "api030.nas"] GLOBAL _api_osselect [SECTION .text] _api_osselect: ; void api_osselect(int i); MOV EDX,30 MOV EAX,[ESP+4] ; i INT 0x40 RET *** 作ったときの感想など(というか苦労話?)ついでに動作原理など -方針1. (本当はすごく使いたいけど)アセンブラは極力使わずにがんばる。アセンブラを使うとすぐに意味わからんと投げ出す人が増えそうなので。 -方針2. できるだけ短く。長いと読むほうが疲れちゃう。 ~ ~ -APIではファイル名指定ではなく、ファイルハンドル指定にした。こうすれば指定されたファイルが存在するかどうかをチェックする必要はなくなるし、とりあえずメモリに読み込まれた状態になっているから。 -APIではファイルが.hrb形式になっているかという最低限のチェックすらしてない。そういう改造はきっと読者がやってくれるだろうと信じているのである(笑)。このページでは基本原理さえ示せばいいだろう。 -関数hrb_apiでは、適当にメモリ512KBを確保してhrb_api_osselectを呼び出しておしまい。簡単ですね。 ~ ~ -hrb_api_osselectは3段ロケット方式になっている。CSを変更しなくてもできることをだいたいやってしまうhrb_api_osselect(以後first)、CSを変更後にCで記述できる範囲の仕事を全部やるhrb_api_osselect_second(以後second)、どうやってもアセンブラでしか記述できない処理をやるhrb_api_osselect_third(以後third)である。 -まずなぜCSを変更しなければいけないかだが、ちょっと考えてみてほしい。bootpackの内容を入れ替えるためには、入れ替え処理プログラムが必要である。しかしその入れ替えプログラムをメモリのどこに置くのか。CS=2*8のところに旧bootpackをおいたまま入れ替えプログラムを実行してしまうと、自分自身を上書きしてしまう事故がおきて、暴走してしまうだろう。 -それでとりあえず現在動作中のbootpack(というかharibote.sys全体)をメモリのあいたところに適当に転送し(これがtmp番地)、そこを指し示すコードセグメントを設定した後に、そこへfar-jmpする。これでCSは書き換わり、tmp上でOSは実行されるようになるのである。 ~ ~ -secondへ移行してしまえば、あとは.bhsファイルの内容をしかるべき番地へ転送する。つまりsecondがやっていることは本文p.170〜171のアセンブラがやっていたことをC言語でやっているだけである。高速化しようと思って32bitのコピーにするために式がややこしくなっているが、8bitのコピーでよければ、もう少しすっきりする。以下の書き方でも処理速度が落ちる以上の問題はないので、理解できなければ以下を使うのもいいかもしれない。 void hrb_api_osselect_second(void) { char *bhs = (char *) *((int *) ADR_BOTPAK); int i, datsiz; char *p, *q, *bootpack = (char *) ADR_BOTPAK; for (i = 0; i < LIMIT_BOTPAK + 1; i++) { bootpack[i] = bhs[i]; } datsiz = *((int *) (bhs + 16)); /* MOV datsiz, DWORD [bhs+16] */ p = bhs + *((int *) (bhs + 20)); /* 以下類推してね */ q = (char *) *((int *) (bhs + 12)); for (i = 0; i < datsiz; i++) { q[i] = p[i]; } asm_osselect_third(*((int *) (bhs + 12))); } -thirdは何をしているのかというと、C言語だけでESPに代入する方法がどうしても思いつかなかったので、アセンブラでやっているというだけのことである。ついでにFSとGSに8を入れていなかったのでそれもやっている。そしてESPに代入した後はfar-jmpしか処理が残っていなかったので、それもアセンブラでやってしまっている(というか、そもそもESPを変更した後はCのプログラムに帰るのがややこしいので、呼び出しもとへ帰らずにfar-jmpするほうが処理が簡単で好ましい)。 ---- -作り始めてしばらくして思ったのだが、普通のブートセレクタよりもこの方式のブートセレクタのほうが2点ほど利点がある。それは何かというと、ブートセレクタ自身がOS上で動くアプリなので、GUIでかっこいいブートセレクタが作りやすい。ブートセレクタに不要なAPIは削ってしまえばいいだろう。もちろん最初に起動するOSをブートセレクタ以外にも使うつもりなら、APIはすべて残しておいて普通に使えるようにしておいてもいいだろう。 -もう一点は、.bhsファイルは圧縮していてもかまわないということである。これでOSをコンパクトにまとめておけるので、よりたくさんのOSをディスクに入れておけるだろう。 * こめんと欄 -おぉおぉ〜感動です!!はりぼてファミリーをCD-Rに焼いて起動時に選択できるとすごぉ〜く嬉しいです。もうバリバリ焼いちゃいますよ♪ -- ''ひよひよ'' SIZE(10){2006-09-24 (日) 13:32:34} -とりあえずページ完成。試してみてくださいね。 -- [[K]] SIZE(10){2006-09-24 (日) 18:21:44} -原理は全然理解していないのですが・・・VirtualPC上で動作しました。QEMUではエラーになっちゃいましたけど。OSCでは、起動OSを選択できるCD-Rを配布したいところです。豪華なランチャーを作成する必要がありますなぁ〜。 -- ''ひよひよ'' SIZE(10){2006-09-24 (日) 22:01:02} -あれえ、うちのQEMUではうまくいったんだけどなあ。まあそういうものなのかなあ。IPLのCYLSが足りないということはありませんでしたか?まあとにかく楽しんで活用してください。 -- [[K]] SIZE(10){2006-09-24 (日) 22:36:36} -で、実機で試してみたのですが、切り替えた瞬間にリセット。切り替え先は、ノーマルharib27fとバージョン6適用harib27fとHiyOS 0.0.7.20060914 です。どこでリセットがかかるのかを追っていませんが、初期化周りかなぁ。 -- ''ひよひよ'' SIZE(10){2006-09-24 (日) 22:48:43} -ノーマルharib27fはバージョン6が適用されていないから、落ちるのは無理ないかなあと思います。でも他の切り替え先でも落ちるのは、なんかちょっとおかしいですね。そのうち当方でも試してみます。 -- [[K]] SIZE(10){2006-09-24 (日) 22:55:48} -はりぼてOSを参考にして大幅に書き換えられたBayOSは、QEMUでもVirtualPCでも切り替え直後にスタック例外が発生しました。 -- ''ひよひよ'' SIZE(10){2006-09-24 (日) 22:56:25} -技術的に可能であることを提示していただけたので、私なりに「はりぼて友の会ランチャー」について検討してみます。 -- ''ひよひよ'' SIZE(10){2006-09-24 (日) 22:58:40} -BayOSの中身はよく知らないのですが、asmhead.nasを大幅に書き換えているのではないでしょうか?「はりぼてOS」のように、アプリと同じフォーマットのbootpack.hrbをくっつけているタイプじゃないと、今回の方法では切り替えられません。・・・参考になったようなので、その点では幸いです。とりあえずうまくいかない例があったのは僕個人としてくやしいので、時間を見つけてがんばります。 -- [[K]] SIZE(10){2006-09-24 (日) 23:18:37} -こちらで hiyos.bhs に切り替える実験をしたところ(QEMU上)、HiyOSに切り替わった後でキー入力したらおかしくなりました(つまり何もしなければ全く正常)。ちょっと思い当たるところがあるので、しばらく研究しますね。 -- ''K'' SIZE(10){2006-09-24 (日) 23:57:12} -BayOSもasmhead.nasは変えていません。また、はりぼてOSと同じようにアプリと同じフォーマットのbootpack.hrbをくっつけています。その後は全然違いますが、そこまでは一緒です。 -- ''bayside'' SIZE(10){2006-09-25 (月) 11:25:14} -baysideさんコメントありがとうございます。それなら当方のバグさえ直せば、BayOSも対応できそうです。今のところ、harib12aまではどのOSでも無事に切り替えられて、harib12bにしても最初の10秒は順調に動きそうなことが確認できました(QEMU上でのテスト)。 -- [[K]] SIZE(10){2006-09-25 (月) 22:03:23} -大変お騒がせしましたが、バグは取れました。thirdに3行ほど書き足して、FSとGSに8が確実に入るようにしました。asmheadではこれをやっているのに、osselectでやり忘れたのがバグの原因だったようです。うちではHiyOSへの切り替えも問題なくできています(QEMU上でしかテストしていませんが・・・手抜きですみません)。 -- ''K'' SIZE(10){2006-09-26 (火) 00:48:27} -バグが取れて落ち着いてみると、COLOR(#7f0000){「OSやアプリは友の会の自作なのにOSセレクタは自作じゃないのかよー」}ってつっこまれたら(僕としては)悲しいので、「これでもう僕のせいじゃないぞ」と自分を納得させるためのコーナーだったかもしれません(苦笑)。 -- ''K'' SIZE(10){2006-09-26 (火) 00:55:24} -実機でもバッチリ動くようになりましたぁ〜。倍率変更もバッチリです!!でも、アプリは各OSで共通になるんですよね・・・。改変した場合オリジナルとファイル名を変えないと整合が取れなくなっちゃいますね・・・。 -- ひよひよ SIZE(10){2006-09-27 (水) 00:40:42} -これからはみんな自作OSを.bhsファイルでも公開だ!・・・そしたら簡単に試せていいよー、と思った。そのためにはまずは僕がこのosselect入りのharibote.sysを入手しやすくしないとダメだな。 -- [[K]] SIZE(10){2006-09-30 (土) 13:46:07} -とりあえず GUI 版を作ってみました→ http://hiyos.info/HariboteOS/20061007.htm GUI なのにマウスで選択できないのがミソ。 -- ''ひよひよ'' SIZE(10){2006-10-07 (土) 11:23:35} -C言語だけでESPに代入する方法も、無くは無いです。でもCコンパイラが適当に最適化してくれちゃうと上手く動かない。理論としては、代入する値をxとして、関数A(int x)を呼び出す。関数Aでは関数B(int x)を呼び出し、関数Bはまず内部でPUSH EBP,MOV EBP,ESPが実行される。*((int*)&x-2)=x+4;としてreturn;し、内部でPOP EBPでEBPがx+4書き換わった所でRET。関数Aに戻ってreturn;するときにもし内部でLEAVEしてからRETするなら、LEAVEでESPにEBPがコピーされてPOP EBPが実行され、結果としてESPにxが入る。(この説明じゃ多分よく分からないと思う・・・。) -- [[Source]] SIZE(10){2008-08-25 (月) 13:25:31} -よくこんなロジック思いつきますね…せっかくなので検証してみました。下のソースをGO/gcc->gas2nask(tolset_h/z_new_wを使用)でnasにして紙の上でトレースしてみました。 void A(int x) { (&x)[-2] = x + 4; } void tester(void) { A(0x040000); } ちなみにnasはこんな感じ(抜粋)になりました。 GLOBAL _A _A: PUSH EBP MOV EBP,ESP MOV EAX,DWORD [8+EBP] ADD EAX,4 MOV DWORD [0+EBP],EAX POP EBP RET GLOBAL _tester _tester: PUSH EBP MOV EBP,ESP PUSH 262144 CALL _A LEAVE RET その結果、espに入る値はどうやら0x040008になりそうです。おそらく*((int*)&x-2)=x+4;は*((int*)&x-2)=x-4;の書き間違いではないかと思います。そこのところどうでしょうか?>>Sourceさん いきなりの長文失礼しました。 -- [[Sero]] SIZE(10){2008-08-27 (水) 16:59頃 手書きで挿入} -私も頭の中で割と適当に考えただけのものなので、「PUSHとPOPでスタックがどっちの方向に進むか」という基本的なところでミスしていたようです。指摘してくれて、ありがとう。 -- [[Source]] SIZE(10){2008-08-27 (水) 21:27:13} #comment
タイムスタンプを変更しない
* OSセレクタ?を作ろう! -(by [[K]], 2006.09.24) -発展課題のページ(全部読む前にここを読むのは混乱するのでおすすめじゃないです) ---- -[[「はりぼて友の会」:http://haribote.org/]]とかを覗いていると、「はりぼてOS」の兄弟OS(姉妹OS?)といえそうなものがたくさん生まれています。これらを別々のディスクにインストールして、好きなときに好きなOSを起動して遊ぶのは楽しいですが、これらのOSはみんなすごく小さいことですし、1枚のディスクにまとめられたら便利かなと思いました。 -そんなわけで、てきとーにOSセレクタ(の元?)を作ってみることにしました。 -というか、実は「はりぼてOS友の会」が[[10月のオープンソースカンファレンス:http://haribote.org/?OSC2006TokyoFall]]に出るので(おめでとう!)、その記念作品だったりします。・・・ということで、このプログラムは「はりぼて友の会」に奉げます(ライセンスは毎度のKL-01なので誰でも使えます)。 *** さてどうやって作ろうか? -景気よく「作るぞー」と意気込んではみたものの、さてどうしましょうか。OSセレクタというとまずはIPLやasmheadの部分を書き換える方法が考えられますが、これはどうやら[[Akkie]]さんがチャレンジする予定らしいので、[[K]]はやらないことにしました。 -そうなるとbootpack.hrb部分をいじるしかないわけで、コンソールにOS切り替えコマンドでもつけようかなと考えました。つまり一度は普通に「はりぼてOS」(かもしくはその兄弟OS)が起動して、そこからコマンドで他のOSに移るわけです。OS切り替えプログラムが超巨大化して、それ自身がOSになってしまった、と考えてもいいでしょう。 --「はりぼてOS」は小さいので、これでも下手なブートセレクタよりも小さかったりするのですが。 -でもこれだと切り替えコマンドがかっこ悪いとか言われそうです。それもくやしいので、切り替えAPIをつけることにしました。APIならOS切り替えアプリをかっこよくすればいいですし、それなら[[K]]がバカにされる心配もありません(笑)。 ~ ~ -仕組みはこうしました。まず、新たに.shsというファイル形式を考えます。これは「Select-bootable Haribote.Sys」の略で、「選択起動可能なharibote.sys」のつもりです。「Sister of Haribote.Sys」の略でもいいんですが(笑)。たいそうな略語ですが中身は簡単で、これはharibote.sysの中のCOLOR(#0000ff){bootpack.hrbの部分だけを取り出して}ファイル名と拡張子を変えただけです。・・・これをディスクから読み込んで、メモリ上にそれっぽく配置してJMPしてやればうまくいきそうだと考えたわけです。・・・こんなてきとーな方法でほんとにうまくいくのかな。 -なんか.shsだとWindowsの挙動がおかしいので、.bhsにしました。「select-Bootable Haribote.Sys」もしくは「Brother of Haribote.Sys」の略。 *** とにかく作ってみるよ -うまくいくかどうかを心配していても前進しないので、気の向くままに作ってみました。API番号はとりあえず30番です。 ~ ~ -console.c int *hrb_api(int edi, int esi, int ebp, int esp, int ebx, int edx, int ecx, int eax) { (中略) } else if (edx == 30) { /* EAXに.bhsへのハンドル */ fh = (struct FILEHANDLE *) reg[7]; hrb_api_osselect(fh->buf, (int *) memman_alloc_4k(memman, 512 * 1024)); } (中略) } void hrb_api_osselect(char *bhs, int *tmp) /* 主な作業内容: bootpackのコード部分をtmpのメモリにコピーする 割り込み禁止にする 0xfff8のセレクタを設定する bhsの内容を0x280000にメモしておく far-jmp 0xfff8:hrb_api_osselect_second */ { struct SEGMENT_DESCRIPTOR *gdt = (struct SEGMENT_DESCRIPTOR *) ADR_GDT; int i, *bootpack = (int *) ADR_BOTPAK; for (i = 0; i < (LIMIT_BOTPAK + 1) / 4; i++) { tmp[i] = bootpack[i]; } /* PICはまた初期化されるのでそのための準備 */ io_out8(PIC0_IMR, 0xff); /* すべて禁止 */ io_out8(PIC1_IMR, 0xff); /* すべて禁止 */ io_cli(); set_segmdesc(gdt + 8191, LIMIT_BOTPAK, (int) tmp, AR_CODE32_ER); *((int *) ADR_BOTPAK) = (int) bhs; farjmp((int) hrb_api_osselect_second, 8191 * 8); } void hrb_api_osselect_second(void) /* 主な作業内容: bhsのコードを0x280000に転送 bhsのデータもヘッダを解析して転送 asm_osselect_third(esp); → ESP=esp; farjmp(0x1b, 2 * 8); */ { char *bhs = (char *) *((int *) ADR_BOTPAK); int i, *bootpack = (int *) ADR_BOTPAK, *bhs_i = (int *) bhs; int *p, *q, datsiz; for (i = 0; i < (LIMIT_BOTPAK + 1) / 4; i++) { bootpack[i] = bhs_i[i]; } datsiz = (bhs_i[16 / 4] + 3) / 4; p = (int *) (bhs_i[20 / 4] + bhs); q = (int *) bhs_i[12 / 4]; for (i = 0; i < datsiz; i++) { q[i] = p[i]; } asm_osselect_third(bhs_i[12 / 4]); } ---- -naskfunc.nas (中略) GLOBAL _asm_osselect_third (中略) _asm_osselect_third: ; void asm_osselect_third(int esp); MOV AX,SS ; SSには8が入っているのでそれを使う MOV FS,AX MOV GS,AX MOV ESP,[ESP+4] JMP 2*8:0x0000001b ---- -bootpack.h : 以下の3行を適当な場所に書き足し void asm_osselect_third(int esp); void hrb_api_osselect(char *bhs, int *tmp); void hrb_api_osselect_second(void); *** 動作チェック用アプリ -osselect.c #include "apilib.h" void api_osselect(int i); /* これはapilib.hに書いておくべきだな */ void HariMain(void) { char s[32], *p; int i; /* コマンドライン解析 */ api_cmdline(s, 30); for (p = s; *p > ' '; p++) { } /* スペースが来るまで読み飛ばす */ for (; *p == ' '; p++) { } /* スペースを読み飛ばす */ i = api_fopen(p); if (i == 0) { api_putstr0("file open error!\n"); api_end(); } api_osselect(i); } -とりあえず >osselect hiyos.bhs のように使う。 -このサンプルをそのまま使う場合は、 STACK = 1k MALLOC = 0k で十分。 ---- -api030.nas [FORMAT "WCOFF"] [INSTRSET "i486p"] [BITS 32] [FILE "api030.nas"] GLOBAL _api_osselect [SECTION .text] _api_osselect: ; void api_osselect(int i); MOV EDX,30 MOV EAX,[ESP+4] ; i INT 0x40 RET *** 作ったときの感想など(というか苦労話?)ついでに動作原理など -方針1. (本当はすごく使いたいけど)アセンブラは極力使わずにがんばる。アセンブラを使うとすぐに意味わからんと投げ出す人が増えそうなので。 -方針2. できるだけ短く。長いと読むほうが疲れちゃう。 ~ ~ -APIではファイル名指定ではなく、ファイルハンドル指定にした。こうすれば指定されたファイルが存在するかどうかをチェックする必要はなくなるし、とりあえずメモリに読み込まれた状態になっているから。 -APIではファイルが.hrb形式になっているかという最低限のチェックすらしてない。そういう改造はきっと読者がやってくれるだろうと信じているのである(笑)。このページでは基本原理さえ示せばいいだろう。 -関数hrb_apiでは、適当にメモリ512KBを確保してhrb_api_osselectを呼び出しておしまい。簡単ですね。 ~ ~ -hrb_api_osselectは3段ロケット方式になっている。CSを変更しなくてもできることをだいたいやってしまうhrb_api_osselect(以後first)、CSを変更後にCで記述できる範囲の仕事を全部やるhrb_api_osselect_second(以後second)、どうやってもアセンブラでしか記述できない処理をやるhrb_api_osselect_third(以後third)である。 -まずなぜCSを変更しなければいけないかだが、ちょっと考えてみてほしい。bootpackの内容を入れ替えるためには、入れ替え処理プログラムが必要である。しかしその入れ替えプログラムをメモリのどこに置くのか。CS=2*8のところに旧bootpackをおいたまま入れ替えプログラムを実行してしまうと、自分自身を上書きしてしまう事故がおきて、暴走してしまうだろう。 -それでとりあえず現在動作中のbootpack(というかharibote.sys全体)をメモリのあいたところに適当に転送し(これがtmp番地)、そこを指し示すコードセグメントを設定した後に、そこへfar-jmpする。これでCSは書き換わり、tmp上でOSは実行されるようになるのである。 ~ ~ -secondへ移行してしまえば、あとは.bhsファイルの内容をしかるべき番地へ転送する。つまりsecondがやっていることは本文p.170〜171のアセンブラがやっていたことをC言語でやっているだけである。高速化しようと思って32bitのコピーにするために式がややこしくなっているが、8bitのコピーでよければ、もう少しすっきりする。以下の書き方でも処理速度が落ちる以上の問題はないので、理解できなければ以下を使うのもいいかもしれない。 void hrb_api_osselect_second(void) { char *bhs = (char *) *((int *) ADR_BOTPAK); int i, datsiz; char *p, *q, *bootpack = (char *) ADR_BOTPAK; for (i = 0; i < LIMIT_BOTPAK + 1; i++) { bootpack[i] = bhs[i]; } datsiz = *((int *) (bhs + 16)); /* MOV datsiz, DWORD [bhs+16] */ p = bhs + *((int *) (bhs + 20)); /* 以下類推してね */ q = (char *) *((int *) (bhs + 12)); for (i = 0; i < datsiz; i++) { q[i] = p[i]; } asm_osselect_third(*((int *) (bhs + 12))); } -thirdは何をしているのかというと、C言語だけでESPに代入する方法がどうしても思いつかなかったので、アセンブラでやっているというだけのことである。ついでにFSとGSに8を入れていなかったのでそれもやっている。そしてESPに代入した後はfar-jmpしか処理が残っていなかったので、それもアセンブラでやってしまっている(というか、そもそもESPを変更した後はCのプログラムに帰るのがややこしいので、呼び出しもとへ帰らずにfar-jmpするほうが処理が簡単で好ましい)。 ---- -作り始めてしばらくして思ったのだが、普通のブートセレクタよりもこの方式のブートセレクタのほうが2点ほど利点がある。それは何かというと、ブートセレクタ自身がOS上で動くアプリなので、GUIでかっこいいブートセレクタが作りやすい。ブートセレクタに不要なAPIは削ってしまえばいいだろう。もちろん最初に起動するOSをブートセレクタ以外にも使うつもりなら、APIはすべて残しておいて普通に使えるようにしておいてもいいだろう。 -もう一点は、.bhsファイルは圧縮していてもかまわないということである。これでOSをコンパクトにまとめておけるので、よりたくさんのOSをディスクに入れておけるだろう。 * こめんと欄 -おぉおぉ〜感動です!!はりぼてファミリーをCD-Rに焼いて起動時に選択できるとすごぉ〜く嬉しいです。もうバリバリ焼いちゃいますよ♪ -- ''ひよひよ'' SIZE(10){2006-09-24 (日) 13:32:34} -とりあえずページ完成。試してみてくださいね。 -- [[K]] SIZE(10){2006-09-24 (日) 18:21:44} -原理は全然理解していないのですが・・・VirtualPC上で動作しました。QEMUではエラーになっちゃいましたけど。OSCでは、起動OSを選択できるCD-Rを配布したいところです。豪華なランチャーを作成する必要がありますなぁ〜。 -- ''ひよひよ'' SIZE(10){2006-09-24 (日) 22:01:02} -あれえ、うちのQEMUではうまくいったんだけどなあ。まあそういうものなのかなあ。IPLのCYLSが足りないということはありませんでしたか?まあとにかく楽しんで活用してください。 -- [[K]] SIZE(10){2006-09-24 (日) 22:36:36} -で、実機で試してみたのですが、切り替えた瞬間にリセット。切り替え先は、ノーマルharib27fとバージョン6適用harib27fとHiyOS 0.0.7.20060914 です。どこでリセットがかかるのかを追っていませんが、初期化周りかなぁ。 -- ''ひよひよ'' SIZE(10){2006-09-24 (日) 22:48:43} -ノーマルharib27fはバージョン6が適用されていないから、落ちるのは無理ないかなあと思います。でも他の切り替え先でも落ちるのは、なんかちょっとおかしいですね。そのうち当方でも試してみます。 -- [[K]] SIZE(10){2006-09-24 (日) 22:55:48} -はりぼてOSを参考にして大幅に書き換えられたBayOSは、QEMUでもVirtualPCでも切り替え直後にスタック例外が発生しました。 -- ''ひよひよ'' SIZE(10){2006-09-24 (日) 22:56:25} -技術的に可能であることを提示していただけたので、私なりに「はりぼて友の会ランチャー」について検討してみます。 -- ''ひよひよ'' SIZE(10){2006-09-24 (日) 22:58:40} -BayOSの中身はよく知らないのですが、asmhead.nasを大幅に書き換えているのではないでしょうか?「はりぼてOS」のように、アプリと同じフォーマットのbootpack.hrbをくっつけているタイプじゃないと、今回の方法では切り替えられません。・・・参考になったようなので、その点では幸いです。とりあえずうまくいかない例があったのは僕個人としてくやしいので、時間を見つけてがんばります。 -- [[K]] SIZE(10){2006-09-24 (日) 23:18:37} -こちらで hiyos.bhs に切り替える実験をしたところ(QEMU上)、HiyOSに切り替わった後でキー入力したらおかしくなりました(つまり何もしなければ全く正常)。ちょっと思い当たるところがあるので、しばらく研究しますね。 -- ''K'' SIZE(10){2006-09-24 (日) 23:57:12} -BayOSもasmhead.nasは変えていません。また、はりぼてOSと同じようにアプリと同じフォーマットのbootpack.hrbをくっつけています。その後は全然違いますが、そこまでは一緒です。 -- ''bayside'' SIZE(10){2006-09-25 (月) 11:25:14} -baysideさんコメントありがとうございます。それなら当方のバグさえ直せば、BayOSも対応できそうです。今のところ、harib12aまではどのOSでも無事に切り替えられて、harib12bにしても最初の10秒は順調に動きそうなことが確認できました(QEMU上でのテスト)。 -- [[K]] SIZE(10){2006-09-25 (月) 22:03:23} -大変お騒がせしましたが、バグは取れました。thirdに3行ほど書き足して、FSとGSに8が確実に入るようにしました。asmheadではこれをやっているのに、osselectでやり忘れたのがバグの原因だったようです。うちではHiyOSへの切り替えも問題なくできています(QEMU上でしかテストしていませんが・・・手抜きですみません)。 -- ''K'' SIZE(10){2006-09-26 (火) 00:48:27} -バグが取れて落ち着いてみると、COLOR(#7f0000){「OSやアプリは友の会の自作なのにOSセレクタは自作じゃないのかよー」}ってつっこまれたら(僕としては)悲しいので、「これでもう僕のせいじゃないぞ」と自分を納得させるためのコーナーだったかもしれません(苦笑)。 -- ''K'' SIZE(10){2006-09-26 (火) 00:55:24} -実機でもバッチリ動くようになりましたぁ〜。倍率変更もバッチリです!!でも、アプリは各OSで共通になるんですよね・・・。改変した場合オリジナルとファイル名を変えないと整合が取れなくなっちゃいますね・・・。 -- ひよひよ SIZE(10){2006-09-27 (水) 00:40:42} -これからはみんな自作OSを.bhsファイルでも公開だ!・・・そしたら簡単に試せていいよー、と思った。そのためにはまずは僕がこのosselect入りのharibote.sysを入手しやすくしないとダメだな。 -- [[K]] SIZE(10){2006-09-30 (土) 13:46:07} -とりあえず GUI 版を作ってみました→ http://hiyos.info/HariboteOS/20061007.htm GUI なのにマウスで選択できないのがミソ。 -- ''ひよひよ'' SIZE(10){2006-10-07 (土) 11:23:35} -C言語だけでESPに代入する方法も、無くは無いです。でもCコンパイラが適当に最適化してくれちゃうと上手く動かない。理論としては、代入する値をxとして、関数A(int x)を呼び出す。関数Aでは関数B(int x)を呼び出し、関数Bはまず内部でPUSH EBP,MOV EBP,ESPが実行される。*((int*)&x-2)=x+4;としてreturn;し、内部でPOP EBPでEBPがx+4書き換わった所でRET。関数Aに戻ってreturn;するときにもし内部でLEAVEしてからRETするなら、LEAVEでESPにEBPがコピーされてPOP EBPが実行され、結果としてESPにxが入る。(この説明じゃ多分よく分からないと思う・・・。) -- [[Source]] SIZE(10){2008-08-25 (月) 13:25:31} -よくこんなロジック思いつきますね…せっかくなので検証してみました。下のソースをGO/gcc->gas2nask(tolset_h/z_new_wを使用)でnasにして紙の上でトレースしてみました。 void A(int x) { (&x)[-2] = x + 4; } void tester(void) { A(0x040000); } ちなみにnasはこんな感じ(抜粋)になりました。 GLOBAL _A _A: PUSH EBP MOV EBP,ESP MOV EAX,DWORD [8+EBP] ADD EAX,4 MOV DWORD [0+EBP],EAX POP EBP RET GLOBAL _tester _tester: PUSH EBP MOV EBP,ESP PUSH 262144 CALL _A LEAVE RET その結果、espに入る値はどうやら0x040008になりそうです。おそらく*((int*)&x-2)=x+4;は*((int*)&x-2)=x-4;の書き間違いではないかと思います。そこのところどうでしょうか?>>Sourceさん いきなりの長文失礼しました。 -- [[Sero]] SIZE(10){2008-08-27 (水) 16:59頃 手書きで挿入} -私も頭の中で割と適当に考えただけのものなので、「PUSHとPOPでスタックがどっちの方向に進むか」という基本的なところでミスしていたようです。指摘してくれて、ありがとう。 -- [[Source]] SIZE(10){2008-08-27 (水) 21:27:13} #comment
テキスト整形のルールを表示する