首先我设计一个简单的mian.c,打开中断然后进入死循环。
#define sti() __asm__ ("sti"::)
void main(void)
{
sti();
while(1);
}
同时对应的我们把head.S中是sti注释掉
代码如下:
#define Descriptor(base,lim,attr)\
.word lim&0xffff;\
.word base&0xffff;\
.byte (base>>16)&0xff;\
.word ((lim>>8)&0xf00)|(attr&0x0f0ff);\
.byte ((base>>24)&0xff)
#define Gate(Selector,Offset,PCount,Attr)\
.2byte (Offset&0xffff);\
.2byte (Selector);\
.2byte (PCount&0x1f)|((Attr<<8)&0xff00);\
.2byte ((Offset>>16)&0xffff)
DA_32=0x4000 //32位模式
DA_LIMIT_4K=0x8000 //颗粒度为4096
DA_DRW=0x92 //数据段可读可写
DA_CR=0x9A //可读可执行
DA_C = 0x98
SETUPSEG = 0x9020
SETUPAddr = SETUPSEG<<4
DA_386CGate = 0x8c
DA_386IGate = 0x8E
DA_PL0 = 0x00
.text
.globl start/*程序从start处开始运行*/
.code32
_pg_dir://页目录将会存放在这里
start:
movl $0x20,%eax
mov %ax,%ds //因为ds是数据段寄存器,所以要加载一个数据段,否则会发生异常(可以试试0x08描述符)
mov %ax,%es
mov %ax,%ss
mov $0xffff,%esp
/*加载gdtr即将全局描述符表gdt的首地址和gdt的界限赋给gdtr寄存器*/
lgdt GdtPtr
lidt IdtPtr
movl $0x20,%eax
mov %ax,%ds
mov %ax,%es
mov %ax,%ss
mov $0xffff,%esp
ljmp $0x8,$LABEL_SEG_CODE32
.align 4
LABEL_SEG_CODE32:
.code32
movw $0x10,%ax
movw %ax,%gs
movl $((80*12+79)*2),%edi/*第12行,79列*/
movb $0x0c,%ah/*高四位表示黑底,低四位表示红字*/
movb $'S',%al/*显示的字符*/
movw %ax,%gs:(%edi)
int $0x80
//sti
jmp after_page_tables
loop1:/*无限循环*/
jmp loop1
.align 4
INT_TEST:
.code32
movl $((80*13+79)*2),%edi/*第11行,79列*/
movb $0x0c,%ah/*高四位表示黑底,低四位表示红字*/
movb $'I',%al/*显示的字符*/
movw %ax,%gs:(%edi)
iret
loop2:/*无限循环*/
jmp loop2
/*
*每个页表长4kb字节,而每个页表项需要4个字节,因此一个页表可以存放1024个表项
*/
.org 0x1000
pg0:
.org 0x2000
pg1:
.org 0x3000
pg2:
.org 0x4000
pg3:
.org 0x5000//定义下面的内存块从0x5000开始
//软盘缓冲区
_tmp_floppy_area:
.fill 1024,1,0 //预留1024项,每项1字节,填充数值为0
after_page_tables:
pushl $0
pushl $0
pushl $0
pushl $L6
pushl $main
jmp setup_paging
L6:
jmp L6
int_msg:
.asciz "Unknown interrupt\n\r"
.align 4
ignore_int:
.code32
movl $((80*13+79)*2),%edi/*第11行,79列*/
movb $0x0c,%ah/*高四位表示黑底,低四位表示红字*/
movb $'I',%al/*显示的字符*/
movw %ax,%gs:(%edi)
iret
loop21:/*无限循环*/
jmp loop21
.align 4
ClockHandler:
movl $((80*14+79)*2),%edi
movw %gs:(%edi),%ax
add $1,%ax
movw %ax,%gs:(%edi)
movb $0x20,%al
out %al,$0x20
iret
loop3:/*无限循环*/
jmp loop3
ret
.align 4 //按4字节方式对齐内存地址边界
setup_paging: //先对5页内存清零(1页目录+4页页表)
movl $1024*5,%ecx
xorl %eax,%eax
xorl %edi,%edi
//重复执行rep下面的语句,每次ecx减一,直到ecx为0
//页目录从0x00地址开始
cld;rep;stosl //eax内容存到es:edi所指内存位置,且edi增4
//STOSL指令相当于将EAX中的值保存到ES:EDI指向的地址中,若设置了EFLAGS中的方向位置位(即在STOSL指令前使用STD指令)则EDI自减4,否则(使用CLD指令)EDI自增4。
//设置页目录
movl $pg0+7,_pg_dir//7表示该页存在、用户可读写
movl $pg1+7,_pg_dir+4
movl $pg2+7,_pg_dir+8
movl $pg3+7,_pg_dir+12
//设置页表,共有4个页表,每个页表1024
movl $pg3+4092,%edi
movl $0xfff007,%eax//16Mb - 4096 + 7 = 0xfff007
//cld,清方向标志,即(DF)=0,地址从低到高
//std,置方向标志1,DF=1,地址从高到低
std
//std(set direction)置方向标志
1:
stosl
subl $0x1000,%eax
jge 1b
xorl %eax,%eax
movl %eax,%cr3
movl %cr0,%eax
orl $0x80000000,%eax
movl %eax,%cr0
//jmp Page_test
ret
/**/
.align 4
.word 0
IdtPtr:
.word (END_IDT-LABEL_IDT)-1 # so does gdt
.long LABEL_IDT # This will be rewrite by code.
.align 4
.word 0
GdtPtr:
.word (GDT_END-GDT_START)-1 # so does gdt
.long GDT_START # This will be rewrite by code.
.align 8
LABEL_IDT:
.rep 32
Gate(0x08,(ignore_int - start),0,(DA_386IGate+DA_PL0))
.endr
Gate(0x08,(ClockHandler - start),0,(DA_386IGate+DA_PL0))
.rep 222
Gate(0x08,(ignore_int - start),0,(DA_386IGate+DA_PL0))
.endr
END_IDT:
GDT_START:
Descriptor_DUMMY:Descriptor(0x0,0x0,0x0)
Descriptor_CODE32 :Descriptor(0x0,0xffffffff,DA_C+DA_32)
Descriptor_VIDEO:Descriptor(0xb8000,0x0ffff,DA_DRW)
Descriptor_SYSTM :Descriptor(0x00000,0xffffffff,DA_C+DA_32)
Descriptor_SYSTM2 :Descriptor(0x00000,0xffffffff,DA_DRW)
GDT_END:
Makefile代码如下:
AS =as
LD =ld
LDFLAGS = --oformat binary -N -e start -Ttext 0x0
Image:bootsect setup system
cat bootsect setup system >Image
bootsect:bootsect.s
$(AS) -o bootsect.o -a bootsect.s
$(LD) $(LDFLAGS) -o bootsect bootsect.o
setup:setup.s
$(AS) -o setup.o -a setup.s
$(LD) $(LDFLAGS) -o setup setup.o
head.o:head.s
$(AS) -o head.o -a head.s
main.o: main.c
gcc -c -o main.o main.c
system: head.o main.o
$(LD) $(LDFLAGS) -o system head.o main.o
clean:
rm -f Image setup bootsect system *.o *.s