mirror of
				https://github.com/cfenollosa/os-tutorial.git
				synced 2025-06-13 12:54:24 +00:00 
			
		
		
		
	Lesson 18
This commit is contained in:
		
							parent
							
								
									418bb11305
								
							
						
					
					
						commit
						c8db77fea9
					
				
							
								
								
									
										26
									
								
								15-video-ports/boot/32bit_print.asm
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										26
									
								
								15-video-ports/boot/32bit_print.asm
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,26 @@
 | 
				
			|||||||
 | 
					[bits 32] ; using 32-bit protected mode
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					; this is how constants are defined
 | 
				
			||||||
 | 
					VIDEO_MEMORY equ 0xb8000
 | 
				
			||||||
 | 
					WHITE_OB_BLACK equ 0x0f ; the color byte for each character
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					print_string_pm:
 | 
				
			||||||
 | 
					    pusha
 | 
				
			||||||
 | 
					    mov edx, VIDEO_MEMORY
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					print_string_pm_loop:
 | 
				
			||||||
 | 
					    mov al, [ebx] ; [ebx] is the address of our character
 | 
				
			||||||
 | 
					    mov ah, WHITE_OB_BLACK
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    cmp al, 0 ; check if end of string
 | 
				
			||||||
 | 
					    je print_string_pm_done
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    mov [edx], ax ; store character + attribute in video memory
 | 
				
			||||||
 | 
					    add ebx, 1 ; next char
 | 
				
			||||||
 | 
					    add edx, 2 ; next video memory position
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    jmp print_string_pm_loop
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					print_string_pm_done:
 | 
				
			||||||
 | 
					    popa
 | 
				
			||||||
 | 
					    ret
 | 
				
			||||||
							
								
								
									
										51
									
								
								15-video-ports/boot/bootsect.asm
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										51
									
								
								15-video-ports/boot/bootsect.asm
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,51 @@
 | 
				
			|||||||
 | 
					; Identical to lesson 13's boot sector, but the %included files have new paths
 | 
				
			||||||
 | 
					[org 0x7c00]
 | 
				
			||||||
 | 
					KERNEL_OFFSET equ 0x1000 ; The same one we used when linking the kernel
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    mov [BOOT_DRIVE], dl ; Remember that the BIOS sets us the boot drive in 'dl' on boot
 | 
				
			||||||
 | 
					    mov bp, 0x9000
 | 
				
			||||||
 | 
					    mov sp, bp
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    mov bx, MSG_REAL_MODE 
 | 
				
			||||||
 | 
					    call print
 | 
				
			||||||
 | 
					    call print_nl
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    call load_kernel ; read the kernel from disk
 | 
				
			||||||
 | 
					    call switch_to_pm ; disable interrupts, load GDT,  etc. Finally jumps to 'BEGIN_PM'
 | 
				
			||||||
 | 
					    jmp $ ; Never executed
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					%include "boot/print.asm"
 | 
				
			||||||
 | 
					%include "boot/print_hex.asm"
 | 
				
			||||||
 | 
					%include "boot/disk.asm"
 | 
				
			||||||
 | 
					%include "boot/gdt.asm"
 | 
				
			||||||
 | 
					%include "boot/32bit_print.asm"
 | 
				
			||||||
 | 
					%include "boot/switch_pm.asm"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[bits 16]
 | 
				
			||||||
 | 
					load_kernel:
 | 
				
			||||||
 | 
					    mov bx, MSG_LOAD_KERNEL
 | 
				
			||||||
 | 
					    call print
 | 
				
			||||||
 | 
					    call print_nl
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    mov bx, KERNEL_OFFSET ; Read from disk and store in 0x1000
 | 
				
			||||||
 | 
					    mov dh, 16 ; Our future kernel will be larger, make this big
 | 
				
			||||||
 | 
					    mov dl, [BOOT_DRIVE]
 | 
				
			||||||
 | 
					    call disk_load
 | 
				
			||||||
 | 
					    ret
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[bits 32]
 | 
				
			||||||
 | 
					BEGIN_PM:
 | 
				
			||||||
 | 
					    mov ebx, MSG_PROT_MODE
 | 
				
			||||||
 | 
					    call print_string_pm
 | 
				
			||||||
 | 
					    call KERNEL_OFFSET ; Give control to the kernel
 | 
				
			||||||
 | 
					    jmp $ ; Stay here when the kernel returns control to us (if ever)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					BOOT_DRIVE db 0 ; It is a good idea to store it in memory because 'dl' may get overwritten
 | 
				
			||||||
 | 
					MSG_REAL_MODE db "Started in 16-bit Real Mode", 0
 | 
				
			||||||
 | 
					MSG_PROT_MODE db "Landed in 32-bit Protected Mode", 0
 | 
				
			||||||
 | 
					MSG_LOAD_KERNEL db "Loading kernel into memory", 0
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					; padding
 | 
				
			||||||
 | 
					times 510 - ($-$$) db 0
 | 
				
			||||||
 | 
					dw 0xaa55
 | 
				
			||||||
							
								
								
									
										46
									
								
								15-video-ports/boot/disk.asm
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										46
									
								
								15-video-ports/boot/disk.asm
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,46 @@
 | 
				
			|||||||
 | 
					; load 'dh' sectors from drive 'dl' into ES:BX
 | 
				
			||||||
 | 
					disk_load:
 | 
				
			||||||
 | 
					    pusha
 | 
				
			||||||
 | 
					    ; reading from disk requires setting specific values in all registers
 | 
				
			||||||
 | 
					    ; so we will overwrite our input parameters from 'dx'. Let's save it
 | 
				
			||||||
 | 
					    ; to the stack for later use.
 | 
				
			||||||
 | 
					    push dx
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    mov ah, 0x02 ; ah <- int 0x13 function. 0x02 = 'read'
 | 
				
			||||||
 | 
					    mov al, dh   ; al <- number of sectors to read (0x01 .. 0x80)
 | 
				
			||||||
 | 
					    mov cl, 0x02 ; cl <- sector (0x01 .. 0x11)
 | 
				
			||||||
 | 
					                 ; 0x01 is our boot sector, 0x02 is the first 'available' sector
 | 
				
			||||||
 | 
					    mov ch, 0x00 ; ch <- cylinder (0x0 .. 0x3FF, upper 2 bits in 'cl')
 | 
				
			||||||
 | 
					    ; dl <- drive number. Our caller sets it as a parameter and gets it from BIOS
 | 
				
			||||||
 | 
					    ; (0 = floppy, 1 = floppy2, 0x80 = hdd, 0x81 = hdd2)
 | 
				
			||||||
 | 
					    mov dh, 0x00 ; dh <- head number (0x0 .. 0xF)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    ; [es:bx] <- pointer to buffer where the data will be stored
 | 
				
			||||||
 | 
					    ; caller sets it up for us, and it is actually the standard location for int 13h
 | 
				
			||||||
 | 
					    int 0x13      ; BIOS interrupt
 | 
				
			||||||
 | 
					    jc disk_error ; if error (stored in the carry bit)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    pop dx
 | 
				
			||||||
 | 
					    cmp al, dh    ; BIOS also sets 'al' to the # of sectors read. Compare it.
 | 
				
			||||||
 | 
					    jne sectors_error
 | 
				
			||||||
 | 
					    popa
 | 
				
			||||||
 | 
					    ret
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					disk_error:
 | 
				
			||||||
 | 
					    mov bx, DISK_ERROR
 | 
				
			||||||
 | 
					    call print
 | 
				
			||||||
 | 
					    call print_nl
 | 
				
			||||||
 | 
					    mov dh, ah ; ah = error code, dl = disk drive that dropped the error
 | 
				
			||||||
 | 
					    call print_hex ; check out the code at http://stanislavs.org/helppc/int_13-1.html
 | 
				
			||||||
 | 
					    jmp disk_loop
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					sectors_error:
 | 
				
			||||||
 | 
					    mov bx, SECTORS_ERROR
 | 
				
			||||||
 | 
					    call print
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					disk_loop:
 | 
				
			||||||
 | 
					    jmp $
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					DISK_ERROR: db "Disk read error", 0
 | 
				
			||||||
 | 
					SECTORS_ERROR: db "Incorrect number of sectors read", 0
 | 
				
			||||||
							
								
								
									
										35
									
								
								15-video-ports/boot/gdt.asm
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										35
									
								
								15-video-ports/boot/gdt.asm
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,35 @@
 | 
				
			|||||||
 | 
					gdt_start: ; don't remove the labels, they're needed to compute sizes and jumps
 | 
				
			||||||
 | 
					    ; the GDT starts with a null 8-byte
 | 
				
			||||||
 | 
					    dd 0x0 ; 4 byte
 | 
				
			||||||
 | 
					    dd 0x0 ; 4 byte
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					; GDT for code segment. base = 0x00000000, length = 0xfffff
 | 
				
			||||||
 | 
					; for flags, refer to os-dev.pdf document, page 36
 | 
				
			||||||
 | 
					gdt_code: 
 | 
				
			||||||
 | 
					    dw 0xffff    ; segment length, bits 0-15
 | 
				
			||||||
 | 
					    dw 0x0       ; segment base, bits 0-15
 | 
				
			||||||
 | 
					    db 0x0       ; segment base, bits 16-23
 | 
				
			||||||
 | 
					    db 10011010b ; flags (8 bits)
 | 
				
			||||||
 | 
					    db 11001111b ; flags (4 bits) + segment length, bits 16-19
 | 
				
			||||||
 | 
					    db 0x0       ; segment base, bits 24-31
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					; GDT for data segment. base and length identical to code segment
 | 
				
			||||||
 | 
					; some flags changed, again, refer to os-dev.pdf
 | 
				
			||||||
 | 
					gdt_data:
 | 
				
			||||||
 | 
					    dw 0xffff
 | 
				
			||||||
 | 
					    dw 0x0
 | 
				
			||||||
 | 
					    db 0x0
 | 
				
			||||||
 | 
					    db 10010010b
 | 
				
			||||||
 | 
					    db 11001111b
 | 
				
			||||||
 | 
					    db 0x0
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					gdt_end:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					; GDT descriptor
 | 
				
			||||||
 | 
					gdt_descriptor:
 | 
				
			||||||
 | 
					    dw gdt_end - gdt_start - 1 ; size (16 bit), always one less of its true size
 | 
				
			||||||
 | 
					    dd gdt_start ; address (32 bit)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					; define some constants for later use
 | 
				
			||||||
 | 
					CODE_SEG equ gdt_code - gdt_start
 | 
				
			||||||
 | 
					DATA_SEG equ gdt_data - gdt_start
 | 
				
			||||||
							
								
								
									
										4
									
								
								15-video-ports/boot/kernel_entry.asm
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										4
									
								
								15-video-ports/boot/kernel_entry.asm
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,4 @@
 | 
				
			|||||||
 | 
					[bits 32]
 | 
				
			||||||
 | 
					[extern main] ; Define calling point. Must have same name as kernel.c 'main' function
 | 
				
			||||||
 | 
					call main ; Calls the C function. The linker will know where it is placed in memory
 | 
				
			||||||
 | 
					jmp $
 | 
				
			||||||
							
								
								
									
										37
									
								
								15-video-ports/boot/print.asm
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										37
									
								
								15-video-ports/boot/print.asm
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,37 @@
 | 
				
			|||||||
 | 
					print:
 | 
				
			||||||
 | 
					    pusha
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					; keep this in mind:
 | 
				
			||||||
 | 
					; while (string[i] != 0) { print string[i]; i++ }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					; the comparison for string end (null byte)
 | 
				
			||||||
 | 
					start:
 | 
				
			||||||
 | 
					    mov al, [bx] ; 'bx' is the base address for the string
 | 
				
			||||||
 | 
					    cmp al, 0 
 | 
				
			||||||
 | 
					    je done
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    ; the part where we print with the BIOS help
 | 
				
			||||||
 | 
					    mov ah, 0x0e
 | 
				
			||||||
 | 
					    int 0x10 ; 'al' already contains the char
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    ; increment pointer and do next loop
 | 
				
			||||||
 | 
					    add bx, 1
 | 
				
			||||||
 | 
					    jmp start
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					done:
 | 
				
			||||||
 | 
					    popa
 | 
				
			||||||
 | 
					    ret
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					print_nl:
 | 
				
			||||||
 | 
					    pusha
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    mov ah, 0x0e
 | 
				
			||||||
 | 
					    mov al, 0x0a ; newline char
 | 
				
			||||||
 | 
					    int 0x10
 | 
				
			||||||
 | 
					    mov al, 0x0d ; carriage return
 | 
				
			||||||
 | 
					    int 0x10
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    popa
 | 
				
			||||||
 | 
					    ret
 | 
				
			||||||
							
								
								
									
										46
									
								
								15-video-ports/boot/print_hex.asm
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										46
									
								
								15-video-ports/boot/print_hex.asm
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,46 @@
 | 
				
			|||||||
 | 
					; receiving the data in 'dx'
 | 
				
			||||||
 | 
					; For the examples we'll assume that we're called with dx=0x1234
 | 
				
			||||||
 | 
					print_hex:
 | 
				
			||||||
 | 
					    pusha
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    mov cx, 0 ; our index variable
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					; Strategy: get the last char of 'dx', then convert to ASCII
 | 
				
			||||||
 | 
					; Numeric ASCII values: '0' (ASCII 0x30) to '9' (0x39), so just add 0x30 to byte N.
 | 
				
			||||||
 | 
					; For alphabetic characters A-F: 'A' (ASCII 0x41) to 'F' (0x46) we'll add 0x40
 | 
				
			||||||
 | 
					; Then, move the ASCII byte to the correct position on the resulting string
 | 
				
			||||||
 | 
					hex_loop:
 | 
				
			||||||
 | 
					    cmp cx, 4 ; loop 4 times
 | 
				
			||||||
 | 
					    je end
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    ; 1. convert last char of 'dx' to ascii
 | 
				
			||||||
 | 
					    mov ax, dx ; we will use 'ax' as our working register
 | 
				
			||||||
 | 
					    and ax, 0x000f ; 0x1234 -> 0x0004 by masking first three to zeros
 | 
				
			||||||
 | 
					    add al, 0x30 ; add 0x30 to N to convert it to ASCII "N"
 | 
				
			||||||
 | 
					    cmp al, 0x39 ; if > 9, add extra 8 to represent 'A' to 'F'
 | 
				
			||||||
 | 
					    jle step2
 | 
				
			||||||
 | 
					    add al, 7 ; 'A' is ASCII 65 instead of 58, so 65-58=7
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					step2:
 | 
				
			||||||
 | 
					    ; 2. get the correct position of the string to place our ASCII char
 | 
				
			||||||
 | 
					    ; bx <- base address + string length - index of char
 | 
				
			||||||
 | 
					    mov bx, HEX_OUT + 5 ; base + length
 | 
				
			||||||
 | 
					    sub bx, cx  ; our index variable
 | 
				
			||||||
 | 
					    mov [bx], al ; copy the ASCII char on 'al' to the position pointed by 'bx'
 | 
				
			||||||
 | 
					    ror dx, 4 ; 0x1234 -> 0x4123 -> 0x3412 -> 0x2341 -> 0x1234
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    ; increment index and loop
 | 
				
			||||||
 | 
					    add cx, 1
 | 
				
			||||||
 | 
					    jmp hex_loop
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					end:
 | 
				
			||||||
 | 
					    ; prepare the parameter and call the function
 | 
				
			||||||
 | 
					    ; remember that print receives parameters in 'bx'
 | 
				
			||||||
 | 
					    mov bx, HEX_OUT
 | 
				
			||||||
 | 
					    call print
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    popa
 | 
				
			||||||
 | 
					    ret
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					HEX_OUT:
 | 
				
			||||||
 | 
					    db '0x0000',0 ; reserve memory for our new string
 | 
				
			||||||
							
								
								
									
										22
									
								
								15-video-ports/boot/switch_pm.asm
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										22
									
								
								15-video-ports/boot/switch_pm.asm
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,22 @@
 | 
				
			|||||||
 | 
					[bits 16]
 | 
				
			||||||
 | 
					switch_to_pm:
 | 
				
			||||||
 | 
					    cli ; 1. disable interrupts
 | 
				
			||||||
 | 
					    lgdt [gdt_descriptor] ; 2. load the GDT descriptor
 | 
				
			||||||
 | 
					    mov eax, cr0
 | 
				
			||||||
 | 
					    or eax, 0x1 ; 3. set 32-bit mode bit in cr0
 | 
				
			||||||
 | 
					    mov cr0, eax
 | 
				
			||||||
 | 
					    jmp CODE_SEG:init_pm ; 4. far jump by using a different segment
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[bits 32]
 | 
				
			||||||
 | 
					init_pm: ; we are now using 32-bit instructions
 | 
				
			||||||
 | 
					    mov ax, DATA_SEG ; 5. update the segment registers
 | 
				
			||||||
 | 
					    mov ds, ax
 | 
				
			||||||
 | 
					    mov ss, ax
 | 
				
			||||||
 | 
					    mov es, ax
 | 
				
			||||||
 | 
					    mov fs, ax
 | 
				
			||||||
 | 
					    mov gs, ax
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    mov ebp, 0x90000 ; 6. update the stack right at the top of the free space
 | 
				
			||||||
 | 
					    mov esp, ebp
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    call BEGIN_PM ; 7. Call a well-known label with useful code
 | 
				
			||||||
							
								
								
									
										26
									
								
								16-video-driver/boot/32bit_print.asm
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										26
									
								
								16-video-driver/boot/32bit_print.asm
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,26 @@
 | 
				
			|||||||
 | 
					[bits 32] ; using 32-bit protected mode
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					; this is how constants are defined
 | 
				
			||||||
 | 
					VIDEO_MEMORY equ 0xb8000
 | 
				
			||||||
 | 
					WHITE_OB_BLACK equ 0x0f ; the color byte for each character
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					print_string_pm:
 | 
				
			||||||
 | 
					    pusha
 | 
				
			||||||
 | 
					    mov edx, VIDEO_MEMORY
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					print_string_pm_loop:
 | 
				
			||||||
 | 
					    mov al, [ebx] ; [ebx] is the address of our character
 | 
				
			||||||
 | 
					    mov ah, WHITE_OB_BLACK
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    cmp al, 0 ; check if end of string
 | 
				
			||||||
 | 
					    je print_string_pm_done
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    mov [edx], ax ; store character + attribute in video memory
 | 
				
			||||||
 | 
					    add ebx, 1 ; next char
 | 
				
			||||||
 | 
					    add edx, 2 ; next video memory position
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    jmp print_string_pm_loop
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					print_string_pm_done:
 | 
				
			||||||
 | 
					    popa
 | 
				
			||||||
 | 
					    ret
 | 
				
			||||||
							
								
								
									
										51
									
								
								16-video-driver/boot/bootsect.asm
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										51
									
								
								16-video-driver/boot/bootsect.asm
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,51 @@
 | 
				
			|||||||
 | 
					; Identical to lesson 13's boot sector, but the %included files have new paths
 | 
				
			||||||
 | 
					[org 0x7c00]
 | 
				
			||||||
 | 
					KERNEL_OFFSET equ 0x1000 ; The same one we used when linking the kernel
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    mov [BOOT_DRIVE], dl ; Remember that the BIOS sets us the boot drive in 'dl' on boot
 | 
				
			||||||
 | 
					    mov bp, 0x9000
 | 
				
			||||||
 | 
					    mov sp, bp
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    mov bx, MSG_REAL_MODE 
 | 
				
			||||||
 | 
					    call print
 | 
				
			||||||
 | 
					    call print_nl
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    call load_kernel ; read the kernel from disk
 | 
				
			||||||
 | 
					    call switch_to_pm ; disable interrupts, load GDT,  etc. Finally jumps to 'BEGIN_PM'
 | 
				
			||||||
 | 
					    jmp $ ; Never executed
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					%include "boot/print.asm"
 | 
				
			||||||
 | 
					%include "boot/print_hex.asm"
 | 
				
			||||||
 | 
					%include "boot/disk.asm"
 | 
				
			||||||
 | 
					%include "boot/gdt.asm"
 | 
				
			||||||
 | 
					%include "boot/32bit_print.asm"
 | 
				
			||||||
 | 
					%include "boot/switch_pm.asm"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[bits 16]
 | 
				
			||||||
 | 
					load_kernel:
 | 
				
			||||||
 | 
					    mov bx, MSG_LOAD_KERNEL
 | 
				
			||||||
 | 
					    call print
 | 
				
			||||||
 | 
					    call print_nl
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    mov bx, KERNEL_OFFSET ; Read from disk and store in 0x1000
 | 
				
			||||||
 | 
					    mov dh, 16 ; Our future kernel will be larger, make this big
 | 
				
			||||||
 | 
					    mov dl, [BOOT_DRIVE]
 | 
				
			||||||
 | 
					    call disk_load
 | 
				
			||||||
 | 
					    ret
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[bits 32]
 | 
				
			||||||
 | 
					BEGIN_PM:
 | 
				
			||||||
 | 
					    mov ebx, MSG_PROT_MODE
 | 
				
			||||||
 | 
					    call print_string_pm
 | 
				
			||||||
 | 
					    call KERNEL_OFFSET ; Give control to the kernel
 | 
				
			||||||
 | 
					    jmp $ ; Stay here when the kernel returns control to us (if ever)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					BOOT_DRIVE db 0 ; It is a good idea to store it in memory because 'dl' may get overwritten
 | 
				
			||||||
 | 
					MSG_REAL_MODE db "Started in 16-bit Real Mode", 0
 | 
				
			||||||
 | 
					MSG_PROT_MODE db "Landed in 32-bit Protected Mode", 0
 | 
				
			||||||
 | 
					MSG_LOAD_KERNEL db "Loading kernel into memory", 0
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					; padding
 | 
				
			||||||
 | 
					times 510 - ($-$$) db 0
 | 
				
			||||||
 | 
					dw 0xaa55
 | 
				
			||||||
							
								
								
									
										46
									
								
								16-video-driver/boot/disk.asm
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										46
									
								
								16-video-driver/boot/disk.asm
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,46 @@
 | 
				
			|||||||
 | 
					; load 'dh' sectors from drive 'dl' into ES:BX
 | 
				
			||||||
 | 
					disk_load:
 | 
				
			||||||
 | 
					    pusha
 | 
				
			||||||
 | 
					    ; reading from disk requires setting specific values in all registers
 | 
				
			||||||
 | 
					    ; so we will overwrite our input parameters from 'dx'. Let's save it
 | 
				
			||||||
 | 
					    ; to the stack for later use.
 | 
				
			||||||
 | 
					    push dx
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    mov ah, 0x02 ; ah <- int 0x13 function. 0x02 = 'read'
 | 
				
			||||||
 | 
					    mov al, dh   ; al <- number of sectors to read (0x01 .. 0x80)
 | 
				
			||||||
 | 
					    mov cl, 0x02 ; cl <- sector (0x01 .. 0x11)
 | 
				
			||||||
 | 
					                 ; 0x01 is our boot sector, 0x02 is the first 'available' sector
 | 
				
			||||||
 | 
					    mov ch, 0x00 ; ch <- cylinder (0x0 .. 0x3FF, upper 2 bits in 'cl')
 | 
				
			||||||
 | 
					    ; dl <- drive number. Our caller sets it as a parameter and gets it from BIOS
 | 
				
			||||||
 | 
					    ; (0 = floppy, 1 = floppy2, 0x80 = hdd, 0x81 = hdd2)
 | 
				
			||||||
 | 
					    mov dh, 0x00 ; dh <- head number (0x0 .. 0xF)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    ; [es:bx] <- pointer to buffer where the data will be stored
 | 
				
			||||||
 | 
					    ; caller sets it up for us, and it is actually the standard location for int 13h
 | 
				
			||||||
 | 
					    int 0x13      ; BIOS interrupt
 | 
				
			||||||
 | 
					    jc disk_error ; if error (stored in the carry bit)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    pop dx
 | 
				
			||||||
 | 
					    cmp al, dh    ; BIOS also sets 'al' to the # of sectors read. Compare it.
 | 
				
			||||||
 | 
					    jne sectors_error
 | 
				
			||||||
 | 
					    popa
 | 
				
			||||||
 | 
					    ret
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					disk_error:
 | 
				
			||||||
 | 
					    mov bx, DISK_ERROR
 | 
				
			||||||
 | 
					    call print
 | 
				
			||||||
 | 
					    call print_nl
 | 
				
			||||||
 | 
					    mov dh, ah ; ah = error code, dl = disk drive that dropped the error
 | 
				
			||||||
 | 
					    call print_hex ; check out the code at http://stanislavs.org/helppc/int_13-1.html
 | 
				
			||||||
 | 
					    jmp disk_loop
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					sectors_error:
 | 
				
			||||||
 | 
					    mov bx, SECTORS_ERROR
 | 
				
			||||||
 | 
					    call print
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					disk_loop:
 | 
				
			||||||
 | 
					    jmp $
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					DISK_ERROR: db "Disk read error", 0
 | 
				
			||||||
 | 
					SECTORS_ERROR: db "Incorrect number of sectors read", 0
 | 
				
			||||||
							
								
								
									
										35
									
								
								16-video-driver/boot/gdt.asm
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										35
									
								
								16-video-driver/boot/gdt.asm
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,35 @@
 | 
				
			|||||||
 | 
					gdt_start: ; don't remove the labels, they're needed to compute sizes and jumps
 | 
				
			||||||
 | 
					    ; the GDT starts with a null 8-byte
 | 
				
			||||||
 | 
					    dd 0x0 ; 4 byte
 | 
				
			||||||
 | 
					    dd 0x0 ; 4 byte
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					; GDT for code segment. base = 0x00000000, length = 0xfffff
 | 
				
			||||||
 | 
					; for flags, refer to os-dev.pdf document, page 36
 | 
				
			||||||
 | 
					gdt_code: 
 | 
				
			||||||
 | 
					    dw 0xffff    ; segment length, bits 0-15
 | 
				
			||||||
 | 
					    dw 0x0       ; segment base, bits 0-15
 | 
				
			||||||
 | 
					    db 0x0       ; segment base, bits 16-23
 | 
				
			||||||
 | 
					    db 10011010b ; flags (8 bits)
 | 
				
			||||||
 | 
					    db 11001111b ; flags (4 bits) + segment length, bits 16-19
 | 
				
			||||||
 | 
					    db 0x0       ; segment base, bits 24-31
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					; GDT for data segment. base and length identical to code segment
 | 
				
			||||||
 | 
					; some flags changed, again, refer to os-dev.pdf
 | 
				
			||||||
 | 
					gdt_data:
 | 
				
			||||||
 | 
					    dw 0xffff
 | 
				
			||||||
 | 
					    dw 0x0
 | 
				
			||||||
 | 
					    db 0x0
 | 
				
			||||||
 | 
					    db 10010010b
 | 
				
			||||||
 | 
					    db 11001111b
 | 
				
			||||||
 | 
					    db 0x0
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					gdt_end:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					; GDT descriptor
 | 
				
			||||||
 | 
					gdt_descriptor:
 | 
				
			||||||
 | 
					    dw gdt_end - gdt_start - 1 ; size (16 bit), always one less of its true size
 | 
				
			||||||
 | 
					    dd gdt_start ; address (32 bit)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					; define some constants for later use
 | 
				
			||||||
 | 
					CODE_SEG equ gdt_code - gdt_start
 | 
				
			||||||
 | 
					DATA_SEG equ gdt_data - gdt_start
 | 
				
			||||||
							
								
								
									
										4
									
								
								16-video-driver/boot/kernel_entry.asm
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										4
									
								
								16-video-driver/boot/kernel_entry.asm
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,4 @@
 | 
				
			|||||||
 | 
					[bits 32]
 | 
				
			||||||
 | 
					[extern main] ; Define calling point. Must have same name as kernel.c 'main' function
 | 
				
			||||||
 | 
					call main ; Calls the C function. The linker will know where it is placed in memory
 | 
				
			||||||
 | 
					jmp $
 | 
				
			||||||
							
								
								
									
										37
									
								
								16-video-driver/boot/print.asm
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										37
									
								
								16-video-driver/boot/print.asm
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,37 @@
 | 
				
			|||||||
 | 
					print:
 | 
				
			||||||
 | 
					    pusha
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					; keep this in mind:
 | 
				
			||||||
 | 
					; while (string[i] != 0) { print string[i]; i++ }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					; the comparison for string end (null byte)
 | 
				
			||||||
 | 
					start:
 | 
				
			||||||
 | 
					    mov al, [bx] ; 'bx' is the base address for the string
 | 
				
			||||||
 | 
					    cmp al, 0 
 | 
				
			||||||
 | 
					    je done
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    ; the part where we print with the BIOS help
 | 
				
			||||||
 | 
					    mov ah, 0x0e
 | 
				
			||||||
 | 
					    int 0x10 ; 'al' already contains the char
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    ; increment pointer and do next loop
 | 
				
			||||||
 | 
					    add bx, 1
 | 
				
			||||||
 | 
					    jmp start
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					done:
 | 
				
			||||||
 | 
					    popa
 | 
				
			||||||
 | 
					    ret
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					print_nl:
 | 
				
			||||||
 | 
					    pusha
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    mov ah, 0x0e
 | 
				
			||||||
 | 
					    mov al, 0x0a ; newline char
 | 
				
			||||||
 | 
					    int 0x10
 | 
				
			||||||
 | 
					    mov al, 0x0d ; carriage return
 | 
				
			||||||
 | 
					    int 0x10
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    popa
 | 
				
			||||||
 | 
					    ret
 | 
				
			||||||
							
								
								
									
										46
									
								
								16-video-driver/boot/print_hex.asm
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										46
									
								
								16-video-driver/boot/print_hex.asm
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,46 @@
 | 
				
			|||||||
 | 
					; receiving the data in 'dx'
 | 
				
			||||||
 | 
					; For the examples we'll assume that we're called with dx=0x1234
 | 
				
			||||||
 | 
					print_hex:
 | 
				
			||||||
 | 
					    pusha
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    mov cx, 0 ; our index variable
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					; Strategy: get the last char of 'dx', then convert to ASCII
 | 
				
			||||||
 | 
					; Numeric ASCII values: '0' (ASCII 0x30) to '9' (0x39), so just add 0x30 to byte N.
 | 
				
			||||||
 | 
					; For alphabetic characters A-F: 'A' (ASCII 0x41) to 'F' (0x46) we'll add 0x40
 | 
				
			||||||
 | 
					; Then, move the ASCII byte to the correct position on the resulting string
 | 
				
			||||||
 | 
					hex_loop:
 | 
				
			||||||
 | 
					    cmp cx, 4 ; loop 4 times
 | 
				
			||||||
 | 
					    je end
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    ; 1. convert last char of 'dx' to ascii
 | 
				
			||||||
 | 
					    mov ax, dx ; we will use 'ax' as our working register
 | 
				
			||||||
 | 
					    and ax, 0x000f ; 0x1234 -> 0x0004 by masking first three to zeros
 | 
				
			||||||
 | 
					    add al, 0x30 ; add 0x30 to N to convert it to ASCII "N"
 | 
				
			||||||
 | 
					    cmp al, 0x39 ; if > 9, add extra 8 to represent 'A' to 'F'
 | 
				
			||||||
 | 
					    jle step2
 | 
				
			||||||
 | 
					    add al, 7 ; 'A' is ASCII 65 instead of 58, so 65-58=7
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					step2:
 | 
				
			||||||
 | 
					    ; 2. get the correct position of the string to place our ASCII char
 | 
				
			||||||
 | 
					    ; bx <- base address + string length - index of char
 | 
				
			||||||
 | 
					    mov bx, HEX_OUT + 5 ; base + length
 | 
				
			||||||
 | 
					    sub bx, cx  ; our index variable
 | 
				
			||||||
 | 
					    mov [bx], al ; copy the ASCII char on 'al' to the position pointed by 'bx'
 | 
				
			||||||
 | 
					    ror dx, 4 ; 0x1234 -> 0x4123 -> 0x3412 -> 0x2341 -> 0x1234
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    ; increment index and loop
 | 
				
			||||||
 | 
					    add cx, 1
 | 
				
			||||||
 | 
					    jmp hex_loop
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					end:
 | 
				
			||||||
 | 
					    ; prepare the parameter and call the function
 | 
				
			||||||
 | 
					    ; remember that print receives parameters in 'bx'
 | 
				
			||||||
 | 
					    mov bx, HEX_OUT
 | 
				
			||||||
 | 
					    call print
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    popa
 | 
				
			||||||
 | 
					    ret
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					HEX_OUT:
 | 
				
			||||||
 | 
					    db '0x0000',0 ; reserve memory for our new string
 | 
				
			||||||
							
								
								
									
										22
									
								
								16-video-driver/boot/switch_pm.asm
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										22
									
								
								16-video-driver/boot/switch_pm.asm
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,22 @@
 | 
				
			|||||||
 | 
					[bits 16]
 | 
				
			||||||
 | 
					switch_to_pm:
 | 
				
			||||||
 | 
					    cli ; 1. disable interrupts
 | 
				
			||||||
 | 
					    lgdt [gdt_descriptor] ; 2. load the GDT descriptor
 | 
				
			||||||
 | 
					    mov eax, cr0
 | 
				
			||||||
 | 
					    or eax, 0x1 ; 3. set 32-bit mode bit in cr0
 | 
				
			||||||
 | 
					    mov cr0, eax
 | 
				
			||||||
 | 
					    jmp CODE_SEG:init_pm ; 4. far jump by using a different segment
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[bits 32]
 | 
				
			||||||
 | 
					init_pm: ; we are now using 32-bit instructions
 | 
				
			||||||
 | 
					    mov ax, DATA_SEG ; 5. update the segment registers
 | 
				
			||||||
 | 
					    mov ds, ax
 | 
				
			||||||
 | 
					    mov ss, ax
 | 
				
			||||||
 | 
					    mov es, ax
 | 
				
			||||||
 | 
					    mov fs, ax
 | 
				
			||||||
 | 
					    mov gs, ax
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    mov ebp, 0x90000 ; 6. update the stack right at the top of the free space
 | 
				
			||||||
 | 
					    mov esp, ebp
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    call BEGIN_PM ; 7. Call a well-known label with useful code
 | 
				
			||||||
							
								
								
									
										26
									
								
								17-video-scroll/boot/32bit_print.asm
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										26
									
								
								17-video-scroll/boot/32bit_print.asm
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,26 @@
 | 
				
			|||||||
 | 
					[bits 32] ; using 32-bit protected mode
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					; this is how constants are defined
 | 
				
			||||||
 | 
					VIDEO_MEMORY equ 0xb8000
 | 
				
			||||||
 | 
					WHITE_OB_BLACK equ 0x0f ; the color byte for each character
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					print_string_pm:
 | 
				
			||||||
 | 
					    pusha
 | 
				
			||||||
 | 
					    mov edx, VIDEO_MEMORY
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					print_string_pm_loop:
 | 
				
			||||||
 | 
					    mov al, [ebx] ; [ebx] is the address of our character
 | 
				
			||||||
 | 
					    mov ah, WHITE_OB_BLACK
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    cmp al, 0 ; check if end of string
 | 
				
			||||||
 | 
					    je print_string_pm_done
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    mov [edx], ax ; store character + attribute in video memory
 | 
				
			||||||
 | 
					    add ebx, 1 ; next char
 | 
				
			||||||
 | 
					    add edx, 2 ; next video memory position
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    jmp print_string_pm_loop
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					print_string_pm_done:
 | 
				
			||||||
 | 
					    popa
 | 
				
			||||||
 | 
					    ret
 | 
				
			||||||
							
								
								
									
										51
									
								
								17-video-scroll/boot/bootsect.asm
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										51
									
								
								17-video-scroll/boot/bootsect.asm
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,51 @@
 | 
				
			|||||||
 | 
					; Identical to lesson 13's boot sector, but the %included files have new paths
 | 
				
			||||||
 | 
					[org 0x7c00]
 | 
				
			||||||
 | 
					KERNEL_OFFSET equ 0x1000 ; The same one we used when linking the kernel
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    mov [BOOT_DRIVE], dl ; Remember that the BIOS sets us the boot drive in 'dl' on boot
 | 
				
			||||||
 | 
					    mov bp, 0x9000
 | 
				
			||||||
 | 
					    mov sp, bp
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    mov bx, MSG_REAL_MODE 
 | 
				
			||||||
 | 
					    call print
 | 
				
			||||||
 | 
					    call print_nl
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    call load_kernel ; read the kernel from disk
 | 
				
			||||||
 | 
					    call switch_to_pm ; disable interrupts, load GDT,  etc. Finally jumps to 'BEGIN_PM'
 | 
				
			||||||
 | 
					    jmp $ ; Never executed
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					%include "boot/print.asm"
 | 
				
			||||||
 | 
					%include "boot/print_hex.asm"
 | 
				
			||||||
 | 
					%include "boot/disk.asm"
 | 
				
			||||||
 | 
					%include "boot/gdt.asm"
 | 
				
			||||||
 | 
					%include "boot/32bit_print.asm"
 | 
				
			||||||
 | 
					%include "boot/switch_pm.asm"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[bits 16]
 | 
				
			||||||
 | 
					load_kernel:
 | 
				
			||||||
 | 
					    mov bx, MSG_LOAD_KERNEL
 | 
				
			||||||
 | 
					    call print
 | 
				
			||||||
 | 
					    call print_nl
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    mov bx, KERNEL_OFFSET ; Read from disk and store in 0x1000
 | 
				
			||||||
 | 
					    mov dh, 16 ; Our future kernel will be larger, make this big
 | 
				
			||||||
 | 
					    mov dl, [BOOT_DRIVE]
 | 
				
			||||||
 | 
					    call disk_load
 | 
				
			||||||
 | 
					    ret
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[bits 32]
 | 
				
			||||||
 | 
					BEGIN_PM:
 | 
				
			||||||
 | 
					    mov ebx, MSG_PROT_MODE
 | 
				
			||||||
 | 
					    call print_string_pm
 | 
				
			||||||
 | 
					    call KERNEL_OFFSET ; Give control to the kernel
 | 
				
			||||||
 | 
					    jmp $ ; Stay here when the kernel returns control to us (if ever)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					BOOT_DRIVE db 0 ; It is a good idea to store it in memory because 'dl' may get overwritten
 | 
				
			||||||
 | 
					MSG_REAL_MODE db "Started in 16-bit Real Mode", 0
 | 
				
			||||||
 | 
					MSG_PROT_MODE db "Landed in 32-bit Protected Mode", 0
 | 
				
			||||||
 | 
					MSG_LOAD_KERNEL db "Loading kernel into memory", 0
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					; padding
 | 
				
			||||||
 | 
					times 510 - ($-$$) db 0
 | 
				
			||||||
 | 
					dw 0xaa55
 | 
				
			||||||
							
								
								
									
										46
									
								
								17-video-scroll/boot/disk.asm
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										46
									
								
								17-video-scroll/boot/disk.asm
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,46 @@
 | 
				
			|||||||
 | 
					; load 'dh' sectors from drive 'dl' into ES:BX
 | 
				
			||||||
 | 
					disk_load:
 | 
				
			||||||
 | 
					    pusha
 | 
				
			||||||
 | 
					    ; reading from disk requires setting specific values in all registers
 | 
				
			||||||
 | 
					    ; so we will overwrite our input parameters from 'dx'. Let's save it
 | 
				
			||||||
 | 
					    ; to the stack for later use.
 | 
				
			||||||
 | 
					    push dx
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    mov ah, 0x02 ; ah <- int 0x13 function. 0x02 = 'read'
 | 
				
			||||||
 | 
					    mov al, dh   ; al <- number of sectors to read (0x01 .. 0x80)
 | 
				
			||||||
 | 
					    mov cl, 0x02 ; cl <- sector (0x01 .. 0x11)
 | 
				
			||||||
 | 
					                 ; 0x01 is our boot sector, 0x02 is the first 'available' sector
 | 
				
			||||||
 | 
					    mov ch, 0x00 ; ch <- cylinder (0x0 .. 0x3FF, upper 2 bits in 'cl')
 | 
				
			||||||
 | 
					    ; dl <- drive number. Our caller sets it as a parameter and gets it from BIOS
 | 
				
			||||||
 | 
					    ; (0 = floppy, 1 = floppy2, 0x80 = hdd, 0x81 = hdd2)
 | 
				
			||||||
 | 
					    mov dh, 0x00 ; dh <- head number (0x0 .. 0xF)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    ; [es:bx] <- pointer to buffer where the data will be stored
 | 
				
			||||||
 | 
					    ; caller sets it up for us, and it is actually the standard location for int 13h
 | 
				
			||||||
 | 
					    int 0x13      ; BIOS interrupt
 | 
				
			||||||
 | 
					    jc disk_error ; if error (stored in the carry bit)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    pop dx
 | 
				
			||||||
 | 
					    cmp al, dh    ; BIOS also sets 'al' to the # of sectors read. Compare it.
 | 
				
			||||||
 | 
					    jne sectors_error
 | 
				
			||||||
 | 
					    popa
 | 
				
			||||||
 | 
					    ret
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					disk_error:
 | 
				
			||||||
 | 
					    mov bx, DISK_ERROR
 | 
				
			||||||
 | 
					    call print
 | 
				
			||||||
 | 
					    call print_nl
 | 
				
			||||||
 | 
					    mov dh, ah ; ah = error code, dl = disk drive that dropped the error
 | 
				
			||||||
 | 
					    call print_hex ; check out the code at http://stanislavs.org/helppc/int_13-1.html
 | 
				
			||||||
 | 
					    jmp disk_loop
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					sectors_error:
 | 
				
			||||||
 | 
					    mov bx, SECTORS_ERROR
 | 
				
			||||||
 | 
					    call print
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					disk_loop:
 | 
				
			||||||
 | 
					    jmp $
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					DISK_ERROR: db "Disk read error", 0
 | 
				
			||||||
 | 
					SECTORS_ERROR: db "Incorrect number of sectors read", 0
 | 
				
			||||||
							
								
								
									
										35
									
								
								17-video-scroll/boot/gdt.asm
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										35
									
								
								17-video-scroll/boot/gdt.asm
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,35 @@
 | 
				
			|||||||
 | 
					gdt_start: ; don't remove the labels, they're needed to compute sizes and jumps
 | 
				
			||||||
 | 
					    ; the GDT starts with a null 8-byte
 | 
				
			||||||
 | 
					    dd 0x0 ; 4 byte
 | 
				
			||||||
 | 
					    dd 0x0 ; 4 byte
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					; GDT for code segment. base = 0x00000000, length = 0xfffff
 | 
				
			||||||
 | 
					; for flags, refer to os-dev.pdf document, page 36
 | 
				
			||||||
 | 
					gdt_code: 
 | 
				
			||||||
 | 
					    dw 0xffff    ; segment length, bits 0-15
 | 
				
			||||||
 | 
					    dw 0x0       ; segment base, bits 0-15
 | 
				
			||||||
 | 
					    db 0x0       ; segment base, bits 16-23
 | 
				
			||||||
 | 
					    db 10011010b ; flags (8 bits)
 | 
				
			||||||
 | 
					    db 11001111b ; flags (4 bits) + segment length, bits 16-19
 | 
				
			||||||
 | 
					    db 0x0       ; segment base, bits 24-31
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					; GDT for data segment. base and length identical to code segment
 | 
				
			||||||
 | 
					; some flags changed, again, refer to os-dev.pdf
 | 
				
			||||||
 | 
					gdt_data:
 | 
				
			||||||
 | 
					    dw 0xffff
 | 
				
			||||||
 | 
					    dw 0x0
 | 
				
			||||||
 | 
					    db 0x0
 | 
				
			||||||
 | 
					    db 10010010b
 | 
				
			||||||
 | 
					    db 11001111b
 | 
				
			||||||
 | 
					    db 0x0
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					gdt_end:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					; GDT descriptor
 | 
				
			||||||
 | 
					gdt_descriptor:
 | 
				
			||||||
 | 
					    dw gdt_end - gdt_start - 1 ; size (16 bit), always one less of its true size
 | 
				
			||||||
 | 
					    dd gdt_start ; address (32 bit)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					; define some constants for later use
 | 
				
			||||||
 | 
					CODE_SEG equ gdt_code - gdt_start
 | 
				
			||||||
 | 
					DATA_SEG equ gdt_data - gdt_start
 | 
				
			||||||
							
								
								
									
										4
									
								
								17-video-scroll/boot/kernel_entry.asm
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										4
									
								
								17-video-scroll/boot/kernel_entry.asm
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,4 @@
 | 
				
			|||||||
 | 
					[bits 32]
 | 
				
			||||||
 | 
					[extern main] ; Define calling point. Must have same name as kernel.c 'main' function
 | 
				
			||||||
 | 
					call main ; Calls the C function. The linker will know where it is placed in memory
 | 
				
			||||||
 | 
					jmp $
 | 
				
			||||||
							
								
								
									
										37
									
								
								17-video-scroll/boot/print.asm
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										37
									
								
								17-video-scroll/boot/print.asm
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,37 @@
 | 
				
			|||||||
 | 
					print:
 | 
				
			||||||
 | 
					    pusha
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					; keep this in mind:
 | 
				
			||||||
 | 
					; while (string[i] != 0) { print string[i]; i++ }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					; the comparison for string end (null byte)
 | 
				
			||||||
 | 
					start:
 | 
				
			||||||
 | 
					    mov al, [bx] ; 'bx' is the base address for the string
 | 
				
			||||||
 | 
					    cmp al, 0 
 | 
				
			||||||
 | 
					    je done
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    ; the part where we print with the BIOS help
 | 
				
			||||||
 | 
					    mov ah, 0x0e
 | 
				
			||||||
 | 
					    int 0x10 ; 'al' already contains the char
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    ; increment pointer and do next loop
 | 
				
			||||||
 | 
					    add bx, 1
 | 
				
			||||||
 | 
					    jmp start
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					done:
 | 
				
			||||||
 | 
					    popa
 | 
				
			||||||
 | 
					    ret
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					print_nl:
 | 
				
			||||||
 | 
					    pusha
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    mov ah, 0x0e
 | 
				
			||||||
 | 
					    mov al, 0x0a ; newline char
 | 
				
			||||||
 | 
					    int 0x10
 | 
				
			||||||
 | 
					    mov al, 0x0d ; carriage return
 | 
				
			||||||
 | 
					    int 0x10
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    popa
 | 
				
			||||||
 | 
					    ret
 | 
				
			||||||
							
								
								
									
										46
									
								
								17-video-scroll/boot/print_hex.asm
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										46
									
								
								17-video-scroll/boot/print_hex.asm
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,46 @@
 | 
				
			|||||||
 | 
					; receiving the data in 'dx'
 | 
				
			||||||
 | 
					; For the examples we'll assume that we're called with dx=0x1234
 | 
				
			||||||
 | 
					print_hex:
 | 
				
			||||||
 | 
					    pusha
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    mov cx, 0 ; our index variable
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					; Strategy: get the last char of 'dx', then convert to ASCII
 | 
				
			||||||
 | 
					; Numeric ASCII values: '0' (ASCII 0x30) to '9' (0x39), so just add 0x30 to byte N.
 | 
				
			||||||
 | 
					; For alphabetic characters A-F: 'A' (ASCII 0x41) to 'F' (0x46) we'll add 0x40
 | 
				
			||||||
 | 
					; Then, move the ASCII byte to the correct position on the resulting string
 | 
				
			||||||
 | 
					hex_loop:
 | 
				
			||||||
 | 
					    cmp cx, 4 ; loop 4 times
 | 
				
			||||||
 | 
					    je end
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    ; 1. convert last char of 'dx' to ascii
 | 
				
			||||||
 | 
					    mov ax, dx ; we will use 'ax' as our working register
 | 
				
			||||||
 | 
					    and ax, 0x000f ; 0x1234 -> 0x0004 by masking first three to zeros
 | 
				
			||||||
 | 
					    add al, 0x30 ; add 0x30 to N to convert it to ASCII "N"
 | 
				
			||||||
 | 
					    cmp al, 0x39 ; if > 9, add extra 8 to represent 'A' to 'F'
 | 
				
			||||||
 | 
					    jle step2
 | 
				
			||||||
 | 
					    add al, 7 ; 'A' is ASCII 65 instead of 58, so 65-58=7
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					step2:
 | 
				
			||||||
 | 
					    ; 2. get the correct position of the string to place our ASCII char
 | 
				
			||||||
 | 
					    ; bx <- base address + string length - index of char
 | 
				
			||||||
 | 
					    mov bx, HEX_OUT + 5 ; base + length
 | 
				
			||||||
 | 
					    sub bx, cx  ; our index variable
 | 
				
			||||||
 | 
					    mov [bx], al ; copy the ASCII char on 'al' to the position pointed by 'bx'
 | 
				
			||||||
 | 
					    ror dx, 4 ; 0x1234 -> 0x4123 -> 0x3412 -> 0x2341 -> 0x1234
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    ; increment index and loop
 | 
				
			||||||
 | 
					    add cx, 1
 | 
				
			||||||
 | 
					    jmp hex_loop
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					end:
 | 
				
			||||||
 | 
					    ; prepare the parameter and call the function
 | 
				
			||||||
 | 
					    ; remember that print receives parameters in 'bx'
 | 
				
			||||||
 | 
					    mov bx, HEX_OUT
 | 
				
			||||||
 | 
					    call print
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    popa
 | 
				
			||||||
 | 
					    ret
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					HEX_OUT:
 | 
				
			||||||
 | 
					    db '0x0000',0 ; reserve memory for our new string
 | 
				
			||||||
							
								
								
									
										22
									
								
								17-video-scroll/boot/switch_pm.asm
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										22
									
								
								17-video-scroll/boot/switch_pm.asm
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,22 @@
 | 
				
			|||||||
 | 
					[bits 16]
 | 
				
			||||||
 | 
					switch_to_pm:
 | 
				
			||||||
 | 
					    cli ; 1. disable interrupts
 | 
				
			||||||
 | 
					    lgdt [gdt_descriptor] ; 2. load the GDT descriptor
 | 
				
			||||||
 | 
					    mov eax, cr0
 | 
				
			||||||
 | 
					    or eax, 0x1 ; 3. set 32-bit mode bit in cr0
 | 
				
			||||||
 | 
					    mov cr0, eax
 | 
				
			||||||
 | 
					    jmp CODE_SEG:init_pm ; 4. far jump by using a different segment
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[bits 32]
 | 
				
			||||||
 | 
					init_pm: ; we are now using 32-bit instructions
 | 
				
			||||||
 | 
					    mov ax, DATA_SEG ; 5. update the segment registers
 | 
				
			||||||
 | 
					    mov ds, ax
 | 
				
			||||||
 | 
					    mov ss, ax
 | 
				
			||||||
 | 
					    mov es, ax
 | 
				
			||||||
 | 
					    mov fs, ax
 | 
				
			||||||
 | 
					    mov gs, ax
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    mov ebp, 0x90000 ; 6. update the stack right at the top of the free space
 | 
				
			||||||
 | 
					    mov esp, ebp
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    call BEGIN_PM ; 7. Call a well-known label with useful code
 | 
				
			||||||
		Loading…
	
		Reference in New Issue
	
	Block a user