123 lines
3.3 KiB
NASM
123 lines
3.3 KiB
NASM
; mybios.asm
|
|
[BITS 16]
|
|
[ORG 0]
|
|
|
|
bios_start:
|
|
; 1. 세그먼트 초기화 (CS=0xF000 이므로 DS, ES도 맞춤)
|
|
mov ax, 0xF000
|
|
mov ds, ax
|
|
mov es, ax
|
|
|
|
; mov ss, ax
|
|
; mov sp, 0xFFF0
|
|
xor ax, ax ; AX = 0
|
|
mov ss, ax ; SS = 0x0000 (RAM)
|
|
mov sp, 0xFFFE ; 0x0000 ~ 0xFFFF 영역 중 가장 끝!
|
|
; mov sp, 0x7C00 ; SP = 0x7C00 (부트로더가 쓰는 안전한 RAM 공간)
|
|
|
|
; 2. 시리얼 포트(COM1) 초기화 (필수!)
|
|
mov dx, 0x3FB ; Line Control Register
|
|
mov al, 0x80 ; DLAB bit set
|
|
out dx, al
|
|
|
|
mov dx, 0x3F8 ; Divisor (Low) - 9600 baud
|
|
mov al, 0x0C
|
|
out dx, al
|
|
|
|
mov dx, 0x3F9 ; Divisor (High)
|
|
mov al, 0x00
|
|
out dx, al
|
|
|
|
mov dx, 0x3FB ; LCR: 8 bits, no parity, 1 stop bit
|
|
mov al, 0x03
|
|
out dx, al
|
|
|
|
; 3. 메시지 출력
|
|
mov si, msg_bios
|
|
call print_serial
|
|
|
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
|
; ===========================================================
|
|
; [ACPI Shutdown Sequence for QEMU PIIX4 Chipset]
|
|
; Target: Bus 0, Device 1, Function 3 (Power Management)
|
|
; Address Format: 1(En) | Bus(0) | Dev(1) | Func(3) | Reg
|
|
; Hex Prefix: 0x80 | 00 | 08 | 03 | ..
|
|
; Combined: 0x80000B.. (Function 3 is the key)
|
|
; ===========================================================
|
|
|
|
; Step 0: Enable I/O Access (Command Register - 0x04)
|
|
; We must tell the chipset to allow I/O port access first.
|
|
mov dx, 0xCF8
|
|
mov eax, 0x80000B04 ; Address: Func 3, Reg 0x04
|
|
out dx, eax
|
|
|
|
mov dx, 0xCFC
|
|
mov eax, 0x0001 ; Value: Bit 0 (I/O Space Enable)
|
|
out dx, eax
|
|
|
|
; Step 1: Set ACPI Base Address (PMBA - 0x40)
|
|
; We map the ACPI registers to I/O port 0xB000.
|
|
mov dx, 0xCF8
|
|
mov eax, 0x80000B40 ; Address: Func 3, Reg 0x40
|
|
out dx, eax
|
|
|
|
mov dx, 0xCFC
|
|
mov eax, 0x0000B001 ; Value: Base 0xB000 | Bit 0 (Hardwired to 1)
|
|
out dx, eax
|
|
|
|
; Step 2: Enable ACPI Function (PMREGMISC - 0x80)
|
|
mov dx, 0xCF8
|
|
mov eax, 0x80000B80 ; Address: Func 3, Reg 0x80
|
|
out dx, eax
|
|
|
|
mov dx, 0xCFC
|
|
mov eax, 0x00000001 ; Value: Bit 0 (ACPI Enable)
|
|
out dx, eax
|
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
|
|
|
mov si, msg_off
|
|
call print_serial
|
|
|
|
; ; Exit with return value 0
|
|
mov dx, 0xB004
|
|
mov ax, 0x2000 ; SLP_TYP(Soft Off) | SLP_EN
|
|
out dx, ax
|
|
|
|
; ; reboot
|
|
; mov dx, 0x64
|
|
; mov al, 0xFE
|
|
; out dx, al
|
|
|
|
; ; exit (isa-debug-exit; need '-device isa-debug-exit,iobase=0x501,iosize=0x04')
|
|
; mov dx, 0x501
|
|
; mov al, 0x02 ; exit code (2) -> qemu exits with exit code (al<<1)|1
|
|
; out dx, al
|
|
|
|
; 그래도 안 꺼지면 그냥 멈춰라
|
|
cli
|
|
hlt
|
|
jmp $
|
|
|
|
; --- 시리얼 출력 함수 ---
|
|
print_serial:
|
|
mov dx, 0x3F8 ; COM1 데이터 포트
|
|
.loop:
|
|
lodsb ; [DS:SI] -> AL
|
|
cmp al, 0
|
|
je .done
|
|
out dx, al ; 한 글자 전송
|
|
jmp .loop
|
|
.done:
|
|
ret
|
|
|
|
; msg_bios db "Hello! This is a CUSTOM BIOS running on QEMU!", 0x0D, 0x0A, 0
|
|
msg_bios db "Hello! This is a CUSTOM BIOS running on QEMU!", 0x0D, 0x0A, 0
|
|
msg_off db "ACPI Enabled. Powering Off NOW!", 0x0D, 0x0A, 0
|
|
|
|
|
|
; Padding
|
|
times 65520-($-$$) db 0
|
|
|
|
reset_vector:
|
|
jmp 0xF000:0x0000
|
|
times 16-($-reset_vector) db 0 |