首先我们先展示一下第四天的成果:
图一:显示纯色
图二:显示格子
图三:使用调色板显示格子
图四:画正方形
最后的图为一个小界面:
第四天的内容其实不难,但是由于前三天写的代码部分有问题,导致今天调试了一天才找到问题所在问题的更正已经在下面的源文件中指出。
代码中唯一没有指出的是Makefile文件中的溢出小错误,将文件名字写错啦具体为:
naskfunc.obj: naskfunc.nas Makefile
$(NASK) naskfunc.nas naskfunc.obj naskfunc.lst
应该改为:
ucan23.sys: ucan23.bin bootpack.hrb Makefile
copy /B ucan23.bin+bootpack.hrb ucan23.sys
下面是程序的源码:naskfunc.nas
; naskfunc
; TAB=4
[FORMAT "WCOFF"]
[INSTRSET "i486p"]
[BITS 32]
[FILE "naskfunc.nas"]
GLOBAL _io_hlt,_write_mem8
GLOBAL _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
[SECTION .text]
_io_hlt: ; void io_hlt(void);
HLT
RET
_write_mem8: ; void write_mem8(int addr, int data);
MOV ECX,[ESP+4] ;
MOV AL,[ESP+8] ;
MOV [ECX],AL
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_in18: ;int io_in16(int port);
MOV EDX, [ESP+4]
MOV EAX, 0
IN AX, DX
RET
_io_in32: ;io_in32(int port);
MOV EDX, [ESP+4]
IN EAX, DX
RET
_io_out8: ;io_out8(int port, int data);
MOV EDX, [ESP+4] ;PORT
MOV AL, [ESP+8] ;DATA
OUT DX, AL
RET
_io_out16: ;io_out16(int port, int data);
MOV EDX, [ESP+4]
MOV EAX, [ESP+8]
OUT DX, AX
_io_out32: ;io_out32(int port, int data);
MOV EDX, [ESP+4]
MOV EAX, [ESP+8]
OUT DX, EAX
RET
_io_load_eflags: ;io_load_eflags(int eflags);
PUSHFD
POP EAX
RET
_io_store_eflags: ;io_store_eflags(int eflags);
MOV EAX, [ESP+4]
PUSH EAX
POPFD
RET
文件ucan23ipl.nas修正后的代码:
; ucan23-os
; TAB-4
; 本程序前一版本存在的错误将CMP DH, 2写成了CMP CH, 2
CYLS EQU 10
ORG 0x7c00 ;指明程序的装载地址
; 以下这段是标准FAT12格式软盘专用的代码
JMP entry
DB 0x90
DB "UCAN23LD" ;启动区的名称可以是任意的字符串(8字节)
DW 512 ;每个扇区的大小
DB 1 ;簇的大小
DW 1
DB 2
DW 224
DW 2880
DB 0xf0
DW 9
DW 18
DW 2
DD 0
DD 2880
DB 0,0,0x29
DD 0xffffffff
DB "UCAN23-OS "
DB "FAT12 "
RESB 18
;程序主体
entry:
MOV AX, 0 ;初始化寄存器
MOV SS, AX
MOV SP, 0x7c00
MOV DS, AX
;读磁盘
MOV AX, 0x0820
MOV ES, AX
MOV CH, 0
MOV DH, 0
MOV CL, 2
readloop:
MOV SI, 0 ;记录失败次数的寄存器
retry:
MOV AH, 0x02
MOV AL, 1
MOV BX, 0
MOV DL, 0x00
INT 0x13
JNC next
ADD SI, 1
CMP SI, 5
JAE error
MOV AH, 0x00
MOV DL, 0x00
INT 0x13
JMP retry
;JMP error
next:
MOV AX, ES
ADD AX, 0x0020
MOV ES, AX
ADD CL, 1
CMP CL, 18
JBE readloop
MOV CL, 1
ADD DH, 1
CMP DH, 2
JB readloop
MOV DH, 0
ADD CH, 1
CMP CH, CYLS
JB readloop
MOV [0x0ff0], CH
JMP 0xc200
error:
MOV SI, msg
putloop:
MOV AL, [SI]
ADD SI, 1
CMP AL, 0
JE fin
MOV AH, 0x0e
MOV BX, 15
INT 0x10
JMP putloop
fin:
HLT
JMP fin
;信息显示部分
msg:
DB 0x0a, 0x0a ;2个换行
DB "Hello, world(ucan23)"
DB 0x0a
DB "This is my first OS"
DB 0x0a
DB "Copyright GPL"
DB 0x0a
DB "Author: ucan23(Howard)"
DB 0x0a
DB "Blog:http://blog.sina.com/rjxx007"
DB 0x0a
DB "Blog:http://blog.csdn.net/ucan23"
DB 0x0a
DB 0
RESB 0x7dfe-$
DB 0x55, 0xaa
bootpack.c文件源码
/*告诉C编译器,有一个函数在别的文件里*/
void io_hlt(void);
void io_cli(void);
void io_out8(int port, int data);
int io_load_eflags(void);
void io_store_eflags(int eflags);
void write_mem8(int addr, int data);
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 x0, int y0, int x1, int y1);
#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
void UcanMain(void)
{
//int i;
char *p;
init_palette();
p = (char *) 0xa0000;
/*for (i=0x0000; i<=0xffff; i++){
//write_mem8(i,i&0x0f);
//write_mem8(i,9);
//p = (char *)i;
//*p = i & 0x0f;
//*((char *)i) = i & 0x0f;
(p[i]) = i & 0x0f;
}
*///END FOR
boxfill8(p, 320, COL8_FF0000, 20, 20, 120, 120);
boxfill8(p, 320, COL8_00FF00, 70, 50, 170, 150);
boxfill8(p, 320, COL8_0000FF, 120, 80, 220, 180);
for (;;){
io_hlt(); /*执行nashfunc.nas里的_io_hlt*/
}
}
void init_palette(void)
{
/*初始化调色板函数的实现*/
static unsigned char table_rgb[16*3] = {
0x00, 0x00, 0x00, /* 0:黑*/
0xff, 0x00, 0x00, /* 1:亮红 */
0x00, 0xff, 0x00, /* 2:亮绿 */
0xff, 0xff, 0x00, /* 3:亮黄 */
0x00, 0x00, 0xff, /* 4:亮蓝 */
0xff, 0x00, 0xff, /* 5:亮紫 */
0x00, 0xff, 0xff, /* 6:浅亮蓝 */
0xff, 0xff, 0xff, /* 7:白 */
0xc6, 0xc6, 0xc6, /* 8:亮灰 */
0x84, 0x00, 0x00, /* 9:暗红 */
0x00, 0x84, 0x00, /* 10:暗绿 */
0x84, 0x84, 0x00, /* 11:暗黄 */
0x00, 0x00, 0x84, /* 12:暗青 */
0x84, 0x00, 0x84, /* 13:暗紫 */
0x00, 0x84, 0x84, /* 14:浅暗蓝 */
0x84, 0x84, 0x84 /* 15:暗灰 */
};
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);
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;
}
}
return;
}
ucan23.nas文件源码
; ucan23-os boot asm
; TAB=4
; 此程序前一个版本存在的错误:将skip写成了ship
; 将[INSTRSET "i486p"]写成了[INSTREST "i486p"]
; 将waitkbdout写成了waitkdbout
BOTPAK EQU 0x00280000
DSKCAC EQU 0x00100000
DSKCAC0 EQU 0x00008000
; 有关BOOT_INFO
CYLS EQU 0x0ff0
LEDS EQU 0x0ff1
VMODE EQU 0x0ff2
SCRNX EQU 0x0ff4
SCRNY EQU 0x0ff6
VRAM EQU 0x0ff8
ORG 0xc200
MOV AL, 0x13
MOV AH, 0x00
INT 0x10
MOV BYTE [VMODE], 8
MOV WORD [SCRNX], 320
MOV WORD [SCRNY], 200
MOV DWORD [VRAM], 0x000a0000
; 用BIOS获取LED指示灯的状态
MOV AH, 0x02
INT 0x16 ; keyboard BIOS
MOV [LEDS], AL
MOV AL, 0xff
OUT 0x21, AL
NOP
OUT 0xa1, AL
CLI
CALL waitkbdout
MOV AL, 0xd1
OUT 0x64, AL
CALL waitkbdout
MOV AL, 0xdf
OUT 0x60, AL
CALL waitkbdout
[INSTRSET "i486p"]
LGDT [GDTR0]
MOV EAX,CR0
AND EAX, 0x7fffffff
OR EAX, 0x00000001
MOV CR0, EAX
JMP pipelineflush
pipelineflush:
MOV AX, 1*8
MOV DS, AX
MOV ES, AX
MOV FS, AX
MOV GS, AX
MOV SS, AX
MOV ESI, bootpack
MOV EDI, BOTPAK
MOV ECX, 512*1024/4
CALL memcpy
MOV ESI, 0x7c00
MOV EDI, DSKCAC
MOV ECX, 512/4
CALL memcpy
MOV ESI, DSKCAC0+512
MOV EDI, DSKCAC+512
MOV ECX, 0
MOV CL, BYTE [CYLS]
IMUL ECX, 512*18*2/4
SUB ECX, 512/4
CALL memcpy
MOV EBX, BOTPAK
MOV ECX, [EBX+16]
ADD ECX, 3
SHR ECX, 2
JZ skip
MOV ESI, [EBX+20]
ADD ESI, EBX
MOV EDI, [EBX+12]
CALL memcpy
skip:
MOV ESP, [EBX+12]
JMP DWORD 2*8:0x0000001b
waitkbdout:
IN AL, 0x64
AND AL, 0x02
JNZ waitkbdout
RET
memcpy:
MOV EAX, [ESI]
ADD ESI, 4
MOV [EDI], EAX
ADD EDI, 4
SUB ECX, 1
JNZ memcpy
RET
ALIGNB 16
GDT0:
RESB 8
DW 0xffff,0x0000,0x9200,0x00cf
DW 0xffff,0x0000,0x9a28,0x0047
DW 0
GDTR0:
DW 8*3-1
DD GDT0
ALIGNB 16
bootpack: