Annotation of qemu/hw/multiboot.c, revision 1.1.1.4

1.1       root        1: /*
                      2:  * QEMU PC System Emulator
                      3:  *
                      4:  * Copyright (c) 2003-2004 Fabrice Bellard
                      5:  *
                      6:  * Permission is hereby granted, free of charge, to any person obtaining a copy
                      7:  * of this software and associated documentation files (the "Software"), to deal
                      8:  * in the Software without restriction, including without limitation the rights
                      9:  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
                     10:  * copies of the Software, and to permit persons to whom the Software is
                     11:  * furnished to do so, subject to the following conditions:
                     12:  *
                     13:  * The above copyright notice and this permission notice shall be included in
                     14:  * all copies or substantial portions of the Software.
                     15:  *
                     16:  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
                     17:  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
                     18:  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
                     19:  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
                     20:  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
                     21:  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
                     22:  * THE SOFTWARE.
                     23:  */
                     24: 
                     25: #include "hw.h"
                     26: #include "fw_cfg.h"
                     27: #include "multiboot.h"
                     28: #include "loader.h"
                     29: #include "elf.h"
                     30: #include "sysemu.h"
                     31: 
                     32: /* Show multiboot debug output */
                     33: //#define DEBUG_MULTIBOOT
                     34: 
                     35: #ifdef DEBUG_MULTIBOOT
                     36: #define mb_debug(a...) fprintf(stderr, ## a)
                     37: #else
                     38: #define mb_debug(a...)
                     39: #endif
                     40: 
                     41: #define MULTIBOOT_STRUCT_ADDR 0x9000
                     42: 
                     43: #if MULTIBOOT_STRUCT_ADDR > 0xf0000
                     44: #error multiboot struct needs to fit in 16 bit real mode
                     45: #endif
                     46: 
                     47: enum {
                     48:     /* Multiboot info */
                     49:     MBI_FLAGS       = 0,
                     50:     MBI_MEM_LOWER   = 4,
                     51:     MBI_MEM_UPPER   = 8,
                     52:     MBI_BOOT_DEVICE = 12,
                     53:     MBI_CMDLINE     = 16,
                     54:     MBI_MODS_COUNT  = 20,
                     55:     MBI_MODS_ADDR   = 24,
                     56:     MBI_MMAP_ADDR   = 48,
                     57: 
                     58:     MBI_SIZE        = 88,
                     59: 
                     60:     /* Multiboot modules */
                     61:     MB_MOD_START    = 0,
                     62:     MB_MOD_END      = 4,
                     63:     MB_MOD_CMDLINE  = 8,
                     64: 
                     65:     MB_MOD_SIZE     = 16,
                     66: 
                     67:     /* Region offsets */
                     68:     ADDR_E820_MAP = MULTIBOOT_STRUCT_ADDR + 0,
                     69:     ADDR_MBI      = ADDR_E820_MAP + 0x500,
                     70: 
                     71:     /* Multiboot flags */
                     72:     MULTIBOOT_FLAGS_MEMORY      = 1 << 0,
                     73:     MULTIBOOT_FLAGS_BOOT_DEVICE = 1 << 1,
                     74:     MULTIBOOT_FLAGS_CMDLINE     = 1 << 2,
                     75:     MULTIBOOT_FLAGS_MODULES     = 1 << 3,
                     76:     MULTIBOOT_FLAGS_MMAP        = 1 << 6,
                     77: };
                     78: 
                     79: typedef struct {
                     80:     /* buffer holding kernel, cmdlines and mb_infos */
                     81:     void *mb_buf;
                     82:     /* address in target */
                     83:     target_phys_addr_t mb_buf_phys;
                     84:     /* size of mb_buf in bytes */
                     85:     unsigned mb_buf_size;
                     86:     /* offset of mb-info's in bytes */
                     87:     target_phys_addr_t offset_mbinfo;
                     88:     /* offset in buffer for cmdlines in bytes */
                     89:     target_phys_addr_t offset_cmdlines;
                     90:     /* offset of modules in bytes */
                     91:     target_phys_addr_t offset_mods;
                     92:     /* available slots for mb modules infos */
                     93:     int mb_mods_avail;
                     94:     /* currently used slots of mb modules */
                     95:     int mb_mods_count;
                     96: } MultibootState;
                     97: 
                     98: static uint32_t mb_add_cmdline(MultibootState *s, const char *cmdline)
                     99: {
                    100:     target_phys_addr_t p = s->offset_cmdlines;
1.1.1.3   root      101:     char *b = (char *)s->mb_buf + p;
1.1       root      102: 
1.1.1.3   root      103:     get_opt_value(b, strlen(cmdline) + 1, cmdline);
                    104:     s->offset_cmdlines += strlen(b) + 1;
1.1       root      105:     return s->mb_buf_phys + p;
                    106: }
                    107: 
                    108: static void mb_add_mod(MultibootState *s,
                    109:                        target_phys_addr_t start, target_phys_addr_t end,
                    110:                        target_phys_addr_t cmdline_phys)
                    111: {
                    112:     char *p;
                    113:     assert(s->mb_mods_count < s->mb_mods_avail);
                    114: 
                    115:     p = (char *)s->mb_buf + s->offset_mbinfo + MB_MOD_SIZE * s->mb_mods_count;
                    116: 
                    117:     stl_p(p + MB_MOD_START,   start);
                    118:     stl_p(p + MB_MOD_END,     end);
                    119:     stl_p(p + MB_MOD_CMDLINE, cmdline_phys);
                    120: 
                    121:     mb_debug("mod%02d: "TARGET_FMT_plx" - "TARGET_FMT_plx"\n",
                    122:              s->mb_mods_count, start, end);
                    123: 
                    124:     s->mb_mods_count++;
                    125: }
                    126: 
                    127: int load_multiboot(void *fw_cfg,
                    128:                    FILE *f,
                    129:                    const char *kernel_filename,
                    130:                    const char *initrd_filename,
                    131:                    const char *kernel_cmdline,
                    132:                    int kernel_file_size,
                    133:                    uint8_t *header)
                    134: {
                    135:     int i, is_multiboot = 0;
                    136:     uint32_t flags = 0;
                    137:     uint32_t mh_entry_addr;
                    138:     uint32_t mh_load_addr;
                    139:     uint32_t mb_kernel_size;
                    140:     MultibootState mbs;
                    141:     uint8_t bootinfo[MBI_SIZE];
                    142:     uint8_t *mb_bootinfo_data;
                    143: 
                    144:     /* Ok, let's see if it is a multiboot image.
                    145:        The header is 12x32bit long, so the latest entry may be 8192 - 48. */
                    146:     for (i = 0; i < (8192 - 48); i += 4) {
                    147:         if (ldl_p(header+i) == 0x1BADB002) {
                    148:             uint32_t checksum = ldl_p(header+i+8);
                    149:             flags = ldl_p(header+i+4);
                    150:             checksum += flags;
                    151:             checksum += (uint32_t)0x1BADB002;
                    152:             if (!checksum) {
                    153:                 is_multiboot = 1;
                    154:                 break;
                    155:             }
                    156:         }
                    157:     }
                    158: 
                    159:     if (!is_multiboot)
                    160:         return 0; /* no multiboot */
                    161: 
                    162:     mb_debug("qemu: I believe we found a multiboot image!\n");
                    163:     memset(bootinfo, 0, sizeof(bootinfo));
                    164:     memset(&mbs, 0, sizeof(mbs));
                    165: 
                    166:     if (flags & 0x00000004) { /* MULTIBOOT_HEADER_HAS_VBE */
                    167:         fprintf(stderr, "qemu: multiboot knows VBE. we don't.\n");
                    168:     }
                    169:     if (!(flags & 0x00010000)) { /* MULTIBOOT_HEADER_HAS_ADDR */
                    170:         uint64_t elf_entry;
                    171:         uint64_t elf_low, elf_high;
                    172:         int kernel_size;
                    173:         fclose(f);
1.1.1.2   root      174: 
                    175:         if (((struct elf64_hdr*)header)->e_machine == EM_X86_64) {
                    176:             fprintf(stderr, "Cannot load x86-64 image, give a 32bit one.\n");
                    177:             exit(1);
                    178:         }
                    179: 
1.1       root      180:         kernel_size = load_elf(kernel_filename, NULL, NULL, &elf_entry,
                    181:                                &elf_low, &elf_high, 0, ELF_MACHINE, 0);
                    182:         if (kernel_size < 0) {
                    183:             fprintf(stderr, "Error while loading elf kernel\n");
                    184:             exit(1);
                    185:         }
                    186:         mh_load_addr = elf_low;
                    187:         mb_kernel_size = elf_high - elf_low;
                    188:         mh_entry_addr = elf_entry;
                    189: 
1.1.1.4 ! root      190:         mbs.mb_buf = g_malloc(mb_kernel_size);
1.1       root      191:         if (rom_copy(mbs.mb_buf, mh_load_addr, mb_kernel_size) != mb_kernel_size) {
                    192:             fprintf(stderr, "Error while fetching elf kernel from rom\n");
                    193:             exit(1);
                    194:         }
                    195: 
                    196:         mb_debug("qemu: loading multiboot-elf kernel (%#x bytes) with entry %#zx\n",
                    197:                   mb_kernel_size, (size_t)mh_entry_addr);
                    198:     } else {
                    199:         /* Valid if mh_flags sets MULTIBOOT_HEADER_HAS_ADDR. */
                    200:         uint32_t mh_header_addr = ldl_p(header+i+12);
1.1.1.4 ! root      201:         uint32_t mh_load_end_addr = ldl_p(header+i+20);
        !           202:         uint32_t mh_bss_end_addr = ldl_p(header+i+24);
1.1       root      203:         mh_load_addr = ldl_p(header+i+16);
                    204:         uint32_t mb_kernel_text_offset = i - (mh_header_addr - mh_load_addr);
1.1.1.4 ! root      205:         uint32_t mb_load_size = mh_load_end_addr - mh_load_addr;
1.1       root      206: 
                    207:         mh_entry_addr = ldl_p(header+i+28);
1.1.1.4 ! root      208:         mb_kernel_size = mh_bss_end_addr - mh_load_addr;
1.1       root      209: 
                    210:         /* Valid if mh_flags sets MULTIBOOT_HEADER_HAS_VBE.
                    211:         uint32_t mh_mode_type = ldl_p(header+i+32);
                    212:         uint32_t mh_width = ldl_p(header+i+36);
                    213:         uint32_t mh_height = ldl_p(header+i+40);
                    214:         uint32_t mh_depth = ldl_p(header+i+44); */
                    215: 
                    216:         mb_debug("multiboot: mh_header_addr = %#x\n", mh_header_addr);
                    217:         mb_debug("multiboot: mh_load_addr = %#x\n", mh_load_addr);
1.1.1.4 ! root      218:         mb_debug("multiboot: mh_load_end_addr = %#x\n", mh_load_end_addr);
        !           219:         mb_debug("multiboot: mh_bss_end_addr = %#x\n", mh_bss_end_addr);
1.1       root      220:         mb_debug("qemu: loading multiboot kernel (%#x bytes) at %#x\n",
1.1.1.4 ! root      221:                  mb_load_size, mh_load_addr);
1.1       root      222: 
1.1.1.4 ! root      223:         mbs.mb_buf = g_malloc(mb_kernel_size);
1.1       root      224:         fseek(f, mb_kernel_text_offset, SEEK_SET);
1.1.1.4 ! root      225:         if (fread(mbs.mb_buf, 1, mb_load_size, f) != mb_load_size) {
1.1       root      226:             fprintf(stderr, "fread() failed\n");
                    227:             exit(1);
                    228:         }
1.1.1.4 ! root      229:         memset(mbs.mb_buf + mb_load_size, 0, mb_kernel_size - mb_load_size);
1.1       root      230:         fclose(f);
                    231:     }
                    232: 
                    233:     mbs.mb_buf_phys = mh_load_addr;
                    234: 
                    235:     mbs.mb_buf_size = TARGET_PAGE_ALIGN(mb_kernel_size);
                    236:     mbs.offset_mbinfo = mbs.mb_buf_size;
                    237: 
                    238:     /* Calculate space for cmdlines and mb_mods */
                    239:     mbs.mb_buf_size += strlen(kernel_filename) + 1;
                    240:     mbs.mb_buf_size += strlen(kernel_cmdline) + 1;
                    241:     if (initrd_filename) {
                    242:         const char *r = initrd_filename;
                    243:         mbs.mb_buf_size += strlen(r) + 1;
                    244:         mbs.mb_mods_avail = 1;
1.1.1.3   root      245:         while (*(r = get_opt_value(NULL, 0, r))) {
1.1       root      246:            mbs.mb_mods_avail++;
                    247:            r++;
                    248:         }
                    249:         mbs.mb_buf_size += MB_MOD_SIZE * mbs.mb_mods_avail;
                    250:     }
                    251: 
                    252:     mbs.mb_buf_size = TARGET_PAGE_ALIGN(mbs.mb_buf_size);
                    253: 
                    254:     /* enlarge mb_buf to hold cmdlines and mb-info structs */
1.1.1.4 ! root      255:     mbs.mb_buf          = g_realloc(mbs.mb_buf, mbs.mb_buf_size);
1.1       root      256:     mbs.offset_cmdlines = mbs.offset_mbinfo + mbs.mb_mods_avail * MB_MOD_SIZE;
                    257: 
                    258:     if (initrd_filename) {
1.1.1.3   root      259:         char *next_initrd, not_last;
1.1       root      260: 
                    261:         mbs.offset_mods = mbs.mb_buf_size;
                    262: 
                    263:         do {
                    264:             char *next_space;
1.1.1.2   root      265:             int mb_mod_length;
1.1       root      266:             uint32_t offs = mbs.mb_buf_size;
                    267: 
1.1.1.3   root      268:             next_initrd = (char *)get_opt_value(NULL, 0, initrd_filename);
                    269:             not_last = *next_initrd;
                    270:             *next_initrd = '\0';
1.1       root      271:             /* if a space comes after the module filename, treat everything
                    272:                after that as parameters */
                    273:             target_phys_addr_t c = mb_add_cmdline(&mbs, initrd_filename);
                    274:             if ((next_space = strchr(initrd_filename, ' ')))
                    275:                 *next_space = '\0';
                    276:             mb_debug("multiboot loading module: %s\n", initrd_filename);
                    277:             mb_mod_length = get_image_size(initrd_filename);
                    278:             if (mb_mod_length < 0) {
1.1.1.3   root      279:                 fprintf(stderr, "Failed to open file '%s'\n", initrd_filename);
1.1       root      280:                 exit(1);
                    281:             }
                    282: 
                    283:             mbs.mb_buf_size = TARGET_PAGE_ALIGN(mb_mod_length + mbs.mb_buf_size);
1.1.1.4 ! root      284:             mbs.mb_buf = g_realloc(mbs.mb_buf, mbs.mb_buf_size);
1.1       root      285: 
                    286:             load_image(initrd_filename, (unsigned char *)mbs.mb_buf + offs);
                    287:             mb_add_mod(&mbs, mbs.mb_buf_phys + offs,
                    288:                        mbs.mb_buf_phys + offs + mb_mod_length, c);
                    289: 
                    290:             mb_debug("mod_start: %p\nmod_end:   %p\n  cmdline: "TARGET_FMT_plx"\n",
                    291:                      (char *)mbs.mb_buf + offs,
                    292:                      (char *)mbs.mb_buf + offs + mb_mod_length, c);
                    293:             initrd_filename = next_initrd+1;
1.1.1.3   root      294:         } while (not_last);
1.1       root      295:     }
                    296: 
                    297:     /* Commandline support */
                    298:     char kcmdline[strlen(kernel_filename) + strlen(kernel_cmdline) + 2];
                    299:     snprintf(kcmdline, sizeof(kcmdline), "%s %s",
                    300:              kernel_filename, kernel_cmdline);
                    301:     stl_p(bootinfo + MBI_CMDLINE, mb_add_cmdline(&mbs, kcmdline));
                    302: 
                    303:     stl_p(bootinfo + MBI_MODS_ADDR,  mbs.mb_buf_phys + mbs.offset_mbinfo);
                    304:     stl_p(bootinfo + MBI_MODS_COUNT, mbs.mb_mods_count); /* mods_count */
                    305: 
                    306:     /* the kernel is where we want it to be now */
                    307:     stl_p(bootinfo + MBI_FLAGS, MULTIBOOT_FLAGS_MEMORY
                    308:                                 | MULTIBOOT_FLAGS_BOOT_DEVICE
                    309:                                 | MULTIBOOT_FLAGS_CMDLINE
                    310:                                 | MULTIBOOT_FLAGS_MODULES
                    311:                                 | MULTIBOOT_FLAGS_MMAP);
                    312:     stl_p(bootinfo + MBI_MEM_LOWER,   640);
1.1.1.2   root      313:     stl_p(bootinfo + MBI_MEM_UPPER,   (ram_size / 1024) - 1024);
1.1.1.3   root      314:     stl_p(bootinfo + MBI_BOOT_DEVICE, 0x8000ffff); /* XXX: use the -boot switch? */
1.1       root      315:     stl_p(bootinfo + MBI_MMAP_ADDR,   ADDR_E820_MAP);
                    316: 
                    317:     mb_debug("multiboot: mh_entry_addr = %#x\n", mh_entry_addr);
                    318:     mb_debug("           mb_buf_phys   = "TARGET_FMT_plx"\n", mbs.mb_buf_phys);
                    319:     mb_debug("           mod_start     = "TARGET_FMT_plx"\n", mbs.mb_buf_phys + mbs.offset_mods);
                    320:     mb_debug("           mb_mods_count = %d\n", mbs.mb_mods_count);
                    321: 
                    322:     /* save bootinfo off the stack */
1.1.1.4 ! root      323:     mb_bootinfo_data = g_malloc(sizeof(bootinfo));
1.1       root      324:     memcpy(mb_bootinfo_data, bootinfo, sizeof(bootinfo));
                    325: 
                    326:     /* Pass variables to option rom */
                    327:     fw_cfg_add_i32(fw_cfg, FW_CFG_KERNEL_ENTRY, mh_entry_addr);
                    328:     fw_cfg_add_i32(fw_cfg, FW_CFG_KERNEL_ADDR, mh_load_addr);
                    329:     fw_cfg_add_i32(fw_cfg, FW_CFG_KERNEL_SIZE, mbs.mb_buf_size);
                    330:     fw_cfg_add_bytes(fw_cfg, FW_CFG_KERNEL_DATA,
                    331:                      mbs.mb_buf, mbs.mb_buf_size);
                    332: 
                    333:     fw_cfg_add_i32(fw_cfg, FW_CFG_INITRD_ADDR, ADDR_MBI);
                    334:     fw_cfg_add_i32(fw_cfg, FW_CFG_INITRD_SIZE, sizeof(bootinfo));
                    335:     fw_cfg_add_bytes(fw_cfg, FW_CFG_INITRD_DATA, mb_bootinfo_data,
                    336:                      sizeof(bootinfo));
                    337: 
1.1.1.2   root      338:     option_rom[nb_option_roms].name = "multiboot.bin";
                    339:     option_rom[nb_option_roms].bootindex = 0;
1.1       root      340:     nb_option_roms++;
                    341: 
                    342:     return 1; /* yes, we are multiboot */
                    343: }

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.