Невозможно загрузить собственное ядро ​​в VirtualBox: & quot; не удалось прочитать с загрузочного носителя & quot;

Я следовал за серией уроков Напишите свою собственную операционную систему за 1 час создать базовую ОС для печати просто «Hello World» всего с 4 файлами: Makefile, kernel.cpp, loader.s а также linker.ld,

Я создаю mykernel.iso файла, но когда я загружаю его в VirtualBox, я получаю сообщение об ошибке «Не удалось прочитать с загрузочного носителя: система остановлена». Я подтвердил, что .iso файл связан с моим экземпляром машины. Похоже, в коде есть другая проблема.

Вот мой Makefile:

#we need to tell the compiler to stop assuming that this will be executed inside an OS
CPPPARAMS = -m32 -fno-use-cxa-atexit -nostdlib -fno-builtin -fno-rtti -fno-exceptions -fno-leading-underscore
ASPARAMS = --32
LDPARAMS = -melf_i386

objects = loader.o kernel.o

%.o: %.cpp
g++ $(CPPPARAMS) -o $@ -c $<

%.o: %.s
as $(ASPARAMS) -o $@ $<

mykernel.bin: linker.ld $(objects)
ld $(LDPARAMS) -T $< -o $@ $(objects)

install: mykernel.bin
sudo cp $< /boot/mykernel.bin

mykernel.iso: mykernel.bin
mkdir iso
mkdir iso/boot
mkdir iso/boot/grub
cp $< iso/boot/
echo 'set default=0' > iso/boot/grub/grub.cfg
echo 'set timeout=0' >> iso/boot/grub/grub.cfg
echo '' >> iso/boot/grub/grub.cfg
echo 'menuentry "My Personal OS" {' >> iso/boot/grub/grub.cfg
echo 'multiboot /boot/mykernel.bin' >> iso/boot/grub/grub.cfg
echo 'boot' >> iso/boot/grub/grub.cfg
echo '}' >> iso/boot/grub/grub.cfg
grub-mkrescue --output $@ iso
rm -rf iso

clean:
rm -rf iso
rm *.o
rm mykernel.iso
rm mykernel.bin

Здесь kernel.cpp

void printf(char *str)
{
unsigned short *VideoMemory = (unsigned short*)0xb8000;

for(int i=0;str[i] != '\0';i++)
VideoMemory[i] = (VideoMemory[i] & 0xFF00) | str[i];
}

typedef void (*constructor)();
extern "C" constructor start_ctors;
extern "C" constructor end_ctors;
extern "C" void callConstructors()
{
for(constructor * i=&start_ctors;i!=&end_ctors;i++)
(*i)();
}

extern "C" void kernelMain(void * multiboot_structure, unsigned int magic_number)
{
printf("Hello World!");

//we do not want to exit from the kernel
while(1);
}

Здесь loader.s :

.set MAGIC, 0x1badb002
.set FLAGS, (1<<0 | 1<<1)
.set CHECKSUM, -(MAGIC + FLAGS)

.section .multiboot
.long MAGIC
.long FLAGS
.long CHECKSUM

.section .text
.extern kernelMain
.extern callConstructors
.global loader

loader:
mov $kernel_stack, %esp
call callConstructors
push %eax #AX register has the pointer of multiboot structure stored by bootloader
push %ebx #BX register has the magic number
call kernelMain

#double check to not come out of the kernel, creating one more loop
_stop:
cli
hlt
jmp _stop.section .bss
.space 2*1024*1024 #2MB  for stack to grow towards left side
kernel_stack:

Здесь linker.ld :

ENTRY(loader)
OUTPUT_FORMAT(elf32-i386)
OUTPUT_ARCH(i386:i386)

SECTIONS
{
. = 0x100000;

.text :
{
*(.multiboot)
*(.text*)
*(.rodata)
}

.data :
{
start_ctors = .;
KEEP(*(.init_array));
KEEP(*(SORT_BY_INIT_PRIORITY(.init_array.*)));
end_ctors = .;

*(.data)
}

.bss :
{
*(.bss)
}

/DISCARD/ :
{
*(.fini_array*)
*(.comment)
}
}

Моя среда разработки — Linux Mint 18.1 64-bit с установленным virtualbox. Мой код почти соответствует коду репетитора в серии, но я не могу загрузиться на виртуальной машине.

РЕДАКТИРОВАТЬ

Я пробовал с qemu-system-i386 -kernel mykernel.bin и он отлично работает с сообщением Hello WorldЭто означает, что существует некоторая проблема со средой и конфигурациями VirtualBox.

2

Решение

У меня нет официального источника для этого ответа. На самом деле это основано на опыте и других вопросах, которые я видел в Stackoverflow и на некоторых выводах, которые я сделал.

Появляется, если вы создаете большие стеки загрузки ядра в BSS сегмент это вызывает GRUB сбой в некоторых средах, а не в других. Это часто происходит, когда общий размер BSS сегмент, кажется, достигает около 2 МБ. Virtualbox, кажется, является частным случаем, когда проблема, кажется, возникает. Проблемы в Virtualbox могут различаться в зависимости от версии и используемой конфигурации виртуального оборудования.

Стек, который вы создаете в своем loader.s загрузиться C ++ среда не должна быть такой большой. Как только вы получите управление памятью и распределители, вы можете зарезервировать область для большего стека ядра и установить SS: ESP к этому в то время.

Для этого вы должны рассмотреть вопрос об изменении:

.section .bss
.space 2*1024*1024 #2MB  for stack to grow towards left side
kernel_stack:

Чтобы что-то 1 МБ или меньше. Я бы, наверное, пошел с чем-то вроде 64 КБ:

.section .bss
.space 64*1024 #64KB  for stack to grow towards left side
kernel_stack:
-1

Другие решения

Я столкнулся с той же проблемой. Просто установив grub-pc-bin и перекомпилировав ядро, он успешно загрузился на виртуальной машине.

sudo apt-get install grub-pc-bin

Кроме того, мне не пришлось менять размер сегмента BSS.

1

По вопросам рекламы [email protected]