344b008c65de0fdcf813b6666744376f270aebdb
[dragonfly.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  * $FreeBSD: src/sys/kern/subr_module.c,v 1.6 1999/10/11 15:19:10 peter Exp $
27  * $DragonFly: src/sys/kern/subr_module.c,v 1.4 2004/05/26 08:32:41 dillon Exp $
28  */
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 caddr_t preload_metadata;
39
40 /*
41  * Search for the preloaded module (name)
42  */
43 caddr_t
44 preload_search_by_name(const char *name)
45 {
46     caddr_t     curp;
47     u_int32_t   *hdr;
48     int         next;
49     int         i;
50     char        *scanname;
51
52     if (preload_metadata == NULL)
53         return(NULL);
54
55     curp = preload_metadata;
56     for (;;) {
57         hdr = (u_int32_t *)curp;
58         if (hdr[0] == 0 && hdr[1] == 0)
59             break;
60
61         /*
62          * Search for a MODINFO_NAME field.  the boot loader really
63          * ought to strip the path names
64          */
65         if (hdr[0] == MODINFO_NAME) {
66             scanname = curp + sizeof(u_int32_t) * 2;
67             i = strlen(scanname);
68             while (i > 0 && scanname[i-1] != '/')
69                 --i;
70             if (strcmp(name, scanname) == 0)
71                 return(curp);
72             if (strcmp(name, scanname + i) == 0)
73                 return(curp);
74         }
75         /* skip to next field */
76         next = sizeof(u_int32_t) * 2 + hdr[1];
77         next = roundup(next, sizeof(u_long));
78         curp += next;
79     }
80     return(NULL);
81 }
82
83 /*
84  * Search for the first preloaded module of (type)
85  */
86 caddr_t
87 preload_search_by_type(const char *type)
88 {
89     caddr_t     curp, lname;
90     u_int32_t   *hdr;
91     int         next;
92
93     if (preload_metadata != NULL) {
94
95         curp = preload_metadata;
96         lname = NULL;
97         for (;;) {
98             hdr = (u_int32_t *)curp;
99             if (hdr[0] == 0 && hdr[1] == 0)
100                 break;
101
102             /* remember the start of each record */
103             if (hdr[0] == MODINFO_NAME)
104                 lname = curp;
105
106             /* Search for a MODINFO_TYPE field */
107             if ((hdr[0] == MODINFO_TYPE) &&
108                 !strcmp(type, curp + sizeof(u_int32_t) * 2))
109                 return(lname);
110
111             /* skip to next field */
112             next = sizeof(u_int32_t) * 2 + hdr[1];
113             next = roundup(next, sizeof(u_long));
114             curp += next;
115         }
116     }
117     return(NULL);
118 }
119
120 /*
121  * Walk through the preloaded module list
122  */
123 caddr_t
124 preload_search_next_name(caddr_t base)
125 {
126     caddr_t     curp;
127     u_int32_t   *hdr;
128     int         next;
129     
130     if (preload_metadata != NULL) {
131         
132         /* Pick up where we left off last time */
133         if (base) {
134             /* skip to next field */
135             curp = base;
136             hdr = (u_int32_t *)curp;
137             next = sizeof(u_int32_t) * 2 + hdr[1];
138             next = roundup(next, sizeof(u_long));
139             curp += next;
140         } else
141             curp = preload_metadata;
142
143         for (;;) {
144             hdr = (u_int32_t *)curp;
145             if (hdr[0] == 0 && hdr[1] == 0)
146                 break;
147
148             /* Found a new record? */
149             if (hdr[0] == MODINFO_NAME)
150                 return curp;
151
152             /* skip to next field */
153             next = sizeof(u_int32_t) * 2 + hdr[1];
154             next = roundup(next, sizeof(u_long));
155             curp += next;
156         }
157     }
158     return(NULL);
159 }
160
161 /*
162  * Given a preloaded module handle (mod), return a pointer
163  * to the data for the attribute (inf).
164  */
165 caddr_t
166 preload_search_info(caddr_t mod, int inf)
167 {
168     caddr_t     curp;
169     u_int32_t   *hdr;
170     u_int32_t   type = 0;
171     int         next;
172
173     curp = mod;
174     for (;;) {
175         hdr = (u_int32_t *)curp;
176         /* end of module data? */
177         if (hdr[0] == 0 && hdr[1] == 0)
178             break;
179         /* 
180          * We give up once we've looped back to what we were looking at 
181          * first - this should normally be a MODINFO_NAME field.
182          */
183         if (type == 0) {
184             type = hdr[0];
185         } else {
186             if (hdr[0] == type)
187                 break;
188         }
189         
190         /* 
191          * Attribute match? Return pointer to data.
192          * Consumer may safely assume that size value preceeds  
193          * data.
194          */
195         if (hdr[0] == inf)
196             return(curp + (sizeof(u_int32_t) * 2));
197
198         /* skip to next field */
199         next = sizeof(u_int32_t) * 2 + hdr[1];
200         next = roundup(next, sizeof(u_long));
201         curp += next;
202     }
203     return(NULL);
204 }
205
206 /*
207  * Delete a preload record by name.
208  *
209  * XXX we should really pass the base of the preloaded module here and not
210  * require rematching of the name.  If the wrong module (or no module) is
211  * deleted, the original preloaded module might be loaded again, causing it's
212  * data to be relocated twice.
213  */
214 void
215 preload_delete_name(const char *name)
216 {
217     caddr_t     curp;
218     u_int32_t   *hdr;
219     int         next;
220     int         clearing;
221     int         i;
222     char        *scanname;
223     
224     if (preload_metadata != NULL) {
225         clearing = 0;
226         curp = preload_metadata;
227         for (;;) {
228             hdr = (u_int32_t *)curp;
229             if (hdr[0] == 0 && hdr[1] == 0)
230                 break;
231
232             /* Search for a MODINFO_NAME field */
233             if (hdr[0] == MODINFO_NAME) {
234                 scanname = curp + sizeof(u_int32_t) * 2;
235                 i = strlen(scanname);
236                 while (i > 0 && scanname[i-1] != '/')
237                     --i;
238                 if (strcmp(name, scanname) == 0)
239                     clearing = 1;
240                 else if (strcmp(name, scanname + i) == 0)
241                     clearing = 1;
242                 else
243                     clearing = 0;       /* at next module now, stop clearing */
244             }
245             if (clearing)
246                 hdr[0] = MODINFO_EMPTY;
247
248             /* skip to next field */
249             next = sizeof(u_int32_t) * 2 + hdr[1];
250             next = roundup(next, sizeof(u_long));
251             curp += next;
252         }
253     }
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     u_int32_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 = (u_int32_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(u_int32_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(u_int32_t) * 2 + hdr[1];
286             next = roundup(next, sizeof(u_long));
287             curp += next;
288         }
289     }
290 }