分頁機制重新來過,完成時也和大家分享一下!

僅僅是打印了三個字符了,但確實是用心去練習了。

rem auto.cmd
@echo off

nasm -fbin -o boot.bin boot.asm
dd if=boot.bin of=c.img seek=0 count=1
echo.
nasm -fbin -o loader.bin loader.asm
dd if=loader.bin of=c.img seek=1 count=2
echo.
nasm -fbin -o kernel.bin kernel.asm
dd if=kernel.bin of=c.img seek=3 count=253
echo.

rem del *.bin
del c.img.lock
;boot. asm
bits 16

start:
	mov ax, 0x7c0
	mov ds, ax
	
	cli
	
	mov dx, 0x1f2
	mov al, 2 ; 2 sector
	out dx, al
	
	mov dx, 0x1f3
	mov al, 1 ; the second sector, from zero to ...
	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 mode
	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
	jne .1
	
	mov dx, 0x1f0
	mov bx, 0x200
	mov cx, 256
.2:
	in ax, dx
	mov [bx], ax
	inc bx
	inc bx
	loop .2
	
	lgdt [gdtr]

	in al, 0x92
	or al, 0000_0010b ; 0x2
	out 0x92, al
	
	mov eax, cr0
	or eax, 0000_0000_0000_0000_0000_0000_0000_0001b ; 0x1
	mov cr0, eax
	
	jmp dword 1 * 8 : 0
	
gdt_start:
	dq 0x0000_0000_0000_0000 ; 0 * 8
	dq 0x00c0_9a00_7e00_ffff ; 1 * 8
	dq 0x00c0_9200_7e00_ffff ; 2 * 8
	dq 0x00c0_920b_8000_ffff ; 3 * 8			
gdt_end:

gdtr:
	dw gdt_end - gdt_start - 1
	dd gdt_start + 0x7c00
		
times 510 - ($ - $$) db 0
dw 0xaa55

 

; loader.asm

bits 32

start:
	mov ax, 3 * 8
	mov gs, ax
	mov ax, 2 * 8
	mov ds, ax
	
;	xor ebx, ebx
;	mov byte [gs: ebx], 'P'
;	inc ebx
;	mov byte [gs: ebx], 0xc
;	inc ebx

	mov dx, 0x1f2
	mov al, 253 ; 253 sectors
	out dx, al
	
	mov dx, 0x1f3
	mov al, 3 ; the third sector 
	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 mode
	out dx, al
	
	mov dx, 0x1f7
	mov al, 0x20 ; read sector instruction
	out dx, al
	
	mov dx, 0x1f7
.1:
	in al, dx
	and al, 0x88
	cmp al, 0x08
	jnz .1
	
	mov dx, 0x1f0
	mov ebx, 0x100000 - 0x7e00
	mov ecx, 253 * 256
.2:
	in ax, dx
	mov [ebx], ax
	inc ebx
	inc ebx
	loop .2
	
	lgdt [gdtr]
	
	jmp dword 4 * 8 : 0
	
gdt_start:
	dq 0x0000_0000_0000_0000 ; 0 * 8
	dq 0x00c0_9a00_7e00_ffff ; 1 * 8
	dq 0x00c0_9200_7e00_ffff ; 2 * 8
	dq 0x00c0_920b_8000_ffff ; 3 * 8
	dq 0x00cf_9a10_0000_ffff ; 4 * 8
	dq 0x00cf_9210_0000_ffff ; 5 * 8
	dq 0x00cf_9a00_0000_ffff ; 6 * 8
	dq 0x00cf_9200_0000_ffff ; 7 * 8	
gdt_end:

gdtr:
	dw gdt_end - gdt_start - 1
	dd gdt_start + 0x7e00	
	
bits 32

%macro enter 0
	push ebp
	mov ebp, esp
%endmacro

%macro push_some 0
	push ecx
	push edx
	push ebx
	push esi
	push edi
%endmacro

%macro pop_some 0
	pop edi
	pop esi
	pop ebx
	pop edx
	pop ecx
%endmacro
;人爲的增加了遠返回的難度,因爲似乎沒有類似的指令, 因此在這裏用宏模擬了一個
%macro jmpf 2
; jmpf instruction(%1), format_address(%2)
	mov eax, [%2]
	mov [%%.0], eax
	mov ax, [%2 + 4]
	mov [%%.0 + 4], ax
	db %1
%%.0:
	dd 0
	dw 0
%endmacro

start:
	mov ax, 5 * 8
	mov ds, ax
	mov es, ax
	mov fs, ax
	mov ss, ax
	mov esp, stack_top
	mov ax, 3 * 8
	mov gs, ax


	sub esp, 20 * 4
	
	call set_page

	call 4 * 8 : cls ;使用遠轉移,返回時要使用指令retf,遠轉移的指令格式是   段選擇符的值:段內偏移地址

	mov dword [esp + 0 * 4], 'P'
	mov dword [esp + 1 * 4], 0xc
	call 4 * 8 : _print_c		


	call 6 * 8 : DEMO

	call set_page2

	call 6 * 8 : DEMO


	add esp, 20 * 4
	jmp $





;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;


cls: ;void cls(void)
	enter
	push_some

	mov eax, [ebp + 4] ;保存遠返回的地址
	mov [ret_addr], eax
	mov ax, [ebp + 2 * 4]
	mov [ret_addr + 4], ax


	xor ebx, ebx
	mov al, ' '
	mov ah, 0xf
	mov ecx, 2000
.1:	
	mov [gs:ebx], ax
	inc ebx
	inc ebx
	loop .1
	
	pop_some
	leave
	;retf ;因爲我們的調用是遠調用,所以這裏也採用遠返回
	
	;pop eax ;因爲沒有段地址,因此這樣返回會有問題
	;ret
	cli
	add esp, 8
	jmpf 0xea, ret_addr ;  這裏是故意複雜化了,其實只要用數據定義指令就好了
						; db 0xea 

ret_addr: dd 0
		  dw 0

set_page: ;void set_page(void) ;全對等的映射,也就是和物理地址和虛擬地址一一對應
	pusha
	
	mov ecx, 1024 ;共1024個頁目錄項目
	mov edi, page_dir_start ;頁目錄表的偏移地址
	mov eax, PAGE_TABLE_BASE + 3 ;要填充的是頁表的物理地址,+3的意思是頁屬性爲 0000000011b
.1:
	stosd ;串傳送指令,每次將eax中的值,傳送到[es:edi]中的連續4個字節中
	add eax, 4 * 1024 ;連續填充,也就是下一個頁目錄表項指向另外一個頁表,這些頁表也是連續存放的
	loop .1
	
	mov ecx, 5 * 1024 ; 可以使用20M的內存
	mov edi, page_table_start ;取頁表的偏移地址
	mov eax, 0 + 3 ;從物理頁的第0頁開始填充
.2:
	stosd
	add eax, 4 * 1024 ;連續填充,也就是指向下一個頁面,每個頁面的大小爲固定 4K
	loop .2
	
	mov eax, PAGE_DIR_BASE ;裝載頁目錄表基地址
	mov cr3, eax
	
	mov eax, cr0
	or eax, 0x8000_0000
	mov cr0, eax ;開啓分頁模式 ;1000_0000_0000_0000_0000_0000_0000_0000b,最高位置1
	
	jmp short .page
.page:	;據說這樣可以刷新高速緩衝
	
	popa
	ret
	
set_page2:
	pusha
	
	mov ecx, 1024
	mov edi, page_dir_start2
	mov eax, PAGE_TABLE_BASE + 3
.1:
	stosd
	add eax, 4 * 1024
	loop .1
	
	mov ecx, 5 * 1024
	mov edi, page_table_start
	mov eax, 0 + 3
.2:
	stosd
	add eax, 4 * 1024
	loop .2
	

	mov eax, FUNC2 ; 這裏是func2的線性地址,也就是分段機制轉化得到的地址形式
	mov ebx, eax ;保留一份副本
	shr eax, 22 ;取得最高10位,得到在頁目錄表中的項目數
	shl eax, 2 ; 乘以4,得到在頁目錄表中的偏移地址
	add eax, page_dir_start2 ;加上頁目錄表的基地址,注意這裏不是物理地址,
							;而是相對於此段的偏移,我們僅使用了一個段
	and ebx, 0000_0000_0011_1111_1111_0000_0000_0000b ;屏蔽無用位
	shr ebx, 12 ;取得中間10位,得到在某個頁表中的項目數
	shl ebx, 2 ;乘以4,得到在此頁表中的偏移 
	mov ecx, [eax] ;取得頁表的基地址,注意這裏是頁表的物理地址
	and ecx, 0xfffff000 ;去掉頁表屬性
	add ecx, ebx ;得到在頁表項在頁表中的物理地址,如果在此處訪問,需要減去段長度
	sub ecx, 0x100000 ;這裏減去段長度,得以訪問頁表項
	mov dword [ecx], FUNC1 + 3 ;將函數的所在頁物理地址和頁屬性存入頁表項中,從而使改變了頁映射關係
								;使func2的線性地址映射到func1

	mov eax, PAGE_DIR_BASE2
	mov cr3, eax
	
	jmp short .page
.page:
	
	popa
	ret

print_c: ; void print_c(char c, int colour) ;字符打印的函數
	enter
	push_some
	sub esp, 20 * 4
	
	mov ebx, [cursor_pos]
	mov al, [ebp + 2 * 4]
	mov ah, [ebp + 3 * 4]
	
	mov [gs:ebx], ax
	inc ebx
	inc ebx
	
	mov [cursor_pos], ebx
	
	add esp, 20 * 4
	leave
	ret

_print_c: ; void _print_c(char c, int colour) ;字符打印的函數
	enter
	push_some
	sub esp, 20 * 4
	
	mov ebx, [cursor_pos] ;遠調用壓入堆棧8個字節分別是段選擇符和偏移地址,所以這裏累計加到3 * 4
	mov al, [ebp + 3 * 4]
	mov ah, [ebp + 4 * 4]
	
	mov [gs:ebx], ax
	inc ebx
	inc ebx
	
	mov [cursor_pos], ebx
	
	add esp, 20 * 4
	leave
	retf

cursor_pos: dd 0 ;光標位置,這裏未設置
;棧空間
stack_bottom:	
times 1024 db 0
stack_top:

;頁目錄表1
align 4 * 1024 ; 4k
page_dir_start:
	times 4 * 1024 db 0
page_dir_end:
PAGE_DIR_BASE equ 0x100000 + page_dir_start ;線性地址,等同於物理地址

;頁表(公用)
page_table_start:
	times 5 * 4 * 1024 db 0 ; 20M
page_table_end:
PAGE_TABLE_BASE equ 0x100000 + page_table_start


;頁目錄表2
page_dir_start2:
	times 4 * 1024 db 0
page_dir_end2:
PAGE_DIR_BASE2 equ 0x100000 + page_dir_start2


align 4096 ;頁對齊

;似乎必須用這樣的格式,???
demo:
	mov eax, FUNC2
	call eax
	retf
	
DEMO equ 0x100000 + demo

align 4096

func2:
	enter
	push_some
	sub esp, 20 * 4
	
	mov dword [esp + 0 * 4], '2'
	mov dword [esp + 1 * 4], 0x9
	call 4 * 8 : _print_c	
	
	add esp, 20 * 4
	leave
	ret

FUNC2 equ 0x100000 + func2

align 4096

func1:
	enter
	push_some
	sub esp, 20 * 4
	
	mov dword [esp + 0 * 4], '1' ;在頁映射變換後,不能調用print(char c, int colour)這個函數,不知道什麼原因
	mov dword [esp + 1 * 4], 0xa
	call 4 * 8 : _print_c
	
;	mov ebx, 160
;	mov al, '1'
;	mov ah, 0xf
;	mov [gs:ebx], ax	
	
	add esp, 20 * 4
	leave
	ret

FUNC1 equ 0x100000 + func1

###############################################################
# bochsrc.txt file for DLX Linux disk image.
###############################################################

# how much memory the emulated machine will have
megs: 64

# filename of ROM images
romimage: file=../BIOS-bochs-latest
vgaromimage: file=../VGABIOS-lgpl-latest

# what disk images will be used 
floppya: 1_44=a.img, status=inserted
##floppyb: 1_44=b.img, status=inserted

# hard disk
ata0: enabled=1, ioaddr1=0x1f0, ioaddr2=0x3f0, irq=14
ata0-master: type=disk, path="c.img", cylinders=306, heads=4, spt=17

# choose the boot disk.
boot: c

# default config interface is textconfig.
#config_interface: textconfig
#config_interface: wx

#display_library: x
# other choices: win32 sdl wx carbon amigaos beos macintosh nogui rfb term svga

# where do we send log messages?
#log: bochsout.txt

# disable the mouse, since DLX is text only
mouse: enabled=0

# set up IPS value and clock sync
cpu: ips=15000000
clock: sync=both

# enable key mapping, using US layout as default.
#
# NOTE: In Bochs 1.4, keyboard mapping is only 100% implemented on X windows.
# However, the key mapping tables are used in the paste function, so 
# in the DLX Linux example I'm enabling keyboard_mapping so that paste 
# will work.  Cut&Paste is currently implemented on win32 and X windows only.

keyboard: keymap=../keymaps/x11-pc-us.map
#keyboard: keymap=../keymaps/x11-pc-fr.map
#keyboard: keymap=../keymaps/x11-pc-de.map
#keyboard: keymap=../keymaps/x11-pc-es.map

 

 

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章