More cleanups to make ports work better.
[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.3 2003/11/20 22:07:33 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 void
210 preload_delete_name(const char *name)
211 {
212     caddr_t     curp;
213     u_int32_t   *hdr;
214     int         next;
215     int         clearing;
216     
217     if (preload_metadata != NULL) {
218         
219         clearing = 0;
220         curp = preload_metadata;
221         for (;;) {
222             hdr = (u_int32_t *)curp;
223             if (hdr[0] == 0 && hdr[1] == 0)
224                 break;
225
226             /* Search for a MODINFO_NAME field */
227             if (hdr[0] == MODINFO_NAME) {
228                 if (!strcmp(name, curp + sizeof(u_int32_t) * 2))
229                     clearing = 1;       /* got it, start clearing */
230                 else if (clearing)
231                     clearing = 0;       /* at next one now.. better stop */
232             }
233             if (clearing)
234                 hdr[0] = MODINFO_EMPTY;
235
236             /* skip to next field */
237             next = sizeof(u_int32_t) * 2 + hdr[1];
238             next = roundup(next, sizeof(u_long));
239             curp += next;
240         }
241     }
242 }
243
244 /* Called from locore on i386.  Convert physical pointers to kvm. Sigh. */
245 void
246 preload_bootstrap_relocate(vm_offset_t offset)
247 {
248     caddr_t     curp;
249     u_int32_t   *hdr;
250     vm_offset_t *ptr;
251     int         next;
252     
253     if (preload_metadata != NULL) {
254         
255         curp = preload_metadata;
256         for (;;) {
257             hdr = (u_int32_t *)curp;
258             if (hdr[0] == 0 && hdr[1] == 0)
259                 break;
260
261             /* Deal with the ones that we know we have to fix */
262             switch (hdr[0]) {
263             case MODINFO_ADDR:
264             case MODINFO_METADATA|MODINFOMD_SSYM:
265             case MODINFO_METADATA|MODINFOMD_ESYM:
266                 ptr = (vm_offset_t *)(curp + (sizeof(u_int32_t) * 2));
267                 *ptr += offset;
268                 break;
269             }
270             /* The rest is beyond us for now */
271
272             /* skip to next field */
273             next = sizeof(u_int32_t) * 2 + hdr[1];
274             next = roundup(next, sizeof(u_long));
275             curp += next;
276         }
277     }
278 }