"12ステップで作る組み込みOS自作入門" で勝手にはまったことをメモ

# はじめに

表題の本[1]はとても親切に書かれていて，順に追っていけば問題なく進めていけるのですが，タイプミスなど自分の不注意でエラーになることがあります．そんなときの対応も含めて勉強になるので，恥を忍んでメモをしていきます．
内容は，随時追加してきます．

なお，私が自爆した内容であり，書籍の記載のせいではないことをここで強調しておきます．


## 6th step もう一度，Hello World!

### 6-1 make エラー
#### 症状

```
> cd os
> make
/usr/local/bin/h8300-elf-gcc startup.o main.o lib.o serial.o -o kozos -Wall -mh -nostdinc -nostdlib -fno-builtin -I. -Os -DKOZOS -static -T ld.scr -L.
/usr/local/lib/gcc/h8300-elf/8.2.0/../../../../h8300-elf/bin/ld:ld.scr:33: warning: memory region `data' not declared
/usr/local/lib/gcc/h8300-elf/8.2.0/../../../../h8300-elf/bin/ld: kozos section `.text.startup' will not fit in region `ram'
/usr/local/lib/gcc/h8300-elf/8.2.0/../../../../h8300-elf/bin/ld: region `ram' overflowed by 122 bytes
collect2: error: ld returned 1 exit status
Makefile:42: ターゲット 'kozos' のレシピで失敗しました
make: *** [kozos] エラー 1
```

#### 原因と対策
"region `ram' overflowed" と言われている通りで，リンカスクリプトのRAM領域のサイズを間違えて小さくしすぎていたため，収まらないとエラーを出してくれていました．

```os/ld.scr
MEMORY
{
	ram(rwx)	: o = 0xfffc20, l = 0x000300 /* ここは，0x003f000 が正しい */
	stack(rw)	: o = 0xffff00, l = 0x000000 /* end of RAM */
}
```

---
### 6-2 エントリーポイントのアドレスが 0x0 になってしまう
#### 症状

```
> readelf -a kozos.elf
ELF ヘッダ:
  マジック:   7f 45 4c 46 01 02 01 00 00 00 00 00 00 00 00 00
  クラス:                            ELF32
  データ:                            2 の補数、ビッグエンディアン
  バージョン:                        1 (current)
  OS/ABI:                            UNIX - System V
  ABI バージョン:                    0
  型:                                EXEC (実行可能ファイル)
  マシン:                            Renesas H8/300
  バージョン:                        0x1
  エントリポイントアドレス:               0x0
  プログラムの開始ヘッダ:          52 (バイト)
  セクションヘッダ始点:          2932 (バイト)
  フラグ:                            0x810000
  このヘッダのサイズ:                52 (バイト)
  プログラムヘッダサイズ:            32 (バイト)
  プログラムヘッダ数:                4
  セクションヘッダ:                  40 (バイト)
  セクションヘッダサイズ:            9
  セクションヘッダ文字列表索引:      8
```

#### 原因と対策

* .SECTIONS 内の ROM 領域の定義は削除していた．（これは正しい）
* かつ，リンカスクリプトの .text セクションの配置先指定が， > ROM のままになっていた

現象としては，リンカが，未定義の領域を 0x0 として処理していたようです．

---
### 6.3 OSが実行できない

OS の ELF をロードして run すると，エントリーポイントの表示が正しくなく，そのまま固まります．readelf -a kozos で表示されるエントリーポイントは正しいことを確認しました (0x00ff0c20)．

```
kzload> load

XMODEM receive succeeded.
kzload> run
starting from entry point: 20kzload (kozos boot loader) started.
kzload>
```

#### 原因と対策

エントリーポイントが 20 と表示されるのは， 0x00ff0c20 のLSB側だけが切り取られて表示されているように見えます．elf_read() の返値がおかしいのではないかと予想し，ソースを確認したところ，返値の型に間違いが見つかりました．

``` bootloader/elf.c
char elf_load(char *buf)  /* 正しくは char *elf_load(char *buf) */
```
ポインタを返すべきところが char になっていたので，MSB側が切り捨てられていたようです．ヘッダも同様に誤りがあったので修正したところ，うまく動きました．


## 7th step 割込み処理を実装する
### 7.1　kozos を load すると bootloader に戻ってしまう
#### 症状
```
kzload> load

XMODEM receive succeeded.
kzload> run
starting from entry point: ffc020
kozos boot succeeded!
> kzload (kozos boot loader) started.
kzload> a
```

#### 原因と対策
割込みハンドラの入り口で，_interrupt に渡すスタックポインタを間違えて，@ が余計についていました．さらに，割込みベクタを設定する vector.c の NULL の数が8個少なかったために，SCIの割込みベクタがずれていました．おそらく 0000 に飛ばされて，bootloader に戻っていたのだと思います．


``` intr.S
  .global _intr_serintr
  .type _intr_serintr,@function
_intr_serintr:
  mov.l er6,@-er7
  mov.l er5,@-er7
  mov.l er4,@-er7
  mov.l er3,@-er7
  mov.l er2,@-er7
  mov.l er1,@-er7
  mov.l er0,@-er7
  mov.l er7,@er1  ; 正しくは mov.l er7,er1
  mov.w #SOFTVEC_TYPE_SOFTERR,r0
  jsr @_interrupt
  mov.l @er7+,er0
  mov.l @er7+,er1
  mov.l @er7+,er2
  mov.l @er7+,er3
  mov.l @er7+,er4
  mov.l @er7+,er5
  mov.l @er7+,er6
  rte
```



# 参考文献
[1] 坂井弘亮, 「12ステップで作る組み込みOS自作入門」, カットシステム