/..

#CONTENT

#TOP

bootstrap.s
TEXT
    .intel_syntax noprefix
    .section .boot16, "awx"
	.code16

    .global _code_16

    .global gdt32_desc
    .global gdt32_offset_code
    .global gdt32_offset_data
    .global print_str
    .global print_hex

    .extern __e820_memory_map_len

    .equ TERMINAL_COLOR, 0x0F
    .equ VIDEO_PAGE,     0x00


_code_16:
    cli
    cld

    mov   si,    offset enter_bootstrap
    call  print_str

    mov   di,    offset __e820_memory_map
    call  do_e820
	jnc   e820_success

    mov   si,    offset _e820_fail
    call  print_str
0:  jmp   0b

e820_success:
    mov   dword ptr [__e820_memory_map_len], ebp
    mov   dword ptr [__e820_memory_map_len + 4], 0

    lgdt  [gdt32_desc]
    mov   eax,   cr0
    or    al,    1
    mov   cr0,   eax

    .att_syntax prefix
    jmpl $0x08, $0x100000
    .intel_syntax noprefix


print_str:
    pushad
    mov    ah,    0x0e                        # ah=0x0E, int 0x10, print character and move cursor
    mov    bx,    0 << 8 | 0x0F
1:
    lodsb
    int    0x10
    cmp    byte ptr [si], 0
    jne    1b
    popad
    ret


print_hex:
    pushad
    mov    bp,    sp

    push   0

1:
    lodsb
    mov    ah,    al
    shr    ah,    4
    and    al,    0x0F
    call   hex
    xchg   al,    ah
    call   hex
    push   ax
    loop   1b

    mov    si,    sp
    call   print_str

    mov    sp,    bp
    popad
    ret


hex:
    add    al,    0x30
    cmp    al,    0x39
    jle    0f
    add    al,    'A' - 0x30 - 0x0A
0:
    ret


# uses eax = 0xe820, int 15h to get memory map
# returns number of entries in bp
# places memory map at es:di
do_e820:
	xor   ebx,   ebx		           # ebx must be 0 to start
	xor   ebp,   ebp	               # keep an entry count in bp
	mov   edx,   0x0534D4150	       # Place "SMAP" into edx
	mov   eax,   0xe820
	mov   dword ptr es:[di + 20], 1    # force a valid ACPI 3.X entry
	mov   ecx, 24		               # ask for 24 bytes
	int   0x15
	jc    short .failed	               # carry set on first call means "unsupported function"
	mov   edx, 0x0534D4150	           # Some BIOSes apparently trash this register?
	cmp   eax, edx		               # on success, eax must have been reset to "SMAP"
	jne   short .failed
	test  ebx, ebx		               # ebx = 0 implies list is only 1 entry long (worthless)
	je    short .failed
	jmp   short .jmpin
.e820lp:
	mov   eax,    0xe820		       # eax, ecx get trashed on every int 0x15 call
	mov   dword ptr es:[di + 20], 1    # force a valid ACPI 3.X entry
	mov   ecx,    24		           # ask for 24 bytes again
	int   0x15
	jc    short .e820f		           # carry set means "end of list already reached"
	mov   edx,   0x0534D4150	       # repair potentially trashed register
.jmpin:
	jcxz  .skipent		               # skip any 0 length entries
	cmp   cl, 20		               # got a 24 byte ACPI 3.X response?
	jbe   short .notext
	test  byte ptr es:[di + 20], 1     # if so: is the "ignore this data" bit clear?
	je    short .skipent
.notext:
	mov   ecx,   es:[di + 8]	       # get lower uint32_t of memory region length
	or    ecx,   es:[di + 12]	       # "or" it with upper uint32_t to test for zero
	jz    .skipent		               # if length uint64_t is 0, skip entry
	inc   ebp   		               # got a good entry: ++count, move to next storage spot
	add   di,   24
.skipent:
	test  ebx, ebx		               # if ebx resets to 0, list is complete
	jne   short .e820lp
.e820f:
	clc			                       # there is "jc" on end of list to this point, so the carry must be cleared
	ret                                # returns the number of entries in bp
.failed:
	stc			                       # "function unsupported" error exit
    ret 


enter_bootstrap: .asciz "[+] enter bootstrap stage\r\n"
_e820_fail: .asciz "e820 unsupported."

# https://web.archive.org/web/20190424213806/http://www.osdever.net/tutorials/view/the-world-of-protected-mode
gdt32:
# 0 byte offset
gdt32_null:
    .8byte 0             # null segment

# 8 byte offset
gdt32_code:
    .2byte 0xffff        # segment limit
    .2byte 0             # base limit
    .byte  0             # base limit continued...
    .byte  0b10011010    # access flags
    .byte  0b11001111
    .byte  0

# 16 byte offset
gdt32_data:
    .2byte 0xffff        # segment limit
    .2byte 0             # base limit
	.byte  0             # base limit continued...
	.byte  0b10010010    # access flags
	.byte  0b11001111
    .byte  0
gdt32_end:

gdt32_desc:                      # gdt descriptor
	.2byte gdt32_end - gdt32 - 1 # size of gdt
	.4byte gdt32                 # address of gdt

    .equ gdt32_offset_code, gdt32_code - gdt32
    .equ gdt32_offset_data, gdt32_data - gdt32


    .att_syntax prefix