CLOSE

Until now our kernel is 16-Bit, and in the last chapter we entered into protective land (32-Bit Protected Mode) but our kernel was 16-Bit so we were not able to call the kernel from the 32 bit mode. In order to call the kernel we have to convert it into 32-Bit. Let's do it.

Convert Kernel from 16 to 32 Bit

As our kernel is in assembly language, in order to switch it to 32 bit, we have just got to replace the BITS 16 to BITS 32. It is easy isn't it. However, we have to replace our printing function dependency, which only works for 16 bit real mode, because those function uses interrupt to print on the screen and in protected mode real mode interrupts is unavailable.

kernel/kernel_entry.asm:

org 0xb000

BITS 32		; Specify that the cod is 32-bit

This is the basic template for the 32 bit flat binary kernel.

Now we have to create the screen clearing and printing functions that will works in protected mode (32-bit) without using interrupts.

boot/stage2/includes/print32.inc:

This file will have all the printing logic for the 32 bit protected mode. These functions write directly to the memory address of the VGA which is mode 0x3 (80*25).

%ifndef _PRINT_32_INC_
%define _PRINT_32_INC_

BITS 32

%define VGA_DEFAULT_MEM_ADDR	0xb8000

%define VGA_ROW		80
%define VGA_COLOUMN	25

; 80*25 Colors
%define 		BLACK		0x0
%define 		BLUE 		0x1
%define 		GREEN 		0x2
%define 		CYAN 		0x3
%define 		RED 		0x4
%define 		MAGENTA 	0x5
%define 		BROWN 		0x6
%define 		LGRAY 		0x7
%define 		DGRAY		0x8
%define 		LBLUE		0x9
%define 		LGREEN		0xA
%define 		LCYAN		0xB
%define 		LRED		0xC
%define 		LMAGENTA	0xD
%define 		YELLOW		0xE
%define 		WHITE		0xF


;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; **************************
; ClearScreen32
; IN:
	; BL: Foreground color
	; BH; Background color
;	Nothing
; Registers:
; 	- Conserves all the Registers
; **************************
ClearScreen32:
	pushad		; Push the complete state
	
	mov esi, VGA_DEFAULT_MEM_ADDR
	mov ecx, VGA_ROW * VGA_COLOUMN
.ClearScreen32Loop:
	mov byte [esi], ' '		; Space
	mov byte [esi + 1], 0x07	; default color - lightgrey on black
	
	add esi, 2			; Increment VGA memory pointer by 2 bytes.

	loop .ClearScreen32Loop		; Loop until ecx is 0
	popad		; Pop all the saved state

ret
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;


;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; **************************
; PrintString32
; IN:
; 	- ESI: Null-Terminated String
; Registers:
; 	- Conserves all the registers
; **************************
PrintString32:
	pushad		; push all 32 bit registers onto the stack
	
	mov ecx, VGA_ROW * VGA_COLOUMN
	mov edi, VGA_DEFAULT_MEM_ADDR
	
	shl bh, 4
	or bl, bh
	
.PrintString32Loop:
	lodsb		; it reads character from the esi to al
	test al, al
	je .PrintString32Done

	;; The first byte in 80*25 ie. mode 0x3 has to be the character
	;; followed by the color,
	;; 	which is lower 4 bits for foreground color
	;; 	upper 4 bits for background color
	mov [edi], al			; Write the character
	mov byte [edi + 1], bl;0x07	; color
	
	add edi, 2
	
	loop .PrintString32Loop
.PrintString32Done:
	
	popad		; pop all saved 32-bit register from the stack
ret
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

%endif

stage2.asm:

Let's modify the stage2.asm to print the message after entering in the protected land and jump to the loaded kernel.

	;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
	;; Load Flat Kernel of Size 1 KB at location 0xB000
	xor eax, eax		; Clear out the eax
	mov esi, eax		; Clear ou the esi
	mov ax, MEMLOCATION_KERNEL_LOAD_SEGMENT	; 0x0000
	mov es, ax		; Set es to 0x0000
	mov bx, MEMLOCATION_KERNEL_LOAD_OFFSET	; 0xB000
	mov eax, 59		; Starting sector low 32 bit (0-indexed LBA)
	mov esi, 0		; Starting sector high 32 bit
	mov ecx, 2		; Sector count
	mov edx, 512		; Sector sizes in bytes
	call ReadFromDiskUsingExtendedBIOSFunction

;; Stop Jumping of Kernel, first we have to be in Protected Mode
;; and then shift the kernel to 32 bit mode.
;	jmp MEMLOCATION_KERNEL_LOAD_SEGMENT:MEMLOCATION_KERNEL_LOAD_OFFSET	; Jump to the Kernel
	;;
	;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;


	;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
	;; Entering Protective Land
	
	;; Enable PE (Protection Enable) Bit
	; Enable Protected Mode
	mov eax, cr0		; Move the current value of CR0 register into eax
	or eax, 0x1             ; Set PE bit (bit 0) to 1
	mov cr0, eax		; Write the modified value back to the CR0 register, 
    				; enabling Protected Mode
	

	; Perform a far jump to clear the prefetch queue
	jmp 0x08:ProtectedMode  ; Segment selector 0x08 (code segment)


;; Entry of 32-Bit world
BITS 32
; 32 Bit Includes
%include 'print32.inc'		; For printing
ProtectedMode:
	; Update segment registers
	xor eax, eax
	mov ax, 0x10            ; Data segment selector 0x10
	mov ds, ax
	mov es, ax
	mov fs, ax
	mov gs, ax
	mov ss, ax
    
	mov esp, 0x7BFF		; set the stack top to the 0x7BFF
    				; The stack grows from high memory to lower memory
    				;  --------
    				;  |______| 0x7BFF
    				;  |______|    
    				;  |......|  it is growing downward as we pushes
    				;  |______|		data
    				;  |______|
    				;  |      | 0x7AFF
    
	; Disable the all irq lines
	mov 	al, 0xff
	out 	0xa1, al
	out 	0x21, al

	cli		; Disable the interrupt as they are no more available
    			; in real mode.
    			
; Now we are in protective land
	
	;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
	;; clear the screen
	call ClearScreen32
	;;
	;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
	

	;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
	;; Print welcome sentence for protected mode
	mov esi, sProtectedModeWelcomeSentence
	mov bl, LMAGENTA	; Foreground = Light Magenta
	mov bh, BLACK		; Background = Black
	call PrintString32
	;;
	;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;


	;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
	;; jmp to the kernel
		jmp MEMLOCATION_KERNEL_LOAD_OFFSET
	;;
	;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

jmp $

; **********
; Variables
; **********
bPhysicalDriveNum 	db	0

WelcomeToStage2 db 'Welcome to the Stage2', 0
sReceivedDriveNumber db 'Received Drive Number in Stage 2: ', 0

sProtectedModeWelcomeSentence	db	'Entered the Protective Land', 0

times STAGE_2_SIZE - ($-$$) db 0		; Fill up the remaining space with zeroes

Now we have the functions for printing to the kernel, let's modify the kernel to clear the screen and print the welcome message.

kernel/kernel_entry.asm:

org 0xb000               ; Set the origin address for the code. This tells the assembler
                         ; that the code should be loaded at memory address 0x0B00.
                         ; So all the jmp statement and string declaration offset is
                         ; calculated based on it.
                         
BITS 32                  ; Specify that the code is 32-bit.

kernel_entry:            ; Label for the kernel entry point.

jmp start		; jmp after the includes

;; Include files
%include "print32.inc"

start:
	;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
	;; Clear the Screen
	call ClearScreen32
	;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;


	;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
	;; Print Welcome Message
	mov esi, sKernelWelcomeStatement
	mov bl, YELLOW		; Foreground color = Yellow
	mov bh, BLACK		; Background color = Black
	call PrintString32
	;;
	;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

jmp $		; Infinite loop to halt execution after printing the message.


;; Put data in second sector
times 512 - ($ - $$) db 0

sKernelWelcomeStatement: db 'Welcome to Flat Binary 32-Bit Kernel Land.', 0
                         ; Define the welcome message string, terminated by a null byte (0).

times 1024 - ($ - $$) db 0	; Fill the rest of the 1 KB (1024 bytes) space with zeros.

Makefile:

Add the stage2 includes directory for the kernel to use, because print32.inc is available at the stage2/includes directory:

BOOT_STAGE2_INCLUDE = boot/stage2/includes

kernel_entry.bin: kernel/kernel_entry.asm
	nasm -f bin -I $(BOOT_STAGE2_INCLUDE) -o build/$@ $<

Output

image-163.png

Source Code

The complete source code is at this commit: https://github.com/The-Jat/TheTaaJ/tree/boot