How can I create a bootable CD image with my kernel?
I have a kernel, to boot I am using command qemu-system-i386 -kernel kernel.bin
. Is any way to create bootable disk image to boot with qemu-system-i386 -cdrom CD.iso
?
The code I am compiling in linux with these commands:
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
and then booting with qemu-system-i386 -kernel kernel.bin
CODE: 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);
idt_ptr[1] = idt_address >> 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] != ' ') {
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) }
}
First I give you basic idea of how booting process really works. Actually when you run command qemu-system-i386 -kernel kernel.bin
Qemu loads up your kernel binary into memory at location 0x7c000 from where booting further proceed. If you want to boot from ISO then you have to tell the BIOS that there is a Bootable image (mark boot flag) in my iso, and give it proper instructions to laod up your kernel.
How to do that?
You have to setup a Bootloader that can be loaded by your BIOS at 0x7c000 and later It would load your Kernel Image into memory and jump to kernel entry point.
So, mark your ISO active (boot flag) and add boot loader code.
I can see you already have setup multiboot entrypoint code
align 4
dd 0x1BADB002
dd 0x00
dd - (0x1BADB002 + 0x00)
You can read more about setting up grub boot chain from here http://wiki.osdev.org/GRUB_2 You can also use syslinux bootloader http://www.syslinux.org/wiki/index.php?title=The_Syslinux_Project
syslinux Copy isolinux.bin, syslinux.cfg and mboot.c32 to your build path of your kernel binary image. configure syslinux.cfg and execute the following command.
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%
链接地址: http://www.djcxy.com/p/31768.html
上一篇: 缓存Maven的Jar依赖关系
下一篇: 我如何用我的内核创建可启动的CD映像?