2 * This file and its contents are supplied under the terms of the
3 * Common Development and Distribution License ("CDDL"), version 1.0.
4 * You may only use this file in accordance with the terms of version
7 * A full copy of the text of the CDDL should have accompanied this
8 * source. A copy of the CDDL is also available via the Internet at
9 * http://www.illumos.org/license/CDDL.
13 * Copyright 2016 Toomas Soome <tsoome@me.com>
17 * dboot module utility functions for multiboot 2 tags processing.
20 #include <sys/inttypes.h>
21 #include <sys/param.h>
22 #include <sys/systm.h>
23 #include <sys/sysmacros.h>
24 #include <sys/multiboot2.h>
25 #include <sys/multiboot2_impl.h>
27 struct dboot_multiboot2_iterate_ctx
;
29 typedef boolean_t (*dboot_multiboot2_iterate_cb_t
)
30 (int, multiboot_tag_t
*, struct dboot_multiboot2_iterate_ctx
*);
32 struct dboot_multiboot2_iterate_ctx
{
33 dboot_multiboot2_iterate_cb_t dboot_iter_callback
;
34 int dboot_iter_index
; /* item from set */
35 uint32_t dboot_iter_tag
; /* tag to search */
36 multiboot_tag_t
*dboot_iter_tagp
; /* search result */
40 * Multiboot2 tag list elements are aligned to MULTIBOOT_TAG_ALIGN.
41 * To get the next item from the list, we first add the tag's size
42 * to the start of the current tag. Next, we round up that address to the
43 * nearest MULTIBOOT_TAG_ALIGN address.
46 static multiboot_tag_t
*
47 dboot_multiboot2_first_tag(multiboot2_info_header_t
*mbi
)
49 return (&mbi
->mbi_tags
[0]);
52 static multiboot_tag_t
*
53 dboot_multiboot2_next_tag(multiboot_tag_t
*tag
)
55 if (tag
== NULL
|| tag
->mb_type
== MULTIBOOT_TAG_TYPE_END
)
58 return ((multiboot_tag_t
*)P2ROUNDUP((uintptr_t)tag
+
59 tag
->mb_size
, MULTIBOOT_TAG_ALIGN
));
63 * Walk the tag list until we hit the first instance of a given tag or
64 * the end of the list.
65 * MB2_NEXT_TAG() will return NULL on end of list.
68 dboot_multiboot2_find_tag_impl(multiboot_tag_t
*tagp
, uint32_t tag
)
70 while (tagp
!= NULL
&& tagp
->mb_type
!= tag
) {
71 tagp
= dboot_multiboot2_next_tag(tagp
);
77 * Walk the entire list to find the first instance of the given tag.
80 dboot_multiboot2_find_tag(multiboot2_info_header_t
*mbi
, uint32_t tag
)
82 multiboot_tag_t
*tagp
= dboot_multiboot2_first_tag(mbi
);
84 return (dboot_multiboot2_find_tag_impl(tagp
, tag
));
88 * dboot_multiboot2_iterate()
90 * While most tags in tag list are unique, the modules are specified
91 * one module per tag and therefore we need an mechanism to process
95 * mbi: multiboot info header
96 * data: callback context.
99 * Processed item count.
100 * Callback returning B_TRUE will terminate the iteration.
103 dboot_multiboot2_iterate(multiboot2_info_header_t
*mbi
,
104 struct dboot_multiboot2_iterate_ctx
*ctx
)
106 dboot_multiboot2_iterate_cb_t callback
= ctx
->dboot_iter_callback
;
107 multiboot_tag_t
*tagp
;
108 uint32_t tag
= ctx
->dboot_iter_tag
;
111 tagp
= dboot_multiboot2_find_tag(mbi
, tag
);
112 while (tagp
!= NULL
) {
113 if (callback
!= NULL
) {
114 if (callback(index
, tagp
, ctx
) == B_TRUE
) {
118 tagp
= dboot_multiboot2_next_tag(tagp
);
119 tagp
= dboot_multiboot2_find_tag_impl(tagp
, tag
);
126 dboot_multiboot2_cmdline(multiboot2_info_header_t
*mbi
)
128 multiboot_tag_string_t
*tag
;
130 tag
= dboot_multiboot2_find_tag(mbi
, MULTIBOOT_TAG_TYPE_CMDLINE
);
133 return (&tag
->mb_string
[0]);
139 * Simple callback to index item in set.
140 * Terminates iteration if the indexed item is found.
143 dboot_multiboot2_iterate_callback(int index
, multiboot_tag_t
*tagp
,
144 struct dboot_multiboot2_iterate_ctx
*ctx
)
146 if (index
== ctx
->dboot_iter_index
) {
147 ctx
->dboot_iter_tagp
= tagp
;
154 dboot_multiboot2_modcount(multiboot2_info_header_t
*mbi
)
156 struct dboot_multiboot2_iterate_ctx ctx
= {
157 .dboot_iter_callback
= NULL
,
158 .dboot_iter_index
= 0,
159 .dboot_iter_tag
= MULTIBOOT_TAG_TYPE_MODULE
,
160 .dboot_iter_tagp
= NULL
163 return (dboot_multiboot2_iterate(mbi
, &ctx
));
167 dboot_multiboot2_modstart(multiboot2_info_header_t
*mbi
, int index
)
169 multiboot_tag_module_t
*tagp
;
170 struct dboot_multiboot2_iterate_ctx ctx
= {
171 .dboot_iter_callback
= dboot_multiboot2_iterate_callback
,
172 .dboot_iter_index
= index
,
173 .dboot_iter_tag
= MULTIBOOT_TAG_TYPE_MODULE
,
174 .dboot_iter_tagp
= NULL
177 if (dboot_multiboot2_iterate(mbi
, &ctx
) != 0) {
178 tagp
= (multiboot_tag_module_t
*)ctx
.dboot_iter_tagp
;
181 return (tagp
->mb_mod_start
);
187 dboot_multiboot2_modend(multiboot2_info_header_t
*mbi
, int index
)
189 multiboot_tag_module_t
*tagp
;
190 struct dboot_multiboot2_iterate_ctx ctx
= {
191 .dboot_iter_callback
= dboot_multiboot2_iterate_callback
,
192 .dboot_iter_index
= index
,
193 .dboot_iter_tag
= MULTIBOOT_TAG_TYPE_MODULE
,
194 .dboot_iter_tagp
= NULL
197 if (dboot_multiboot2_iterate(mbi
, &ctx
) != 0) {
198 tagp
= (multiboot_tag_module_t
*)ctx
.dboot_iter_tagp
;
201 return (tagp
->mb_mod_end
);
207 dboot_multiboot2_modcmdline(multiboot2_info_header_t
*mbi
, int index
)
209 multiboot_tag_module_t
*tagp
;
210 struct dboot_multiboot2_iterate_ctx ctx
= {
211 .dboot_iter_callback
= dboot_multiboot2_iterate_callback
,
212 .dboot_iter_index
= index
,
213 .dboot_iter_tag
= MULTIBOOT_TAG_TYPE_MODULE
,
214 .dboot_iter_tagp
= NULL
217 if (dboot_multiboot2_iterate(mbi
, &ctx
) != 0) {
218 tagp
= (multiboot_tag_module_t
*)ctx
.dboot_iter_tagp
;
221 return (&tagp
->mb_cmdline
[0]);
226 multiboot_tag_mmap_t
*
227 dboot_multiboot2_get_mmap_tagp(multiboot2_info_header_t
*mbi
)
229 return (dboot_multiboot2_find_tag(mbi
, MULTIBOOT_TAG_TYPE_MMAP
));
233 dboot_multiboot2_basicmeminfo(multiboot2_info_header_t
*mbi
,
234 uint32_t *lower
, uint32_t *upper
)
236 multiboot_tag_basic_meminfo_t
*mip
;
238 mip
= dboot_multiboot2_find_tag(mbi
, MULTIBOOT_TAG_TYPE_BASIC_MEMINFO
);
240 *lower
= mip
->mb_mem_lower
;
241 *upper
= mip
->mb_mem_upper
;
248 * Return the type of mmap entry referenced by index.
251 dboot_multiboot2_mmap_get_type(multiboot2_info_header_t
*mbi
,
252 multiboot_tag_mmap_t
*mb2_mmap_tagp
, int index
)
254 multiboot_mmap_entry_t
*mapentp
;
256 if (mb2_mmap_tagp
== NULL
)
257 mb2_mmap_tagp
= dboot_multiboot2_get_mmap_tagp(mbi
);
259 if (mb2_mmap_tagp
== NULL
)
262 if (dboot_multiboot2_mmap_nentries(mbi
, mb2_mmap_tagp
) < index
)
265 mapentp
= (multiboot_mmap_entry_t
*)(mb2_mmap_tagp
->mb_entries
+
266 index
* mb2_mmap_tagp
->mb_entry_size
);
267 return (mapentp
->mmap_type
);
271 * Return the length of mmap entry referenced by index.
274 dboot_multiboot2_mmap_get_length(multiboot2_info_header_t
*mbi
,
275 multiboot_tag_mmap_t
*mb2_mmap_tagp
, int index
)
277 multiboot_mmap_entry_t
*mapentp
;
279 if (mb2_mmap_tagp
== NULL
)
280 mb2_mmap_tagp
= dboot_multiboot2_get_mmap_tagp(mbi
);
282 if (mb2_mmap_tagp
== NULL
)
285 if (dboot_multiboot2_mmap_nentries(mbi
, mb2_mmap_tagp
) < index
)
288 mapentp
= (multiboot_mmap_entry_t
*)(mb2_mmap_tagp
->mb_entries
+
289 index
* mb2_mmap_tagp
->mb_entry_size
);
290 return (mapentp
->mmap_len
);
294 * Return the address from mmap entry referenced by index.
297 dboot_multiboot2_mmap_get_base(multiboot2_info_header_t
*mbi
,
298 multiboot_tag_mmap_t
*mb2_mmap_tagp
, int index
)
300 multiboot_mmap_entry_t
*mapentp
;
302 if (mb2_mmap_tagp
== NULL
)
303 mb2_mmap_tagp
= dboot_multiboot2_get_mmap_tagp(mbi
);
305 if (mb2_mmap_tagp
== NULL
)
308 if (dboot_multiboot2_mmap_nentries(mbi
, mb2_mmap_tagp
) < index
)
311 mapentp
= (multiboot_mmap_entry_t
*)(mb2_mmap_tagp
->mb_entries
+
312 index
* mb2_mmap_tagp
->mb_entry_size
);
313 return (mapentp
->mmap_addr
);
317 * Count and return the number of mmap entries provided by the tag.
320 dboot_multiboot2_mmap_nentries(multiboot2_info_header_t
*mbi
,
321 multiboot_tag_mmap_t
*mb2_mmap_tagp
)
323 if (mb2_mmap_tagp
== NULL
)
324 mb2_mmap_tagp
= dboot_multiboot2_get_mmap_tagp(mbi
);
326 if (mb2_mmap_tagp
!= NULL
) {
327 return ((mb2_mmap_tagp
->mb_size
-
328 offsetof(multiboot_tag_mmap_t
, mb_entries
)) /
329 mb2_mmap_tagp
->mb_entry_size
);
335 * Return the highest address used by info header.
338 dboot_multiboot2_highest_addr(multiboot2_info_header_t
*mbi
)
340 return ((paddr_t
)(uintptr_t)mbi
+ mbi
->mbi_total_size
);