xref: /titanic_44/usr/src/uts/i86pc/dboot/dboot_multiboot2.c (revision 6b48797ae2139f7d9df87dda133fa5269c576b77)
1*e84622caSToomas Soome /*
2*e84622caSToomas Soome  * This file and its contents are supplied under the terms of the
3*e84622caSToomas Soome  * Common Development and Distribution License ("CDDL"), version 1.0.
4*e84622caSToomas Soome  * You may only use this file in accordance with the terms of version
5*e84622caSToomas Soome  * 1.0 of the CDDL.
6*e84622caSToomas Soome  *
7*e84622caSToomas Soome  * A full copy of the text of the CDDL should have accompanied this
8*e84622caSToomas Soome  * source.  A copy of the CDDL is also available via the Internet at
9*e84622caSToomas Soome  * http://www.illumos.org/license/CDDL.
10*e84622caSToomas Soome  */
11*e84622caSToomas Soome 
12*e84622caSToomas Soome /*
13*e84622caSToomas Soome  * Copyright 2016 Toomas Soome <tsoome@me.com>
14*e84622caSToomas Soome  */
15*e84622caSToomas Soome 
16*e84622caSToomas Soome /*
17*e84622caSToomas Soome  * dboot module utility functions for multiboot 2 tags processing.
18*e84622caSToomas Soome  */
19*e84622caSToomas Soome 
20*e84622caSToomas Soome #include <sys/inttypes.h>
21*e84622caSToomas Soome #include <sys/param.h>
22*e84622caSToomas Soome #include <sys/systm.h>
23*e84622caSToomas Soome #include <sys/sysmacros.h>
24*e84622caSToomas Soome #include <sys/multiboot2.h>
25*e84622caSToomas Soome #include <sys/multiboot2_impl.h>
26*e84622caSToomas Soome 
27*e84622caSToomas Soome struct dboot_multiboot2_iterate_ctx;
28*e84622caSToomas Soome 
29*e84622caSToomas Soome typedef boolean_t (*dboot_multiboot2_iterate_cb_t)
30*e84622caSToomas Soome 	(int, multiboot_tag_t *, struct dboot_multiboot2_iterate_ctx *);
31*e84622caSToomas Soome 
32*e84622caSToomas Soome struct dboot_multiboot2_iterate_ctx {
33*e84622caSToomas Soome 	dboot_multiboot2_iterate_cb_t dboot_iter_callback;
34*e84622caSToomas Soome 	int dboot_iter_index;			/* item from set */
35*e84622caSToomas Soome 	uint32_t dboot_iter_tag;		/* tag to search */
36*e84622caSToomas Soome 	multiboot_tag_t *dboot_iter_tagp;	/* search result */
37*e84622caSToomas Soome };
38*e84622caSToomas Soome 
39*e84622caSToomas Soome /*
40*e84622caSToomas Soome  * Multiboot2 tag list elements are aligned to MULTIBOOT_TAG_ALIGN.
41*e84622caSToomas Soome  * To get the next item from the list, we first add the tag's size
42*e84622caSToomas Soome  * to the start of the current tag. Next, we round up that address to the
43*e84622caSToomas Soome  * nearest MULTIBOOT_TAG_ALIGN address.
44*e84622caSToomas Soome  */
45*e84622caSToomas Soome 
46*e84622caSToomas Soome static multiboot_tag_t *
dboot_multiboot2_first_tag(multiboot2_info_header_t * mbi)47*e84622caSToomas Soome dboot_multiboot2_first_tag(multiboot2_info_header_t *mbi)
48*e84622caSToomas Soome {
49*e84622caSToomas Soome 	return (&mbi->mbi_tags[0]);
50*e84622caSToomas Soome }
51*e84622caSToomas Soome 
52*e84622caSToomas Soome static multiboot_tag_t *
dboot_multiboot2_next_tag(multiboot_tag_t * tag)53*e84622caSToomas Soome dboot_multiboot2_next_tag(multiboot_tag_t *tag)
54*e84622caSToomas Soome {
55*e84622caSToomas Soome 	if (tag == NULL || tag->mb_type == MULTIBOOT_TAG_TYPE_END)
56*e84622caSToomas Soome 		return (NULL);
57*e84622caSToomas Soome 
58*e84622caSToomas Soome 	return ((multiboot_tag_t *)P2ROUNDUP((uintptr_t)tag +
59*e84622caSToomas Soome 	    tag->mb_size, MULTIBOOT_TAG_ALIGN));
60*e84622caSToomas Soome }
61*e84622caSToomas Soome 
62*e84622caSToomas Soome /*
63*e84622caSToomas Soome  * Walk the tag list until we hit the first instance of a given tag or
64*e84622caSToomas Soome  * the end of the list.
65*e84622caSToomas Soome  * MB2_NEXT_TAG() will return NULL on end of list.
66*e84622caSToomas Soome  */
67*e84622caSToomas Soome static void *
dboot_multiboot2_find_tag_impl(multiboot_tag_t * tagp,uint32_t tag)68*e84622caSToomas Soome dboot_multiboot2_find_tag_impl(multiboot_tag_t *tagp, uint32_t tag)
69*e84622caSToomas Soome {
70*e84622caSToomas Soome 	while (tagp != NULL && tagp->mb_type != tag) {
71*e84622caSToomas Soome 		tagp = dboot_multiboot2_next_tag(tagp);
72*e84622caSToomas Soome 	}
73*e84622caSToomas Soome 	return (tagp);
74*e84622caSToomas Soome }
75*e84622caSToomas Soome 
76*e84622caSToomas Soome /*
77*e84622caSToomas Soome  * Walk the entire list to find the first instance of the given tag.
78*e84622caSToomas Soome  */
79*e84622caSToomas Soome void *
dboot_multiboot2_find_tag(multiboot2_info_header_t * mbi,uint32_t tag)80*e84622caSToomas Soome dboot_multiboot2_find_tag(multiboot2_info_header_t *mbi, uint32_t tag)
81*e84622caSToomas Soome {
82*e84622caSToomas Soome 	multiboot_tag_t *tagp = dboot_multiboot2_first_tag(mbi);
83*e84622caSToomas Soome 
84*e84622caSToomas Soome 	return (dboot_multiboot2_find_tag_impl(tagp, tag));
85*e84622caSToomas Soome }
86*e84622caSToomas Soome 
87*e84622caSToomas Soome /*
88*e84622caSToomas Soome  * dboot_multiboot2_iterate()
89*e84622caSToomas Soome  *
90*e84622caSToomas Soome  * While most tags in tag list are unique, the modules are specified
91*e84622caSToomas Soome  * one module per tag and therefore we need an mechanism to process
92*e84622caSToomas Soome  * tags in set.
93*e84622caSToomas Soome  *
94*e84622caSToomas Soome  * Arguments:
95*e84622caSToomas Soome  *	mbi: multiboot info header
96*e84622caSToomas Soome  *	data: callback context.
97*e84622caSToomas Soome  *
98*e84622caSToomas Soome  * Return value:
99*e84622caSToomas Soome  *	Processed item count.
100*e84622caSToomas Soome  * Callback returning B_TRUE will terminate the iteration.
101*e84622caSToomas Soome  */
102*e84622caSToomas Soome static int
dboot_multiboot2_iterate(multiboot2_info_header_t * mbi,struct dboot_multiboot2_iterate_ctx * ctx)103*e84622caSToomas Soome dboot_multiboot2_iterate(multiboot2_info_header_t *mbi,
104*e84622caSToomas Soome     struct dboot_multiboot2_iterate_ctx *ctx)
105*e84622caSToomas Soome {
106*e84622caSToomas Soome 	dboot_multiboot2_iterate_cb_t callback = ctx->dboot_iter_callback;
107*e84622caSToomas Soome 	multiboot_tag_t *tagp;
108*e84622caSToomas Soome 	uint32_t tag = ctx->dboot_iter_tag;
109*e84622caSToomas Soome 	int index = 0;
110*e84622caSToomas Soome 
111*e84622caSToomas Soome 	tagp = dboot_multiboot2_find_tag(mbi, tag);
112*e84622caSToomas Soome 	while (tagp != NULL) {
113*e84622caSToomas Soome 		if (callback != NULL) {
114*e84622caSToomas Soome 			if (callback(index, tagp, ctx) == B_TRUE) {
115*e84622caSToomas Soome 				return (index + 1);
116*e84622caSToomas Soome 			}
117*e84622caSToomas Soome 		}
118*e84622caSToomas Soome 		tagp = dboot_multiboot2_next_tag(tagp);
119*e84622caSToomas Soome 		tagp = dboot_multiboot2_find_tag_impl(tagp, tag);
120*e84622caSToomas Soome 		index++;
121*e84622caSToomas Soome 	}
122*e84622caSToomas Soome 	return (index);
123*e84622caSToomas Soome }
124*e84622caSToomas Soome 
125*e84622caSToomas Soome char *
dboot_multiboot2_cmdline(multiboot2_info_header_t * mbi)126*e84622caSToomas Soome dboot_multiboot2_cmdline(multiboot2_info_header_t *mbi)
127*e84622caSToomas Soome {
128*e84622caSToomas Soome 	multiboot_tag_string_t *tag;
129*e84622caSToomas Soome 
130*e84622caSToomas Soome 	tag = dboot_multiboot2_find_tag(mbi, MULTIBOOT_TAG_TYPE_CMDLINE);
131*e84622caSToomas Soome 
132*e84622caSToomas Soome 	if (tag != NULL)
133*e84622caSToomas Soome 		return (&tag->mb_string[0]);
134*e84622caSToomas Soome 	else
135*e84622caSToomas Soome 		return (NULL);
136*e84622caSToomas Soome }
137*e84622caSToomas Soome 
138*e84622caSToomas Soome /*
139*e84622caSToomas Soome  * Simple callback to index item in set.
140*e84622caSToomas Soome  * Terminates iteration if the indexed item is found.
141*e84622caSToomas Soome  */
142*e84622caSToomas Soome static boolean_t
dboot_multiboot2_iterate_callback(int index,multiboot_tag_t * tagp,struct dboot_multiboot2_iterate_ctx * ctx)143*e84622caSToomas Soome dboot_multiboot2_iterate_callback(int index, multiboot_tag_t *tagp,
144*e84622caSToomas Soome     struct dboot_multiboot2_iterate_ctx *ctx)
145*e84622caSToomas Soome {
146*e84622caSToomas Soome 	if (index == ctx->dboot_iter_index) {
147*e84622caSToomas Soome 		ctx->dboot_iter_tagp = tagp;
148*e84622caSToomas Soome 		return (B_TRUE);
149*e84622caSToomas Soome 	}
150*e84622caSToomas Soome 	return (B_FALSE);
151*e84622caSToomas Soome }
152*e84622caSToomas Soome 
153*e84622caSToomas Soome int
dboot_multiboot2_modcount(multiboot2_info_header_t * mbi)154*e84622caSToomas Soome dboot_multiboot2_modcount(multiboot2_info_header_t *mbi)
155*e84622caSToomas Soome {
156*e84622caSToomas Soome 	struct dboot_multiboot2_iterate_ctx ctx = {
157*e84622caSToomas Soome 		.dboot_iter_callback = NULL,
158*e84622caSToomas Soome 		.dboot_iter_index = 0,
159*e84622caSToomas Soome 		.dboot_iter_tag = MULTIBOOT_TAG_TYPE_MODULE,
160*e84622caSToomas Soome 		.dboot_iter_tagp = NULL
161*e84622caSToomas Soome 	};
162*e84622caSToomas Soome 
163*e84622caSToomas Soome 	return (dboot_multiboot2_iterate(mbi, &ctx));
164*e84622caSToomas Soome }
165*e84622caSToomas Soome 
166*e84622caSToomas Soome uint32_t
dboot_multiboot2_modstart(multiboot2_info_header_t * mbi,int index)167*e84622caSToomas Soome dboot_multiboot2_modstart(multiboot2_info_header_t *mbi, int index)
168*e84622caSToomas Soome {
169*e84622caSToomas Soome 	multiboot_tag_module_t *tagp;
170*e84622caSToomas Soome 	struct dboot_multiboot2_iterate_ctx ctx = {
171*e84622caSToomas Soome 		.dboot_iter_callback = dboot_multiboot2_iterate_callback,
172*e84622caSToomas Soome 		.dboot_iter_index = index,
173*e84622caSToomas Soome 		.dboot_iter_tag = MULTIBOOT_TAG_TYPE_MODULE,
174*e84622caSToomas Soome 		.dboot_iter_tagp = NULL
175*e84622caSToomas Soome 	};
176*e84622caSToomas Soome 
177*e84622caSToomas Soome 	if (dboot_multiboot2_iterate(mbi, &ctx) != 0) {
178*e84622caSToomas Soome 		tagp = (multiboot_tag_module_t *)ctx.dboot_iter_tagp;
179*e84622caSToomas Soome 
180*e84622caSToomas Soome 		if (tagp != NULL)
181*e84622caSToomas Soome 			return (tagp->mb_mod_start);
182*e84622caSToomas Soome 	}
183*e84622caSToomas Soome 	return (0);
184*e84622caSToomas Soome }
185*e84622caSToomas Soome 
186*e84622caSToomas Soome uint32_t
dboot_multiboot2_modend(multiboot2_info_header_t * mbi,int index)187*e84622caSToomas Soome dboot_multiboot2_modend(multiboot2_info_header_t *mbi, int index)
188*e84622caSToomas Soome {
189*e84622caSToomas Soome 	multiboot_tag_module_t *tagp;
190*e84622caSToomas Soome 	struct dboot_multiboot2_iterate_ctx ctx = {
191*e84622caSToomas Soome 		.dboot_iter_callback = dboot_multiboot2_iterate_callback,
192*e84622caSToomas Soome 		.dboot_iter_index = index,
193*e84622caSToomas Soome 		.dboot_iter_tag = MULTIBOOT_TAG_TYPE_MODULE,
194*e84622caSToomas Soome 		.dboot_iter_tagp = NULL
195*e84622caSToomas Soome 	};
196*e84622caSToomas Soome 
197*e84622caSToomas Soome 	if (dboot_multiboot2_iterate(mbi, &ctx) != 0) {
198*e84622caSToomas Soome 		tagp = (multiboot_tag_module_t *)ctx.dboot_iter_tagp;
199*e84622caSToomas Soome 
200*e84622caSToomas Soome 		if (tagp != NULL)
201*e84622caSToomas Soome 			return (tagp->mb_mod_end);
202*e84622caSToomas Soome 	}
203*e84622caSToomas Soome 	return (0);
204*e84622caSToomas Soome }
205*e84622caSToomas Soome 
206*e84622caSToomas Soome char *
dboot_multiboot2_modcmdline(multiboot2_info_header_t * mbi,int index)207*e84622caSToomas Soome dboot_multiboot2_modcmdline(multiboot2_info_header_t *mbi, int index)
208*e84622caSToomas Soome {
209*e84622caSToomas Soome 	multiboot_tag_module_t *tagp;
210*e84622caSToomas Soome 	struct dboot_multiboot2_iterate_ctx ctx = {
211*e84622caSToomas Soome 		.dboot_iter_callback = dboot_multiboot2_iterate_callback,
212*e84622caSToomas Soome 		.dboot_iter_index = index,
213*e84622caSToomas Soome 		.dboot_iter_tag = MULTIBOOT_TAG_TYPE_MODULE,
214*e84622caSToomas Soome 		.dboot_iter_tagp = NULL
215*e84622caSToomas Soome 	};
216*e84622caSToomas Soome 
217*e84622caSToomas Soome 	if (dboot_multiboot2_iterate(mbi, &ctx) != 0) {
218*e84622caSToomas Soome 		tagp = (multiboot_tag_module_t *)ctx.dboot_iter_tagp;
219*e84622caSToomas Soome 
220*e84622caSToomas Soome 		if (tagp != NULL)
221*e84622caSToomas Soome 			return (&tagp->mb_cmdline[0]);
222*e84622caSToomas Soome 	}
223*e84622caSToomas Soome 	return (NULL);
224*e84622caSToomas Soome }
225*e84622caSToomas Soome 
226*e84622caSToomas Soome multiboot_tag_mmap_t *
dboot_multiboot2_get_mmap_tagp(multiboot2_info_header_t * mbi)227*e84622caSToomas Soome dboot_multiboot2_get_mmap_tagp(multiboot2_info_header_t *mbi)
228*e84622caSToomas Soome {
229*e84622caSToomas Soome 	return (dboot_multiboot2_find_tag(mbi, MULTIBOOT_TAG_TYPE_MMAP));
230*e84622caSToomas Soome }
231*e84622caSToomas Soome 
232*e84622caSToomas Soome boolean_t
dboot_multiboot2_basicmeminfo(multiboot2_info_header_t * mbi,uint32_t * lower,uint32_t * upper)233*e84622caSToomas Soome dboot_multiboot2_basicmeminfo(multiboot2_info_header_t *mbi,
234*e84622caSToomas Soome     uint32_t *lower, uint32_t *upper)
235*e84622caSToomas Soome {
236*e84622caSToomas Soome 	multiboot_tag_basic_meminfo_t *mip;
237*e84622caSToomas Soome 
238*e84622caSToomas Soome 	mip = dboot_multiboot2_find_tag(mbi, MULTIBOOT_TAG_TYPE_BASIC_MEMINFO);
239*e84622caSToomas Soome 	if (mip != NULL) {
240*e84622caSToomas Soome 		*lower = mip->mb_mem_lower;
241*e84622caSToomas Soome 		*upper = mip->mb_mem_upper;
242*e84622caSToomas Soome 		return (B_TRUE);
243*e84622caSToomas Soome 	}
244*e84622caSToomas Soome 	return (B_FALSE);
245*e84622caSToomas Soome }
246*e84622caSToomas Soome 
247*e84622caSToomas Soome /*
248*e84622caSToomas Soome  * Return the type of mmap entry referenced by index.
249*e84622caSToomas Soome  */
250*e84622caSToomas Soome uint32_t
dboot_multiboot2_mmap_get_type(multiboot2_info_header_t * mbi,multiboot_tag_mmap_t * mb2_mmap_tagp,int index)251*e84622caSToomas Soome dboot_multiboot2_mmap_get_type(multiboot2_info_header_t *mbi,
252*e84622caSToomas Soome     multiboot_tag_mmap_t *mb2_mmap_tagp, int index)
253*e84622caSToomas Soome {
254*e84622caSToomas Soome 	multiboot_mmap_entry_t *mapentp;
255*e84622caSToomas Soome 
256*e84622caSToomas Soome 	if (mb2_mmap_tagp == NULL)
257*e84622caSToomas Soome 		mb2_mmap_tagp = dboot_multiboot2_get_mmap_tagp(mbi);
258*e84622caSToomas Soome 
259*e84622caSToomas Soome 	if (mb2_mmap_tagp == NULL)
260*e84622caSToomas Soome 		return (0);
261*e84622caSToomas Soome 
262*e84622caSToomas Soome 	if (dboot_multiboot2_mmap_nentries(mbi, mb2_mmap_tagp) < index)
263*e84622caSToomas Soome 		return (0);
264*e84622caSToomas Soome 
265*e84622caSToomas Soome 	mapentp = (multiboot_mmap_entry_t *)(mb2_mmap_tagp->mb_entries +
266*e84622caSToomas Soome 	    index * mb2_mmap_tagp->mb_entry_size);
267*e84622caSToomas Soome 	return (mapentp->mmap_type);
268*e84622caSToomas Soome }
269*e84622caSToomas Soome 
270*e84622caSToomas Soome /*
271*e84622caSToomas Soome  * Return the length of mmap entry referenced by index.
272*e84622caSToomas Soome  */
273*e84622caSToomas Soome uint64_t
dboot_multiboot2_mmap_get_length(multiboot2_info_header_t * mbi,multiboot_tag_mmap_t * mb2_mmap_tagp,int index)274*e84622caSToomas Soome dboot_multiboot2_mmap_get_length(multiboot2_info_header_t *mbi,
275*e84622caSToomas Soome     multiboot_tag_mmap_t *mb2_mmap_tagp, int index)
276*e84622caSToomas Soome {
277*e84622caSToomas Soome 	multiboot_mmap_entry_t *mapentp;
278*e84622caSToomas Soome 
279*e84622caSToomas Soome 	if (mb2_mmap_tagp == NULL)
280*e84622caSToomas Soome 		mb2_mmap_tagp = dboot_multiboot2_get_mmap_tagp(mbi);
281*e84622caSToomas Soome 
282*e84622caSToomas Soome 	if (mb2_mmap_tagp == NULL)
283*e84622caSToomas Soome 		return (0);
284*e84622caSToomas Soome 
285*e84622caSToomas Soome 	if (dboot_multiboot2_mmap_nentries(mbi, mb2_mmap_tagp) < index)
286*e84622caSToomas Soome 		return (0);
287*e84622caSToomas Soome 
288*e84622caSToomas Soome 	mapentp = (multiboot_mmap_entry_t *)(mb2_mmap_tagp->mb_entries +
289*e84622caSToomas Soome 	    index * mb2_mmap_tagp->mb_entry_size);
290*e84622caSToomas Soome 	return (mapentp->mmap_len);
291*e84622caSToomas Soome }
292*e84622caSToomas Soome 
293*e84622caSToomas Soome /*
294*e84622caSToomas Soome  * Return the address from mmap entry referenced by index.
295*e84622caSToomas Soome  */
296*e84622caSToomas Soome uint64_t
dboot_multiboot2_mmap_get_base(multiboot2_info_header_t * mbi,multiboot_tag_mmap_t * mb2_mmap_tagp,int index)297*e84622caSToomas Soome dboot_multiboot2_mmap_get_base(multiboot2_info_header_t *mbi,
298*e84622caSToomas Soome     multiboot_tag_mmap_t *mb2_mmap_tagp, int index)
299*e84622caSToomas Soome {
300*e84622caSToomas Soome 	multiboot_mmap_entry_t *mapentp;
301*e84622caSToomas Soome 
302*e84622caSToomas Soome 	if (mb2_mmap_tagp == NULL)
303*e84622caSToomas Soome 		mb2_mmap_tagp = dboot_multiboot2_get_mmap_tagp(mbi);
304*e84622caSToomas Soome 
305*e84622caSToomas Soome 	if (mb2_mmap_tagp == NULL)
306*e84622caSToomas Soome 		return (0);
307*e84622caSToomas Soome 
308*e84622caSToomas Soome 	if (dboot_multiboot2_mmap_nentries(mbi, mb2_mmap_tagp) < index)
309*e84622caSToomas Soome 		return (0);
310*e84622caSToomas Soome 
311*e84622caSToomas Soome 	mapentp = (multiboot_mmap_entry_t *)(mb2_mmap_tagp->mb_entries +
312*e84622caSToomas Soome 	    index * mb2_mmap_tagp->mb_entry_size);
313*e84622caSToomas Soome 	return (mapentp->mmap_addr);
314*e84622caSToomas Soome }
315*e84622caSToomas Soome 
316*e84622caSToomas Soome /*
317*e84622caSToomas Soome  * Count and return the number of mmap entries provided by the tag.
318*e84622caSToomas Soome  */
319*e84622caSToomas Soome int
dboot_multiboot2_mmap_nentries(multiboot2_info_header_t * mbi,multiboot_tag_mmap_t * mb2_mmap_tagp)320*e84622caSToomas Soome dboot_multiboot2_mmap_nentries(multiboot2_info_header_t *mbi,
321*e84622caSToomas Soome     multiboot_tag_mmap_t *mb2_mmap_tagp)
322*e84622caSToomas Soome {
323*e84622caSToomas Soome 	if (mb2_mmap_tagp == NULL)
324*e84622caSToomas Soome 		mb2_mmap_tagp = dboot_multiboot2_get_mmap_tagp(mbi);
325*e84622caSToomas Soome 
326*e84622caSToomas Soome 	if (mb2_mmap_tagp != NULL) {
327*e84622caSToomas Soome 		return ((mb2_mmap_tagp->mb_size -
328*e84622caSToomas Soome 		    offsetof(multiboot_tag_mmap_t, mb_entries)) /
329*e84622caSToomas Soome 		    mb2_mmap_tagp->mb_entry_size);
330*e84622caSToomas Soome 	}
331*e84622caSToomas Soome 	return (0);
332*e84622caSToomas Soome }
333*e84622caSToomas Soome 
334*e84622caSToomas Soome /*
335*e84622caSToomas Soome  * Return the highest address used by info header.
336*e84622caSToomas Soome  */
337*e84622caSToomas Soome paddr_t
dboot_multiboot2_highest_addr(multiboot2_info_header_t * mbi)338*e84622caSToomas Soome dboot_multiboot2_highest_addr(multiboot2_info_header_t *mbi)
339*e84622caSToomas Soome {
340*e84622caSToomas Soome 	return ((paddr_t)(uintptr_t)mbi + mbi->mbi_total_size);
341*e84622caSToomas Soome }
342