分割コンパイル・Makefile整理・ヘッダ整理については後からMakefileを載せる。

GDTRレジスタの扱い

1
2
3
4
5
load_gdtr:		; void load_gdtr(int limit, int addr);
MOV AX,[ESP+4] ; limit
MOV [ESP+6],AX
LGDT [ESP+6]
RET

GDTRは48bitレジスタ。LGDTはアドレス指定でそこから6バイト読み込む。

1
load_gdtr(0x0000FFFF, 0x00270000);
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
FF FF 00 00 00 00 27 00
↑ ↑ ↑
ESP+4 ESP+6 ESP+8

MOVはWORDを読み取ってコピーするので、

MOV AX,[ESP+4]は
FF FF 00 00
を読み取る

MOV [ESP+6],AXで
FF FF 00 00 00 00 27 00
+) FF FF 00 00
-------------------------
FF FF FF FF 00 00 27 00
↑ ↑ ↑
ESP+4 ESP+6 ESP+8

[ESP+6]からLGDTで6バイト読み出すので、それは、
FF FF 00 00 27 00
になる

set_segmdesc関数

エンディアンを考慮せずに右側が下位バイト・ビットだとすると

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
 base  limit        base 
high high ar mid baselow limitlow
| A |H |E | I | B | F | G | C | D |

base | A | B | C | D |
limit |E | F | G |
access right(ar) |H | I |

HとIはリトルエンディアンだと繋がる。

Hをビットごとに表すと、
|G|D|0|0|

G
=0: limitが1B単位
=1: limitが1page(4KB)単位
D
=1: 32bit
=0: 16bit
1
2
3
4
if (limit > 0xfffff) {
ar |= 0x8000; /* G_bit = 1 */
limit /= 0x1000; // limitをpage単位にしてる
}

PICレジスタ

すべて8bit

レジスタ名
IMR Interrupt Mask Register. 1になっているビットの信号を無視する。
ICW3 マスタではスレーブがつながっているビットを1にする。スレーブではつながっているマスタのIRQ番号
ICW2 IRQをどの割り込み番号で受けるか。個々に設定した値から連続する8個でINT 0x??のように受ける。

ICW1 ICW4は触ると爆発するらしいのでそのまま。

デバイス IRQ INT番号
キーボード IRQ1 0x20
マウス IRQ12 0x2c

新出アセンブリ

命令
IRETD 割り込み処理終了後にはRETではなくこれを使う
PUSHAD
POPAD
下記参照
CALL 関数呼び出し
EXTERN ラベルの定義は他にあるということを明示する

PUSH EAXは以下と同値

1
2
ADD ESP,-4
MOV [SS:ESP],EAX

POP EAXは以下と同値

1
2
MOV EAX,[SS:ESP]
ADD ESP,4

PUSHAD

1
2
3
4
5
6
7
8
PUSH AX
PUSH CX
PUSH DX
PUSH BX
PUSH SP
PUSH BP
PUSH SI
PUSH DI

POPADはこの逆にPOP

C言語ではDS ES SSが同じセグメントを指していないといけないというルールがあるらしい。

割り込み登録とset_gatedesc関数

エンディアンを考慮せずに右側が下位バイト・ビットだとすると

1
2
3
4
5
6
7
                    dw
offset high ar count selector offset low
| A | B | H | G | E | F | C | D |

offset | A | B | C | D |
selector | E | F |
access right(ar) | G | H |

selectorの下位3桁はセグメント番号に使えないので2<<3でずらす。(int)asm_inthandler21は関数のアドレスを表す。

1
set_gatedesc(idt + 0x21, (int) asm_inthandler21, 2<<3, AR_INTGATE32);

https://blog.shosato.jp/2019/09/14/hand-made-os-in-30-days-day-5/#%E3%82%BB%E3%82%B0%E3%83%A1%E3%83%B3%E3%83%86%E3%83%BC%E3%82%B7%E3%83%A7%E3%83%B3

動作確認

Makefileを整理したので載せておく。自分で書いたCライブラリはmyclib.cというファイル名だとする。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
TARGET=os.img
SYSFILE=haribote.sys
FONT_SRC=font

FONT_OBJ=$(FONT_SRC).o

default:$(TARGET)

$(TARGET): ipl10.o $(SYSFILE)
mformat -f 1440 -C -B $< -i $(TARGET) ::
mcopy $(SYSFILE) -i $(TARGET) ::

$(SYSFILE): asmhead.o bootpack.bin
cat $^ > [email protected]

bootpack.bin:$(FONT_OBJ) myclib.o int.o graphic.o dsctbl.o naskfunc.o bootpack.o
ld -m elf_i386 -T os.ld $^ -o [email protected]

%.o: %.c
gcc -w -c -m32 -nostdlib -fno-pie $*.c -o $*.o

%.o: %.nas
nasm $*.nas -o $*.o

naskfunc.o: naskfunc.nas
nasm -f elf $< -o [email protected]

$(FONT_OBJ):
objcopy -I binary -O elf32-i386 -B i386 --redefine-sym _binary_font_start=hankaku $(FONT_SRC) [email protected]

clean:
rm *.bin *.sys *.img *.o

run:
qemu-system-x86_64 -fda ./$(TARGET)

pre:
nkf --overwrite *.nas *.c
sed -i s/0x7dfe-\\$$/0x01fe-\(\\$$\-\\$$\\$$\)/ ipl10.nas
sed -i -E 's/( |\t|^)_/\1/g' naskfunc.nas
sed -i s/^\\[/\;\\[/ naskfunc.nas asmhead.nas