如何使用内核创建可启动CD映像?

我有一个内核,要启动我正在使用命令qemu-system-i386 -kernel kernel.bin 。 有没有办法用qemu-system-i386 -cdrom CD.iso创建可引导的磁盘映像?

我在linux中用这些命令编译的代码:

 nasm -f elf32 kernel.asm -o kernelasm.o gcc -m32 -c kernel.c -o kernelc.o ld -m elf_i386 -T link.ld -o kernel.bin kernelasm.o kernelc.o 

然后使用qemu-system-i386 -kernel kernel.bin

代码:kernel.asm:

 [BITS 32] SECTION .text align 4 dd 0x1BADB002 dd 0x00 dd - (0x1BADB002 + 0x00) global start global keyboard_handler global read_port global write_port global load_idt extern kmain extern keyboard_handler_main read_port: mov edx, [esp + 4] in al, dx ret write_port: mov edx, [esp + 4] mov al, [esp + 4 + 4] out dx, al ret load_idt: mov edx, [esp + 4] lidt [edx] sti ret keyboard_handler: call keyboard_handler_main iretd start: cli mov esp, stack_space call kmain hlt section .bss resb 8192 stack_space: 

kernel.c:

 #include "keyboard_map.h" #define LINES 25 #define COLUMNS_IN_LINE 80 #define BYTES_FOR_EACH_ELEMENT 2 #define SCREENSIZE BYTES_FOR_EACH_ELEMENT * COLUMNS_IN_LINE * LINES #define KEYBOARD_DATA_PORT 0x60 #define KEYBOARD_STATUS_PORT 0x64 #define IDT_SIZE 256 #define INTERRUPT_GATE 0x8e #define KERNEL_CODE_SEGMENT_OFFSET 0x08 #define ENTER_KEY_CODE 0x1C extern unsigned char keyboard_map[128]; extern void keyboard_handler(void); extern char read_port(unsigned short port); extern void write_port(unsigned short port, unsigned char data); extern void load_idt(unsigned long *idt_ptr); unsigned int current_loc = 0; char *vidptr = (char*)0xb8000; struct IDT_entry { unsigned short int offset_lowerbits; unsigned short int selector; unsigned char zero; unsigned char type_attr; unsigned short int offset_higherbits; }; struct IDT_entry IDT[IDT_SIZE]; void idt_init(void) { unsigned long keyboard_address; unsigned long idt_address; unsigned long idt_ptr[2]; keyboard_address = (unsigned long)keyboard_handler; IDT[0x21].offset_lowerbits = keyboard_address & 0xffff; IDT[0x21].selector = KERNEL_CODE_SEGMENT_OFFSET; IDT[0x21].zero = 0; IDT[0x21].type_attr = INTERRUPT_GATE; IDT[0x21].offset_higherbits = (keyboard_address & 0xffff0000) >> 16; write_port(0x20 , 0x11); write_port(0xA0 , 0x11); write_port(0x21 , 0x20); write_port(0xA1 , 0x28); write_port(0x21 , 0x00); write_port(0xA1 , 0x00); write_port(0x21 , 0x01); write_port(0xA1 , 0x01); write_port(0x21 , 0xff); write_port(0xA1 , 0xff); idt_address = (unsigned long)IDT ; idt_ptr[0] = (sizeof (struct IDT_entry) * IDT_SIZE) + ((idt_address & 0xffff) <> 16 ; load_idt(idt_ptr); } void kb_init(void) { write_port(0x21 , 0xFD); } void kprint(const char *str) { unsigned int i = 0; while (str[i] != '\0') { vidptr[current_loc++] = str[i++]; vidptr[current_loc++] = 0x07; } } void kprint_newline(void) { unsigned int line_size = BYTES_FOR_EACH_ELEMENT * COLUMNS_IN_LINE; current_loc = current_loc + (line_size - current_loc % (line_size)); } void clear_screen(void) { unsigned int i = 0; while (i < SCREENSIZE) { vidptr[i++] = ' '; vidptr[i++] = 0x07; } } void keyboard_handler_main(void) { unsigned char status; char keycode; write_port(0x20, 0x20); status = read_port(KEYBOARD_STATUS_PORT); if (status & 0x01) { keycode = read_port(KEYBOARD_DATA_PORT); if(keycode < 0) return; if(keycode == ENTER_KEY_CODE) { kprint_newline(); return; } vidptr[current_loc++] = keyboard_map[(unsigned char) keycode]; vidptr[current_loc++] = 0x07; } } void kmain(void) { const char *str = "my first kernel with keyboard support"; clear_screen(); kprint(str); kprint_newline(); kprint_newline(); idt_init(); kb_init(); while(1); } 

keyboard_map.h:

 unsigned char keyboard_map[128] = { 0, 27, '1', '2', '3', '4', '5', '6', '7', '8', /* 9 */ '9', '0', '-', '=', '\b', /* Backspace */ '\t', /* Tab */ 'q', 'w', 'e', 'r', /* 19 */ 't', 'y', 'u', 'i', 'o', 'p', '[', ']', '\n', /* Enter key */ 0, /* 29 - Control */ 'a', 's', 'd', 'f', 'g', 'h', 'j', 'k', 'l', ';', /* 39 */ '\'', '`', 0, /* Left shift */ '\\', 'z', 'x', 'c', 'v', 'b', 'n', /* 49 */ 'm', ',', '.', '/', 0, /* Right shift */ '*', 0, /* Alt */ ' ', /* Space bar */ 0, /* Caps lock */ 0, /* 59 - F1 key ... > */ 0, 0, 0, 0, 0, 0, 0, 0, 0, /* < ... F10 */ 0, /* 69 - Num lock*/ 0, /* Scroll Lock */ 0, /* Home key */ 0, /* Up Arrow */ 0, /* Page Up */ '-', 0, /* Left Arrow */ 0, 0, /* Right Arrow */ '+', 0, /* 79 - End key*/ 0, /* Down Arrow */ 0, /* Page Down */ 0, /* Insert Key */ 0, /* Delete Key */ 0, 0, 0, 0, /* F11 Key */ 0, /* F12 Key */ 0, /* All other keys are undefined */ }; 

link.ld:

 OUTPUT_FORMAT(elf32-i386) ENTRY(start) SECTIONS { . = 0x100000; .text : { *(.text) } .data : { *(.data) } .bss : { *(.bss) } } 

首先,我给出了启动过程如何真正起作用的基本概念。 实际上当你运行命令qemu-system-i386 -kernel kernel.bin Qemu会将你的内核二进制文件加载到位于0x7c000的内存中,然后继续进行引导。 如果你想从ISO启动,那么你必须告诉BIOS我的iso中有一个可启动映像(标记启动标志),并给出适当的指令来填充你的内核。

怎么做?
您必须设置一个可以由您的BIOS在0x7c000及更高版本下加载的Bootloader它会将您的内核映像加载到内存并跳转到内核入口点。
因此,标记您的ISO活动(引导标志)并添加引导加载程序代码。

我可以看到你已经设置了多引导入口点代码

 align 4 dd 0x1BADB002 dd 0x00 dd - (0x1BADB002 + 0x00) 

您可以从这里了解更多关于设置grub引导链的信息http://wiki.osdev.org/GRUB_2您还可以使用syslinux bootloader http://www.syslinux.org/wiki/index.php?title=The_Syslinux_Project

syslinux将isolinux.bin,syslinux.cfg和mboot.c32复制到内核二进制映像的构建路径。 配置syslinux.cfg并执行以下命令。

 mkisofs.exe -o %OUTPUT_DIR%\%BUILD_NAME%.iso -b isolinux/isolinux.bin -c isolinux/boot.cat -no-emul-boot -boot-load-size 4 -boot-info-table %ISO_DIR%