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