091211

|



動きはじめると、まだ辛い。ぶりかえしてしまったかも。健康って素晴しい。

ちょっとNetBSD/sh3について徒然に。
sh3/param.h

#define	UPAGES		3		/* pages of u-area */
#define	USPACE		(UPAGES * NBPG)	/* total size of u-area */
#if UPAGES == 1
#error "too small u-area"
#elif UPAGES == 2
#define	P1_STACK	/* kernel stack is P1-area */
#else
#undef	P1_STACK	/* kernel stack is P3-area */
#endif
UPAGESが2の場合、カーネルスタックは1ページのみで連続領域なのでスタック ポインタをP1で持てる。しかし、UPAGESが3以上の場合、そのカーネルスタック 2ページはP3では連続していてもP1では必ずしも連続しないので、スタックポイ ンタはP3で持たないといけない。
実際のところは最初のページのstruct user(今はpcb)の後までカーネルスタック として使えるのだけど、そこはなしということになる。
なんでこれがあるかというと、SH3の場合はH/Wでワイヤードエントリを作れな いので、割込まれた時にカーネルスタックをアクセスしてさらにフォルトして しまうのを避けるために、その場で直接カーネルスタックをTLBに載せるという 方法をとった。そのトリッキーな動作のデバッグ用。実際のところ、割込みが きつくなると4KBではカーネルスタックが足りなくなる。
NetBSD/sh3の実装は最初から__SWAP_BROKEN、つまりu-areaはスワップアウトし ない。これはなんでこうしたかというと、u-areaの中のポインタをu-areaに持っ ていると、それをスワップアウト/インされた時にリマップしないといけないの が面倒だからだ。
今回u-areaのスワップが廃止された。カーネル側でそれを廃止したため、 u-areaは匿名領域からとるのではなく、uvm_km.cあたりのカーネル領域のプー ルからとることになった(スワップアウトする必要が一切なくなったので)。カー ネル領域はページアウトされない。
匿名領域の確保の場合、保護のために(ユーザにも使われるので)ページをゼロ クリアするのだけど、カーネル領域はそれは必要ないのでゼロクリアされない。 ということでゼロクリアを期待していたコードが動かなくなってしまった。 pcb_onfaultにゴミが入っていたりすると、TLBミスした時におかしい挙動になっ てしまう。
昔からu-areaはゼロにしないという設定だったのだけど、いろいろな設定の関 係でたまたまゼロになっていた。(もしかするとたまにゼロじゃない時もあった のかも)
ちょっと後半あやふや。
昔のカーネル
cpu0 at mainbus0: SH4A 599.999 MHz PCLOCK 49.999 MHz
cpu0: 32KB/32B 4-way set-associative Instruction cache.
cpu0: 32KB/32B 4-way set-associative Data cache.
cpu0: U0, P0, P3 write-back; P1 write-back
cpu0: full-associative 4 ITLB, 64 UTLB entries
cpu0: multiple virtual storage mode, SQ access: kernel, wired 7
cpu0: 32bit physical address mode. TLB-compatible mode.
VPN:80000000 (V) PPN:0 (V) 512MB, bufferd write, cacheable, write-back,
VPN:a0000000 (V) PPN:0 (V) 512MB, bufferd write, uncacheable, write-back,
shb0 at mainbus0
scif0 at shb0
scif0: console
PCB0xc1820000=>5ffde000 ←u-areaはanonからもってきている。これはゼロクリア
PCB0xc1823000=>5ffdb000
PCB0xc1826000=>5ffd8000
PCB0xc1829000=>5ffd5000
PCB0xc182c000=>5ffd2000
PCB0xc182f000=>5ffcf000
PCB0xc1832000=>5ffcc000
PCB0xc1835000=>5ffc9000
pmap_prefer 1
PCB0xc1832000=>5ffcc000
rn_init: radix functions require max_keylen be set
PCB0xc1835000=>5ffc9000
root on md0a dumps on md0b
mountroot: trying ffs...
root file system type: ffs
今のカーネル
cpu0: 32bit physical address mode. TLB-compatible mode.
VPN:80000000 (V) PPN:0 (V) 512MB, bufferd write, cacheable, write-back,
VPN:a0000000 (V) PPN:0 (V) 512MB, bufferd write, uncacheable, write-back,
shb0 at mainbus0
scif0 at shb0
scif0: console
PCB(new)0xc2262000=>febc000 ←u-areaはカーネルのプールページから持ってきている。
PCB(new)0xc2265000=>feb9000
PCB(new)0xc2268000=>feb6000
PCB(new)0xc226b000=>feb3000
PCB(new)0xc226e000=>feb0000
PCB(new)0xc2271000=>feac000
PCB(new)0xc2274000=>fea9000
PCB(new)0xc2277000=>fea6000
pmap_prefer 1
pmap_growkernel: fe93000 for 9
pmap_growkernel: fe92000 for 10
PCB(new)0xc2274000=>fea9000
rn_init: radix functions require max_keylen be set
PCB(new)0xc2277000=>fea6000
root on md0a dumps on md0b
mountroot: trying ffs...
root file system type: ffs
WARNING: no TOD clock present
WARNING: using filesystem time
WARNING: CHECK AND RESET THE DATE!
PCB(new)0xc2271000=>feac000
PCB(new)0xc226e000=>feb0000
PCB(new)0xc226b000=>feb3000
PCB(new)0xc2268000=>feb6000
__pmap_asid_alloc: 1
init: copying out flags `-s' 3
プロセスの起動について。
init: copying out flags `-s' 3
ここで新しくプロセスを作ってそれがASID1になった。
tlb_exception: ASID1
まずはスタックをアクセスしてフォルト。ここで失敗するのはこの領域の
ページテーブルページもないから。
FAILED __pmap_pte_load ASID=1 va=7fffeffd
ここでuvm_faultして、ページテーブルページを割当てて、その中の該当ページ
をマップする。pcb_onfaultにゴミが入っていると、ここまでに来ずにページテー
ブルにないというところでそのままリターンしてしまうのでAbort trapしてし
まう。
------------------------------START
uvm_fault_internal start=7fffeffd 0x8900b978
pmap_enter pa=5ffc6000 va=7fffe000 0x8909aa8a
__pmap_pte_alloc 7fffe000
------------------------------END
ここではじめて触ったスタックがロードされる。ここまでで一回の例外処理。
__pmap_pte_load ASID=1 va=7fffeffd
init: copying out path `/sbin/init' 11