update qemu study

This commit is contained in:
2025-12-30 08:19:49 +00:00
parent ac241a9148
commit 8f1a81b699
11 changed files with 885 additions and 0 deletions
+152
View File
@@ -0,0 +1,152 @@
; mybios_ssh.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
; 2. 시리얼 포트 초기화 (가장 중요!)
call init_serial
; 3. 부팅 메시지 출력
mov si, msg_boot
call print_serial
; 4. 메인 루프 (입력 대기)
mov si, msg_menu
call print_serial
main_loop:
; --- Heartbeat (살아있음을 표시) ---
; 입력이 없어도 멈춘 게 아니라는 걸 보여주기 위해 점(.)을 찍을 수도 있지만,
; 너무 지저분해지니 생략하고 입력만 기다립니다.
; [입력 확인] 0x3FD 포트의 0번 비트가 1이면 데이터가 온 것임
mov dx, 0x3FD
in al, dx
test al, 1
jz main_loop ; 데이터 없으면 계속 뺑뺑이(Loop)
; [데이터 읽기] 0x3F8 포트에서 읽음
mov dx, 0x3F8
in al, dx
; [내가 누른 키 화면에 보여주기 (Echo)]
; 이게 없으면 내가 뭘 눌렀는지 터미널에 안 보임!
out dx, al
; [키 판별]
cmp al, '1'
je action_shutdown
cmp al, '2'
je action_reboot
jmp main_loop
; ===========================================================
; [Actions]
; ===========================================================
action_shutdown:
mov si, msg_bye
call print_serial
; PIIX4 ACPI Shutdown (Power Off)
; 1. I/O Enable
mov dx, 0xCF8
mov eax, 0x80000B04
out dx, eax
mov dx, 0xCFC
mov eax, 0x0001
out dx, eax
; 2. PMBA -> 0xB000
mov dx, 0xCF8
mov eax, 0x80000B40
out dx, eax
mov dx, 0xCFC
mov eax, 0x0000B001
out dx, eax
; 3. ACPI Enable
mov dx, 0xCF8
mov eax, 0x80000B80
out dx, eax
mov dx, 0xCFC
mov eax, 0x00000001
out dx, eax
; 4. Shutdown Command
mov dx, 0xB004
mov ax, 0x2000
out dx, ax
; 안 꺼지면 대기
hlt
jmp $
action_reboot:
mov si, msg_reboot
call print_serial
; Reboot Command
mov dx, 0x64
mov al, 0xFE
out dx, al
hlt
jmp $
; ===========================================================
; [Drivers]
; ===========================================================
init_serial:
mov dx, 0x3FB
mov al, 0x80 ; DLAB ON
out dx, al
mov dx, 0x3F8
mov al, 0x0C ; 9600 baud
out dx, al
mov dx, 0x3F9
mov al, 0x00
out dx, al
mov dx, 0x3FB
mov al, 0x03 ; 8N1, DLAB OFF
out dx, al
ret
print_serial:
mov dx, 0x3F8
.loop:
lodsb
cmp al, 0
je .done
out dx, al
jmp .loop
.done:
ret
; ===========================================================
; [Data]
; ===========================================================
; 줄바꿈(0x0D, 0x0A)을 명확히 넣었습니다.
msg_boot db 0x0D, 0x0A, "===============================", 0x0D, 0x0A
db " SSH Serial BIOS v1.0 ", 0x0D, 0x0A
db "===============================", 0x0D, 0x0A, 0
msg_menu db 0x0D, 0x0A, "COMMANDS: [1] Shutdown [2] Reboot", 0x0D, 0x0A
db "Input > ", 0
msg_bye db 0x0D, 0x0A, ">>> System is HALTING...", 0x0D, 0x0A, 0
msg_reboot db 0x0D, 0x0A, ">>> REBOOTING...", 0x0D, 0x0A, 0
times 65520-($-$$) db 0
reset_vector:
jmp 0xF000:0x0000
times 16-($-reset_vector) db 0
+156
View File
@@ -0,0 +1,156 @@
; 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
+123
View File
@@ -0,0 +1,123 @@
; mybios_boot.asm
[BITS 16]
[ORG 0x7C00] ; BIOS가 우리를 0x7C00에 로딩해줍니다.
start:
; 1. 세그먼트 초기화
xor ax, ax ; AX = 0
mov ds, ax ; DS = 0
mov es, ax ; ES = 0
mov ss, ax ; SS = 0
mov sp, 0x7C00 ; 스택 설정
; 2. 화면 초기화 (블루 스크린)
; BIOS가 이미 VGA를 텍스트 모드로 켜둔 상태입니다!
; 우리는 메모리에 색칠만 하면 됩니다.
mov ax, 0xB800
mov es, ax ; ES = 비디오 메모리 세그먼트
xor di, di ; DI = 0
mov cx, 2000 ; 80x25 = 2000 글자
mov ax, 0x1F20 ; 파란바탕(1F) + 공백(20)
rep stosw ; 화면 지우기
; 3. 메시지 출력
mov si, msg_title
mov di, 0
call print_vga
mov si, msg_menu
mov di, 160
call print_vga
; 4. 키보드 입력 대기
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
; ===========================================================
; [Actions]
; ===========================================================
action_shutdown:
mov si, msg_bye
mov di, 320
call print_vga
; ACPI Shutdown (PIIX4) - 부트로더 상태에서도 똑같이 동작합니다.
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 "=== SSH Curses Bootloader (Blue Screen) ===", 0
msg_menu db "Press [1] to Shutdown, [2] to Reboot", 0
msg_bye db "System Halted.", 0
msg_reboot db "Rebooting...", 0
; --- 부트 섹터 마법 (512바이트 맞추기) ---
times 510-($-$$) db 0 ; 510바이트까지 0으로 채움
dw 0xAA55 ; 부트 서명 (Boot Signature)
+11
View File
@@ -0,0 +1,11 @@
# read&write
```bash
nasm -f bin mybios.asm -o mybios.bin
qemu-system-i386 -bios mybios.bin -nographic
```
```bash
nasm -f bin myboot.asm -o myboot.bin
qemu-system-i386 -M pc -drive file=myboot.bin,format=raw,index=0,media=disk -display curses
```