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(®s, 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, ®s); 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