⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 mboot.c

📁 linux内核
💻 C
📖 第 1 页 / 共 3 页
字号:
/* *  mboot.c * *  Loader for Multiboot-compliant kernels and modules. *  *  Copyright (C) 2005 Tim Deegan <Tim.Deegan@cl.cam.ac.uk> *  Parts based on GNU GRUB, Copyright (C) 2000  Free Software Foundation, Inc. *  Parts based on SYSLINUX, Copyright (C) 1994-2005  H. Peter Anvin. * *  This program is free software; you can redistribute it and/or *  modify it under the terms of the GNU General Public License as *  published by the Free Software Foundation; either version 2 of the *  License, or (at your option) any later version. * *  This program is distributed in the hope that it will be useful, *  but WITHOUT ANY WARRANTY; without even the implied warranty of *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU *  General Public License for more details. * *  You should have received a copy of the GNU General Public License *  along with this program; if not, write to the Free Software *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA *  02111-1307, USA. *  */#include <stdio.h>#include <stdlib.h>#include <stddef.h>#include <string.h>#include <malloc.h>#include <consoles.h>#include <zlib.h>#include <com32.h>#include "i386-elf.h"#include "mb_info.h"#include "mb_header.h"#include <klibc/compiler.h> /* For __constructor */#define MIN(_x, _y) (((_x)<(_y))?(_x):(_y))#define MAX(_x, _y) (((_x)>(_y))?(_x):(_y))/* Define this for some more printout */#undef DEBUG/* Memory magic numbers */#define STACK_SIZE      0x20000      /* XXX Could be much smaller */#define MALLOC_SIZE     0x100000     /* XXX Could be much smaller */#define MIN_RUN_ADDR    0x10000      /* Lowest address we'll consider using */#define MEM_HOLE_START  0xa0000      /* Memory hole runs from 640k ... */#define MEM_HOLE_END    0x100000     /* ... to 1MB */#define X86_PAGE_SIZE   0x1000size_t __stack_size = STACK_SIZE;    /* How much stack we'll use */extern void *__mem_end;              /* Start of malloc() heap */extern char _end[];                  /* End of static data *//* Pointer to free memory for loading into: load area is between here * and section_addr */static char *next_load_addr;/* Memory map for run-time */typedef struct section section_t;struct section {    size_t dest;                     /* Start of run-time allocation */    char *src;                       /* Current location of data for memmove(),                                      * or NULL for bzero() */    size_t size;                     /* Length of allocation */};static char *section_addr;static int section_count;static size_t max_run_addr;          /* Highest address we'll consider using */static size_t next_mod_run_addr;     /* Where the next module will be put *//* File loads are in units of this much */#define LOAD_CHUNK 0x20000/* Layout of the input to the 32-bit lidt instruction */struct lidt_operand {    unsigned int limit:16;    unsigned int base:32;} __attribute__((packed));/* Magic strings */static const char version_string[]   = "COM32 Multiboot loader v0.1";static const char copyright_string[] = "Copyright (C) 2005 Tim Deegan.";static const char module_separator[] = "---";/* *  Start of day magic, run from __start during library init. */static void __constructor check_version(void)    /* Check the SYSLINUX version.  Docs say we should be OK from v2.08,      * but in fact we crash on anything below v2.12 (when libc came in). */{    com32sys_t regs_in, regs_out;    const char *p, *too_old = "Fatal: SYSLINUX image is too old; "                              "mboot.c32 needs at least version 2.12.\r\n";    memset(&regs_in, 0, sizeof(regs_in));    regs_in.eax.l = 0x0001;  /* "Get version" */    __intcall(0x22, &regs_in, &regs_out);    if (regs_out.ecx.w[0] >= 0x020c) return;    /* Pointless: on older versions this print fails too. :( */    for (p = too_old ; *p ; p++) {        memset(&regs_in, 0, sizeof(regs_in));        regs_in.eax.b[1] = 0x02;      /* "Write character" */        regs_in.edx.b[0] = *p;        __intcall(0x21, &regs_in, &regs_out);    }    __intcall(0x20, &regs_in, &regs_out);  /* "Terminate program" */}static void __constructor grab_memory(void)    /* Runs before init_memory_arena() (com32/lib/malloc.c) to let     * the malloc() code know how much space it's allowed to use.     * We don't use malloc() directly, but some of the library code     * does (zlib, for example). */ {     /* Find the stack pointer */    register char * sp;    asm volatile("movl %%esp, %0" : "=r" (sp));    /* Initialize the allocation of *run-time* memory: don't let ourselves      * overwrite the stack during the relocation later. */    max_run_addr = (size_t) sp - (MALLOC_SIZE + STACK_SIZE);    /* Move the end-of-memory marker: malloc() will use only memory     * above __mem_end and below the stack.  We will load files starting     * at the old __mem_end and working towards the new one, and allocate     * section descriptors at the top of that area, working down. */    next_load_addr = __mem_end;     section_addr = sp - (MALLOC_SIZE + STACK_SIZE);    section_count = 0;    /* But be careful not to move it the wrong direction if memory is     * tight.  Instead we'll fail more gracefully later, when we try to      * load a file and find that next_load_addr > section_addr. */    __mem_end = MAX(section_addr, next_load_addr);}/* *  Run-time memory map functions: allocating and recording allocations. */static int cmp_sections(const void *a, const void *b)     /* For sorting section descriptors by destination address */{    const section_t *sa = a;    const section_t *sb = b;    if (sa->dest < sb->dest) return -1;    if (sa->dest > sb->dest) return 1;    return 0;}static void add_section(size_t dest, char *src, size_t size)    /* Adds something to the list of sections to relocate. */{    section_t *sec;#ifdef DEBUG    printf("SECTION: %#8.8x --> %#8.8x (%#x)\n", (size_t) src, dest, size);#endif    section_addr -= sizeof (section_t);     if (section_addr < next_load_addr) {        printf("Fatal: out of memory allocating section descriptor.\n");        exit(1);    }    sec = (section_t *) section_addr;    section_count++;    sec->src = src;    sec->dest = dest;    sec->size = size;        /* Keep the list sorted */    qsort(sec, section_count, sizeof (section_t), cmp_sections);}static size_t place_low_section(size_t size, size_t align)     /* Find a space in the run-time memory map, below 640K */{    int i;    size_t start;    section_t *sections = (section_t *) section_addr;    start = MIN_RUN_ADDR;    start = (start + (align-1)) & ~(align-1);    /* Section list is sorted by destination, so can do this in one pass */    for (i = 0; i < section_count; i++) {        if (sections[i].dest < start + size) {            /* Hit the bottom of this section */            start = sections[i].dest + sections[i].size;            start = (start + (align-1)) & ~(align-1);        }    }    if (start + size < MEM_HOLE_START) return start;    else return 0;}static size_t place_module_section(size_t size, size_t align)     /* Find a space in the run-time memory map for this module. */{    /* Ideally we'd run through the sections looking for a free space     * like place_low_section() does, but some OSes (Xen, at least)     * assume that the bootloader has loaded all the modules     * consecutively, above the kernel.  So, what we actually do is     * keep a pointer to the highest address allocated so far, and     * always allocate modules there. */     size_t start = next_mod_run_addr;    start = (start + (align-1)) & ~(align-1);    if (start + size > max_run_addr) return 0;    next_mod_run_addr = start + size;    return start;}static void place_kernel_section(size_t start, size_t size)    /* Allocate run-time space for part of the kernel, checking for     * sanity.  We assume the kernel isn't broken enough to have     * overlapping segments. */{    /* We always place modules above the kernel */    next_mod_run_addr = MAX(next_mod_run_addr, start + size);    if (start > max_run_addr || start + size > max_run_addr) {        /* Overruns the end of memory */        printf("Fatal: kernel loads too high (%#8.8x+%#x > %#8.8x).\n",               start, size, max_run_addr);        exit(1);    }    if (start >= MEM_HOLE_END) {        /* Above the memory hole: easy */#ifdef DEBUG        printf("Placed kernel section (%#8.8x+%#x)\n", start, size);#endif        return;    }    if (start >= MEM_HOLE_START) {        /* In the memory hole.  Not so good */        printf("Fatal: kernel load address (%#8.8x) is in the memory hole.\n",               start);        exit(1);    }    if (start + size > MEM_HOLE_START) {        /* Too big for low memory */        printf("Fatal: kernel (%#8.8x+%#x) runs into the memory hole.\n",               start, size);        exit(1);    }       if (start < MIN_RUN_ADDR) {        /* Loads too low */        printf("Fatal: kernel load address (%#8.8x) is too low (<%#8.8x).\n",               start, MIN_RUN_ADDR);        exit(1);    }    /* Kernel loads below the memory hole: OK */#ifdef DEBUG    printf("Placed kernel section (%#8.8x+%#x)\n", start, size);#endif}static void reorder_sections(void)     /* Reorders sections into a safe order, where no relocation      * overwrites the source of a later one.  */{    section_t *secs = (section_t *) section_addr;    section_t tmp;    int i, j, tries;#ifdef DEBUG    printf("Relocations:\n");    for (i = 0; i < section_count ; i++) {        printf("    %#8.8x --> %#8.8x (%#x)\n",                (size_t)secs[i].src, secs[i].dest, secs[i].size);     }#endif    for (i = 0; i < section_count; i++) {        tries = 0;    scan_again:        for (j = i + 1 ; j < section_count; j++) {            if (secs[j].src != NULL                && secs[i].dest + secs[i].size > (size_t) secs[j].src                 && secs[i].dest < (size_t) secs[j].src + secs[j].size) {                /* Would overwrite the source of the later move */                if (++tries > section_count) {                    /* Deadlock! */                    /* XXX Try to break deadlocks? */                    printf("Fatal: circular dependence in relocations.\n");                    exit(1);                }                /* Swap these sections (using struct copies) */                tmp = secs[i]; secs[i] = secs[j]; secs[j] = tmp;                /* Start scanning again from the new secs[i]... */                goto scan_again;            }        }    }#ifdef DEBUG    printf("Relocations:\n");    for (i = 0; i < section_count ; i++) {        printf("    %#8.8x --> %#8.8x (%#x)\n",                (size_t)secs[i].src, secs[i].dest, secs[i].size);     }

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -