OSDev http://osdev.su/ |
|
Не загружается ядро. Прошу помочь http://osdev.su/viewtopic.php?f=6&t=4125 |
Страница 1 из 1 |
Автор: | skripsaha [ 30 май 2025, 17:36 ] |
Заголовок сообщения: | Не загружается ядро. Прошу помочь |
значит решил я написать загрузчик. я не очень в этом прокачен, поэтому обратился сюда. stage1.asm: org 0x7C00 bits 16 start: cli xor ax, ax mov ds, ax mov es, ax mov ss, ax mov sp, 0x7C00 sti mov si, msg_loading call print_string ; Загружаем stage2 с диска mov ah, 0x02 mov al, 1 mov ch, 0 mov cl, 2 ; Сектор 2 (следующий после MBR) mov dh, 0 mov dl, 0x80 mov bx, 0x7E00 int 0x13 jc disk_error ;передача управления stage2 jmp 0x7E00 print_string: lodsb or al, al jz .done mov ah, 0x0E ; Функция BIOS "вывести символ" int 0x10 ; Вызываем BIOS jmp print_string .done: ret disk_error: mov si, msg_disk_error call print_string hlt msg_loading db "Loading BoxOS Stage2...", 0x0D, 0x0A, 0 msg_disk_error db "Disk error!", 0x0D, 0x0A, 0 times 510 - ($ - $$) db 0 dw 0xAA55 stage2.asm: ; ============================================= ; stage2.asm - Загрузчик (переход в Protected Mode) ; ============================================= org 0x7E00 ; Загружаемся после stage1 (0x7E00) bits 16 start: cli ; Отлючаем прерывания ; Вывод сообщения mov si, msg_stage2 call print_string ; Включаем A20 линию! call enable_a20 ; Загружаем ядро (kernel.bin) в память по адресу 0x100000 (1 МБ) mov ebx, 0x1000 ; Сегмент (0x1000 << 4 = 0x10000) mov es, bx mov bx, 0x0000 ; Смещение (0x10000 + 0x0000 = 0x10000) mov ecx, 0x3 ; Начинаем с сектора 3 (после stage1 и stage2) mov edx, 10 ; Читаем 10 секторов (5 КБ — хватит для ядра) call load_kernel mov si, msg_kernel_loaded call print_string lgdt[gdt_descriptor] ; Загружаем GDT (Global Descriptor Table) ; Включаем Protected Mode mov eax, cr0 or eax, 0x1 mov cr0, eax jmp CODE_SEG:init_pm ; Дальний прыжок для активации Protected Mode ; ====== Включение A20 линии ====== enable_a20: ; Проверяем, включена ли уже A20 call check_a20 cmp ax, 1 je .done ; Способ 1: Через BIOS mov ax, 0x2401 int 0x15 ; Способ 2: Через клавиатурный контроллер cli call .wait_kbd mov al, 0xAD out 0x64, al call .wait_kbd mov al, 0xD0 out 0x64, al call .wait_kbd2 in al, 0x60 push eax call .wait_kbd mov al, 0xD1 out 0x64, al call .wait_kbd pop eax or al, 2 out 0x60, al call .wait_kbd mov al, 0xAE out 0x64, al sti .done: ret .wait_kbd: in al, 0x64 test al, 2 jnz .wait_kbd ret .wait_kbd2: in al, 0x64 test al, 1 jz .wait_kbd2 ret ; Проверка статуса A20 check_a20: pushf push ds push es push di push si xor ax, ax mov es, ax mov di, 0x0500 mov ax, 0xFFFF mov ds, ax mov si, 0x0510 mov al, [es:di] push ax mov al, [ds:si] push ax mov byte [es:di], 0x00 mov byte [ds:si], 0xFF cmp byte [es:di], 0xFF pop ax mov [ds:si], al pop ax mov [es:di], al mov ax, 0 je .exit mov ax, 1 .exit: pop si pop di pop es pop ds popf ret ; ====== Функция загрузки ядра ====== load_kernel: ; Загружаем ядро в 0x10000 (временный буфер) mov ax, 0x1000 ; Сегмент 0x1000 (адрес 0x10000) mov es, ax xor bx, bx ; ES:BX = 0x1000:0x0000 = 0x10000 ; Параметры для int 0x13 (CHS) mov ah, 0x02 ; Функция чтения mov al, 10 ; Секторов для чтения (ядро ~5KB) mov ch, 0 ; Цилиндр 0 mov cl, 3 ; Сектор 3 (после stage1 и stage2) mov dh, 0 ; Головка 0 mov dl, 0x80 ; Жесткий диск 0x80 int 0x13 jc .error ; Если ошибка (CF=1) ; Копируем из 0x10000 в 0x100000 (1MB) mov esi, 0x10000 ; Источник mov edi, 0x100000 ; Назначение mov ecx, 5120 ; 10 секторов * 512 байт cld ; Направление копирования (вперед) rep movsb ; Копируем байт за байтом ; Проверка копирования (первые 4 байта) mov eax, [0x100000] cmp eax, 0x000900BC ; Сигнатура из hexdump (первые 4 байта ядра) jne .error ret .error: mov si, msg_disk_error call print_string hlt ; ====== Подпрограммы (16-bit) ====== print_string: lodsb or al, al jz .done mov ah, 0x0E int 0x10 jmp print_string .done: ret ; ====== Данные (16-bit) ====== msg_stage2 db "Entering Protected Mode...", 0x0D, 0x0A, 0 msg_disk_error db "Kernel load error!", 0x0D, 0x0A, 0 msg_kernel_loaded db "Kernel loaded!", 0x0D, 0x0A, 0 ; ====== GDT (Global Descriptor Table) ====== gdt_start: ; Нулевой дескриптор (обязательно) dq 0x0 gdt_code: ; Дескриптор кода (32-битный сегмент) dw 0xFFFF ; Лимит (0-15) dw 0x0 ; База (0-15) db 0x0 ; База (16-23) db 10011010b ; Флаги доступа (P=1, DPL=00, S=1, Type=1010) db 11001111b ; Флаги + лимит (16-19) (G=1, D/B=1, L=0, AVL=0) db 0x0 ; База (24-31) gdt_data: ; Дескриптор данных (32-битный сегмент) dw 0xFFFF dw 0x0 db 0x0 db 10010010b ; Type=0010 (данные) db 11001111b db 0x0 gdt_end: gdt_descriptor: dw gdt_end - gdt_start - 1 ; Размер GDT dd gdt_start ; Адрес GDT CODE_SEG equ gdt_code - gdt_start ; Селектор кода (смещение 8) DATA_SEG equ gdt_data - gdt_start ; Селектор данных (смещение 16) bits 32 init_pm: mov ax, DATA_SEG mov ds, ax mov es, ax mov fs, ax mov gs, ax mov ss, ax mov esp, 90000 ; Устанавливаем стек ; Выводим сообщение (теперь через VGA) mov si, msg_pm mov edi, 0xB8000 ; Видеопамять call print_string_pm ; Переход в ядро jmp 0x100000 cli .hlt_loop: hlt ; Останавливаем процессор jmp .hlt_loop ; На случай пробуждения print_string_pm: mov ah, 0x03 ; Атрибут текста (Ярко бирюзовый, cyan) .loop: lodsb or al, al jz .done stosw ; [EDI] = AX (символ + атрибут) jmp .loop .done: ret msg_pm db "BoxOS: Protected Mode Active!", 0 ; ====== Заполняем до 512 байт ====== times 512 - ($ - $$) db 0 файл kernel.asm: bits 32 section .text global _start _start: extern kernel_main _start: ; Настраиваем стек mov esp, 0x90000 call kernel_main cli .hlt_loop: hlt jmp .hlt_loop linker.ld: ENTRY(_start) SECTIONS { . = 0x100000; .text : { *(.text) } .data : { *(.data) } .bss : { *(.bss) } } kernel.c: // Ядро работает в 32-битном Protected Mode void kernel_main() { // Указатель на видеопамять (текстовый режим 80x25) volatile unsigned short *vga_buffer = (unsigned short *)0xB8000; // Очищаем экран for (int i = 0; i < 80 * 25; i++) { vga_buffer[i] = (unsigned short)0x0700; // Чёрный фон, серый текст } // Выводим строку const char *str = "Hello, BoxOS Kernel!"; for (int i = 0; str[i] != '\0'; i++) { vga_buffer[i] = (unsigned short)(0x0700 | str[i]); // Атрибут + символ } // Бесконечный цикл while (1) { __asm__ volatile ("hlt"); // Останавливаем процессор } } start.sh: nasm -f bin src/boot/stage1/stage1.asm -o stage1.bin nasm -f bin src/boot/stage2/stage2.asm -o stage2.bin gcc -m32 -ffreestanding -c src/kernel/kernel.c -o kernel.o nasm -f elf32 src/kernel/kernel.asm -o kernel_asm.o ld -m elf_i386 -T src/kernel/linker.ld -o kernel.elf kernel_asm.o kernel.o objcopy -O binary kernel.elf kernel.bin cat stage1.bin stage2.bin kernel.bin > boxos.img qemu-system-x86_64 -drive format=raw,file=boxos.img -monitor stdio структура проекта (пока написано то что я прислал): . ├── Makefile ├── boxos.img ├── docs │ └── specs.md ├── kernel.bin ├── kernel.elf ├── kernel.o ├── kernel_asm.o ├── qemu.log ├── src │ ├── boot │ │ ├── stage1 │ │ │ ├── stage1.asm │ │ │ └── stage1.bin │ │ ├── stage2 │ │ │ ├── config.inc │ │ │ ├── fs.asm │ │ │ ├── stage2.asm │ │ │ └── stage2.bin │ │ └── stage3 │ │ └── stage3.c │ ├── kernel │ │ ├── arch │ │ │ └── x86 │ │ ├── drivers │ │ ├── fs │ │ ├── kernel.asm │ │ ├── kernel.bin │ │ ├── kernel.c │ │ ├── kernel.elf │ │ ├── kernel.o │ │ ├── kernel_asm.o │ │ ├── linker.ld │ │ └── mm │ └── lib │ └── string.asm ├── stage1.bin ├── stage2.bin ├── start.sh └── tools └── mkbootimg.py при запуске start.sh не загружается, выводится сообщение "Kernel load error!". Что мне надо исправть или добавть, чтобы запускался kernel.c. Буду очень благодарен за помощь! ![]() |
Автор: | SII [ 31 май 2025, 06:48 ] |
Заголовок сообщения: | Re: Не загружается ядро. Прошу помочь |
Что boxos.img собрался корректно, проверили? Что все части стадий загрузки попадают, куда положено, и всё такое. Плюс, в QEMU наверняка можно выполнять загрузчик хоть по командам -- и точно увидеть место, где что-то пошло не так. (Это на настоящем ПК придётся гадать, ибо железные отладчики простым смертным недоступны.) |
Автор: | JackKatch [ 31 май 2025, 11:30 ] |
Заголовок сообщения: | Re: Не загружается ядро. Прошу помочь |
Во первых правильно вам посоветовали, проверить что всё собралось. Во вторых в терминале qemu набираете help и смотрите как устанавливать точки останова (я в qemu мало работал, в bochs для меня проще), например установить точку останова на 0x7c00, как выполнять программу по шагам. В третьих устанавливайте в своём коде "точки останова" jmp $ (переход на адрес инструкции jmp $). Например после первой стадии загрузки, если сообщений нет, значит на точке останова стоим, ищем ошибку по шагам. Перемещаем jmp дальше по коду, вышло сообщение Kernel load error!, значит до jmp не дошли, смотрим по шагам. |
Страница 1 из 1 | Часовой пояс: UTC + 3 часа |
Powered by phpBB® Forum Software © phpBB Group http://www.phpbb.com/ |