たなしょのメモ

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

OS作成奮闘記day25

本では21日目に突入しました。
文字列表示APIを作成します。
console.c

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);
        *((int *) 0xfe8) = (int) p;
        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;
}

void hrb_api(int edi, int esi, int ebp, int esp, int ebx, int edx, int ecx, int eax)
{
    int cs_base = *((int *) 0xfe8);
    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 + cs_base);
    } else if (edx == 3) {
        cons_putstr1(cons, (char *) ebx + cs_base, ecx);
    }
    return;
}

C言語でアプリケーションを作成してみたいと思います。
a.c

void api_putchar(int c);

void HariMain(void)
{
    api_putchar('A');
    return;
}

a_nask.nas

[FORMAT "WCOFF"]                ; オブジェクトファイルを作るモード
[INSTRSET "i486p"]                ; 486の命令まで使いたいという記述
[BITS 32]                       ; 32ビットモード用の機械語を作らせる
[FILE "a_nask.nas"]             ; ソースファイル名情報

        GLOBAL  _api_putchar

[SECTION .text]

_api_putchar:   ; void api_putchar(int c);
        MOV     EDX,1
        MOV     AL,[ESP+4]      ; c
        INT     0x40
        RET

Makefile

a.bim : a.obj a_nask.obj Makefile
    $(OBJ2BIM) @$(RULEFILE) out:a.bim map:a.map a.obj a_nask.obj

a.hrb : a.bim Makefile
    $(BIM2HRB) a.bim a.hrb 0

hello3.bim : hello3.obj a_nask.obj Makefile
    $(OBJ2BIM) @$(RULEFILE) out:hello3.bim map:hello3.map hello3.obj a_nask.obj

hello3.hrb : hello3.bim Makefile
    $(BIM2HRB) hello3.bim hello3.hrb 0

haribote.img : ipl10.bin haribote.sys Makefile \
        hello.hrb hello2.hrb a.hrb hello3.hrb
    $(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:@: \
        copy from:a.hrb to:@: \
        copy from:hello3.hrb to:@: \
        imgout:haribote.img

# rules

%.gas : %.c bootpack.h Makefile
    $(CC1) -o $*.gas $*.c

%.nas : %.gas Makefile
    $(GAS2NASK) $*.gas $*.nas

%.obj : %.nas Makefile
    $(NASK) $*.nas $*.obj $*.lst

# command

img :
    $(MAKE) haribote.img

run :
    $(MAKE) img
    $(COPY) haribote.img ..\..\z_tools\qemu\fdimage0.bin
    $(MAKE) -C ..\..\z_tools\qemu

install :
    $(MAKE) img
    $(IMGTOL) w a: haribote.img

clean :
    -$(DEL) *.bin
    -$(DEL) *.lst
    -$(DEL) *.obj
    -$(DEL) *.map
    -$(DEL) *.bim
    -$(DEL) *.hrb
    -$(DEL) haribote.sys

hello3.c

void api_putchar(int c);

void HariMain(void)
{
    api_putchar('h');
    api_putchar('e');
    api_putchar('l');
    api_putchar('l');
    api_putchar('o');
    return;
}

console.c

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);
        *((int *) 0xfe8) = (int) p;
        file_loadfile(finfo->clustno, finfo->size, p, fat, (char *) (ADR_DISKIMG + 0x003e00));
        set_segmdesc(gdt + 1003, finfo->size - 1, (int) p, AR_CODE32_ER);
        if (finfo->size >= 8 && strncmp(p + 4, "Hari", 4) == 0) {
            p[0] = 0xe8;
            p[1] = 0x16;
            p[2] = 0x00;
            p[3] = 0x00;
            p[4] = 0x00;
            p[5] = 0xcb;
        }
        farcall(0, 1003 * 8);
        memman_free_4k(memman, (int) p, finfo->size);
        cons_newline(cons);
        return 1;
    }
    /* ファイルが見つからなかった場合 */
    return 0;
}

osを破壊してみるモジュールを作ってみます。
Makefile

crack1.bim : crack1.obj Makefile
    $(OBJ2BIM) @$(RULEFILE) out:crack1.bim map:crack1.map crack1.obj

crack1.hrb : crack1.bim Makefile
    $(BIM2HRB) crack1.bim crack1.hrb 0

haribote.img : ipl10.bin haribote.sys Makefile \
        hello.hrb hello2.hrb a.hrb hello3.hrb crack1.hrb
    $(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:@: \
        copy from:a.hrb to:@: \
        copy from:hello3.hrb to:@: \
        copy from:crack1.hrb to:@: \
        imgout:haribote.img

crack1.c

void HariMain(void)
{
    *((char *) 0x00102600) = 0;
    return;
}

アプリがOSの管理用のメモリにアクセスしないように改造します。 console.c

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, *q;
    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);
        q = (char *) memman_alloc_4k(memman, 64 * 1024);
        *((int *) 0xfe8) = (int) p;
        file_loadfile(finfo->clustno, finfo->size, p, fat, (char *) (ADR_DISKIMG + 0x003e00));
        set_segmdesc(gdt + 1003, finfo->size - 1, (int) p, AR_CODE32_ER);
        set_segmdesc(gdt + 1004, 64 * 1024 - 1,   (int) q, AR_DATA32_RW);
        if (finfo->size >= 8 && strncmp(p + 4, "Hari", 4) == 0) {
            p[0] = 0xe8;
            p[1] = 0x16;
            p[2] = 0x00;
            p[3] = 0x00;
            p[4] = 0x00;
            p[5] = 0xcb;
        }
        start_app(0, 1003 * 8, 64 * 1024, 1004 * 8);
        memman_free_4k(memman, (int) p, finfo->size);
        memman_free_4k(memman, (int) q, 64 * 1024);
        cons_newline(cons);
        return 1;
    }
    /* ファイルが見つからなかった場合 */
    return 0;
}

naskfunc.nas

; naskfunc
; TAB=4

[FORMAT "WCOFF"]              ; オブジェクトファイルを作るモード 
[INSTRSET "i486p"]                ; 486の命令まで使いたいという記述
[BITS 32]                        ; 32ビットモード用の機械語を作らせる
[FILE "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, _start_app
        EXTERN _inthandler20, _inthandler21
        EXTERN _inthandler27, _inthandler2c
        EXTERN _hrb_api

[SECTION .text]

_io_hlt: ; void io_hlt(void);
        HLT
        RET

_io_cli: ; void io_cli(void);
        CLI
        RET

_io_sti: ; void io_sti(void);
        STI
        RET

_io_stihlt:  ; void io_stihlt(void);
        STI
        HLT
        RET

_io_in8: ; int io_in8(int port);
        MOV       EDX,[ESP+4]        ; port
        MOV       EAX,0
        IN        AL,DX
        RET

_io_in16:    ; int io_in16(int port);
        MOV       EDX,[ESP+4]        ; port
        MOV       EAX,0
        IN        AX,DX
        RET

_io_in32:    ; int io_in32(int port);
        MOV       EDX,[ESP+4]        ; port
        IN        EAX,DX
        RET

_io_out8:    ; void io_out8(int port, int data);
        MOV       EDX,[ESP+4]        ; port
        MOV       AL,[ESP+8]     ; data
        OUT       DX,AL
        RET

_io_out16:   ; void io_out16(int port, int data);
        MOV       EDX,[ESP+4]        ; port
        MOV       EAX,[ESP+8]        ; data
        OUT       DX,AX
        RET

_io_out32:   ; void io_out32(int port, int data);
        MOV       EDX,[ESP+4]        ; port
        MOV       EAX,[ESP+8]        ; data
        OUT       DX,EAX
        RET

_io_load_eflags: ; int io_load_eflags(void);
        PUSHFD        ; PUSH EFLAGS という意味
        POP       EAX
        RET

_io_store_eflags:    ; void io_store_eflags(int eflags);
        MOV       EAX,[ESP+4]
        PUSH  EAX
        POPFD     ; POP EFLAGS という意味
        RET

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

_load_idtr:      ; void load_idtr(int limit, int addr);
        MOV       AX,[ESP+4]     ; limit
        MOV       [ESP+6],AX
        LIDT  [ESP+6]
        RET

_load_cr0:       ; int load_cr0(void);
        MOV       EAX,CR0
        RET

_store_cr0:      ; void store_cr0(int cr0);
        MOV       EAX,[ESP+4]
        MOV       CR0,EAX
        RET

_load_tr:        ; void load_tr(int tr);
        LTR       [ESP+4]            ; tr
        RET

_asm_inthandler20:
        PUSH  ES
        PUSH  DS
        PUSHAD
        MOV       AX,SS
        CMP       AX,1*8
        JNE       .from_app
;  OSが動いているときに割り込まれたのでほぼ今までどおり
        MOV       EAX,ESP
        PUSH  SS              ; 割り込まれたときのSSを保存
        PUSH  EAX             ; 割り込まれたときのESPを保存
        MOV       AX,SS
        MOV       DS,AX
        MOV       ES,AX
        CALL  _inthandler20
        ADD       ESP,8
        POPAD
        POP       DS
        POP       ES
        IRETD
.from_app:
;  アプリが動いているときに割り込まれた
        MOV       EAX,1*8
        MOV       DS,AX           ; とりあえずDSだけOS用にする
        MOV       ECX,[0xfe4]        ; OSのESP
        ADD       ECX,-8 
        MOV       [ECX+4],SS     ; 割り込まれたときのSSを保存
        MOV       [ECX  ],ESP     ; 割り込まれたときのESPを保存
        MOV       SS,AX
        MOV       ES,AX
        MOV       ESP,ECX
        CALL  _inthandler20
        POP       ECX
        POP       EAX
        MOV       SS,AX           ; SSをアプリ用に戻す
        MOV       ESP,ECX         ; ESPもアプリ用に戻す
        POPAD
        POP       DS
        POP       ES
        IRETD

_asm_inthandler21:
        PUSH  ES
        PUSH  DS
        PUSHAD
        MOV       AX,SS
        CMP       AX,1*8
        JNE       .from_app
;  OSが動いているときに割り込まれたのでほぼ今までどおり
        MOV       EAX,ESP
        PUSH  SS              ; 割り込まれたときのSSを保存
        PUSH  EAX             ; 割り込まれたときのESPを保存
        MOV       AX,SS
        MOV       DS,AX
        MOV       ES,AX
        CALL  _inthandler21
        ADD       ESP,8
        POPAD
        POP       DS
        POP       ES
        IRETD
.from_app:
;  アプリが動いているときに割り込まれた
        MOV       EAX,1*8
        MOV       DS,AX           ; とりあえずDSだけOS用にする
        MOV       ECX,[0xfe4]        ; OSのESP
        ADD       ECX,-8
        MOV       [ECX+4],SS     ; 割り込まれたときのSSを保存
        MOV       [ECX  ],ESP     ; 割り込まれたときのESPを保存
        MOV       SS,AX
        MOV       ES,AX
        MOV       ESP,ECX
        CALL  _inthandler21
        POP       ECX
        POP       EAX
        MOV       SS,AX           ; SSをアプリ用に戻す
        MOV       ESP,ECX         ; ESPもアプリ用に戻す
        POPAD
        POP       DS
        POP       ES
        IRETD

_asm_inthandler27:
        PUSH  ES
        PUSH  DS
        PUSHAD
        MOV       AX,SS
        CMP       AX,1*8
        JNE       .from_app
;  OSが動いているときに割り込まれたのでほぼ今までどおり
        MOV       EAX,ESP
        PUSH  SS              ; 割り込まれたときのSSを保存
        PUSH  EAX             ; 割り込まれたときのESPを保存
        MOV       AX,SS
        MOV       DS,AX
        MOV       ES,AX
        CALL  _inthandler27
        ADD       ESP,8
        POPAD
        POP       DS
        POP       ES
        IRETD
.from_app:
;  アプリが動いているときに割り込まれた
        MOV       EAX,1*8
        MOV       DS,AX           ; とりあえずDSだけOS用にする
        MOV       ECX,[0xfe4]        ; OSのESP
        ADD       ECX,-8
        MOV       [ECX+4],SS     ; 割り込まれたときのSSを保存
        MOV       [ECX  ],ESP     ; 割り込まれたときのESPを保存
        MOV       SS,AX
        MOV       ES,AX
        MOV       ESP,ECX
        CALL  _inthandler27
        POP       ECX
        POP       EAX
        MOV       SS,AX           ; SSをアプリ用に戻す
        MOV       ESP,ECX         ; ESPもアプリ用に戻す
        POPAD
        POP       DS
        POP       ES
        IRETD

_asm_inthandler2c:
        PUSH  ES
        PUSH  DS
        PUSHAD
        MOV       AX,SS
        CMP       AX,1*8
        JNE       .from_app
;  OSが動いているときに割り込まれたのでほぼ今までどおり
        MOV       EAX,ESP
        PUSH  SS              ; 割り込まれたときのSSを保存
        PUSH  EAX             ; 割り込まれたときのESPを保存
        MOV       AX,SS
        MOV       DS,AX
        MOV       ES,AX
        CALL  _inthandler2c
        ADD       ESP,8
        POPAD
        POP       DS
        POP       ES
        IRETD
.from_app:
;  アプリが動いているときに割り込まれた
        MOV       EAX,1*8
        MOV       DS,AX           ; とりあえずDSだけOS用にする
        MOV       ECX,[0xfe4]        ; OSのESP
        ADD       ECX,-8
        MOV       [ECX+4],SS     ; 割り込まれたときのSSを保存
        MOV       [ECX  ],ESP     ; 割り込まれたときのESPを保存
        MOV       SS,AX
        MOV       ES,AX
        MOV       ESP,ECX
        CALL  _inthandler2c
        POP       ECX
        POP       EAX
        MOV       SS,AX           ; SSをアプリ用に戻す
        MOV       ESP,ECX         ; ESPもアプリ用に戻す
        POPAD
        POP       DS
        POP       ES
        IRETD

_memtest_sub:    ; unsigned int memtest_sub(unsigned int start, unsigned int end)
        PUSH  EDI                     ; (EBX, ESI, EDI も使いたいので)
        PUSH  ESI
        PUSH  EBX
        MOV       ESI,0xaa55aa55         ; pat0 = 0xaa55aa55;
        MOV       EDI,0x55aa55aa         ; pat1 = 0x55aa55aa;
        MOV       EAX,[ESP+12+4]            ; i = start;
mts_loop:
        MOV       EBX,EAX
        ADD       EBX,0xffc              ; p = i + 0xffc;
        MOV       EDX,[EBX]               ; old = *p;
        MOV       [EBX],ESI               ; *p = pat0;
        XOR       DWORD [EBX],0xffffffff    ; *p ^= 0xffffffff;
        CMP       EDI,[EBX]               ; if (*p != pat1) goto fin;
        JNE       mts_fin
        XOR       DWORD [EBX],0xffffffff    ; *p ^= 0xffffffff;
        CMP       ESI,[EBX]               ; if (*p != pat0) goto fin;
        JNE       mts_fin
        MOV       [EBX],EDX               ; *p = old;
        ADD       EAX,0x1000             ; i += 0x1000;
        CMP       EAX,[ESP+12+8]            ; if (i <= end) goto mts_loop;
        JBE       mts_loop
        POP       EBX
        POP       ESI
        POP       EDI
        RET
mts_fin:
        MOV       [EBX],EDX               ; *p = old;
        POP       EBX
        POP       ESI
        POP       EDI
        RET

_farjmp:     ; void farjmp(int eip, int cs);
        JMP       FAR    [ESP+4]                ; eip, cs
        RET

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

_asm_hrb_api:
        ; 都合のいいことに最初から割り込み禁止になっている
        PUSH  DS
        PUSH  ES
        PUSHAD        ; 保存のためのPUSH
        MOV       EAX,1*8
        MOV       DS,AX           ; とりあえずDSだけOS用にする
        MOV       ECX,[0xfe4]        ; OSのESP
        ADD       ECX,-40
        MOV       [ECX+32],ESP   ; アプリのESPを保存
        MOV       [ECX+36],SS        ; アプリのSSを保存

; PUSHADした値をシステムのスタックにコピーする
        MOV       EDX,[ESP   ]
        MOV       EBX,[ESP+ 4]
        MOV       [ECX   ],EDX    ; hrb_apiに渡すためコピー
        MOV       [ECX+ 4],EBX   ; hrb_apiに渡すためコピー
        MOV       EDX,[ESP+ 8]
        MOV       EBX,[ESP+12]
        MOV       [ECX+ 8],EDX   ; hrb_apiに渡すためコピー
        MOV       [ECX+12],EBX   ; hrb_apiに渡すためコピー
        MOV       EDX,[ESP+16]
        MOV       EBX,[ESP+20]
        MOV       [ECX+16],EDX   ; hrb_apiに渡すためコピー
        MOV       [ECX+20],EBX   ; hrb_apiに渡すためコピー
        MOV       EDX,[ESP+24]
        MOV       EBX,[ESP+28]
        MOV       [ECX+24],EDX   ; hrb_apiに渡すためコピー
        MOV       [ECX+28],EBX   ; hrb_apiに渡すためコピー

        MOV       ES,AX           ; 残りのセグメントレジスタもOS用にする
        MOV       SS,AX
        MOV       ESP,ECX
        STI           ; やっと割り込み許可

        CALL  _hrb_api

        MOV       ECX,[ESP+32]   ; アプリのESPを思い出す
        MOV       EAX,[ESP+36]   ; アプリのSSを思い出す
        CLI
        MOV       SS,AX
        MOV       ESP,ECX
        POPAD
        POP       ES
        POP       DS
        IRETD     ; この命令が自動でSTIしてくれる

_start_app:      ; void start_app(int eip, int cs, int esp, int ds);
        PUSHAD        ; 32ビットレジスタを全部保存しておく
        MOV       EAX,[ESP+36]   ; アプリ用のEIP
        MOV       ECX,[ESP+40]   ; アプリ用のCS
        MOV       EDX,[ESP+44]   ; アプリ用のESP
        MOV       EBX,[ESP+48]   ; アプリ用のDS/SS
        MOV       [0xfe4],ESP        ; OS用のESP
        CLI           ; 切り替え中に割り込みが起きてほしくないので禁止
        MOV       ES,BX
        MOV       SS,BX
        MOV       DS,BX
        MOV       FS,BX
        MOV       GS,BX
        MOV       ESP,EDX
        STI           ; 切り替え完了なので割り込み可能に戻す
        PUSH  ECX             ; far-CALLのためにPUSH(cs)
        PUSH  EAX             ; far-CALLのためにPUSH(eip)
        CALL  FAR [ESP]      ; アプリを呼び出す

;  アプリが終了するとここに帰ってくる

        MOV       EAX,1*8           ; OS用のDS/SS
        CLI           ; また切り替えるので割り込み禁止
        MOV       ES,AX
        MOV       SS,AX
        MOV       DS,AX
        MOV       FS,AX
        MOV       GS,AX
        MOV       ESP,[0xfe4]
        STI           ; 切り替え完了なので割り込み可能に戻す
        POPAD ; 保存しておいたレジスタを回復
        RET

bootpack.h

void asm_hrb_api(void);
void start_app(int eip, int cs, int esp, int ds);

crack1を打って壊した後もdirは出るようになりました。

実装過程
・ 9511499fa63c8d419d2ab85490516a65efb270b7