156 lines
3.6 KiB
NASM
156 lines
3.6 KiB
NASM
; mybios_real.asm
|
|
[BITS 16]
|
|
[ORG 0]
|
|
|
|
bios_start:
|
|
; 1. 세그먼트 초기화
|
|
mov ax, 0xF000
|
|
mov ds, ax
|
|
mov es, ax
|
|
xor ax, ax
|
|
mov ss, ax
|
|
mov sp, 0x7C00
|
|
|
|
; ==========================================================
|
|
; [VGA BIOS (Option ROM) 실행하기]
|
|
; QEMU는 0xC0000 번지에 표준 VGA BIOS를 올려둡니다.
|
|
; 이걸 실행해야 화면이 켜지고 curses가 작동합니다.
|
|
; ==========================================================
|
|
|
|
; 2-1. VGA BIOS가 있는지 확인 (Signature Check)
|
|
; 0xC000:0000 = 0x55, 0xC000:0001 = 0xAA 여야 함
|
|
mov ax, 0xC000
|
|
mov es, ax
|
|
|
|
cmp byte [es:0], 0x55
|
|
jne no_vga
|
|
cmp byte [es:1], 0xAA
|
|
jne no_vga
|
|
|
|
; 2-2. VGA BIOS 실행 (Far Call)
|
|
; 보통 3번째 바이트부터 코드가 시작됩니다.
|
|
; PUSH CS, PUSH IP 방식으로 돌아올 주소를 저장하고 점프합니다.
|
|
push cs ; 돌아올 세그먼트 (0xF000)
|
|
push word .vga_ret ; 돌아올 오프셋 (Label 주소)
|
|
|
|
; 0xC000:0003 으로 점프!
|
|
push 0xC000 ; VGA Segment
|
|
push 0x0003 ; VGA Entry Point
|
|
retf ; (Far Return을 이용한 점프 기법)
|
|
|
|
.vga_ret:
|
|
; 여기까지 오면 VGA BIOS가 화면을 초기화하고 돌아온 상태입니다!
|
|
; 이제 다시 우리의 세그먼트 복구
|
|
mov ax, 0xF000
|
|
mov ds, ax
|
|
mov es, ax
|
|
|
|
; 3. 화면 파란색으로 칠하기 (이제 먹힘!)
|
|
mov ax, 0xB800
|
|
mov es, ax
|
|
|
|
xor di, di
|
|
mov cx, 2000
|
|
mov ax, 0x1F20 ; 파란바탕 + 공백
|
|
rep stosw
|
|
|
|
; 4. 메시지 출력
|
|
mov si, msg_title
|
|
mov di, 0
|
|
call print_vga
|
|
|
|
mov si, msg_menu
|
|
mov di, 160
|
|
call print_vga
|
|
|
|
; 5. 메인 루프 (키보드 0x60)
|
|
main_loop:
|
|
in al, 0x64
|
|
test al, 1
|
|
jz main_loop
|
|
|
|
in al, 0x60
|
|
|
|
cmp al, 0x02 ; '1'
|
|
je action_shutdown
|
|
cmp al, 0x03 ; '2'
|
|
je action_reboot
|
|
jmp main_loop
|
|
|
|
; --- 에러 처리: VGA BIOS가 없을 때 ---
|
|
no_vga:
|
|
; 시리얼로 에러 메시지라도 보내야 함 (여기선 생략하고 무한루프)
|
|
cli
|
|
hlt
|
|
jmp $
|
|
|
|
; ===========================================================
|
|
; [Actions] (이전과 동일)
|
|
; ===========================================================
|
|
action_shutdown:
|
|
mov si, msg_bye
|
|
mov di, 320
|
|
call print_vga
|
|
|
|
; ACPI PIIX4 Shutdown
|
|
mov dx, 0xCF8
|
|
mov eax, 0x80000B04
|
|
out dx, eax
|
|
mov dx, 0xCFC
|
|
mov eax, 0x0001
|
|
out dx, eax
|
|
mov dx, 0xCF8
|
|
mov eax, 0x80000B40
|
|
out dx, eax
|
|
mov dx, 0xCFC
|
|
mov eax, 0x0000B001
|
|
out dx, eax
|
|
mov dx, 0xCF8
|
|
mov eax, 0x80000B80
|
|
out dx, eax
|
|
mov dx, 0xCFC
|
|
mov eax, 0x00000001
|
|
out dx, eax
|
|
mov dx, 0xB004
|
|
mov ax, 0x2000
|
|
out dx, ax
|
|
hlt
|
|
jmp $
|
|
|
|
action_reboot:
|
|
mov si, msg_reboot
|
|
mov di, 320
|
|
call print_vga
|
|
mov dx, 0x64
|
|
mov al, 0xFE
|
|
out dx, al
|
|
hlt
|
|
jmp $
|
|
|
|
; ===========================================================
|
|
; [Drivers]
|
|
; ===========================================================
|
|
print_vga:
|
|
mov ah, 0x1F
|
|
.loop:
|
|
lodsb
|
|
cmp al, 0
|
|
je .done
|
|
stosw
|
|
jmp .loop
|
|
.done:
|
|
ret
|
|
|
|
; ===========================================================
|
|
; [Data]
|
|
; ===========================================================
|
|
msg_title db "=== REAL BIOS (VGA Initialized) ===", 0
|
|
msg_menu db "Press [1] to Shutdown, [2] to Reboot", 0
|
|
msg_bye db "System Halted.", 0
|
|
msg_reboot db "Rebooting...", 0
|
|
|
|
; --- BIOS 크기 맞추기 (64KB) ---
|
|
times 65520-($-$$) db 0
|
|
reset_vector:
|
|
jmp 0xF000:0x0000
|
|
times 16-($-reset_vector) db 0 |