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; }
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);
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