1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

「30日でできる!OS自作入門」六〜八日目(harib03a〜harib05d)をUbuntu18.04/NASMで作る

Last updated at Posted at 2020-04-16

#はじめに
「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だけ変えました。

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を追加します。

Makefile
%.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を変えてみます。

msprintf.c
#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関数がマイナス表記に対応していないためです。
そこでまた変更するついでに右寄せ表記にも対応させます。

mprintf.c
#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詰めの表示ができるようにもなりました。

1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?