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