진짜 정신이 나가겠네요;;
안녕하세요, 전 혼자 DOS를 ㅁ나들고 있는 사람입니다.
제가 그 아무래도 어셈블리어로 개발을 하다보니깐 코드가 너무 길어져가지고 그래서인지 더 쉽게 작업하기 위해 제 (커널) 코드를 C언어로 바꿔주었는데요. 그래서 처음 어셈블리어로 개발할 때와 달리 오류가 많이 나기 시작했습니다. (주로 qemu로 실행할 떄요) 일단 코드를 보시면은 이런데요.
(커널쪽) (코드 눌르고 복붙하면 코드가 아니라 그냥 텍스트 상태로 붙여놓은 상태가 되기 때문에 걍 일반 텍스트로 하겠습니다)
#include <stddef.h>
#define DATA_SEG_SELECTOR 0x10
#define VGA_MEMORY 0xB8000
#define VGA_WIDTH 80
#define VGA_HEIGHT 25
#define WHITE_ON_BLACK 0x07
#define KEYBOARD_PORT 0x60
static unsigned int cursor = 0;
volatile unsigned short* vga_buffer = (volatile unsigned short*)VGA_MEMORY;
unsigned char inb(unsigned short port) {
unsigned char ret;
asm volatile ( "inb %1, %0"
: "=a"(ret)
: "Nd"(port) );
return ret;
}
// [수정 후]
void putchar(char c) {
if (c == '\n') {
cursor = (cursor / 80 + 1) * 80;
} else {
// 전역 vga_buffer 사용
vga_buffer[cursor++] = (WHITE_ON_BLACK << 8) | c;
}
}
void print(const char* s) {
while (*s) putchar(*s++);
}
char get_key() {
unsigned char scancode = 0;
while ((scancode = inb(KEYBOARD_PORT)) == 0);
if (scancode >= 0x02 && scancode <= 0x0A) return '0' + scancode - 1;
if (scancode >= 0x10 && scancode <= 0x19) return 'Q' + scancode - 0x10;
if (scancode == 0x1C) return '\n'; // Enter
return '?';
}
void clear_screen() {
for (int i = 0; i < VGA_WIDTH * VGA_HEIGHT; i++)
vga_buffer[i] = (0x07 << 8) | ' ';
cursor = 0;
}
void to_uppercase(char* s) {
while (*s) {
if (*s >= 'a' && *s <= 'z') *s -= 32;
s++;
}
}
int strcmp(const char* a, const char* b) {
while (*a && *b) {
if (*a != *b) return 1;
a++; b++;
}
return (*a == *b) ? 0 : 1;
}
int strncmp(const char* a, const char* b, int n) {
for (int i = 0; i < n; i++) {
if (a[i] != b[i]) return 1;
if (a[i] == 0 || b[i] == 0) break;
}
return 0;
}
void kmain() {
asm volatile ( "movw %%ax, %%ds" :: "a" (DATA_SEG_SELECTOR));
clear_screen();
print("RRRR OOOO OOO SSS\n");
print("R R O O O O S\n");
print("RRRR --- O O O O SS\n");
print("R R O O O O S\n");
print("R R OOOO OOO SSS\n\n");
print("Welcome to R-DOS v0.3\n");
print("Type HELP for commands or TUTORIAL for shortcuts.\n\n");
char buffer[64];
int idx = 0;
char c;
while (1) {
print("\nR-DOS> ");
idx = 0;
while (1) {
char c = get_key();
if (c == '\n') break;
if (idx < 63) {
buffer[idx++] = c;
putchar(c);
}
}
buffer[idx] = 0;
print("\n");
to_uppercase(buffer);
if (strcmp(buffer, "HELP") == 0) {
print("HELP - Show this help\nTUTORIAL - Show keyboard shortcuts\nECHO - Print text\nCLEAR - Clear screen\nCALC - Do math stuff\nUWU - ???\n");
} else if (strcmp(buffer, "TUTORIAL") == 0) {
print("CTRL+W - Scroll up\nCTRL+S - Scroll down\n");
} else if (strncmp(buffer, "ECHO ", 5) == 0) {
print(buffer + 5);
print("\n");
} else if (strcmp(buffer, "CLEAR") == 0) {
clear_screen();
} else if (strcmp(buffer, "UWU") == 0) {
print("U U U U\nU U W W U U\n UUU W W UUU\n");
} else {
print("Unknown command.\n");
}
}
}
(부트 파일쪽)
[org 0x7C00]
; ... (cli, 세그먼트 초기화 등)
; **************************************************
; *** 누락되었을 가능성이 높은 디스크 로딩 루틴 ***
; **************************************************
; 커널을 메모리 0x1000으로 로드하는 코드 (int 0x13 사용)
mov al, 12 ; 읽을 섹터 수 (커널 크기에 따라 다름)
mov ch, 0 ; 실린더 0
mov cl, 2 ; 시작 섹터 (부트 섹터는 1, 커널은 2부터 시작)
mov dh, 0 ; 헤드 0
mov dl, 0x00 ; 드라이브 0 (플로피)
mov bx, 0x1000 ; 로드할 메모리 주소 (0x1000)
mov es, bx
xor bx, bx ; ES:BX = 0x1000:0x0000
mov ah, 0x02 ; AH = 0x02 (디스크 섹터 읽기)
int 0x13 ; BIOS 디스크 인터럽트 호출
; ******************************************************
; *** 필수 추가: CF 플래그를 확인하여 로드 성공 여부 검사 ***
; ******************************************************
jc disk_error ; Carry Flag가 설정되었으면 (오류), disk_error로 점프
; 성공하면 GDT 로드 코드로 진행
; lgdt [gdt_descriptor]
; ...
disk_error:
; 오류 발생 시 CPU를 영원히 멈춤
cli
hlt
jmp disk_error
; 오류 체크 및 점프 (생략)
; ... 이후 프로텍티드 모드 전환 코드 ...
jmp CODE_SEG:init_pm
init_pm:
mov ax, DATA_SEG
mov ds, ax
mov ss, ax ; SS (Stack Segment)도 설정
mov es, ax
mov fs, ax
mov gs, ax
; ************************************
; *** 스택 포인터 설정 추가 (ESP) ***
; ************************************
; 스택을 커널 코드(0x1000)보다 훨씬 높은 주소(예: 0x90000 = 576KB)로 설정
mov esp, 0x90000
; ************************************
call 0x1000 ; 커널 진입점 호출 (kmain)
hang:
jmp hang
; GDT 정의 섹션
gdt_start:
gdt_null: dq 0
gdt_code: dq 0x00CF9A000000FFFF ; GDT 코드 세그먼트
gdt_data: dq 0x00CF92000000FFFF ; GDT 데이터 세그먼트
gdt_end:
gdt_descriptor:
dw gdt_end - gdt_start - 1 ; GDT 크기
dd gdt_start ; GDT 시작 주소
; 세그먼트 상수 정의 (GDT의 오프셋)
CODE_SEG equ gdt_code - gdt_start
DATA_SEG equ gdt_data - gdt_start
; 부트 시그니처 및 패딩
times 510-($-$$) db 0
dw 0xAA55
(링커 스크립트 쪽)
Code snippet
/* linker.ld 파일 */
OUTPUT_FORMAT(elf32-i386)
ENTRY(kmain)
SECTIONS
{
. = 0x1000; /* 커널 로드 주소 */
.text : {
*(.text)
}
.data : {
*(.data)
}
.bss : {
*(.bss)
}
/* ****************************************************** */
/* *** 최종 해결: 커널 파일 크기를 512바이트 배수로 패딩 *** */
/* ****************************************************** */
. = ALIGN(0x200); /* 현재 위치를 512바이트(0x200) 경계로 정렬 */
/* 링커가 생성하는 불필요한 섹션을 버림 (선택적이지만 권장) */
/DISCARD/ : { *(.fini) *(.eh_frame) }
}

겉으로만 보면 문제가 없을 거 같지만….. 이게 실행해보면 본 사진처럼 거기에서 계속 멈추게 됩니다….
그래서 진짜 전신이 나갈 것 같은데요. 그래서 제가 제미니한테 물어보고 코드를 제미니가 시키는대로 계속 수정했더니 계속 오류는 그대로입니다.. 그래서 진짜 정신이 나갈 거 같은데 어떻게 해결할 수 있을지 알려줄 수 있나요? 이제 AI는 못 믿겟습니다.
댓글을 남기려면 로그인이 필요합니다.
로그인 후 이 페이지로 돌아와 바로 댓글을 남길 수 있습니다.