8322 nl: misleading-indentation
[unleashed/tickless.git] / usr / src / uts / i86pc / dboot / dboot_multiboot2.c
blobccf81cf773ee25450960454ce13a30a18517b12b
1 /*
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
5 * 1.0 of the CDDL.
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)
56 return (NULL);
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.
67 static void *
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);
73 return (tagp);
77 * Walk the entire list to find the first instance of the given tag.
79 void *
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
92 * tags in set.
94 * Arguments:
95 * mbi: multiboot info header
96 * data: callback context.
98 * Return value:
99 * Processed item count.
100 * Callback returning B_TRUE will terminate the iteration.
102 static int
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;
109 int index = 0;
111 tagp = dboot_multiboot2_find_tag(mbi, tag);
112 while (tagp != NULL) {
113 if (callback != NULL) {
114 if (callback(index, tagp, ctx) == B_TRUE) {
115 return (index + 1);
118 tagp = dboot_multiboot2_next_tag(tagp);
119 tagp = dboot_multiboot2_find_tag_impl(tagp, tag);
120 index++;
122 return (index);
125 char *
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);
132 if (tag != NULL)
133 return (&tag->mb_string[0]);
134 else
135 return (NULL);
139 * Simple callback to index item in set.
140 * Terminates iteration if the indexed item is found.
142 static boolean_t
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;
148 return (B_TRUE);
150 return (B_FALSE);
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));
166 uint32_t
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;
180 if (tagp != NULL)
181 return (tagp->mb_mod_start);
183 return (0);
186 uint32_t
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;
200 if (tagp != NULL)
201 return (tagp->mb_mod_end);
203 return (0);
206 char *
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;
220 if (tagp != NULL)
221 return (&tagp->mb_cmdline[0]);
223 return (NULL);
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));
232 boolean_t
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);
239 if (mip != NULL) {
240 *lower = mip->mb_mem_lower;
241 *upper = mip->mb_mem_upper;
242 return (B_TRUE);
244 return (B_FALSE);
248 * Return the type of mmap entry referenced by index.
250 uint32_t
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)
260 return (0);
262 if (dboot_multiboot2_mmap_nentries(mbi, mb2_mmap_tagp) < index)
263 return (0);
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.
273 uint64_t
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)
283 return (0);
285 if (dboot_multiboot2_mmap_nentries(mbi, mb2_mmap_tagp) < index)
286 return (0);
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.
296 uint64_t
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)
306 return (0);
308 if (dboot_multiboot2_mmap_nentries(mbi, mb2_mmap_tagp) < index)
309 return (0);
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);
331 return (0);
335 * Return the highest address used by info header.
337 paddr_t
338 dboot_multiboot2_highest_addr(multiboot2_info_header_t *mbi)
340 return ((paddr_t)(uintptr_t)mbi + mbi->mbi_total_size);