Back to home page

LXR

 
 

    


File indexing completed on 2025-05-11 08:24:10

0001 /* SPDX-License-Identifier: BSD-2-Clause */
0002 
0003 /**
0004  * @file
0005  *
0006  * @ingroup RTEMSBSPsX8664AMD64
0007  *
0008  * @brief Routines for parsing information passed by the FreeBSD bootloader
0009  */
0010 
0011 /*
0012  * Copyright (C) 2024 Matheus Pecoraro
0013  *
0014  * Redistribution and use in source and binary forms, with or without
0015  * modification, are permitted provided that the following conditions
0016  * are met:
0017  * 1. Redistributions of source code must retain the above copyright
0018  *    notice, this list of conditions and the following disclaimer.
0019  * 2. Redistributions in binary form must reproduce the above copyright
0020  *    notice, this list of conditions and the following disclaimer in the
0021  *    documentation and/or other materials provided with the distribution.
0022  *
0023  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
0024  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
0025  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
0026  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
0027  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
0028  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
0029  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
0030  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
0031  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
0032  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
0033  * POSSIBILITY OF SUCH DAMAGE.
0034  */
0035 
0036 #include <acpi/acpi.h>
0037 #include <freebsd_loader.h>
0038 
0039 #include <stdlib.h>
0040 #include <string.h>
0041 #include <sys/param.h>
0042 
0043 #define MODINFO_NAME    0x0001    /* Name of module (string) */
0044 #define MODINFO_TYPE    0x0002    /* Type of module (string) */
0045 
0046 #define MODINFOMD_ENVP    0x0006  /* env variables (envp[]) */
0047 #define MODINFO_METADATA  0x8000  /* Module-specfic */
0048 
0049 static char* modules_metadata = NULL;
0050 
0051 /**
0052  * Retrieves the handle to the metadata of the module.
0053  *
0054  * This routine was taken from sys/kern/subr_module.c in the FreeBSD source code
0055  * and modified for readability and coding convention purposes.
0056  *
0057  * Copyright (c) 1998 Michael Smith
0058  * All rights reserved.
0059  * Copyright (c) 2020 NetApp Inc.
0060  * Copyright (c) 2020 Klara Inc.
0061  */
0062 static const char* modules_metadata_search_by_type(const char* type)
0063 {
0064   if (modules_metadata != NULL) {
0065     const char* curr_addr = modules_metadata;
0066     const char* last_name = NULL;
0067 
0068     for (;;) {
0069       int next;
0070       uint32_t* hdr = (uint32_t*) curr_addr;
0071 
0072       if (hdr[0] == 0 && hdr[1] == 0) {
0073         break;
0074       }
0075 
0076       /* Remember the start of each record */
0077       if (hdr[0] == MODINFO_NAME) {
0078         last_name = curr_addr;
0079       }
0080 
0081       /* Search for a MODINFO_TYPE field */
0082       if ((hdr[0] == MODINFO_TYPE) &&
0083           !strcmp(type, curr_addr + sizeof(uint32_t) * 2))
0084       {
0085         return last_name;
0086       }
0087 
0088       /* Skip to next field */
0089       next = sizeof(uint32_t) * 2 + hdr[1];
0090       next = roundup(next, sizeof(u_long));
0091       curr_addr += next;
0092     }
0093   }
0094 
0095   return NULL;
0096 }
0097 
0098 /**
0099  * Given a module metadata handle return the specified attribute
0100  *
0101  * This routine was taken from sys/kern/subr_module.c in the FreeBSD source code
0102  * and modified for readability and coding convention purposes.
0103  *
0104  * Copyright (c) 1998 Michael Smith
0105  * All rights reserved.
0106  * Copyright (c) 2020 NetApp Inc.
0107  * Copyright (c) 2020 Klara Inc.
0108  */
0109 static const char* module_metadata_search_info(const char* mod, int info)
0110 {
0111   const char* curr_addr;
0112   uint32_t type = 0;
0113 
0114   if (mod == NULL) {
0115     return (NULL);
0116   }
0117 
0118   curr_addr = mod;
0119   for (;;) {
0120     uint32_t *hdr;
0121     int next;
0122 
0123     hdr = (uint32_t*) curr_addr;
0124 
0125     /* End of module data? */
0126     if (hdr[0] == 0 && hdr[1] == 0) {
0127         break;
0128     }
0129 
0130     /*
0131      * We give up once we've looped back to what we were looking at
0132      * first - this should normally be a MODINFO_NAME field.
0133      */
0134     if (type == 0) {
0135         type = hdr[0];
0136     }
0137     else if (hdr[0] == type) {
0138       break;
0139     }
0140 
0141     /*
0142      * Attribute match? Return pointer to data.
0143      * Consumer may safely assume that size value precedes data.
0144      */
0145     if (hdr[0] == info)
0146       return(curr_addr + (sizeof(uint32_t) * 2));
0147 
0148     /* Skip to next field */
0149     next = sizeof(uint32_t) * 2 + hdr[1];
0150     next = roundup(next, sizeof(u_long));
0151     curr_addr += next;
0152   }
0153 
0154   return NULL;
0155 }
0156 
0157 static const char* get_static_env(const char* envp, const char* name)
0158 {
0159   size_t name_len = strlen(name);
0160 
0161   while (*envp != '\0') {
0162     if (strncmp(envp, name, name_len) == 0 && envp[name_len] == '=') {
0163       return envp + name_len + 1;
0164     }
0165 
0166     while (*envp != '\0') {
0167       envp++;
0168     }
0169     envp++;
0170   }
0171 
0172   return NULL;
0173 }
0174 
0175 void retrieve_info_from_freebsd_loader(uint32_t modules_metadata_addr)
0176 {
0177   const char* kernel_mod = NULL;
0178   const char* envp = NULL;
0179   const char* rsdp_str = NULL;
0180   long rsdp_addr = 0;
0181 
0182   modules_metadata = (char*) ((uint64_t) modules_metadata_addr);
0183 
0184   kernel_mod = modules_metadata_search_by_type("elf kernel");
0185   if (kernel_mod == NULL) {
0186     kernel_mod = modules_metadata_search_by_type("elf64 kernel");
0187   }
0188 
0189   envp = module_metadata_search_info(kernel_mod, MODINFO_METADATA | MODINFOMD_ENVP);
0190   if (envp != NULL) {
0191     envp = (char*) *((uint64_t*) envp);
0192   }
0193 
0194   rsdp_str = get_static_env(envp, "acpi.rsdp");
0195   if (rsdp_str != NULL) {
0196     char* end_ptr;
0197     rsdp_addr = strtol(rsdp_str, &end_ptr, 16);
0198     acpi_rsdp_addr = rsdp_addr;
0199   }
0200 }