2015-02-25 24 views
5

Ho scritto un kernel semplice che tenta di scrivere due caratteri nel frame buffer.Errore 13: Eseguibile non valido o non supportato durante l'avvio di kernel semplice in grub con stringa letterale

Se io definisco una stringa letterale nel kernel, ottengo il seguente output quando si avvia:

Booting 'os'                 

kernel /boot/kernel.elf               

Error 13: Invalid or unsupported executable format        

Press any key to continue... 

In caso contrario, se io definisco due personaggi ottengo il seguente (si noti 'ab' all'inizio del l'uscita):

abBooting 'os'                 

kernel /boot/kernel.elf              
    [Multiboot-elf, <0x100000:0x201:0x0>, <0x101000:0x0:0x1000>,  shtab=0x102168, 
    entry=0x1001f0] 

loader

ho scritto il caricatore di montaggio:

global loader     ; the entry symbol for ELF 

MAGIC_NUMBER equ 0x1BADB002  ; define the magic number constant 
FLAGS  equ 0x0   ; multiboot flags 
CHECKSUM  equ -MAGIC_NUMBER ; calculate the checksum 
           ; (magic number + checksum + flags should equal 0) 
KERNEL_STACK_SIZE equ 4096  ; size of stack in bytes 

section .text:     ; start of the text (code) section 
align 4       ; the code must be 4 byte aligned 
    dd MAGIC_NUMBER    ; write the magic number to the machine code, 
    dd FLAGS     ; the flags, 
    dd CHECKSUM     ; and the checksum 

loader:       ; the loader label (defined as entry point in linker script) 
    mov eax, 0xCAFEBABE   ; place the number 0xCAFEBABE in the register eax 

    mov esp, kernel_stack + KERNEL_STACK_SIZE ; point esp to the start of the 
               ; stack (end of memory area) 
    extern run 
    call run 

.loop: 
    jmp .loop     ; loop forever 

section .bss 
align 4       ; align at 4 bytes 
kernel_stack:     ; label points to beginning of memory 
    resb KERNEL_STACK_SIZE   ; reserve stack for the kernel 

Il kernel è scritto in C

#include "io.h" 
#include "fb.h" 

void run() 
{ 
    // try writing message to port 
    char* c = (char *) 10000; 
    c[0] = 'a'; 
    c[1] = 'b'; 

    fb_write(c, 2); // this does not cause the error 

    // fb_write("ab",2); // this line would cause the error 
} 

intestazioni esterne

ci sono due intestazioni esterni. Uno per porte IO chiamato io.h e uno per la scrittura nel buffer fotogramma chiamato fb.h

Ecco io.h e l'attuazione io.s

io.h:

#ifndef INCLUDE_IO_H 
#define INCLUDE_IO_H 

/** outb: 
* Sends the given data to the given I/O port. Defined in io.s 
* 
* @param port The I/O port to send the data to 
* @param data The data to send to the I/O port 
*/ 
void outb(unsigned short port, unsigned char data); 

#endif /* INCLUDE_IO_H */ 

io.s:

global outb  ; make the label outb visible outside this file 

; outb - send a byte to an I/O port 
; stack: [esp + 8] the data byte 
;  [esp + 4] the I/O port 
;  [esp ] return address 
outb: 
    mov al, [esp + 8] 
    mov dx, [esp + 4] 
    out dx, al 
    ret 

fb.h

#include "io.h" 

// FRAME BUFFER ================================ 

// Text colors 
#define FB_BLACK  0 
#define FB_BLUE   1 
#define FB_GREEN  2 
#define FB_CYAN   3 
#define FB_RED   4 
#define FB_MAGENTA  5 
#define FB_BROWN  6 
#define FB_LT_GREY  7 
#define FB_DARK_GREY 8 
#define FB_LT_BLUE  9 
#define FB_LT_GREEN 10 
#define FB_LT_CYAN  11 
#define FB_LT_RED  12 
#define FB_LT_MAGENTA 13 
#define FB_LT_BROWN 14 
#define FB_WHITE  15 

// IO PORTS 
#define FB_COMMAND_PORT 0x3D4 
#define FB_DATA_PORT 0x3D5 

// IO PORT COMMANDS 
#define FB_HIGH_BYTE_COMMAND 14 // move cursor command low 
#define FB_LOW_BYTE_COMMAND  15 // move cursor command high 


/** fb_write_cell: 
* used to write a character to a cell in the framebuffer 
* 
* param i which cell to write to 
* param c the ascii char to write 
* param fg foreground color 
* param bf background color 
*/ 
void fb_write_cell(unsigned int i, char c, unsigned char fg, unsigned char bg); 


/** fb_move_cursor: 
* used to move the cursor within the frame buffer 
* 
* param pos position within frame buffer to move cursor to 
*/ 
void fb_move_cursor(unsigned short pos); 


/** fb_write: 
* write some text to the cursor 
* 
* param buf pointer to character string 
* param len length of string to write 
*/ 
int fb_write(char *buf, unsigned int len); 

fb.c

#include "fb.h" 

void fb_write_cell(unsigned int i, char c, unsigned char fg, unsigned char bg) 
{ 
    char *fb = (char *) 0x000B8000; 
    fb[i*2] = c; 
    fb[i*2 + 1] = ((fg & 0x0F) << 4) | (bg & 0x0F); 
} 

void fb_move_cursor(unsigned short pos) { 
    outb(FB_COMMAND_PORT, FB_HIGH_BYTE_COMMAND); 
    outb(FB_DATA_PORT, ((pos>>8) & 0x00FF)); 
    outb(FB_COMMAND_PORT, FB_LOW_BYTE_COMMAND); 
    outb(FB_DATA_PORT, pos & 0x00FF); 
} 

int fb_write(char *buf, unsigned int len) { 

    unsigned int i = 0; 
    for(i = 0; i < len; i++) { 
     fb_write_cell(i, buf[i], FB_BLACK, FB_WHITE); 
    } 

    return 0; 

} 

Edificio che

Ho uno script del linker chiamato link.ld e un Makefile. Sto usando gcc cross compiler per i386-elf che ho compilato usando questa guida (http://wiki.osdev.org/GCC_Cross-Compiler).

ENTRY(loader)    /* the name of the entry label */ 

SECTIONS { 
    . = 0x00100000;   /* the code should be loaded at 1 MB */ 

    .text ALIGN (0x1000) : /* align at 4 KB */ 
    { 
     *(.text)    /* all text sections from all files */ 
    } 

    .rodata ALIGN (0x1000) : /* align at 4 KB */ 
    { 
     *(.rodata*)   /* all read-only data sections from all files */ 
    } 

    .data ALIGN (0x1000) : /* align at 4 KB */ 
    { 
     *(.data)    /* all data sections from all files */ 
    } 

    .bss ALIGN (0x1000) : /* align at 4 KB */ 
    { 
     sbss = .; 
     *(COMMON)   /* all COMMON sections from all files */ 
     *(.bss)    /* all bss sections from all files */ 
     ebss = .; 


    } 
} 

E qui è il mio makefile

OBJECTS = io.o fb.o loader.o kmain.o 
#CC = gcc 
CC = /home/albertlockett/opt/cross/bin/i386-elf-gcc 
CFLAGS = -m32 -nostdlib -nostdinc -fno-builtin -fno-stack-protector \ 
     -nostartfiles -nodefaultlibs -Wall -Wextra -Werror -c 
LDFLAGS = -T link.ld -melf_i386 
AS = nasm 
ASFLAGS = -f elf 

all: kernel.elf 

kernel.elf: $(OBJECTS) 
    ld $(LDFLAGS) $(OBJECTS) -o kernel.elf 

os.iso: kernel.elf 
    cp kernel.elf iso/boot/kernel.elf 
    genisoimage -R        \ 
       -b boot/grub/stage2_eltorito \ 
       -no-emul-boot     \ 
       -boot-load-size 4    \ 
       -A os       \ 
       -input-charset utf8    \ 
       -quiet       \ 
       -boot-info-table    \ 
       -o os.iso      \ 
       iso 

run: os.iso 
    bochs -f bochsrc.txt -q 

%.o: %.c 
    $(CC) $(CFLAGS) $< -o [email protected] 

%.o: %.s 
    $(AS) $(ASFLAGS) $< -o [email protected] 

clean: 
    rm -rf *.o kernel.elf os.iso 

Run it

Il makefile costruisce un iso dai contenuti di una directory chiamata iso. Quella cartella contiene una versione preconfigurata di grub che sono arrivato qui (https://github.com/littleosbook/littleosbook/blob/master/files/stage2_eltorito) e un file menu.lst per grub

menu.lst:

default=0 
timeout=0 

title os 
kernel /boot/kernel.elf 

contenuto della directory iso:

iso 
`-- boot 
    |-- grub 
    | |-- menu.lst 
    | `-- stage2_eltorito 
    `-- kernel.elf 

L'immagine iso si avvia in boch. Ecco la mia bochsrc.file txt

megs:   32 
display_library: term 
romimage:  file=/usr/share/bochs/BIOS-bochs-latest 
vgaromimage:  file=/usr/share/bochs/VGABIOS-lgpl-latest 
ata0-master:  type=cdrom, path=os.iso, status=inserted 
boot:   cdrom 
log:    bochslog.txt 
clock:   sync=realtime, time0=local 
cpu:    count=1, ips=1000000 
com1:   enabled=1, mode=file, dev=com1.out 

Qualcuno sa il motivo per cui la stringa letterale nel file kernel genera l'errore quando provo ad avviare l'iso?

+0

Wow, davvero non mi aspettavo qualcuno di aver avuto lo stesso problema come me – cstack

+0

Avessi anche questo ... i due punti .text è un errore di battitura nel littleosbook stesso. – cmlaverdiere

risposta

6

Si dispone di due punti in più alla fine di section .text: in modo da creare una nuova sezione denominata .text:. Per qualche oscuro motivo che non ho potuto scoprire da una rapida occhiata alla documentazione, questa sezione viene emessa nell'output anche se non è elencata nello script del linker. Quando non si dispone di dati letterali nel codice C, si è fortunati che rientri ancora nel primo 8kiB dell'immagine, in modo che l'intestazione di avvio multiplo si trovi nella parte richiesta. Se si dispone di una stringa letterale, si otterrà una nuova sezione .rodata e che, anche per un'altra ragione oscura, ottiene ordinato prima .text: ma dopo lo standard .text. Esempio:

Sections: 
Idx Name   Size  VMA  LMA  File off Algn 
    0 .text   00000001 00100000 00100000 00001000 2**4 
        CONTENTS, ALLOC, LOAD, READONLY, CODE 
    1 .rodata  00000005 00101000 00101000 00002000 2**2 
        CONTENTS, ALLOC, LOAD, READONLY, DATA 
    2 .text:  00000018 00101008 00101008 00002008 2**2 
        CONTENTS, ALLOC, LOAD, READONLY, DATA 
    3 .bss   0000100a 00102000 00102000 00003000 2**2 
        ALLOC 

Come si può vedere non è più entro il primo 8kiB dell'immagine è, quindi grub sarà molto triste.

TL; DR: rimuovere i due punti in più dopo section .text:.

+0

Grazie! quello lo ha riparato. Come hai prodotto quell'output? – albertlockett

+0

Utilizzato 'objdump -h' – Jester

+0

Perché i due punti creano un'altra sezione? – cstack