; boot.asm
bits 16
start16:
mov ax, 0x7c0 ;实模式下,数据段、堆栈段基地址都为0x7c00
mov ds, ax
mov ss, ax
mov sp, 0x0
cli ;应关闭中断
; 读取硬盘第二个扇区到内存0x7e00处, 是紧挨着引导扇区内存处的一个扇区
mov dx, 0x1f2
mov al, 2 ;一下加载了两个扇区,因此,下面的向缓冲区中写入数据也应该是,一个扇区的两倍
out dx, al
mov dx, 0x1f3
mov al, 1 ;第二个扇区,逻辑扇区从0开始计数。这也是容易出问题的地方
out dx, al
mov dx, 0x1f4
mov al, 0
out dx, al
mov dx, 0x1f5
mov al, 0
out dx, al
mov dx, 0x1f6
mov al, 0xe0 ;第一块硬盘,LBA模式
out dx, al
mov dx, 0x1f7
mov al, 0x20 ;读命令
out dx, al
mov dx, 0x1f7
.1:
in al, dx
and al, 0x88
cmp al, 0x08 ;测试是否完成操作
jnz .1
mov bx, 0x200 ; 0x7c00 + 0x200,512 bytes,即0x7e00
mov dx, 0x1f0
mov cx, 2 * 256
.2:
in ax, dx
mov [bx], ax
inc bx
inc bx
loop .2
lgdt [gdtr]
;open A20 address line
in al, 0x92
or al, 0x2
out 0x92, al
;set CR0 protected mode bit
mov eax, cr0
or al, 0x1
mov cr0, eax
jmp dword 1 * 8 : 0 ;更新cs,eip
gdtr:
dw gdt_end - gdt_start - 1; global descriptor table size -- xxx bytes
dd gdt_start + 0x7c00; phy Address
gdt_start:
dq 0x0000000000000000 ; 0 * 8
dq 0x00c09a007e00ffff ; 1 * 8 segment base address 0x7c00 + 0x200
dq 0x00c092007e00ffff ; 2 * 8
dq 0x00c0920b8000ffff ; 3 * 8 video memory address
dq 0x00c092100000ffff ; 4 * 8 other data segment
dq 0x000092000000ffff ; 5 * 8 other data segment
dq 0x000098000000ffff ; 6 * 8 other data segment
gdt_end:
times 512 - 2 - ($ - $$) db 0
dw 0xaa55 ; == db 0x55, 0xaa
;loader.asm
bits 32
start:
mov ax, 2 * 8
mov ds, ax
mov ax, 3 * 8
mov es, ax
mov ebx, 3 * 160
mov byte [es: ebx], 'l'
inc ebx
mov byte [es: ebx], 0xc
inc ebx
jmp 6 * 8 : 0x7e00 + start16 ;这里《orange's一个操作系统的实现》说是应该切换到16位代码段
;但古老的清华书似乎没有这么说,但是还是这样做了
;决定明天按照清华老书里直接切换到实模式,验证一下,到底谁的对。
jmp $
align 32
bits 16
start16:
mov ax, 5 * 8
mov ds, ax
mov fs, ax
mov gs, ax
mov ss, ax
;位0清零后,切换到实模式,紧接着就要刷新高速缓存,从而进入实模式
mov eax, cr0
and eax, 1111_1111_1111_1110b
mov cr0, eax
;这段显示字符的程序一定要在保护模式位清零后,方可执行,否则宕机
xor bx, bx
mov ax, 0xb800
mov es, ax
mov byte [es: bx], 'a'
inc bx
mov byte [es: bx], 0xe
inc bx
;这里使用db伪指令定义的跳转到实模式的代码段的指令,nasm应该怎么表示,我不太知道
;明天也要验证一下这里,看看nasm的jmp指令是否也生成同样的机器码。
db 0xea
dw 0x8000
dw 0
; kernel.asm
bits 16
start16:
mov ax, 0
mov ds, ax
mov fs, ax
mov gs, ax
mov ss, ax
mov sp, 0
;应该关闭a20地址线
in al, 0x92
and al, 1111_1101b
out 0x92, al
mov bx, 160
mov ax, 0xb800
mov es, ax
mov byte [es: bx], 'r'
inc bx
mov byte [es: bx], 0xa
inc bx
;一定要打开中断,否则没法用BIOS中断读软盘引导扇区到0x7c00处。
sti
mov dx, 0
mov cx, 1
mov ax, 0x7c0
mov es, ax
mov bx, 0
mov ax, 0x201
int 0x13
jmp 0x7c0 : 0 ;跳转到软盘的引导扇区,我们的系统是用硬盘引导扇区加载的。
;软盘里面预制的是menuetOS,一个纯粹用汇编语言写成的操作系统。这样就完成王爽老师大作业中的一个小知识点。
weixin_39410618 发布了159 篇原创文章 · 获赞 14 · 访问量 1万+ 私信 关注