代码
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_STACK
2.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进制的字符串。
运行结果: