DISK_ID EQU 0x81 org 0x7C00 bits 16 jmp .start [bits 16] ; Function: check_a20 ; ; Purpose: to check the status of the a20 line in a completely self-contained state-preserving way. ; The function can be modified as necessary by removing push's at the beginning and their ; respective pop's at the end if complete self-containment is not required. ; ; Returns: 0 in ax if the a20 line is disabled (memory wraps around) ; 1 in ax if the a20 line is enabled (memory does not wrap around) check_a20: pushf push ds push es push di push si cli xor ax, ax ; ax = 0 mov es, ax not ax ; ax = 0xFFFF mov ds, ax mov di, 0x0500 mov si, 0x0510 mov al, byte [es:di] push ax mov al, byte [ds:si] push ax mov byte [es:di], 0x00 mov byte [ds:si], 0xFF cmp byte [es:di], 0xFF pop ax mov byte [ds:si], al pop ax mov byte [es:di], al mov ax, 0 je check_a20__exit mov ax, 1 check_a20__exit: pop si pop di pop es pop ds popf ret ;;; Print string at bx puts: mov al, '!' mov ah, 0x0e int 0x10 .puts_loop: mov al, [bx] ; load the character cmp al, 0 ; check for null byte je .end_puts_loop mov ah, 0x0e int 0x10 ; print charachter inc bx jmp .puts_loop .end_puts_loop: ret ;;; Print bl as hex puthex: ; Print high bits mov dl, bl shr dl, 4 cmp dl, 9 jg .puthex_high_alpha ; It's < 10, print as digit mov al, dl add al, 0x30 mov ah, 0x0e int 0x10 jmp .puthex_low .puthex_high_alpha: ; It's >= 10, print as letter mov al, dl add al, 0x57 ; 0x57 = (0x61 - 10) mov ah, 0x0e int 0x10 .puthex_low: ; Print low bits mov dl, bl and dl, 0b1111 cmp dl, 9 jg .puthex_low_alpha ; It's < 10, print as digit mov al, dl add al, 0x30 mov ah, 0x0e int 0x10 jmp .puthex_end .puthex_low_alpha: ; It's >= 10, print as letter mov al, dl add al, 0x57 ; 0x57 = (0x61 - 10) mov ah, 0x0e int 0x10 .puthex_end: ret .start: ; reset disk system mov ah, 0x00 mov dl, DISK_ID int 0x13 ; print result on error jnc .reset_disk_no_error mov bl, ah call puthex .reset_disk_no_error: mov cx, 1 ; start at sector 1 mov bx, 0x8000 ; write to 0x8000 push bx push cx .read_disk_loop: ; Read sector dl into memory mov ah, 0x02 mov al, 0x01 ; number of sectors mov ch, 0x00 ; cylinder number, low 8 bits ; mov cl, 0x01 ; cylinder number, high 2 bits + sector number (6 bits) mov dh, 0x00 ; head number mov dl, DISK_ID ; drive number int 0x13 jc .read_disk_error ; print result on error jnc .read_disk_no_error mov bl, ah call puthex .read_disk_no_error: pop cx pop bx inc cl ; next sector add bx, 512 ; add 512 to data start so we don't overwrite sectors push bx push cx jmp .read_disk_loop .read_disk_error: call check_a20 cmp ax, 1 je .a20_enabled mov bx, .str_no_A20 call puts jmp .end .a20_enabled: ; disable interrupts cli ; reset ds xor ax, ax mov ds, ax ; load the GDT lgdt [.gdt_desc] ; switch to protected mode mov eax, cr0 or eax, 1 mov cr0, eax ; jump to 32 bit code jmp 0x08:.clear_pipe [BITS 32] .clear_pipe: ; set Data Segment and Stack segment mov ax, 10h mov ds, ax mov ss, ax ; set up stack mov esp, 0x090000 ; load offset from ELF file ; mind the differing endian mov edx, 0x8018 mov ah, [ds:edx+2] mov al, [ds:edx+3] shl eax, 16 mov ah, [ds:edx] mov al, [ds:edx+1] ; add the beginning 0x8000 add eax, 0x8000 jmp eax .end: jmp .end .data: .str_no_A20: db "A20 not enabled" db 0 .gdt: dd 0 dd 0 dw 0FFFFh dw 0 db 0 db 10011010b db 11001111b db 0 dw 0FFFFh dw 0 db 0 db 10010010b db 11001111b db 0 .gdt_end: .gdt_desc: dw .gdt_end - .gdt - 1 dd .gdt ; print padding nullbytes times 510 - ($ - $$) db 0 ; write magic string dw 0xAA55