]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/kern/subr_module.c
libfdt: Update to 1.4.6, switch to using libfdt for overlay support
[FreeBSD/FreeBSD.git] / sys / kern / subr_module.c
1 /*-
2  * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
3  *
4  * Copyright (c) 1998 Michael Smith
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  *
16  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26  * SUCH DAMAGE.
27  */
28
29 #include <sys/cdefs.h>
30 __FBSDID("$FreeBSD$");
31
32 #include <sys/param.h>
33 #include <sys/systm.h>
34 #include <sys/linker.h>
35
36 /*
37  * Preloaded module support
38  */
39
40 vm_offset_t preload_addr_relocate = 0;
41 caddr_t preload_metadata;
42
43 /*
44  * Search for the preloaded module (name)
45  */
46 caddr_t
47 preload_search_by_name(const char *name)
48 {
49     caddr_t     curp;
50     uint32_t    *hdr;
51     int         next;
52     
53     if (preload_metadata != NULL) {
54         
55         curp = preload_metadata;
56         for (;;) {
57             hdr = (uint32_t *)curp;
58             if (hdr[0] == 0 && hdr[1] == 0)
59                 break;
60
61             /* Search for a MODINFO_NAME field */
62             if ((hdr[0] == MODINFO_NAME) &&
63                 !strcmp(name, curp + sizeof(uint32_t) * 2))
64                 return(curp);
65
66             /* skip to next field */
67             next = sizeof(uint32_t) * 2 + hdr[1];
68             next = roundup(next, sizeof(u_long));
69             curp += next;
70         }
71     }
72     return(NULL);
73 }
74
75 /*
76  * Search for the first preloaded module of (type)
77  */
78 caddr_t
79 preload_search_by_type(const char *type)
80 {
81     caddr_t     curp, lname;
82     uint32_t    *hdr;
83     int         next;
84
85     if (preload_metadata != NULL) {
86
87         curp = preload_metadata;
88         lname = NULL;
89         for (;;) {
90             hdr = (uint32_t *)curp;
91             if (hdr[0] == 0 && hdr[1] == 0)
92                 break;
93
94             /* remember the start of each record */
95             if (hdr[0] == MODINFO_NAME)
96                 lname = curp;
97
98             /* Search for a MODINFO_TYPE field */
99             if ((hdr[0] == MODINFO_TYPE) &&
100                 !strcmp(type, curp + sizeof(uint32_t) * 2))
101                 return(lname);
102
103             /* skip to next field */
104             next = sizeof(uint32_t) * 2 + hdr[1];
105             next = roundup(next, sizeof(u_long));
106             curp += next;
107         }
108     }
109     return(NULL);
110 }
111
112 /*
113  * Walk through the preloaded module list
114  */
115 caddr_t
116 preload_search_next_name(caddr_t base)
117 {
118     caddr_t     curp;
119     uint32_t    *hdr;
120     int         next;
121     
122     if (preload_metadata != NULL) {
123         
124         /* Pick up where we left off last time */
125         if (base) {
126             /* skip to next field */
127             curp = base;
128             hdr = (uint32_t *)curp;
129             next = sizeof(uint32_t) * 2 + hdr[1];
130             next = roundup(next, sizeof(u_long));
131             curp += next;
132         } else
133             curp = preload_metadata;
134
135         for (;;) {
136             hdr = (uint32_t *)curp;
137             if (hdr[0] == 0 && hdr[1] == 0)
138                 break;
139
140             /* Found a new record? */
141             if (hdr[0] == MODINFO_NAME)
142                 return curp;
143
144             /* skip to next field */
145             next = sizeof(uint32_t) * 2 + hdr[1];
146             next = roundup(next, sizeof(u_long));
147             curp += next;
148         }
149     }
150     return(NULL);
151 }
152
153 /*
154  * Given a preloaded module handle (mod), return a pointer
155  * to the data for the attribute (inf).
156  */
157 caddr_t
158 preload_search_info(caddr_t mod, int inf)
159 {
160     caddr_t     curp;
161     uint32_t    *hdr;
162     uint32_t    type = 0;
163     int         next;
164
165     if (mod == NULL)
166         return (NULL);
167
168     curp = mod;
169     for (;;) {
170         hdr = (uint32_t *)curp;
171         /* end of module data? */
172         if (hdr[0] == 0 && hdr[1] == 0)
173             break;
174         /* 
175          * We give up once we've looped back to what we were looking at 
176          * first - this should normally be a MODINFO_NAME field.
177          */
178         if (type == 0) {
179             type = hdr[0];
180         } else {
181             if (hdr[0] == type)
182                 break;
183         }
184         
185         /* 
186          * Attribute match? Return pointer to data.
187          * Consumer may safely assume that size value precedes  
188          * data.
189          */
190         if (hdr[0] == inf)
191             return(curp + (sizeof(uint32_t) * 2));
192
193         /* skip to next field */
194         next = sizeof(uint32_t) * 2 + hdr[1];
195         next = roundup(next, sizeof(u_long));
196         curp += next;
197     }
198     return(NULL);
199 }
200
201 /*
202  * Delete a preload record by name.
203  */
204 void
205 preload_delete_name(const char *name)
206 {
207     caddr_t     curp;
208     uint32_t    *hdr;
209     int         next;
210     int         clearing;
211     
212     if (preload_metadata != NULL) {
213         
214         clearing = 0;
215         curp = preload_metadata;
216         for (;;) {
217             hdr = (uint32_t *)curp;
218             if (hdr[0] == 0 && hdr[1] == 0)
219                 break;
220
221             /* Search for a MODINFO_NAME field */
222             if (hdr[0] == MODINFO_NAME) {
223                 if (!strcmp(name, curp + sizeof(uint32_t) * 2))
224                     clearing = 1;       /* got it, start clearing */
225                 else if (clearing)
226                     clearing = 0;       /* at next one now.. better stop */
227             }
228             if (clearing)
229                 hdr[0] = MODINFO_EMPTY;
230
231             /* skip to next field */
232             next = sizeof(uint32_t) * 2 + hdr[1];
233             next = roundup(next, sizeof(u_long));
234             curp += next;
235         }
236     }
237 }
238
239 void *
240 preload_fetch_addr(caddr_t mod)
241 {
242         caddr_t *mdp;
243
244         mdp = (caddr_t *)preload_search_info(mod, MODINFO_ADDR);
245         if (mdp == NULL)
246                 return (NULL);
247         return (*mdp + preload_addr_relocate);
248 }
249
250 size_t
251 preload_fetch_size(caddr_t mod)
252 {
253         size_t *mdp;
254
255         mdp = (size_t *)preload_search_info(mod, MODINFO_SIZE);
256         if (mdp == NULL)
257                 return (0);
258         return (*mdp);
259 }
260
261 /* Called from locore.  Convert physical pointers to kvm. Sigh. */
262 void
263 preload_bootstrap_relocate(vm_offset_t offset)
264 {
265     caddr_t     curp;
266     uint32_t    *hdr;
267     vm_offset_t *ptr;
268     int         next;
269     
270     if (preload_metadata != NULL) {
271         
272         curp = preload_metadata;
273         for (;;) {
274             hdr = (uint32_t *)curp;
275             if (hdr[0] == 0 && hdr[1] == 0)
276                 break;
277
278             /* Deal with the ones that we know we have to fix */
279             switch (hdr[0]) {
280             case MODINFO_ADDR:
281             case MODINFO_METADATA|MODINFOMD_SSYM:
282             case MODINFO_METADATA|MODINFOMD_ESYM:
283                 ptr = (vm_offset_t *)(curp + (sizeof(uint32_t) * 2));
284                 *ptr += offset;
285                 break;
286             }
287             /* The rest is beyond us for now */
288
289             /* skip to next field */
290             next = sizeof(uint32_t) * 2 + hdr[1];
291             next = roundup(next, sizeof(u_long));
292             curp += next;
293         }
294     }
295 }