实模式到保护模式再到实模式,完成时的分享!

; 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,一个纯粹用汇编语言写成的操作系统。这样就完成王爽老师大作业中的一个小知识点。
	
发布了159 篇原创文章 · 获赞 14 · 访问量 1万+

猜你喜欢

转载自blog.csdn.net/weixin_39410618/article/details/103962035