xref: /illumos-gate/usr/src/cmd/boot/common/mboot_extra.c (revision 6a634c9dca3093f3922e4b7ab826d7bdf17bf78e)
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  */
24 
25 #include <stdio.h>
26 #include <errno.h>
27 #include <assert.h>
28 #include <unistd.h>
29 #include <libintl.h>
30 #include <sys/multiboot.h>
31 #include <sys/sysmacros.h>
32 
33 #include "bblk_einfo.h"
34 #include "boot_utils.h"
35 #include "mboot_extra.h"
36 
37 /*
38  * Common functions to deal with the fake-multiboot encapsulation of the
39  * bootblock and the location of the extra information area.
40  */
41 
42 /* mboot checksum routine. */
43 uint32_t
44 compute_checksum(char *data, uint32_t size)
45 {
46 	uint32_t	*ck_ptr;
47 	uint32_t	cksum = 0;
48 	int		i;
49 
50 	ck_ptr = (uint32_t *)data;
51 	for (i = 0; i < size; i += sizeof (uint32_t))
52 		cksum += *ck_ptr++;
53 
54 	return (-cksum);
55 }
56 
57 /* Given a buffer, look for a multiboot header within it. */
58 int
59 find_multiboot(char *buffer, uint32_t buf_size, uint32_t *mboot_off)
60 {
61 	multiboot_header_t	*mboot;
62 	uint32_t		*iter;
63 	uint32_t		cksum;
64 	uint32_t		boundary;
65 	int			i = 0;
66 
67 	iter = (uint32_t *)buffer;
68 	*mboot_off = 0;
69 	/* multiboot header has to be within the first 32K. */
70 	boundary = MBOOT_SCAN_SIZE;
71 	if (boundary > buf_size)
72 		boundary = buf_size;
73 
74 	boundary = boundary - sizeof (multiboot_header_t);
75 
76 	for (i = 0; i < boundary; i += 4, iter++) {
77 
78 		mboot = (multiboot_header_t *)iter;
79 		if (mboot->magic != MB_HEADER_MAGIC)
80 			continue;
81 
82 		/* Found magic signature -- check checksum. */
83 		cksum = -(mboot->flags + mboot->magic);
84 		if (mboot->checksum != cksum) {
85 			BOOT_DEBUG("multiboot magic found at %p, but checksum "
86 			    "mismatches (is %x, should be %x)\n", mboot,
87 			    mboot->checksum, cksum);
88 			continue;
89 		} else {
90 			if (!(mboot->flags & BB_MBOOT_AOUT_FLAG)) {
91 				BOOT_DEBUG("multiboot structure found, but no "
92 				    "AOUT kludge specified, skipping.\n");
93 				continue;
94 			} else {
95 				/* proper multiboot structure found. */
96 				*mboot_off = i;
97 				return (BC_SUCCESS);
98 			}
99 		}
100 	}
101 
102 	return (BC_ERROR);
103 }
104 
105 /*
106  * Given a pointer to the extra information area (a sequence of bb_header_ext_t
107  * + payload chunks), find the extended information structure.
108  */
109 bblk_einfo_t *
110 find_einfo(char *extra)
111 {
112 	bb_header_ext_t		*ext_header;
113 	bblk_einfo_t		*einfo;
114 	uint32_t		cksum;
115 
116 	assert(extra != NULL);
117 
118 	ext_header = (bb_header_ext_t *)extra;
119 	cksum = compute_checksum(extra + sizeof (bb_header_ext_t),
120 	    ext_header->size);
121 	BOOT_DEBUG("Extended information header checksum is %x\n", cksum);
122 
123 	if (cksum != ext_header->checksum) {
124 		BOOT_DEBUG("Unable to find extended versioning information, "
125 		    "data looks corrupted\n");
126 		return (NULL);
127 	}
128 
129 	/*
130 	 * Currently we only have one extra header so it must be encapsulating
131 	 * the extended information structure.
132 	 */
133 	einfo = (bblk_einfo_t *)(extra + sizeof (bb_header_ext_t));
134 	if (memcmp(einfo->magic, EINFO_MAGIC, EINFO_MAGIC_SIZE) != 0) {
135 		BOOT_DEBUG("Unable to read stage2 extended versioning "
136 		    "information, wrong magic identifier\n");
137 		BOOT_DEBUG("Found %s, expected %s\n", einfo->magic,
138 		    EINFO_MAGIC);
139 		return (NULL);
140 	}
141 
142 	return (einfo);
143 }
144 
145 /*
146  * Given a pointer to the extra area, add the extended information structure
147  * encapsulated by a bb_header_ext_t structure.
148  */
149 void
150 add_einfo(char *extra, char *updt_str, bblk_hs_t *hs, uint32_t avail_space)
151 {
152 	bb_header_ext_t	*ext_hdr;
153 	uint32_t	used_space;
154 	unsigned char	*dest;
155 	int		ret;
156 
157 	assert(extra != NULL);
158 
159 	if (updt_str == NULL) {
160 		BOOT_DEBUG("WARNING: no update string passed to "
161 		    "add_stage2_einfo()\n");
162 		return;
163 	}
164 
165 	/* Reserve space for the extra header. */
166 	ext_hdr = (bb_header_ext_t *)extra;
167 	dest = (unsigned char *)extra + sizeof (*ext_hdr);
168 	/* Place the extended information structure. */
169 	ret = prepare_and_write_einfo(dest, updt_str, hs, avail_space,
170 	    &used_space);
171 	if (ret != 0) {
172 		(void) fprintf(stderr, gettext("Unable to write the extended "
173 		    "versioning information\n"));
174 		return;
175 	}
176 
177 	/* Fill the extended information associated header. */
178 	ext_hdr->size = P2ROUNDUP(used_space, 8);
179 	ext_hdr->checksum = compute_checksum((char *)dest, ext_hdr->size);
180 }
181