OSDev

для всех
Текущее время: 01 июл 2025, 07:24

Часовой пояс: UTC + 3 часа




Начать новую тему Ответить на тему  [ Сообщений: 3 ] 
Автор Сообщение
 Заголовок сообщения: Не загружается ядро. Прошу помочь
СообщениеДобавлено: 30 май 2025, 17:36 

Зарегистрирован: 30 май 2025, 17:18
Сообщения: 1
значит решил я написать загрузчик. я не очень в этом прокачен, поэтому обратился сюда.
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. Буду очень благодарен за помощь! :)


Вернуться к началу
 Профиль  
 
СообщениеДобавлено: 31 май 2025, 06:48 

Зарегистрирован: 28 окт 2007, 18:33
Сообщения: 1449
Что boxos.img собрался корректно, проверили? Что все части стадий загрузки попадают, куда положено, и всё такое.

Плюс, в QEMU наверняка можно выполнять загрузчик хоть по командам -- и точно увидеть место, где что-то пошло не так. (Это на настоящем ПК придётся гадать, ибо железные отладчики простым смертным недоступны.)


Вернуться к началу
 Профиль  
 
СообщениеДобавлено: 31 май 2025, 11:30 

Зарегистрирован: 06 янв 2025, 17:29
Сообщения: 22
Во первых правильно вам посоветовали, проверить что всё собралось. Во вторых в терминале qemu набираете help и смотрите как устанавливать точки останова (я в qemu мало работал, в bochs для меня проще), например установить точку останова на 0x7c00, как выполнять программу по шагам. В третьих устанавливайте в своём коде "точки останова" jmp $ (переход на адрес инструкции jmp $). Например после первой стадии загрузки, если сообщений нет, значит на точке останова стоим, ищем ошибку по шагам. Перемещаем jmp дальше по коду, вышло сообщение Kernel load error!, значит до jmp не дошли, смотрим по шагам.


Вернуться к началу
 Профиль  
 
Показать сообщения за:  Поле сортировки  
Начать новую тему Ответить на тему  [ Сообщений: 3 ] 

Часовой пояс: UTC + 3 часа


Кто сейчас на конференции

Сейчас этот форум просматривают: нет зарегистрированных пользователей и гости: 2


Вы не можете начинать темы
Вы не можете отвечать на сообщения
Вы не можете редактировать свои сообщения
Вы не можете удалять свои сообщения
Вы не можете добавлять вложения

Найти:
Перейти:  
Создано на основе phpBB® Forum Software © phpBB Group
Русская поддержка phpBB