たなしょのメモ

日々勉強していることをつらつらと

OS作成奮闘記day24

1文字表示させるAPIを作っていきます。
naskfunk.nas

       GLOBAL _io_hlt, _io_cli, _io_sti, _io_stihlt
        GLOBAL _io_in8,  _io_in16,  _io_in32
        GLOBAL _io_out8, _io_out16, _io_out32
        GLOBAL _io_load_eflags, _io_store_eflags
        GLOBAL _load_gdtr, _load_idtr
        GLOBAL _load_cr0, _store_cr0
        GLOBAL _load_tr
        GLOBAL _asm_inthandler20, _asm_inthandler21
        GLOBAL _asm_inthandler27, _asm_inthandler2c
        GLOBAL _memtest_sub
        GLOBAL _farjmp
        GLOBAL _asm_cons_putchar
        EXTERN _inthandler20, _inthandler21
        EXTERN _inthandler27, _inthandler2c
        EXTERN _cons_putchar
_asm_cons_putchar:
        PUSH  1
        AND       EAX,0xff   ; AHやEAXの上位を0にして、EAXに文字コードが入った状態にする。
        PUSH  EAX
        PUSH  DWORD [0x0fec]    ; メモリの内容を読み込んでその値をPUSHする
        CALL  _cons_putchar
        ADD       ESP,12     ; スタックに積んだデータを捨てる
        RET

console.c

void console_task(struct SHEET *sheet, unsigned int memtotal)
{
    struct TIMER *timer;
    struct TASK *task = task_now();
    struct MEMMAN *memman = (struct MEMMAN *) MEMMAN_ADDR;
    int i, fifobuf[128], *fat = (int *) memman_alloc_4k(memman, 4 * 2880);
    struct CONSOLE cons;
    char cmdline[30];
    cons.sht = sheet;
    cons.cur_x =  8;
    cons.cur_y = 28;
    cons.cur_c = -1;
    *((int *) 0x0fec) = (int) &cons;

hlt.nas

[BITS 32]
        MOV       AL,'A'
        CALL    0xbe3
fin:
        HLT
        JMP       fin

エミュレーターが動かなくなってしまって動くように直します hlt.nas

[BITS 32]
        MOV       AL,'A'
        CALL            2*8:0xbe3
fin:
        HLT
        JMP       fin

naskfunc.nas

_asm_cons_putchar:
        PUSH  1
        AND       EAX,0xff   ; AHやEAXの上位を0にして、EAXに文字コードが入った状態にする。
        PUSH  EAX
        PUSH  DWORD [0x0fec]    ; メモリの内容を読み込んでその値をPUSHする
        CALL  _cons_putchar
        ADD       ESP,12     ; スタックに積んだデータを捨てる
        RET
        RETF

アプリケーションに終了処理を作ってみたいと思います。
naskfunc.nas

GLOBAL    _farjmp, _farcall
_farcall:       ; void farcall(int eip, int cs);
        CALL  FAR    [ESP+4]                ; eip, cs
        RET

_asm_cons_putchar:
        PUSH  1
        AND       EAX,0xff   ; AHやEAXの上位を0にして、EAXに文字コードが入った状態にする。
        PUSH  EAX
        PUSH  DWORD [0x0fec]    ; メモリの内容を読み込んでその値をPUSHする
        CALL  _cons_putchar
        ADD       ESP,12     ; スタックに積んだデータを捨てる
        RETF

console.c

void cmd_hlt(struct CONSOLE *cons, int *fat)
{
    struct MEMMAN *memman = (struct MEMMAN *) MEMMAN_ADDR;
    struct FILEINFO *finfo = file_search("HLT.HRB", (struct FILEINFO *) (ADR_DISKIMG + 0x002600), 224);
    struct SEGMENT_DESCRIPTOR *gdt = (struct SEGMENT_DESCRIPTOR *) ADR_GDT;
    char *p;
    if (finfo != 0) {
        /* ファイルが見つかった場合 */
        p = (char *) memman_alloc_4k(memman, finfo->size);
        file_loadfile(finfo->clustno, finfo->size, p, fat, (char *) (ADR_DISKIMG + 0x003e00));
        set_segmdesc(gdt + 1003, finfo->size - 1, (int) p, AR_CODE32_ER);
        farcall(0, 1003 * 8);
        memman_free_4k(memman, (int) p, finfo->size);
    } else {
        /* ファイルが見つからなかった場合 */
        putfonts8_asc_sht(cons->sht, 8, cons->cur_y, COL8_FFFFFF, COL8_000000, "File not found.", 15);
        cons_newline(cons);
    }
    cons_newline(cons);
    return;
}

bootpack.h

void farcall(int eip, int cs);
void asm_cons_putchar(void);

hlt.nas

[BITS 32]
        MOV       AL,'h'
        CALL      2*8:0xbe8
        MOV             AL,'e'
        CALL            2*8:0xbe8
        MOV             AL,'l'
        CALL            2*8:0xbe8
        MOV             AL,'l'
        CALL            2*8:0xbe8
        MOV             AL,'o'
        CALL            2*8:0xbe8
        RETF

hlt.hrbのアプリサイズを小さくしてみます。
dsctbl.c

void init_gdtidt(void)
{
    struct SEGMENT_DESCRIPTOR *gdt = (struct SEGMENT_DESCRIPTOR *) ADR_GDT;
    struct GATE_DESCRIPTOR    *idt = (struct GATE_DESCRIPTOR    *) ADR_IDT;
    int i;

    /* GDTの初期化 */
    for (i = 0; i <= LIMIT_GDT / 8; i++) {
        set_segmdesc(gdt + i, 0, 0, 0);
    }
    set_segmdesc(gdt + 1, 0xffffffff,   0x00000000, AR_DATA32_RW);
    set_segmdesc(gdt + 2, LIMIT_BOTPAK, ADR_BOTPAK, AR_CODE32_ER);
    load_gdtr(LIMIT_GDT, ADR_GDT);

    /* IDTの初期化 */
    for (i = 0; i <= LIMIT_IDT / 8; i++) {
        set_gatedesc(idt + i, 0, 0, 0);
    }
    load_idtr(LIMIT_IDT, ADR_IDT);

    /* IDTの設定 */
    set_gatedesc(idt + 0x20, (int) asm_inthandler20, 2 * 8, AR_INTGATE32);
    set_gatedesc(idt + 0x21, (int) asm_inthandler21, 2 * 8, AR_INTGATE32);
    set_gatedesc(idt + 0x27, (int) asm_inthandler27, 2 * 8, AR_INTGATE32);
    set_gatedesc(idt + 0x2c, (int) asm_inthandler2c, 2 * 8, AR_INTGATE32);
    set_gatedesc(idt + 0x40, (int) asm_cons_putchar, 2 * 8, AR_INTGATE32);

    return;
}

hlt.nas

[BITS 32]
        MOV       AL,'h'
        INT       0x40
        MOV             AL,'e'
        INT            0x40
        MOV             AL,'l'
        INT            0x40
        MOV             AL,'l'
        INT            0x40
        MOV             AL,'o'
        INT            0x40
        RETF
        

naskfunc.nas

_asm_cons_putchar:
        STI
        PUSH  1
        AND       EAX,0xff   ; AHやEAXの上位を0にして、EAXに文字コードが入った状態にする。
        PUSH  EAX
        PUSH  DWORD [0x0fec]    ; メモリの内容を読み込んでその値をPUSHする
        CALL  _cons_putchar
        ADD       ESP,12     ; スタックに積んだデータを捨てる
        IRETD

アプリケーション名を変更しようと思います。
bootpack.h

/* console.c */
struct CONSOLE {
    struct SHEET *sht;
    int cur_x, cur_y, cur_c;
};
void console_task(struct SHEET *sheet, unsigned int memtotal);
void cons_putchar(struct CONSOLE *cons, int chr, char move);
void cons_newline(struct CONSOLE *cons);
void cons_runcmd(char *cmdline, struct CONSOLE *cons, int *fat, unsigned int memtotal);
void cmd_mem(struct CONSOLE *cons, unsigned int memtotal);
void cmd_cls(struct CONSOLE *cons);
void cmd_dir(struct CONSOLE *cons);
void cmd_type(struct CONSOLE *cons, int *fat, char *cmdline);
int cmd_app(struct CONSOLE *cons, int *fat, char *cmdline);

console.c

void cons_runcmd(char *cmdline, struct CONSOLE *cons, int *fat, unsigned int memtotal)
{
    if (strcmp(cmdline, "mem") == 0) {
        cmd_mem(cons, memtotal);
    } else if (strcmp(cmdline, "cls") == 0) {
        cmd_cls(cons);
    } else if (strcmp(cmdline, "dir") == 0) {
        cmd_dir(cons);
    } else if (strncmp(cmdline, "type ", 5) == 0) {
        cmd_type(cons, fat, cmdline);
    } else if (cmdline[0] != 0) {
        if (cmd_app(cons, fat, cmdline) == 0) {
            /* コマンドではなく、アプリでもなく、さらに空行でもない */
            putfonts8_asc_sht(cons->sht, 8, cons->cur_y, COL8_FFFFFF, COL8_000000, "Bad command.", 12);
            cons_newline(cons);
            cons_newline(cons);
        }
    }
    return;
}
int cmd_app(struct CONSOLE *cons, int *fat, char *cmdline)
{
    struct MEMMAN *memman = (struct MEMMAN *) MEMMAN_ADDR;
    struct FILEINFO *finfo;
    struct SEGMENT_DESCRIPTOR *gdt = (struct SEGMENT_DESCRIPTOR *) ADR_GDT;
    char name[18], *p;
    int i;

    /* コマンドラインからファイル名を生成 */
    for (i = 0; i < 13; i++) {
        if (cmdline[i] <= ' ') {
            break;
        }
        name[i] = cmdline[i];
    }
    name[i] = 0; /* とりあえずファイル名の後ろを0にする */

    /* ファイルを探す */
    finfo = file_search(name, (struct FILEINFO *) (ADR_DISKIMG + 0x002600), 224);
    if (finfo == 0 && name[i - 1] != '.') {
        /* 見つからなかったので後ろに".HRB"をつけてもう一度探してみる */
        name[i    ] = '.';
        name[i + 1] = 'H';
        name[i + 2] = 'R';
        name[i + 3] = 'B';
        name[i + 4] = 0;
        finfo = file_search(name, (struct FILEINFO *) (ADR_DISKIMG + 0x002600), 224);
    }

    if (finfo != 0) {
        /* ファイルが見つかった場合 */
        p = (char *) memman_alloc_4k(memman, finfo->size);
        file_loadfile(finfo->clustno, finfo->size, p, fat, (char *) (ADR_DISKIMG + 0x003e00));
        set_segmdesc(gdt + 1003, finfo->size - 1, (int) p, AR_CODE32_ER);
        farcall(0, 1003 * 8);
        memman_free_4k(memman, (int) p, finfo->size);
        cons_newline(cons);
        return 1;
    }
    /* ファイルが見つからなかった場合 */
    return 0;
}

Makefile

hello.hrb : hello.nas Makefile
    $(NASK) hello.nas hello.hrb hello.lst

haribote.sys : asmhead.bin bootpack.hrb Makefile
    cat asmhead.bin bootpack.hrb > haribote.sys

haribote.img : ipl10.bin haribote.sys hello.hrb Makefile
    $(EDIMG)   imgin:..\..\z_tools\fdimg0at.tek \
        wbinimg src:ipl10.bin len:512 from:0 to:0 \
        copy from:haribote.sys to:@: \
        copy from:ipl10.nas to:@: \
        copy from:make.bat to:@: \
        copy from:hello.hrb to:@: \
        imgout:haribote.img

hello.nas

[BITS 32]
        MOV       AL,'h'
        INT       0x40
        MOV             AL,'e'
        INT            0x40
        MOV             AL,'l'
        INT            0x40
        MOV             AL,'l'
        INT            0x40
        MOV             AL,'o'
        INT            0x40
        RETF

hello.hrbをさらに小さくしてみます(結局ここでは小さくなりませんが)
hello.nas

[INSTRSET "i486p"]
[BITS 32]
        MOV     ECX,msg
putloop:
        MOV     AL,[CS:ECX]
        CMP     AL,0
        JE      fin
        INT     0x40
        ADD     ECX,1
        JMP     putloop
fin:
        RETF
msg:
        DB  "hello",0

naskfunc.nas

_asm_cons_putchar:
        STI
        PUSHAD
        PUSH  1
        AND       EAX,0xff   ; AHやEAXの上位を0にして、EAXに文字コードが入った状態にする。
        PUSH  EAX
        PUSH  DWORD [0x0fec]    ; メモリの内容を読み込んでその値をPUSHする
        CALL  _cons_putchar
        ADD       ESP,12     ; スタックに積んだデータを捨てる
        POPAD
        IRETD

文字列表示アプリを作ってみます。 bootpack.h

/* naskfunc.nas */
void io_hlt(void);
void io_cli(void);
void io_sti(void);
void io_stihlt(void);
int io_in8(int port);
void io_out8(int port, int data);
int io_load_eflags(void);
void io_store_eflags(int eflags);
void load_gdtr(int limit, int addr);
void load_idtr(int limit, int addr);
int load_cr0(void);
void store_cr0(int cr0);
void load_tr(int tr);
void asm_inthandler20(void);
void asm_inthandler21(void);
void asm_inthandler27(void);
void asm_inthandler2c(void);
unsigned int memtest_sub(unsigned int start, unsigned int end);
void farjmp(int eip, int cs);
void farcall(int eip, int cs);
void asm_hrb_api(void);
/* console.c */
struct CONSOLE {
    struct SHEET *sht;
    int cur_x, cur_y, cur_c;
};
void console_task(struct SHEET *sheet, unsigned int memtotal);
void cons_putchar(struct CONSOLE *cons, int chr, char move);
void cons_newline(struct CONSOLE *cons);
void cons_putstr0(struct CONSOLE *cons, char *s);
void cons_putstr1(struct CONSOLE *cons, char *s, int l);
void cons_runcmd(char *cmdline, struct CONSOLE *cons, int *fat, unsigned int memtotal);
void cmd_mem(struct CONSOLE *cons, unsigned int memtotal);
void cmd_cls(struct CONSOLE *cons);
void cmd_dir(struct CONSOLE *cons);
void cmd_type(struct CONSOLE *cons, int *fat, char *cmdline);
int cmd_app(struct CONSOLE *cons, int *fat, char *cmdline);
void hrb_api(int edi, int esi, int ebp, int esp, int ebx, int edx, int ecx, int eax);

Makefile

hello.hrb : hello.nas Makefile
    $(NASK) hello.nas hello.hrb hello.lst

hello2.hrb : hello2.nas Makefile
    $(NASK) hello2.nas hello2.hrb hello2.lst

haribote.sys : asmhead.bin bootpack.hrb Makefile
    cat asmhead.bin bootpack.hrb > haribote.sys

haribote.img : ipl10.bin haribote.sys hello.hrb hello2.hrb Makefile
    $(EDIMG)   imgin:..\..\z_tools\fdimg0at.tek \
        wbinimg src:ipl10.bin len:512 from:0 to:0 \
        copy from:haribote.sys to:@: \
        copy from:ipl10.nas to:@: \
        copy from:make.bat to:@: \
        copy from:hello.hrb to:@: \
        copy from:hello2.hrb to:@: \
        imgout:haribote.img

console.c

void cons_runcmd(char *cmdline, struct CONSOLE *cons, int *fat, unsigned int memtotal)
{
    if (strcmp(cmdline, "mem") == 0) {
        cmd_mem(cons, memtotal);
    } else if (strcmp(cmdline, "cls") == 0) {
        cmd_cls(cons);
    } else if (strcmp(cmdline, "dir") == 0) {
        cmd_dir(cons);
    } else if (strncmp(cmdline, "type ", 5) == 0) {
        cmd_type(cons, fat, cmdline);
    } else if (cmdline[0] != 0) {
        if (cmd_app(cons, fat, cmdline) == 0) {
            /* コマンドではなく、アプリでもなく、さらに空行でもない */
            cons_putstr0(cons, "Bad command.\n\n");
        }
    }
    return;
}

void cmd_mem(struct CONSOLE *cons, unsigned int memtotal)
{
    struct MEMMAN *memman = (struct MEMMAN *) MEMMAN_ADDR;
    char s[60];
    sprintf(s, "total   %dMB\nfree %dKB\n\n", memtotal / (1024 * 1024), memman_total(memman) / 1024);
    cons_putstr0(cons, s);
    return;
} 
void cmd_dir(struct CONSOLE *cons)
{
    struct FILEINFO *finfo = (struct FILEINFO *) (ADR_DISKIMG + 0x002600);
    int i, j;
    char s[30];
    for (i = 0; i < 224; i++) {
        if (finfo[i].name[0] == 0x00) {
            break;
        }
        if (finfo[i].name[0] != 0xe5) {
            if ((finfo[i].type & 0x18) == 0) {
                sprintf(s, "filename.ext   %7d\n", finfo[i].size);
                for (j = 0; j < 8; j++) {
                    s[j] = finfo[i].name[j];
                }
                s[ 9] = finfo[i].ext[0];
                s[10] = finfo[i].ext[1];
                s[11] = finfo[i].ext[2];
                cons_putstr0(cons, s);
            }
        }
    }
    cons_newline(cons);
    return;
}

void cmd_type(struct CONSOLE *cons, int *fat, char *cmdline)
{
    struct MEMMAN *memman = (struct MEMMAN *) MEMMAN_ADDR;
    struct FILEINFO *finfo = file_search(cmdline + 5, (struct FILEINFO *) (ADR_DISKIMG + 0x002600), 224);
    char *p;
    if (finfo != 0) {
        /* ファイルが見つかった場合 */
        p = (char *) memman_alloc_4k(memman, finfo->size);
        file_loadfile(finfo->clustno, finfo->size, p, fat, (char *) (ADR_DISKIMG + 0x003e00));
        cons_putstr1(cons, p, finfo->size);
        memman_free_4k(memman, (int) p, finfo->size);
    } else {
        /* ファイルが見つからなかった場合 */
        cons_putstr0(cons, "File not found.\n");
    }
    cons_newline(cons);
    return;
}
void hrb_api(int edi, int esi, int ebp, int esp, int ebx, int edx, int ecx, int eax)
{
    struct CONSOLE *cons = (struct CONSOLE *) *((int *) 0x0fec);
    if (edx == 1) {
        cons_putchar(cons, eax & 0xff, 1);
    } else if (edx == 2) {
        cons_putstr0(cons, (char *) ebx);
    } else if (edx == 3) {
        cons_putstr1(cons, (char *) ebx, ecx);
    }
    return;
}

naskfunc.nas

   GLOBAL _io_hlt, _io_cli, _io_sti, _io_stihlt
        GLOBAL _io_in8,  _io_in16,  _io_in32
        GLOBAL _io_out8, _io_out16, _io_out32
        GLOBAL _io_load_eflags, _io_store_eflags
        GLOBAL _load_gdtr, _load_idtr
        GLOBAL _load_cr0, _store_cr0
        GLOBAL _load_tr
        GLOBAL _asm_inthandler20, _asm_inthandler21
        GLOBAL _asm_inthandler27, _asm_inthandler2c
        GLOBAL _memtest_sub
        GLOBAL _farjmp, _farcall
        GLOBAL _asm_hrb_api
        EXTERN _inthandler20, _inthandler21
        EXTERN _inthandler27, _inthandler2c
        EXTERN _hrb_api
_asm_hrb_api:
        STI
        PUSHAD    ; 保存のためのPUSH
        PUSHAD    ; hrb_apiに渡すためのPUSH
        CALL  _hrb_api
        ADD       ESP,32
        POPAD
        IRETD

dsctbl.c

void init_gdtidt(void)
{
    struct SEGMENT_DESCRIPTOR *gdt = (struct SEGMENT_DESCRIPTOR *) ADR_GDT;
    struct GATE_DESCRIPTOR    *idt = (struct GATE_DESCRIPTOR    *) ADR_IDT;
    int i;

    /* GDTの初期化 */
    for (i = 0; i <= LIMIT_GDT / 8; i++) {
        set_segmdesc(gdt + i, 0, 0, 0);
    }
    set_segmdesc(gdt + 1, 0xffffffff,   0x00000000, AR_DATA32_RW);
    set_segmdesc(gdt + 2, LIMIT_BOTPAK, ADR_BOTPAK, AR_CODE32_ER);
    load_gdtr(LIMIT_GDT, ADR_GDT);

    /* IDTの初期化 */
    for (i = 0; i <= LIMIT_IDT / 8; i++) {
        set_gatedesc(idt + i, 0, 0, 0);
    }
    load_idtr(LIMIT_IDT, ADR_IDT);

    /* IDTの設定 */
    set_gatedesc(idt + 0x20, (int) asm_inthandler20, 2 * 8, AR_INTGATE32);
    set_gatedesc(idt + 0x21, (int) asm_inthandler21, 2 * 8, AR_INTGATE32);
    set_gatedesc(idt + 0x27, (int) asm_inthandler27, 2 * 8, AR_INTGATE32);
    set_gatedesc(idt + 0x2c, (int) asm_inthandler2c, 2 * 8, AR_INTGATE32);
    set_gatedesc(idt + 0x40, (int) asm_hrb_api,      2 * 8, AR_INTGATE32);

    return;
}

hello2.nas

[INSTRSET "i486p"]
[BITS 32]
        MOV     EDX,2
        MOV     EBX,msg
        INT     0x40
        RETF
msg:
        DB  "hello",0

hello.nas

[INSTRSET "i486p"]
[BITS 32]
        MOV     ECX,msg
        MOV     EDX,1
putloop:
        MOV     AL,[CS:ECX]
        CMP     AL,0
        JE      fin
        INT     0x40
        ADD     ECX,1
        JMP     putloop
fin:
        RETF
msg:
        DB  "hello",0

実装過程
・ 37b33928e2fba0c8a51ab876c2f102d99cbebfc9