2016-02-01 26 views
7

Tôi có hạt nhân, để khởi động Tôi đang sử dụng lệnh qemu-system-i386 -kernel kernel.bin. Có cách nào để tạo ảnh đĩa có thể khởi động để khởi động với qemu-system-i386 -cdrom CD.iso không?Làm cách nào để tạo ảnh đĩa CD có thể khởi động bằng hạt nhân?

Mã Tôi đang biên soạn trong linux với các lệnh:

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 

và sau đó khởi động với qemu-system-i386 -kernel kernel.bin

Mã sản phẩm: 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] != '\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) } 
} 
+4

https://www.gnu.org/software/grub/manual/html_node/Making-a-GRUB-bootable-CD_002dROM.html –

+0

Nhìn xung quanh "** El-Torito **" tiêu chuẩn http: //wiki.osdev.org/El-Torito – rom1nux

+0

Bản sao có thể có của [Tạo hình ảnh ISO có thể khởi động với trình khởi động tùy chỉnh] (http://stackoverflow.com/questions/34268518/creating-a-bootable-iso-image-with- bộ nạp khởi động tùy chỉnh) –

Trả lời

3

Trước tiên tôi cung cấp cho bạn ý tưởng cơ bản về cách trình khởi động thực sự hoạt động. Trên thực tế khi bạn chạy lệnh qemu-system-i386 -kernel kernel.bin Qemu tải lên hạt nhân nhị phân của bạn vào bộ nhớ tại vị trí 0x7c000 từ nơi khởi động tiếp tục tiến hành. Nếu bạn muốn khởi động từ ISO, bạn phải thông báo cho BIOS biết rằng có một hình ảnh có khả năng khởi động (đánh dấu cờ khởi động) trong iso của tôi, và đưa ra các chỉ dẫn thích hợp để nạp kernel của bạn.

Làm cách nào để thực hiện điều đó?
Bạn phải cài đặt Bộ nạp khởi động có thể được tải bởi BIOS của bạn tại 0x7c000 và sau đó Nó sẽ tải Kernel Image của bạn vào bộ nhớ và chuyển đến điểm nhập hạt nhân.
Vì vậy, đánh dấu ISO của bạn hoạt động (cờ khởi động) và thêm mã bộ nạp khởi động.

tôi có thể thấy bạn đã có cài đặt multiboot đang entrypoint

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

Bạn có thể đọc thêm về việc thiết lập grub chuỗi khởi động từ đây http://wiki.osdev.org/GRUB_2 Bạn cũng có thể sử dụng syslinux bootloaderhttp://www.syslinux.org/wiki/index.php?title=The_Syslinux_Project

syslinux Sao chép isolinux.bin, syslinux.cfg và mboot.c32 vào đường dẫn xây dựng của bạn hình ảnh nhị phân của hạt nhân. định cấu hình syslinux.cfg và thực thi lệnh sau.

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% 
Các vấn đề liên quan