; Today, we continue Day 3's code and load C++ code 
;
; We first write a C++ code in kmain.cpp and plan to use i386 gcc to compile it 
; We also write a link strategy to place the bootloader at an offset of 0x7c00, which makes sure the AA55 are at 510th position.
; At the end of the bootloader, we reserve 16KB for kernal to call C++
;
; Give credits to http://3zanders.co.uk/2017/10/18/writing-a-bootloader3/
; Comments partially added by Yu Wang
; -------------------------------------------------------------------

section .boot 	; Marking this to be .boot section. Will be checked by linker script
bits 16
global boot
;org 0x7c00 ; this is realized in the "linker.ld" with code ". = 0x7c00;"

boot:
	; enable A20 bit
	mov ax, 0x2401
	int 0x15      

	; set vga to be normal mode 
	mov ax, 0x3
	int 0x10

	mov [disk], dl  ; store disk id to [disk] from DL. When bootup, BIOS sets disk id to DL implicitly. 

	mov ah, 0x2     ; AH=0x02: read sectors. More can be found https://en.wikipedia.org/wiki/INT_13H
	mov al, 6       ; Since we need more disk for bootsector, data, C++, we need more space. Here we load 6 sectors
	mov ch, 0       ; cylinder idx
	mov dh, 0       ; head idx
	mov cl, 2       ; sector idx
	mov dl, [disk]  ; disk idx
	mov bx, copy_target ;target code pointer
	int 0x13        ; Call BIOS interrupt to operate disk 
	
	cli 					; Clear interrupt flag;
	lgdt [gdt_pointer] 		; Load Global/Interrupt Descriptor Table Register defined below
	mov eax, cr0 			; CR0 has various control flags that modify the basic operation of the processor
	or eax,0x1 				; EAX |= 0x01 set the protected mode bit on special CPU reg cr0
	mov cr0, eax			;
	mov ax, DATA_SEG
	mov ds, ax
	mov es, ax
	mov fs, ax
	mov gs, ax
	mov ss, ax
	jmp CODE_SEG:boot2

gdt_start:
gdt_null: ; the GDT starts with a null 8-byte
	dq 0x00000000 	 		; 4 bytes zeros

; GDT for code segment. base = 0x00000000, length = 0xfffff
gdt_code:
	dw 0xFFFF 				; segment length, bits 0-15
	dw 0x0000				; segment base, bits 0-15
	db 0x00  				; segment base, bits 16-23
	db 10011010b 			; flags (8 bits)
	db 11001111b 			; flags (4 bits) + segment length, bits 16-19
	db 0x00 				; segment base, bits 24-31

; GDT for data segment. base and length identical to code segment
gdt_data:
	dw 0xFFFF
	dw 0x00
	db 0x00
	db 10010010b
	db 11001111b
	db 0x00
gdt_end:

; GDT descripto
gdt_pointer:
	dw gdt_end - gdt_start-1 ; some instructions say there must be a "-1" here, but the original code doesn't
	dd gdt_start

disk:
	db 0x0

; define some constants for later use
CODE_SEG equ gdt_code - gdt_start 	
DATA_SEG equ gdt_data - gdt_start

times 510 - ($-$$) db 0
dw 0xaa55

; Compare to previous two days code, the following code are in the second 512-byte sector.
copy_target:
bits 32

hello: db "Hello more than 512 bytes world!!", 0
msg:
	db "C++ calls assembly function success!!", 0

; The following are the assembly code to print
boot2:
	mov esi,hello
	mov ebx,0xb8000
.loop:
	lodsb
	or al,al
	jz cppcode
	or eax,0x0F00
	mov word [ebx], ax
	add ebx,2
	jmp .loop

; The following is to call C++
cppcode:
	mov esp, kernel_stack_top
	extern main
	call main			; the actual name in c++ obj file. If name mangling is used, "main" may need to be changed.

global fin				; declare a function name called "fin"
fin:
	cli
	hlt

global assemblyprint 	; declare a function name called "assemblyprint"
assemblyprint:
	mov esi,msg
	mov ebx,0xb8000
	add ebx, 80*2*2		; 80 chars is one line, one char is 2 bytes. spare two lines
.loop2:
	lodsb
	or al,al
	jz fin
	or eax,0x0F00
	mov word [ebx], ax
	add ebx,2
	jmp .loop2
	
	

section .bss 	; Mark the following to be .bss section. Will be checked by linker script
align 4 		; aligns the current location to a specified boundary by padding 0.
kernel_stack_bottom: equ $
	resb 16384 ; reserve 16 KB for kernel stack from current place (marked by $)
kernel_stack_top: