#はじめに
「30日でできる!OS自作入門」五日目の続きです。今回は変更箇所が少ないので、三日分をまとめました。
#環境
$ uname -a
Linux furble 5.3.0-45-generic #37~18.04.1-Ubuntu SMP Fri Mar 27 15:58:10 UTC 2020 x86_64 x86_64 x86_64 GNU/Linux
$ nasm -v
NASM version 2.13.02
$ qemu-system-i386 --version
QEMU emulator version 2.11.1(Debian 1:2.11+dfsg-1ubuntu7.23)
$ gcc --version
gcc (Ubuntu 7.5.0-3ubuntu1~18.04) 7.5.0
#harib03a
新しく変える必要のある箇所無し。
#harib03b
Makefileだけ変えました。
MAKE = make -r
NASM = nasm
CFLAGS = -m32 -march=i486 -nostdlib -fno-pie
...
%.o : %.c Makefile
gcc $(CFLAGS) -c $*.c -o $*.o
...
#harib03c、harib03d
新しく変える必要のある箇所無し。
#harib03e
nasmfunc.asmに追加する関数の頭にある"_"はすべて消します。
$ diff -u harib03d/nasmfunc.asm harib03e/nasmfunc.asm
--- harib03d/nasmfunc.asm 2020-04-09 17:36:46.935452049 +0900
+++ harib03e/nasmfunc.asm 2020-04-09 17:28:08.816957515 +0900
@@ -4,6 +4,8 @@
GLOBAL io_out8, io_out16, io_out32
GLOBAL io_load_eflags, io_store_eflags
GLOBAL load_gdtr, load_idtr
+ GLOBAL asm_inthandler21, asm_inthandler27, asm_inthandler2c
+ EXTERN inthandler21, inthandler27, inthandler2c
io_hlt: ; void io_hlt(void);
@@ -80,3 +82,51 @@
MOV [ESP+6],AX
LIDT [ESP+6]
RET
+
+asm_inthandler21:
+ PUSH ES
+ PUSH DS
+ PUSHAD
+ MOV EAX,ESP
+ PUSH EAX
+ MOV AX,SS
+ MOV DS,AX
+ MOV ES,AX
+ CALL inthandler21
+ POP EAX
+ POPAD
+ POP DS
+ POP ES
+ IRETD
+
+asm_inthandler27:
+ PUSH ES
+ PUSH DS
+ PUSHAD
+ MOV EAX,ESP
+ PUSH EAX
+ MOV AX,SS
+ MOV DS,AX
+ MOV ES,AX
+ CALL inthandler27
+ POP EAX
+ POPAD
+ POP DS
+ POP ES
+ IRETD
+
+asm_inthandler2c:
+ PUSH ES
+ PUSH DS
+ PUSHAD
+ MOV EAX,ESP
+ PUSH EAX
+ MOV AX,SS
+ MOV DS,AX
+ MOV ES,AX
+ CALL inthandler2c
+ POP EAX
+ POPAD
+ POP DS
+ POP ES
+ IRETD
#harib04a
Makefileの依存ファイルにbootpack.hを追加します。
%.o : %.c bootpack.h Makefile
gcc $(CFLAGS) -c $*.c -o $*.o
#harib04b
必要な箇所を変更してmake runすると、どのキーを押しても2Xとしか表示されません。これは、五日目に追加したmprintf関数がmsprintf(s, "%02X", i);という表記に対応していないためです。
これをmsprintf(s, "%x", i);にすると表示されます。
しかしせっかくなので、0詰めの表記に対応できるようにmsprintfを変えてみます。
#include <stdarg.h>
//10進数からASCIIコードに変換
int dec2asc (char *str, int dec, int dig) {
int len = 0, len_buf, fill; //桁数
int buf[10];
while (1) { //10で割れた回数(つまり桁数)をlenに、各桁をbufに格納
buf[len++] = dec % 10;
if (dec < 10) break;
dec /= 10;
}
len_buf = len;
fill = dig - len; //0で満たす必要のある桁数
if(fill > 0)len_buf += fill;
while(fill > 0){
*(str++) = '0';
fill--;
}
while (len) {
*(str++) = buf[--len] + 0x30;
}
return len_buf;
}
//16進数からASCIIコードに変換
int hex2asc (char *str, int dec, int dig) { //16で割れた回数(つまり桁数)をlenに、各桁をbufに格納
int len = 0, len_buf, fill; //桁数
int buf[10];
while (1) {
buf[len++] = dec % 16;
if (dec < 16) break;
dec /= 16;
}
len_buf = len;
fill = dig - len; //0で満たす必要のある桁数
if(fill > 0)len_buf += fill;
while(fill > 0){
*(str++) = 0x30;
fill--;
}
while (len) {
len --;
*(str++) = (buf[len]<10)?(buf[len] + 0x30):(buf[len] - 9 + 0x60);
}
return len_buf;
}
void msprintf (char *str, char *fmt, ...) {
va_list list;
int i, len, dig = 0;
va_start (list, fmt);
while (*fmt) {
if(*fmt=='%') {
fmt++;
if('1' < *fmt && *fmt <= '9'){
dig = *fmt - '0';
fmt++;
}
switch(*fmt){
case 'd':
len = dec2asc(str, va_arg (list, int), dig);
break;
case 'x':
len = hex2asc(str, va_arg (list, int), dig);
break;
}
str += len; fmt++;
} else {
*(str++) = *(fmt++);
}
}
*str = 0x00; //最後にNULLを追加
va_end (list);
}
これでbootpack.cにmsprintf(s, "%2x", i);と書けば、iが2桁の0詰めで表示できるようになりました。これは当然9桁までしか指定できませんが、今はそれで十分なのでこのまま進めます。
#harib04c〜harib04g、harib05a〜harib05c
新しく変える必要のある箇所無し。
#harib05d
make runで実行すると、bootpack.cの
msprintf(s, "[lcr %4d %4d]", mdec.x, mdec.y);
の箇所の表示がおかしくなります。これはmprintf関数がマイナス表記に対応していないためです。
そこでまた変更するついでに右寄せ表記にも対応させます。
#include <stdarg.h>
//10進数からASCIIコードに変換
//digは表示すべき桁数、pad0は空いた箇所を0で満たすかどうか
int dec2asc (char *str, int dec, int dig, int pad0) {
int len = 0, len_buf, fill, fminus = 0;
int buf[10];
if(dec < 0){
fminus = 1;
dec *= -1;
}
while (1) { //10で割れた回数(つまり桁数)をlenに、各桁をbufに格納
buf[len++] = dec % 10;
if (dec < 10) break;
dec /= 10;
}
len_buf = len + fminus;
fill = dig - len - fminus; //0で満たす必要のある桁数
if(fill > 0)len_buf += fill;
while(fill > 0){
if(pad0){
*(str++) = '0';
}else{
*(str++) = ' ';
}
fill--;
}
if(fminus){
*(str++) = '-';
}
while (len) {
*(str++) = buf[--len] + '0';
}
return len_buf;
}
//16進数からASCIIコードに変換
int hex2asc (char *str, int dec, int dig, int pad0) {
int len = 0, len_buf, fill, fminus = 0;
int buf[10];
while (1) {//16で割れた回数(つまり桁数)をlenに、各桁をbufに格納
buf[len++] = dec % 16;
if (dec < 16) break;
dec /= 16;
}
len_buf = len + fminus;
fill = dig - len - fminus; //0で満たす必要のある桁数
if(fill > 0)len_buf += fill;
while(fill > 0){
if(pad0){
*(str++) = '0';
}else{
*(str++) = ' ';
}
fill--;
}
if(fminus){
*(str++) = '-';
}
while (len) {
len --;
*(str++) = (buf[len]<10)?(buf[len] + 0x30):(buf[len] - 9 + 0x60);
}
return len_buf;
}
void msprintf (char *str, char *fmt, ...) {
va_list list;
int i, len, dig = 0, pad0 = 0;
va_start (list, fmt);
while (*fmt) {
if(*fmt=='%') {
fmt++;
if(*fmt == '0'){
pad0 = 1;//0詰め表記
fmt++;
}else{
pad0 = 0;//スペース詰め(右寄せ)表記
}
if('1' < *fmt && *fmt <= '9'){
dig = *fmt - '0';
fmt++;
}
switch(*fmt){
case 'd':
len = dec2asc(str, va_arg (list, int), dig, pad0);
break;
case 'x':
len = hex2asc(str, va_arg (list, int), dig, pad0);
break;
}
str += len; fmt++;
} else {
*(str++) = *(fmt++);
}
}
*str = 0x00; //最後にNULLを追加
va_end (list);
}
だいぶコードが汚くなりましたが、これでマイナス表記ができます。
msprintf(s, "[lcr %4d %4d]", mdec.x, mdec.y);
で数値を4桁の右寄せで表示、%04dで0詰めの表示ができるようにもなりました。