;BIOS Functions
SET_CURSOR_POS     = 2h
PRINT_CHARACTER    = 9h
PRINT_STRING       = 13h

;BIOS interrupt
BIOS_CALL          = 10h

;Function flags
FLAG_USE_COLOR     = 10b
FLAG_UPDATE_CUSROR = 1b

;Values for the screen
MAIN_SCREEN_PAGE   = 0
ROWS               = 25
COLS               = 80

;Length of "Hello, World!"
STRLEN             = 13

;Values for assembling the binary as x86 bootsector
BOOTSECT_SIZE      = 512
BOOTSECT_OFFSET    = 7c00h

;This is where BIOS loads our code in memory
org BOOTSECT_OFFSET

;We set up some registers before we can call BIOS functions
init:
    cli        ;Disable all maskable interrupts. We don't need them
    xor ax,ax  ;Clear the AX register. This is shorter than "mov ax,0"
    mov ds,ax  ;Clear DS and ES register. You can't directly do "mov ds,0" or "mov es,0"
    mov es,ax
    ;Set stack pointer just below the address of our entry point.
    ;The memory area below our bootloader is free for us to use down to 0x500.
    mov sp,init

    call cls   ;Clear the screen

;This uses the BIOS print string function to output our string with colors
print:
    mov ah,PRINT_STRING
    mov al,(FLAG_USE_COLOR or FLAG_UPDATE_CUSROR)
    mov bh,MAIN_SCREEN_PAGE
    mov bl,0                  ;Ignored
    mov cx,STRLEN
    mov dh,ROWS/2             ;Center vertically
    mov dl,COLS/2-(STRLEN/2)  ;Center horizontally
    mov bp,text               ;String address
    int BIOS_CALL

;End execution of our bootloader
done:
    hlt       ;Halt processor
    jmp done  ;Go back to halting if the processor was awakened by an interrupt

;Reset cursor to top left
set0:
    mov ah,SET_CURSOR_POS
    mov dx,0  ;Sets DH and DL to 0 simultaneously
    int BIOS_CALL
    ret

;Clear the screen by writing 80*25 spaces to it
cls:
    call set0
    mov ah,PRINT_CHARACTER
    mov al,' '
    mov bh,0         ;Page
    mov bl,7         ;Color
    mov cx,ROWS*COLS ;Screen size
    int BIOS_CALL
    call set0
    ret

;String to print. This is alternating between character and attributes.
;The character comes first, then the color of that character.
;This repeats for as many characters you want to print.
text:
    db 'H',2,'e',3,'l',4,'l',5,'o',6,',',7,' ',0,'W',8,'o',9,'r',10,'l',11,'d',12,'!',13

;Add magic number to mark this as bootable
bootsect:
    ;Write "hlt" instructions until binary is 510 bytes
    ;The formula subtracts space already in use by the code.
    ;It also takes the "org" at the beginning into account.
    db (init+(BOOTSECT_SIZE-2)-bootsect) dup 0F4h
    ;Write 55,AA to mark as bootable and be exactly 512 bytes.
    db 55h,0AAh