; 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