這幾天K了2本有關Assembly的書,及一個教寫OS的網頁(這個)。
呼~ 上次認真用Assembly來寫code是何時呢? 我想已經10年之前的事了,天啊~ 真是太可怖了,太難了吧(相對於PHP? XD),連bug都是非常low level的,寫了一整天,才可以在螢幕上Print出一句話 @@"
OK,說回正題,這次還是用上了NASM來compile,首先是loader.asm,已經在loader把Protect Mode轉好了:
---------- loader.asm ----------
;*********************************************
; ABCOS - Bootloader
;*********************************************
%define KERNEL_ADDR 0x1000
bits 16 ;Tell the assembler it is in 16 bit
org 0x7c00 ;Tell the assembler we start at 0x7C00
;Reset the drive first
reset_drive:
MOV AH, 0
INT 13h
OR AH, AH
JNZ reset_drive
;Loading the kernel from disk to memory
MOV AX, 0
MOV ES, AX
MOV BX, KERNEL_ADDR ;copy the kernel to 0000:1000
MOV AL, 02h ;Number of sectors to read
MOV CH, 0 ;Disk cylinder
MOV CL, 02h ;Disk sector (starts with 1, not 0)
MOV DH, 0 ;Disk head
MOV AH, 02h ;Command - 02h for 'Read sector from disk'
INT 13h
OR AH, AH
JNZ reset_drive ;any problem, back to reset_drive label and try again
CLI ;no interrupts for now
LGDT [gdt_desc] ;***load GDT into GDTR, GDT set done
;***to Protect Mode (set CR0 bit 0 to 1)
MOV EAX, CR0
OR EAX, 1
MOV CR0, EAX
;make it becomes Descriptor:Address memory model by a far jump
jmp 08h:p_mode ;08h because the code selector at 08h of the GDT
bits 32 ;tell assembler we are in 32 bits mode now
p_mode:
MOV AX, 10h ; set data segments to data selector (0x10) (as they are incorrect after enter to PMode)
MOV DS, AX
MOV SS, AX
MOV ES, AX
;Method 3.1: Enables A20 through keyboard controller
MOV AL, 0xdd ; command 0xdd: enable a20
OUT 64h, AL ; send command to controller
JMP KERNEL_ADDR ;jump to kernel
;Construct Global Descriptor Table
;Offset 0 in GDT: Descriptor code=0
gdt_data:
dd 0 ; null descriptor
dd 0
; Offset 0x8 bytes from start of GDT: Descriptor code therfore is 8
; gdt code: ; code descriptor
dw 0FFFFh ; limit low
dw 0 ; base low
db 0 ; base middle
db 10011010b ; access
db 11001111b ; granularity
db 0 ; base high
; Offset 16 bytes (0x10) from start of GDT. Descriptor code therfore is 0x10.
; gdt data: ; data descriptor
dw 0FFFFh ; limit low (Same as code)
dw 0 ; base low
db 0 ; base middle
db 10010010b ; access
db 11001111b ; granularity
db 0 ; base high
;...Other descriptors begin at offset 0x18. Remember that each descriptor is 8 bytes in size?
; Add other descriptors for Ring 3 applications, stack, whatever here...
end_of_gdt:
gdt_desc:
dw end_of_gdt - gdt_data - 1 ; limit (Size of GDT)
dd gdt_data ; base of GDT
times 510 - ($-$$) db 0 ; We have to be 512 bytes. Clear the rest of the bytes with 0
dw 0xAA55 ; Boot Signiture
---------- loader.asm ----------
> nasm d:\os\loader.asm -f bin -o d:\os\loader.bin
;*********************************************
; ABCOS - Bootloader
;*********************************************
%define KERNEL_ADDR 0x1000
bits 16 ;Tell the assembler it is in 16 bit
org 0x7c00 ;Tell the assembler we start at 0x7C00
;Reset the drive first
reset_drive:
MOV AH, 0
INT 13h
OR AH, AH
JNZ reset_drive
;Loading the kernel from disk to memory
MOV AX, 0
MOV ES, AX
MOV BX, KERNEL_ADDR ;copy the kernel to 0000:1000
MOV AL, 02h ;Number of sectors to read
MOV CH, 0 ;Disk cylinder
MOV CL, 02h ;Disk sector (starts with 1, not 0)
MOV DH, 0 ;Disk head
MOV AH, 02h ;Command - 02h for 'Read sector from disk'
INT 13h
OR AH, AH
JNZ reset_drive ;any problem, back to reset_drive label and try again
CLI ;no interrupts for now
LGDT [gdt_desc] ;***load GDT into GDTR, GDT set done
;***to Protect Mode (set CR0 bit 0 to 1)
MOV EAX, CR0
OR EAX, 1
MOV CR0, EAX
;make it becomes Descriptor:Address memory model by a far jump
jmp 08h:p_mode ;08h because the code selector at 08h of the GDT
bits 32 ;tell assembler we are in 32 bits mode now
p_mode:
MOV AX, 10h ; set data segments to data selector (0x10) (as they are incorrect after enter to PMode)
MOV DS, AX
MOV SS, AX
MOV ES, AX
;Method 3.1: Enables A20 through keyboard controller
MOV AL, 0xdd ; command 0xdd: enable a20
OUT 64h, AL ; send command to controller
JMP KERNEL_ADDR ;jump to kernel
;Construct Global Descriptor Table
;Offset 0 in GDT: Descriptor code=0
gdt_data:
dd 0 ; null descriptor
dd 0
; Offset 0x8 bytes from start of GDT: Descriptor code therfore is 8
; gdt code: ; code descriptor
dw 0FFFFh ; limit low
dw 0 ; base low
db 0 ; base middle
db 10011010b ; access
db 11001111b ; granularity
db 0 ; base high
; Offset 16 bytes (0x10) from start of GDT. Descriptor code therfore is 0x10.
; gdt data: ; data descriptor
dw 0FFFFh ; limit low (Same as code)
dw 0 ; base low
db 0 ; base middle
db 10010010b ; access
db 11001111b ; granularity
db 0 ; base high
;...Other descriptors begin at offset 0x18. Remember that each descriptor is 8 bytes in size?
; Add other descriptors for Ring 3 applications, stack, whatever here...
end_of_gdt:
gdt_desc:
dw end_of_gdt - gdt_data - 1 ; limit (Size of GDT)
dd gdt_data ; base of GDT
times 510 - ($-$$) db 0 ; We have to be 512 bytes. Clear the rest of the bytes with 0
dw 0xAA55 ; Boot Signiture
---------- loader.asm ----------
> nasm d:\os\loader.asm -f bin -o d:\os\loader.bin
跟著是kernel.asm,只是在螢幕上Print一句話:
---------- kernel.asm ----------
;*********************************************
; ABCOS - Kernel
;*********************************************
bits 32
org 0x1000
MOV SI, msg
MOV BH, 23
MOV BL, 70
CALL PrintString
HLT
msg db 'ha1234', 10, 13, 'this is next line', 0
; *** Define screen constant ***
%define VIDMEM 0xB8000 ; video memory start address
%define VIDMEM_END 0xB8FA0 ; video memory last address
%define SCR_COLS 80
%define SCR_ROWS 25
; *** Set cursor position ***
; BH = Y (row) position
; BL = X (column) position
SetCursor:
MOV AX, SCR_COLS
MUL BH
XOR BH, BH
ADD AX, BX
MOV BX, AX ; BX = BH * SCR_COLS + BL
MOV AL, 0x0F ; Cursor location low byte index
MOV DX, 0x03D4 ; Write it to the CRT index register
OUT DX, AL
MOV AL, BL ; The current location is in EBX. BL contains the low byte, BH high byte
MOV DX, 0x03D5 ; Write it to the data register
OUT DX, AL ; low byte
MOV AL, 0x0E ; Cursor location high byte index
MOV DX, 0x03D4 ; Write to the CRT index register
OUT DX, AL
MOV AL, BH ; the current location is in EBX. BL contains low byte, BH high byte
MOV DX, 0x03D5 ; Write it to the data register
OUT DX, AL ; high byte
RET
; *** End of Set cursor position ***
; *** Print character in text mode ***
; DL = Ascii code of character
; BH = Y (row) position
; BL = X (column) position
PrintChar:
MOV EAX, SCR_COLS
MUL BH ; AX = 80d or 50h, BH max = 24d or 18h
XOR BH, BH
ADD AX, BX ; AX max = 1920d or 780h, result AX max = 2000d or 7D0h
ADD AX, AX ; result AX max = 4000d or FA0h
MOV EDI, EAX ; DI = ( BH * SCR_COLS + BL ) * 2
ADD EDI, VIDMEM
MOV DH, 0x7 ; character attribute
MOV [EDI], DX ; print character
RET
; *** End of Print character in text mode ***
; *** Print String in text mode ***
; SI = Address of String, string end by 0 (eg. MOV SI, msg)
; BH = Y (row) start position
; BL = X (column) start position
PrintString:
MOV EAX, SCR_COLS
MUL BH ; AX = 80d or 50h, BH max = 24d or 18h
XOR BH, BH
ADD AX, BX ; AX max = 1920d or 780h, result AX max = 2000d or 7D0h
ADD AX, AX ; result AX max = 4000d or FA0h
MOV EDI, EAX ; DI = ( BH * SCR_COLS + BL ) * 2
ADD EDI, VIDMEM
PrintString_loop:
MOV AL, [SI]
CMP AL, 0
JE PrintString_end
MOV AH, 0x7 ; character attribute
MOV [EDI], AX ; print character that BL point to
INC SI
INC EDI
INC EDI
CMP EDI, VIDMEM_END
JE PrintString_end
JMP PrintString_loop
PrintString_end:
RET
; *** End of Print String in text mode ***
; *** Clear Screen in text mode ***
ClearScreen:
MOV EDI, VIDMEM
MOV CX, 2000
ClearScreen_loop:
MOV word [EDI], 0x0720
ADD EDI, 2
LOOP ClearScreen_loop
RET
; *** End of Clear Screen in text mode ***
---------- kernel.asm ----------
> nasm d:\os\kernel.asm -f bin -o d:\os\kernel.bin
> copy /b /y loader.bin+kernel.bin boot.img
;*********************************************
; ABCOS - Kernel
;*********************************************
bits 32
org 0x1000
MOV SI, msg
MOV BH, 23
MOV BL, 70
CALL PrintString
HLT
msg db 'ha1234', 10, 13, 'this is next line', 0
; *** Define screen constant ***
%define VIDMEM 0xB8000 ; video memory start address
%define VIDMEM_END 0xB8FA0 ; video memory last address
%define SCR_COLS 80
%define SCR_ROWS 25
; *** Set cursor position ***
; BH = Y (row) position
; BL = X (column) position
SetCursor:
MOV AX, SCR_COLS
MUL BH
XOR BH, BH
ADD AX, BX
MOV BX, AX ; BX = BH * SCR_COLS + BL
MOV AL, 0x0F ; Cursor location low byte index
MOV DX, 0x03D4 ; Write it to the CRT index register
OUT DX, AL
MOV AL, BL ; The current location is in EBX. BL contains the low byte, BH high byte
MOV DX, 0x03D5 ; Write it to the data register
OUT DX, AL ; low byte
MOV AL, 0x0E ; Cursor location high byte index
MOV DX, 0x03D4 ; Write to the CRT index register
OUT DX, AL
MOV AL, BH ; the current location is in EBX. BL contains low byte, BH high byte
MOV DX, 0x03D5 ; Write it to the data register
OUT DX, AL ; high byte
RET
; *** End of Set cursor position ***
; *** Print character in text mode ***
; DL = Ascii code of character
; BH = Y (row) position
; BL = X (column) position
PrintChar:
MOV EAX, SCR_COLS
MUL BH ; AX = 80d or 50h, BH max = 24d or 18h
XOR BH, BH
ADD AX, BX ; AX max = 1920d or 780h, result AX max = 2000d or 7D0h
ADD AX, AX ; result AX max = 4000d or FA0h
MOV EDI, EAX ; DI = ( BH * SCR_COLS + BL ) * 2
ADD EDI, VIDMEM
MOV DH, 0x7 ; character attribute
MOV [EDI], DX ; print character
RET
; *** End of Print character in text mode ***
; *** Print String in text mode ***
; SI = Address of String, string end by 0 (eg. MOV SI, msg)
; BH = Y (row) start position
; BL = X (column) start position
PrintString:
MOV EAX, SCR_COLS
MUL BH ; AX = 80d or 50h, BH max = 24d or 18h
XOR BH, BH
ADD AX, BX ; AX max = 1920d or 780h, result AX max = 2000d or 7D0h
ADD AX, AX ; result AX max = 4000d or FA0h
MOV EDI, EAX ; DI = ( BH * SCR_COLS + BL ) * 2
ADD EDI, VIDMEM
PrintString_loop:
MOV AL, [SI]
CMP AL, 0
JE PrintString_end
MOV AH, 0x7 ; character attribute
MOV [EDI], AX ; print character that BL point to
INC SI
INC EDI
INC EDI
CMP EDI, VIDMEM_END
JE PrintString_end
JMP PrintString_loop
PrintString_end:
RET
; *** End of Print String in text mode ***
; *** Clear Screen in text mode ***
ClearScreen:
MOV EDI, VIDMEM
MOV CX, 2000
ClearScreen_loop:
MOV word [EDI], 0x0720
ADD EDI, 2
LOOP ClearScreen_loop
RET
; *** End of Clear Screen in text mode ***
---------- kernel.asm ----------
> nasm d:\os\kernel.asm -f bin -o d:\os\kernel.bin
> copy /b /y loader.bin+kernel.bin boot.img
跟著想做的,就是盡量把hardware的資料拿出來。
ps. 這幾天有一個感想,在電腦科技發展的數十年,我覺得從來都是量的改變,質是沒有改變過的,現在大部份有關的知識理論,都是當時的想法,大家都沒法跳出來想似的?
2 則留言:
一切都是換了包裝
內裏做法大都不外如是
boot 了機,都是window 式介面 ( 不論你是微軟, Linux or Mac )
一大堆software, 不論你說何種方言( Basic , C .. ) ,都走不出執行的先後次序,創意何在!
對呢~ 真難搞~ 可能要做的,就是先由改變自己的思維模式開始~~~
發佈留言