代码 1.kernel.asm
%include "pm.inc" org 0x9000 VRAM_ADDRESS equ 0x000a0000 jmp LABEL_BEGIN [SECTION .gdt] ; 段基址 段界限 属性 LABEL_GDT: Descriptor 0, 0, 0 LABEL_DESC_CODE32: Descriptor 0, SegCode32Len - 1, DA_C + DA_32 LABEL_DESC_VIDEO: Descriptor 0B8000h, 0ffffh, DA_DRW LABEL_DESC_VRAM: Descriptor 0, 0ffffffffh, DA_DRW LABEL_DESC_STACK: Descriptor 0, TopOfStack, DA_DRWA+DA_32 GdtLen equ $ - LABEL_GDT GdtPtr dw GdtLen - 1 dd 0 SelectorCode32 equ LABEL_DESC_CODE32 - LABEL_GDT SelectorVideo equ LABEL_DESC_VIDEO - LABEL_GDT SelectorStack equ LABEL_DESC_STACK - LABEL_GDT SelectorVram equ LABEL_DESC_VRAM - LABEL_GDT LABEL_IDT: %rep 33 Gate SelectorCode32, SpuriousHandler,0, DA_386IGate %endrep .021h: Gate SelectorCode32, KeyBoardHandler,0, DA_386IGate %rep 10 Gate SelectorCode32, SpuriousHandler,0, DA_386IGate %endrep .2CH: Gate SelectorCode32, mouseHandler,0, DA_386IGate IdtLen equ $ - LABEL_IDT IdtPtr dw IdtLen - 1 dd 0 [SECTION .s16] [BITS 16] LABEL_BEGIN: mov ax, cs mov ds, ax mov es, ax mov ss, ax mov sp, 0100h ;calculate memory ComputeMemory: mov ebx, 0 mov di, MemChkBuf .loop: mov eax, 0E820h mov ecx, 20 mov edx, 0534D4150h int 15h jc LABEL_MEM_CHK_FAIL add di, 20 inc dword [dwMCRNumber] cmp ebx, 0 jne .loop jmp LABEL_MEM_CHK_OK LABEL_MEM_CHK_FAIL: mov dword [dwMCRNumber], 0 LABEL_MEM_CHK_OK: mov al, 0x13 mov ah, 0 int 0x10 xor eax, eax mov ax, cs shl eax, 4 add eax, LABEL_SEG_CODE32 mov word [LABEL_DESC_CODE32 + 2], ax shr eax, 16 mov byte [LABEL_DESC_CODE32 + 4], al mov byte [LABEL_DESC_CODE32 + 7], ah xor eax, eax mov ax, ds shl eax, 4 add eax, LABEL_GDT mov dword [GdtPtr + 2], eax lgdt [GdtPtr] cli ;关中断 call init8259A ;prepare for loading IDT xor eax, eax mov ax, ds shl eax, 4 add eax, LABEL_IDT mov dword [IdtPtr + 2], eax lidt [IdtPtr] in al, 92h or al, 00000010b out 92h, al mov eax, cr0 or eax , 1 mov cr0, eax jmp dword SelectorCode32: 0 init8259A: mov al, 011h out 020h, al call io_delay out 0A0h, al call io_delay mov al, 020h out 021h, al call io_delay mov al, 028h out 0A1h, al call io_delay mov al, 004h out 021h, al call io_delay mov al, 002h out 0A1h, al call io_delay mov al, 001h out 021h, al call io_delay out 0A1h, al call io_delay mov al, 11111001b ;允许键盘中断 out 021h, al call io_delay mov al, 11101111b ;允许鼠标中断 out 0A1h, al call io_delay ret io_delay: nop nop nop nop ret [SECTION .s32] [BITS 32] LABEL_SEG_CODE32: ;initialize stack for c code mov ax, SelectorStack mov ss, ax mov esp, TopOfStack mov ax, SelectorVram mov ds, ax mov ax, SelectorVideo mov gs, ax sti %include "write_vga_desktop.asm" jmp $ _SpuriousHandler: SpuriousHandler equ _SpuriousHandler - $$ iretd _KeyBoardHandler: KeyBoardHandler equ _KeyBoardHandler - $$ push es push ds pushad mov eax, esp push eax call intHandlerFromC pop eax mov esp, eax popad pop ds pop es iretd _mouseHandler: mouseHandler equ _mouseHandler - $$ push es push ds pushad mov eax, esp push eax call intHandlerForMouse pop eax mov esp, eax popad pop ds pop es iretd io_hlt: ;void io_hlt(void); HLT RET io_cli: CLI RET io_sti: STI RET io_stihlt: STI HLT RET io_in8: mov edx, [esp + 4] mov eax, 0 in al, dx ret io_in16: mov edx, [esp + 4] mov eax, 0 in ax, dx ret io_in32: mov edx, [esp + 4] in eax, dx ret io_out8: mov edx, [esp + 4] mov al, [esp + 8] out dx, al ret io_out16: mov edx, [esp + 4] mov eax, [esp + 8] out dx, ax ret io_out32: mov edx, [esp + 4] mov eax, [esp + 8] out dx, eax ret io_load_eflags: pushfd pop eax ret io_store_eflags: mov eax, [esp + 4] push eax popfd ret get_memory_block_count: mov eax, [dwMCRNumber] ret %include "fontData.inc" SegCode32Len equ $ - LABEL_SEG_CODE32 MemChkBuf: times 256 db 0 dwMCRNumber: dd 0 [SECTION .gs] ALIGN 32 [BITS 32] LABEL_STACK: times 512 db 0 TopOfStack equ $ - LABEL_STACK2.write_vga_desktop.c
#define COL8_000000 0 #define COL8_FF0000 1 #define COL8_00FF00 2 #define COL8_FFFF00 3 #define COL8_0000FF 4 #define COL8_FF00FF 5 #define COL8_00FFFF 6 #define COL8_FFFFFF 7 #define COL8_C6C6C6 8 #define COL8_840000 9 #define COL8_008400 10 #define COL8_848400 11 #define COL8_000084 12 #define COL8_840084 13 #define COL8_008484 14 #define COL8_848484 15 #define PORT_KEYDAT 0x0060 #define PIC_OCW2 0x20 #define PIC1_OCW2 0xA0 void io_hlt(void); void io_cli(void); void io_sti(void); void io_out(int port, int data); int io_load_eflags(void); void io_store_eflags(int eflags); void show_char(void); void init_palette(void); void set_palette(int start, int end, unsigned char *rgb); void boxfill8(unsigned char *vram,int xsize, unsigned char c, int x, int y, int x0, int y0); struct BOOTINFO { char* vgaRam; short screenX, screenY; }; void initBootInfo(struct BOOTINFO *pBootInfo); extern char systemFont[16]; void showFont8(char *vram, int xsize, int x, int y, char c, char* font); void showString(char* vram, int xsize, int x, int y, char color, unsigned char *s ); void putblock(char* vram, int vxsize, int pxsize, int pysize, int px0, int py0, char* buf, int bxsize); void init_mouse_cursor(char* mouse, char bc); void intHandlerFromC(char* esp); static char mcursor[256]; static struct BOOTINFO bootInfo; static char keyval[5] = {'0', 'X', 0, 0, 0}; struct FIFO8 { unsigned char* buf; int p, q, size, free, flags; }; static struct FIFO8 keyinfo; static struct FIFO8 mouseinfo; static char keybuf[32]; static char mousebuf[128]; struct MOUSE_DEC { unsigned char buf[3], phase; int x, y, btn; }; static struct MOUSE_DEC mdec; void fifo8_init(struct FIFO8 *fifo, int size, unsigned char* buf); int fifo8_put(struct FIFO8 *fifo, unsigned char data); int fifo8_get(struct FIFO8 *fifo); int fifo8_status(struct FIFO8 *fifo); char charToHexVal(char c); char* charToHexStr(unsigned char c); char* intToHexStr(unsigned int d); void init_keyboard(void); void enable_mouse(struct MOUSE_DEC *mdec); void show_mouse_info(); int mouse_decode(struct MOUSE_DEC *mdec, unsigned char dat); int get_memory_block_count(void); static int mx = 0, my = 0; static int xsize = 0, ysize = 0; void CMain(void) { initBootInfo(&bootInfo); char*vram = bootInfo.vgaRam; xsize = bootInfo.screenX, ysize = bootInfo.screenY; fifo8_init(&keyinfo, 32, keybuf); fifo8_init(&mouseinfo, 128, mousebuf); init_palette(); init_keyboard(); boxfill8(vram, xsize, COL8_008484, 0, 0, xsize-1, ysize-29); boxfill8(vram, xsize, COL8_C6C6C6, 0, ysize-28, xsize-1, ysize-28); boxfill8(vram, xsize, COL8_FFFFFF, 0, ysize-27, xsize-1, ysize-27); boxfill8(vram, xsize, COL8_C6C6C6, 0, ysize-26, xsize-1, ysize-1); boxfill8(vram, xsize, COL8_FFFFFF, 3, ysize-24, 59, ysize-24); boxfill8(vram, xsize, COL8_FFFFFF, 2, ysize-24, 2, ysize-4); boxfill8(vram, xsize, COL8_848484, 3, ysize-4, 59, ysize-4); boxfill8(vram, xsize, COL8_848484, 59, ysize-23, 59, ysize-5); boxfill8(vram, xsize, COL8_000000, 2, ysize-3, 59, ysize-3); boxfill8(vram, xsize, COL8_000000, 60, ysize-24, 60, ysize-3); boxfill8(vram, xsize, COL8_848484, xsize-47, ysize-24, xsize-4, ysize-24); boxfill8(vram, xsize, COL8_848484, xsize-47, ysize-23, xsize-47, ysize-4); boxfill8(vram, xsize, COL8_FFFFFF, xsize-47, ysize-3, xsize-4, ysize-3); boxfill8(vram, xsize, COL8_FFFFFF, xsize-3, ysize-24, xsize-3, ysize-3); mx = (xsize - 16) / 2; my = (ysize - 28 - 16) / 2; init_mouse_cursor(mcursor, COL8_008484); putblock(vram, xsize, 16, 16, mx, my, mcursor, 16); int memCnt = get_memory_block_count(); char* pStr = intToHexStr(memCnt); showString(vram, xsize, 0, 0, COL8_FFFFFF, pStr); io_sti(); enable_mouse(&mdec); int data = 0; for(;;) { io_cli(); if (fifo8_status(&keyinfo) + fifo8_status(&mouseinfo) == 0) { io_stihlt(); } else if(fifo8_status(&keyinfo) != 0){ io_sti(); data = fifo8_get(&keyinfo); char* pStr = charToHexStr(data); static int showPos = 0; showString(vram, xsize, showPos, 16, COL8_FFFFFF, pStr); showPos += 32; } else if (fifo8_status(&mouseinfo) != 0) { show_mouse_info(); } } } void computeMousePosition(struct MOUSE_DEC* mdec) { mx += mdec->x; my += mdec->y; if (mx < 0) { mx = 0; } if (my < 0) { my = 0; } if (mx > xsize - 16) { mx = xsize - 16; } if (my > ysize - 16) { my = ysize - 16; } } void eraseMouse(char* vram) { boxfill8(vram, xsize, COL8_008484, mx, my, mx+15, my+15); } void drawMouse(char* vram) { putblock(vram, xsize, 16, 16, mx, my, mcursor, 16); } void show_mouse_info(void) { char*vram = bootInfo.vgaRam; unsigned char data = 0; io_sti(); data = fifo8_get(&mouseinfo); if (mouse_decode(&mdec, data) != 0) { eraseMouse(vram); computeMousePosition(&mdec); drawMouse(vram); } } void initBootInfo(struct BOOTINFO *pBootInfo) { pBootInfo->vgaRam = (char*)0xa0000; pBootInfo->screenX = 320; pBootInfo->screenY = 200; } void showString(char* vram, int xsize, int x, int y, char color, unsigned char *s ) { for (; *s != 0x00; s++) { showFont8(vram, xsize, x, y,color, systemFont+ *s * 16); x += 8; } } void init_palette(void) { static unsigned char table_rgb[16 *3] = { 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0xff, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc6, 0xc6, 0xc6, 0x84, 0x00, 0x00, 0x00, 0x84, 0x00, 0x84, 0x84, 0x00, 0x00, 0x00, 0x84, 0x84, 0x00, 0x84, 0x00, 0x84, 0x84, 0x84, 0x84, 0x84, }; set_palette(0, 15, table_rgb); return; } void set_palette(int start, int end, unsigned char* rgb) { int i, eflags; eflags = io_load_eflags(); io_cli(); io_out8(0x03c8, start); //set palette number for (i = start; i <=end; i++ ) { io_out8(0x03c9, rgb[0] / 4); io_out8(0x03c9, rgb[1] / 4); io_out8(0x03c9, rgb[2] / 4); rgb += 3; } io_store_eflags(eflags); return; } void boxfill8(unsigned char* vram, int xsize, unsigned char c, int x0, int y0, int x1, int y1) { int x, y; for (y = y0; y <= y1; y++) for (x = x0; x <= x1; x++) { vram[y * xsize + x] = c; } } void showFont8(char *vram, int xsize, int x, int y, char c, char* font) { int i; char d; for (i = 0; i < 16; i++) { d = font[i]; if ((d & 0x80) != 0) {vram[(y+i)*xsize + x + 0] = c;} if ((d & 0x40) != 0) {vram[(y+i)*xsize + x + 1] = c;} if ((d & 0x20) != 0) {vram[(y+i)*xsize + x + 2] = c;} if ((d & 0x10) != 0) {vram[(y+i)*xsize + x + 3] = c;} if ((d & 0x08) != 0) {vram[(y+i)*xsize + x + 4] = c;} if ((d & 0x04) != 0) {vram[(y+i)*xsize + x + 5] = c;} if ((d & 0x02) != 0) {vram[(y+i)*xsize + x + 6] = c;} if ((d & 0x01) != 0) {vram[(y+i)*xsize + x + 7] = c;} } } void init_mouse_cursor(char* mouse, char bc) { static char cursor[16][16] = { "**************..", "*OOOOOOOOOOO*...", "*OOOOOOOOOO*....", "*OOOOOOOOO*.....", "*OOOOOOOO*......", "*OOOOOOO*.......", "*OOOOOOO*.......", "*OOOOOOOO*......", "*OOOO**OOO*.....", "*OOO*..*OOO*....", "*OO*....*OOO*...", "*O*......*OOO*..", "**........*OOO*.", "*..........*OOO*", "............*OO*", ".............***" }; int x, y; for (y = 0; y < 16; y++) { for (x = 0; x < 16; x++) { if (cursor[y][x] == '*') { mouse[y*16 + x] = COL8_000000; } if (cursor[y][x] == 'O') { mouse[y*16 + x] = COL8_FFFFFF; } if (cursor[y][x] == '.') { mouse[y*16 + x] = bc; } } } } void putblock(char* vram, int vxsize, int pxsize, int pysize, int px0, int py0, char* buf, int bxsize) { int x, y; for (y = 0; y < pysize; y++) for (x = 0; x < pxsize; x++) { vram[(py0+y) * vxsize + (px0+x)] = buf[y * bxsize + x]; } } void intHandlerFromC(char* esp) { char*vram = bootInfo.vgaRam; int xsize = bootInfo.screenX, ysize = bootInfo.screenY; io_out8(PIC_OCW2, 0x20); unsigned char data = 0; data = io_in8(PORT_KEYDAT); fifo8_put(&keyinfo, data); return; } char charToHexVal(char c) { if (c >= 10) { return 'A' + c - 10; } return '0' + c; } char* charToHexStr(unsigned char c) { int i = 0; char mod = c % 16; keyval[3] = charToHexVal(mod); c = c / 16; keyval[2] = charToHexVal(c); return keyval; } char* intToHexStr(unsigned int d) { static char str[11]; str[0] = '0'; str[1] = 'X'; str[10] = 0; int i = 2; for(; i < 10; i++) { str[i] = '0'; } int p = 9; while (p > 1 && d > 0) { int e = d % 16; d /= 16; if (e >= 10) { str[p] = 'A' + e - 10; } else { str[p] = '0' + e; } p--; } return str; } #define PORT_KEYDAT 0x0060 #define PORT_KEYSTA 0x0064 #define PORT_KEYCMD 0x0064 #define KEYSTA_SEND_NOTREADY 0x02 #define KEYCMD_WRITE_MODE 0x60 #define KBC_MODE 0x47 void wait_KBC_sendready() { for(;;) { if ((io_in8(PORT_KEYSTA) & KEYSTA_SEND_NOTREADY) == 0) { break; } } } void init_keyboard(void) { wait_KBC_sendready(); io_out8(PORT_KEYCMD, KEYCMD_WRITE_MODE); wait_KBC_sendready(); io_out8(PORT_KEYDAT, KBC_MODE); return; } #define KEYCMD_SENDTO_MOUSE 0xd4 #define MOUSECMD_ENABLE 0xf4 void enable_mouse(struct MOUSE_DEC* mdec) { wait_KBC_sendready(); io_out8(PORT_KEYCMD, KEYCMD_SENDTO_MOUSE); wait_KBC_sendready(); io_out8(PORT_KEYDAT, MOUSECMD_ENABLE); mdec->phase = 0; return; } void intHandlerForMouse(char* esp) { unsigned char data; io_out8(PIC1_OCW2, 0x20); io_out8(PIC_OCW2, 0x20); data = io_in8(PORT_KEYDAT); fifo8_put(&mouseinfo, data); } void fifo8_init(struct FIFO8 *fifo, int size, unsigned char *buf) { fifo->size = size; fifo->buf = buf; fifo->free = size; fifo->flags = 0; fifo->p = 0; fifo->q = 0; return ; } #define FLAGS_OVERRUN 0x0001 int fifo8_put(struct FIFO8 *fifo, unsigned char data) { if (fifo->free ==0) { fifo->flags |= FLAGS_OVERRUN; return -1; } fifo->buf[fifo->p] = data; fifo->p++; if (fifo->p == fifo->size) { fifo->p = 0; } fifo->free--; return 0; } int fifo8_get(struct FIFO8 *fifo) { int data; if (fifo->free == fifo->size) { return -1; } data = fifo->buf[fifo->q]; fifo->q++; if (fifo->q == fifo->size) { fifo->q = 0; } fifo->free++; return data; } int fifo8_status(struct FIFO8 *fifo) { return fifo->size - fifo->free; } int mouse_decode(struct MOUSE_DEC *mdec, unsigned char dat) { if (mdec->phase == 0) { if (dat == 0xfa) { mdec->phase = 1; } return 0; } if (mdec->phase == 1) { if ((dat & 0xc8) == 0x08) { mdec->buf[0] = dat; mdec->phase = 2; } return 0; } if (mdec->phase == 2) { mdec->buf[1] = dat; mdec->phase = 3; return 0; } if (mdec->phase == 3) { mdec->buf[2] = dat; mdec->phase = 1; mdec->btn = mdec->buf[0] & 0x07; mdec->x = mdec->buf[1]; mdec->y = mdec->buf[2]; if ((mdec->buf[0] & 0x10) != 0) { mdec->x |= 0xffffff00; } if ((mdec->buf[0] & 0x20) != 0) { mdec->y |= 0xffffff00; } mdec->y = -mdec->y; return 1; } return -1; }分析 本节是为后面的内存管理做准备的,程序是通过中断15h来实现的,但是方法不止这一个。看代码的ComputeMemory:处,因为在调用中断15h之前,需要设置一些寄存器。在第一次调用时ebx必须为0。es:di指向一个地址范围描述符结构ARDS(Address Range Descriptor Structure),BIOS将会填充此结构。 ARDS结构如下图: MemChkBuf是一块256字节的缓冲区,在程序的下面有定义,里面存储着内存段的大小和一些其他的信息,进入循环,一但ebx为零或CF被置位,循环结束。int 15h的执行,需要ax值来决定,我们想要获取内存信息,ax赋值为0E820h,ecx是es:di所指向的地址范围描述符结构的大小,以字节为单位。通常情况下无论ecx为多大,BIOS只填充20字节。edx寄存器的值设置为0534D4150h(‘SMAP’)。寄存器di的值将会递增,每次增加20字节。每次循环让dwMCRNumber的值加1,它就是地址范围描述符结构的个数。函数get_memory_block_count是汇编导出给c语言的接口。 c代码主要是在屏幕上用16进制打印内存的大小,intToHexStr函数将32位整型数转换为16进制的字符串。 运行结果:
