Home | History | Annotate | Download | only in modules
      1 /* ----------------------------------------------------------------------- *
      2  *
      3  *   Copyright 2008 H. Peter Anvin - All Rights Reserved
      4  *   Copyright 2009 Intel Corporation; author: H. Peter Anvin
      5  *
      6  *   This program is free software; you can redistribute it and/or modify
      7  *   it under the terms of the GNU General Public License as published by
      8  *   the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
      9  *   Boston MA 02110-1301, USA; either version 2 of the License, or
     10  *   (at your option) any later version; incorporated herein by reference.
     11  *
     12  * ----------------------------------------------------------------------- */
     13 
     14 /*
     15  * sdi.c
     16  *
     17  * Loader for the Microsoft System Deployment Image (SDI) format.
     18  * Based on a historical patch by Remi Lefevre.
     19  */
     20 
     21 #include <stdio.h>
     22 #include <stdlib.h>
     23 #include <inttypes.h>
     24 #include <string.h>
     25 #include <fcntl.h>
     26 #include <unistd.h>
     27 #include <errno.h>
     28 #include <minmax.h>
     29 #include <sys/stat.h>
     30 #include <console.h>
     31 #include <dprintf.h>
     32 
     33 #include <syslinux/loadfile.h>
     34 #include <syslinux/movebits.h>
     35 #include <syslinux/bootrm.h>
     36 
     37 typedef uint8_t guid_t[16];
     38 
     39 struct SDIHeader {
     40     uint32_t Signature;
     41     char Version[4];
     42     uint64_t MDBtype;
     43     uint64_t BootCodeOffset;
     44     uint64_t BootCodeSize;
     45     uint64_t VendorID;
     46     uint64_t DeviceID;
     47     guid_t DeviceModel;
     48     uint64_t DeviceRole;
     49     uint64_t Reserved1;
     50     guid_t RuntimeGUID;
     51     uint64_t RuntimeOEMrev;
     52     uint64_t Reserved2;
     53     uint64_t PageAlignment;	/* BLOB alignment value in pages */
     54     uint64_t Reserved3[48];
     55     uint64_t Checksum;
     56 };
     57 
     58 #define SDI_LOAD_ADDR	(16 << 20)	/* 16 MB */
     59 #define SDI_SIGNATURE	('$' + ('S' << 8) + ('D' << 16) + ('I' << 24))
     60 
     61 static inline void error(const char *msg)
     62 {
     63     fputs(msg, stderr);
     64 }
     65 
     66 static int boot_sdi(void *ptr, size_t len)
     67 {
     68     const struct SDIHeader *hdr = ptr;
     69     struct syslinux_memmap *mmap = NULL, *amap = NULL;
     70     struct syslinux_rm_regs regs;
     71     struct syslinux_movelist *ml = NULL;
     72 
     73     /* **** Basic sanity checking **** */
     74     if (hdr->Signature != SDI_SIGNATURE) {
     75 	fputs("No $SDI signature in file\n", stdout);
     76 	goto bail;
     77     }
     78     if (memcmp(hdr->Version, "0001", 4)) {
     79 	int i;
     80 	fputs("Warning: unknown SDI version: ", stdout);
     81 	for (i = 0; i < 4; i++)
     82 	    putchar(hdr->Version[i]);
     83 	putchar('\n');
     84 	/* Then try anyway... */
     85     }
     86 
     87     /* **** Setup **** */
     88     mmap = syslinux_memory_map();
     89     amap = syslinux_dup_memmap(mmap);
     90     if (!mmap || !amap)
     91 	goto bail;
     92 
     93     /* **** Map the BOOT BLOB to 0x7c00 **** */
     94     if (!hdr->BootCodeOffset) {
     95 	fputs("No BOOT BLOB in image\n", stdout);
     96 	goto bail;
     97     }
     98     if (!hdr->BootCodeSize) {
     99 	fputs("BOOT BLOB is empty\n", stdout);
    100 	goto bail;
    101     }
    102     if (len < hdr->BootCodeOffset + hdr->BootCodeSize) {
    103 	fputs("BOOT BLOB extends beyond file\n", stdout);
    104 	goto bail;
    105     }
    106 
    107     if (syslinux_memmap_type(amap, 0x7c00, hdr->BootCodeSize) != SMT_FREE) {
    108 	fputs("BOOT BLOB too large for memory\n", stdout);
    109 	goto bail;
    110     }
    111     if (syslinux_add_memmap(&amap, 0x7c00, hdr->BootCodeSize, SMT_ALLOC))
    112 	goto bail;
    113     if (syslinux_add_movelist(&ml, 0x7c00, (addr_t) ptr + hdr->BootCodeOffset,
    114 			      hdr->BootCodeSize))
    115 	goto bail;
    116 
    117     /* **** Map the entire image to SDI_LOAD_ADDR **** */
    118     if (syslinux_memmap_type(amap, SDI_LOAD_ADDR, len) != SMT_FREE) {
    119 	fputs("Image too large for memory\n", stdout);
    120 	goto bail;
    121     }
    122     if (syslinux_add_memmap(&amap, SDI_LOAD_ADDR, len, SMT_ALLOC))
    123 	goto bail;
    124     if (syslinux_add_movelist(&ml, SDI_LOAD_ADDR, (addr_t) ptr, len))
    125 	goto bail;
    126 
    127     /* **** Set up registers **** */
    128     memset(&regs, 0, sizeof regs);
    129     regs.ip = 0x7c00;
    130     regs.esp.l = 0x7c00;
    131     regs.edx.l = SDI_LOAD_ADDR | 0x41;
    132 
    133     fputs("Booting...\n", stdout);
    134     syslinux_shuffle_boot_rm(ml, mmap, 0, &regs);
    135 
    136 bail:
    137     syslinux_free_memmap(amap);
    138     syslinux_free_memmap(mmap);
    139     syslinux_free_movelist(ml);
    140     return -1;
    141 }
    142 
    143 /*
    144  * Check that the sum of all bytes from first 512 bytes (SDI header)
    145  * is 0 modulo 256.
    146  */
    147 int has_valid_header(unsigned char *header)
    148 {
    149     unsigned char checksum;
    150     unsigned int i;
    151 
    152     checksum = 0;
    153     for (i = 0; i < sizeof(struct SDIHeader); i++)
    154 	checksum += header[i];
    155     return (!checksum);
    156 }
    157 
    158 int main(int argc, char *argv[])
    159 {
    160     void *data;
    161     size_t data_len;
    162 
    163     if (argc != 2) {
    164 	error("Usage: sdi.c32 sdi_file\n");
    165 	return 1;
    166     }
    167 
    168     fputs("Loading ", stdout);
    169     fputs(argv[1], stdout);
    170     fputs("... ", stdout);
    171     if (zloadfile(argv[1], &data, &data_len)) {
    172 	error("failed!\n");
    173 	return 1;
    174     }
    175     fputs("ok\n", stdout);
    176 
    177     if (!has_valid_header(data)) {
    178 	error("SDI header is corrupted\n");
    179 	return 1;
    180     }
    181 
    182     boot_sdi(data, data_len);
    183     error("Invalid SDI file or insufficient memory\n");
    184     return 1;
    185 }
    186