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