NetBSD の src/sys/arch/x68k/stand/boot_ustar/boot_ustar.S のメモ。
| $Id: boot_ustar.S,v 1.2 2009/11/20 06:37:45 isaki Exp $
| NetBSD/x68k のプライマリブートローダ boot_ustar の解説です。
| boot_ustar はディスクの先頭から 8KB 目以降にある ustarfs という
| ファイルシステム(?)上からセカンダリブートローダ (/boot) を
| 読み込んでそこに実行を移します。
| ustarfs というファイルシステムの構成はというと実は tar フォーマット
| そのものです。つまりこんな感じ?。わけわからんけど。
|
| ディスクの先頭 ディスクの終り
| +------------------------------------+
| |ブートストラップ | 必要なファイルを |
| |用領域(8KB) | tar したもの |
| +------------------------------------+
|
| このディスクに置かれている tar ファイルには次のものが
| (この順で) 含まれています。
|
| 1. USTAR.volsize.4540
| セカンダリブートローダ /usr/mdec/boot をリネームしたもの
|
| 2. netbsd
| カーネル
|
| tar フォーマットは 512 バイトブロックを基本としているらしく、
| ファイルはすべて 512 バイトごとに区切られるようです。
| もちろん端数は切り上げて 0 でパディングされる、んだと思います。
| そして各ファイルの前には1ブロック (つまり 512 バイト) のヘッダがつきます。
| tar アーカイブ自体のヘッダはありません。
| つまりファイルの先頭はいきなり1番目のファイルのヘッダです。
| file: boot_ustar.S
| author: chapuni(webmaster@chapuni.com)
| Yasha(itohy@netbsd.org)
| minoura@netbsd.org
|
| $NetBSD: boot_ustar.S,v 1.4 2002/05/19 08:14:13 isaki Exp $
| supports floppy only
#include <sys/reboot.h>
#include <machine/asm.h>
#include <machine/bootinfo.h>
#include "iocscall.h"
| エラーメッセージを SP に積ませる技。
#define BOOT_ERROR(s) jbsr boot_error; .asciz s; .even
#define SRAM_MEMSIZE (0x00ed0008)
.text
| ここがディスクの先頭。0x2000 になる部分。
ASENTRY_NOPROFILE(start)
ASENTRY_NOPROFILE(top)
| いきなり entry0 へ相対ジャンプする。
| IPL-ROM とのお約束により先頭は bra 命令でなければ
| ならない。"SHARP/X680x0" はマーカなのかしら?
| その後ろの文字列は謎(笑)。
bras _ASM_LABEL(entry0)
.ascii "SHARP/"
.ascii "X680x0"
.word 0x8199,0x94e6,0x82ea,0x82bd
.word 0x8e9e,0x82c9,0x82cd,0x8cbb
.word 0x8ec0,0x93a6,0x94f0,0x8149
.word 0
ASENTRY_NOPROFILE(entry0)
| 起動情報を得る。上位8ビットは不要なので落しておく。
IOCS(__BOOTINF)
lsll #8,%d0 | clear MSByte
lsrl #8,%d0 |
| これが戻り値
|
| 0x80...0x8F SASI
| 0x90...0x93 Floppy
| 0xED0000...0xED3FFE SRAM
| others ROM (SCSI?)
|
| d0 は保存しておいて、d1 でテストする。
| d1 の下位8ビットをクリアした結果が 0.l でなければ
| SRAM か ROM 起動なのでエラー
movel %d0,%d1
clrb %d1
tstl %d1
jne boot_dev_unsupported
| 続きは disklabel の後で。
bra _ASM_LABEL(entry)
| Disklabel= 404bytes
| Since LABELLOFFSET in <machine/disklabel.h> is 0x40,
| entry must be after 0x000001d4 (0x000021d4)
nop
GLOBAL(disklabel)
.space 404
|
| ここまでをダンプすると以下のようになる。
|
| +0000 6026 bra entry0
| +0002 5348 4152 502f .ascii "SHARP/"
| +0008 5836 3830 7830 .ascii "X680x0"
| +000e 8199 94e6 82ea 82bd .word ...
| +0016 8e9e 82c9 82cd 8cbb .word ...
| +001e 8ec0 93a6 94f0 8149 .word ...
| +0026 0000 .word 0
| entry0:
| +0028 708e 4e4f IOCS(__BOOTINF)
| +002c e188 lsll #8,%d0
| +002e e088 lsrl #8,%d0
| +0030 2200 movel %d0,%d1
| +0032 4201 clrb %d1
| +0034 4a81 tstl %d1
| +0036 6600 0270 jne boot_dev_unsupported
| +003a 6000 0198 bra entry
| +003e 4e71 nop
| disklabel:
| +0040 .space 404
| entry:
| +0444
|
ASENTRY_NOPROFILE(entry)
|
| SASI or Floppy
| d0 を d6 にも保存しておく。下位8ビットが 9x なら
| FD ブート。そうでなければ SASI ? なのでエラー。
|
movel %d0,%d6
andib #0xFC,%d0
cmpib #0x90,%d0
jne boot_dev_unsupported | boot from SASI?
|
| Floppy
| read first 64KB (XXX: CONSTANT!!)
| フロッピーの最初の64KBを読み込む。
| XXX 定数埋め込みなのでセカンダリブートローダがもっと大きく
| なったらここも変更しないといけない。
|
| %d0 にドライブ番号を入れて FD フォーマットをチェックする。
| check_fd_format は chkfmt.s の中。
| %d1.w の上位バイトはメディア。__BOOTINF のをそのまま使う。
| %d1.w の下位バイトはモード。0x70 は リトライあり/シークなしらしい。
| %d2.l は目的読み込み位置。??
| %d3.l が読み込むバイト数。ここでは 64KB 読み込む。
| 実際のセカンダリブートローダは 40KB ほどなので
| ブートストラップ用領域 8KB と合わせて 48KB ほど読み込めば
| よいことになる。逆にいうとこのままのブートローダでは
| セカンダリブートローダがあと 16KB 大きくなると読み込みきれない。
|
| %a1 は読み込みバッファのアドレス。セカンダリブートローダに
| 実行を移すためのジャンプ先が BOOT_TEXTADDR (Makefile に書いてある)
| になるように読み込む。- 8192 - 0x200 - 32 の内訳は次の通り。
| セクタ 0 から数えると tar フォーマットが始まるまでに 8KB の
| ブートストラップ領域があるので 8192。その後 tar のヘッダが
| 512 バイト (= 0x200)。そして /boot の a.out ヘッダが 32 バイト。
|
andib #0x03,%d0 | drive # (head=0)
jbsr check_fd_format
moveb %d6,%d2
lslw #8,%d2
moveq #0x70,%d1
orw %d2,%d1 | PDA*256 + MODE
movel %d0,%d2 | read position (first sector)
movel #65536,%d3 | read bytes
moval #(BOOT_TEXTADDR-8192-0x200-32),%a1
moval %a1,%a4 | save buffer addr
| 読み込んで boot_read_done へ飛ぶ。
IOCS(__B_READ)
jra boot_read_done
#include "chkfmt.s"
boot_dev_unsupported:
BOOT_ERROR("unsupported boot device")
booterr_msg: .ascii "\r\n\n"
.ascii BOOT
.asciz ": "
reboot_msg: .asciz "\r\n[Hit key to reboot]"
.even
ASENTRY_NOPROFILE(boot_error)
lea %pc@(booterr_msg),%a1
IOCS(__B_PRINT)
moveal %sp@+,%a1
IOCS(__B_PRINT)
lea %pc@(reboot_msg),%a1
IOCS(__B_PRINT)
| wait for a key press (or release of a modifier)
IOCS(__B_KEYINP)
| issue software reset
trap #10
| NOTREACHED
|
| FD の先頭 64KB を読み込んでからの処理。
|
boot_read_done:
| %a4 から 8192 バイト先の番地を %a1 に入れる。
| %a4 は FD から読み込んだバッファの先頭番地なので
| %a1 はデータ領域の開始位置 (tar の開始位置) になる。
|
| %a1 からの8バイトが "USTAR.vo" であることを確認する。
| そうでなければ invalidname。
lea %a4@(8192),%a1 | USTAR header
cmpl #0x55535441,%a1@ | filename `USTA
bne error_invalidname
cmpl #0x522e766f,%a1@(4) | R.vo...'
bne error_invalidname
| %a1 + 256 からの6バイトが "\0ustar" で
| あることを確認する。そうでなければ invalidfs。
cmpl #0x00757374,%a1@(256) | magic `\0ust'
bne error_invalidfs
cmpw #0x6172,%a1@(260) | magic `ar'
bne error_invalidfs
| %a1 + 512 を %a2 に入れる。
| %a2 は 1つ目のファイル (/usr/mdec/boot) の先頭。
| 先頭の32バイト(ロングワード8つ)は a.out のヘッダ。そのうち
| 最初の6つをレジスタに代入。残りの2つはいらないので単に
| ポインタを進める。各レジスタには以下の内容が入る。
| (FreeBSD 4.x の /usr/include/sys/imgact_aout.h より)
| %d0 a_midmag (flags << 26 | mid << 16 | magic)
| %d1 a_text text segment size
| %d2 a_data initialized data size
| %d3 a_bss uninitialized data size
| %d4 a_syms symbol table size
| %a5 a_entry entry point
| %a2 text segment の先頭
|
lea %a1@(0x200),%a2 | a.out header
movml %a2@+,%d0-%d4/%a5
addal #8,%a2 | start of text
| entry point (セカンダリブートローダへのジャンプ先) が
| あらかじめ固定されたアドレスと違うならエラーにする。
cmpal #BOOT_TEXTADDR,%a5
bne error_invalidboot
| a.out のマジックが違っていればエラー。
cmpl #0x00870107,%d0 | a.out magic
bne error_invalidmagic
| BSS をクリアする。
| %d1 が text segment 先頭 (%a2) からのオフセットで BSS 開始位置。
| %d3 が text segment 先頭 (%a2) からのオフセットで BSS 終了位置。
| %d4 が BSS のサイズ。
addl %d2,%d1 | a_text+a_data
movl %d3,%d4 | save a_bss
addl %d1,%d3 | a_text+a_data+a_bss
/* clear out bss */
| dbra 使わないのは 64KB 以上を想定しているから?
| 実際は数100バイト程度。
lea %a2@(%d1),%a3
1: movb #0,%a3@+
subl #1,%d4
bne 1b
/* set args for /boot */
| /boot への引数。
| firstpa, lastpa, esym はスタックで渡す。
| でもこいつら何者?
pea %a2@(%d3) | esym (unused)
movel SRAM_MEMSIZE,%sp@- | lastpa (unused)
pea %a2@ | firstpa (unused)
| 使わないレジスタはクリアしとくってことかしら?
movq #0,%d0 | unused
movq #0,%d1 | unused
movq #0,%d2 | unused
movq #0,%d3 | unused
movq #0,%d4 | unused
movq #0,%d5 | unused
| /boot への引数のうち、起動デバイス、起動方法は d6, d7 で
| レジスタ渡しする。
| まず d6 の起動デバイス情報はこんな感じ。 参照。
|
| (4) (4) (4) (4) (8) (8)
| --------------------------------
| |MA | AD| CT| UN| PART | TYPE |
| --------------------------------
|
| この時点までで d6 には IOCS __BOOTINF の戻り値が保存されている。
| これはこのコードの先頭の entry0 あたり参照。
| で、それの下位2ビットは FD ドライブ番号、つまりユニット番号を
| 示しているので swap すると、図でいう UN を用意したことになる。
| それにマジック(MA)と FD のメジャー番号(TYPE)を追加して完成。
andil #3,%d6 | bootdev
swap %d6
addil #(B_DEVMAGIC+X68K_MAJOR_FD),%d6
| d7 に起動方法を用意する。 参照。
| RB_SINGLE はシングルユーザモードで起動するの意だが
| この値は使われてないらしい。
movl #RB_SINGLE,%d7 | boothowto (unused)
| a2 に入っていたエントリポイントを a0 に移して
| a1 〜 a6 もクリアする。
moval %a2,%a0 | entry
moval %d0,%a1 | unused
moval %d0,%a2 | unused
moval %d0,%a3 | unused
moval %d0,%a4 | unused
moval %d0,%a5 | unused
moval %d0,%a6 | unused
| /boot へジャンプ
jmp %a0@ | here we go
error_invalidboot:
error_invalidname: BOOT_ERROR("Illegal secondary boot");
error_invalidfs:
error_invalidmagic: BOOT_ERROR("Invalid magic")
| ここまでが 1KB に収まってないといけないので
| チェック用のグローバルラベル。
ASGLOBAL(first_kbyte)
目次へ戻る
isaki@NetBSD.org