1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 /* 22 * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved. 23 * Copyright 2012 Nexenta Systems, Inc. All rights reserved. 24 */ 25 26 #include <stdio.h> 27 #include <errno.h> 28 #include <assert.h> 29 #include <unistd.h> 30 #include <libintl.h> 31 #include <sys/multiboot.h> 32 #include <sys/sysmacros.h> 33 34 #include "bblk_einfo.h" 35 #include "boot_utils.h" 36 #include "mboot_extra.h" 37 38 /* 39 * Common functions to deal with the fake-multiboot encapsulation of the 40 * bootblock and the location of the extra information area. 41 */ 42 43 /* mboot checksum routine. */ 44 uint32_t 45 compute_checksum(char *data, uint32_t size) 46 { 47 uint32_t *ck_ptr; 48 uint32_t cksum = 0; 49 int i; 50 51 ck_ptr = (uint32_t *)data; 52 for (i = 0; i < size; i += sizeof (uint32_t)) 53 cksum += *ck_ptr++; 54 55 return (-cksum); 56 } 57 58 /* Given a buffer, look for a multiboot header within it. */ 59 int 60 find_multiboot(char *buffer, uint32_t buf_size, uint32_t *mboot_off) 61 { 62 multiboot_header_t *mboot; 63 uint32_t *iter; 64 uint32_t cksum; 65 uint32_t boundary; 66 int i = 0; 67 68 iter = (uint32_t *)buffer; 69 *mboot_off = 0; 70 /* multiboot header has to be within the first 32K. */ 71 boundary = MBOOT_SCAN_SIZE; 72 if (boundary > buf_size) 73 boundary = buf_size; 74 75 boundary = boundary - sizeof (multiboot_header_t); 76 77 for (i = 0; i < boundary; i += 4, iter++) { 78 79 mboot = (multiboot_header_t *)iter; 80 if (mboot->magic != MB_HEADER_MAGIC) 81 continue; 82 83 /* Found magic signature -- check checksum. */ 84 cksum = -(mboot->flags + mboot->magic); 85 if (mboot->checksum != cksum) { 86 BOOT_DEBUG("multiboot magic found at %p, but checksum " 87 "mismatches (is %x, should be %x)\n", mboot, 88 mboot->checksum, cksum); 89 continue; 90 } else { 91 if (!(mboot->flags & BB_MBOOT_AOUT_FLAG)) { 92 BOOT_DEBUG("multiboot structure found, but no " 93 "AOUT kludge specified, skipping.\n"); 94 continue; 95 } else { 96 /* proper multiboot structure found. */ 97 *mboot_off = i; 98 return (BC_SUCCESS); 99 } 100 } 101 } 102 103 return (BC_ERROR); 104 } 105 106 /* 107 * Given a pointer to the extra information area (a sequence of bb_header_ext_t 108 * + payload chunks), find the extended information structure. 109 */ 110 bblk_einfo_t * 111 find_einfo(char *extra, uint32_t size) 112 { 113 bb_header_ext_t *ext_header; 114 bblk_einfo_t *einfo; 115 uint32_t cksum; 116 117 assert(extra != NULL); 118 119 ext_header = (bb_header_ext_t *)extra; 120 if (ext_header->size > size) { 121 BOOT_DEBUG("Unable to find extended versioning information, " 122 "data size too big\n"); 123 return (NULL); 124 } 125 126 cksum = compute_checksum(extra + sizeof (bb_header_ext_t), 127 ext_header->size); 128 BOOT_DEBUG("Extended information header checksum is %x\n", cksum); 129 130 if (cksum != ext_header->checksum) { 131 BOOT_DEBUG("Unable to find extended versioning information, " 132 "data looks corrupted\n"); 133 return (NULL); 134 } 135 136 /* 137 * Currently we only have one extra header so it must be encapsulating 138 * the extended information structure. 139 */ 140 einfo = (bblk_einfo_t *)(extra + sizeof (bb_header_ext_t)); 141 if (memcmp(einfo->magic, EINFO_MAGIC, EINFO_MAGIC_SIZE) != 0) { 142 BOOT_DEBUG("Unable to read stage2 extended versioning " 143 "information, wrong magic identifier\n"); 144 BOOT_DEBUG("Found %s, expected %s\n", einfo->magic, 145 EINFO_MAGIC); 146 return (NULL); 147 } 148 149 return (einfo); 150 } 151 152 /* 153 * Given a pointer to the extra area, add the extended information structure 154 * encapsulated by a bb_header_ext_t structure. 155 */ 156 void 157 add_einfo(char *extra, char *updt_str, bblk_hs_t *hs, uint32_t avail_space) 158 { 159 bb_header_ext_t *ext_hdr; 160 uint32_t used_space; 161 unsigned char *dest; 162 int ret; 163 164 assert(extra != NULL); 165 166 if (updt_str == NULL) { 167 BOOT_DEBUG("WARNING: no update string passed to " 168 "add_stage2_einfo()\n"); 169 return; 170 } 171 172 /* Reserve space for the extra header. */ 173 ext_hdr = (bb_header_ext_t *)extra; 174 dest = (unsigned char *)extra + sizeof (*ext_hdr); 175 /* Place the extended information structure. */ 176 ret = prepare_and_write_einfo(dest, updt_str, hs, avail_space, 177 &used_space); 178 if (ret != 0) { 179 (void) fprintf(stderr, gettext("Unable to write the extended " 180 "versioning information\n")); 181 return; 182 } 183 184 /* Fill the extended information associated header. */ 185 ext_hdr->size = P2ROUNDUP(used_space, 8); 186 ext_hdr->checksum = compute_checksum((char *)dest, ext_hdr->size); 187 } 188