Initial import from FreeBSD RELENG_4:
[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  */
28
29 #include <sys/param.h>
30 #include <sys/systm.h>
31 #include <sys/linker.h>
32
33 /*
34  * Preloaded module support
35  */
36
37 caddr_t preload_metadata;
38
39 /*
40  * Search for the preloaded module (name)
41  */
42 caddr_t
43 preload_search_by_name(const char *name)
44 {
45     caddr_t     curp;
46     u_int32_t   *hdr;
47     int         next;
48     
49     if (preload_metadata != NULL) {
50         
51         curp = preload_metadata;
52         for (;;) {
53             hdr = (u_int32_t *)curp;
54             if (hdr[0] == 0 && hdr[1] == 0)
55                 break;
56
57             /* Search for a MODINFO_NAME field */
58             if ((hdr[0] == MODINFO_NAME) &&
59                 !strcmp(name, curp + sizeof(u_int32_t) * 2))
60                 return(curp);
61
62             /* skip to next field */
63             next = sizeof(u_int32_t) * 2 + hdr[1];
64             next = roundup(next, sizeof(u_long));
65             curp += next;
66         }
67     }
68     return(NULL);
69 }
70
71 /*
72  * Search for the first preloaded module of (type)
73  */
74 caddr_t
75 preload_search_by_type(const char *type)
76 {
77     caddr_t     curp, lname;
78     u_int32_t   *hdr;
79     int         next;
80
81     if (preload_metadata != NULL) {
82
83         curp = preload_metadata;
84         lname = NULL;
85         for (;;) {
86             hdr = (u_int32_t *)curp;
87             if (hdr[0] == 0 && hdr[1] == 0)
88                 break;
89
90             /* remember the start of each record */
91             if (hdr[0] == MODINFO_NAME)
92                 lname = curp;
93
94             /* Search for a MODINFO_TYPE field */
95             if ((hdr[0] == MODINFO_TYPE) &&
96                 !strcmp(type, curp + sizeof(u_int32_t) * 2))
97                 return(lname);
98
99             /* skip to next field */
100             next = sizeof(u_int32_t) * 2 + hdr[1];
101             next = roundup(next, sizeof(u_long));
102             curp += next;
103         }
104     }
105     return(NULL);
106 }
107
108 /*
109  * Walk through the preloaded module list
110  */
111 caddr_t
112 preload_search_next_name(caddr_t base)
113 {
114     caddr_t     curp;
115     u_int32_t   *hdr;
116     int         next;
117     
118     if (preload_metadata != NULL) {
119         
120         /* Pick up where we left off last time */
121         if (base) {
122             /* skip to next field */
123             curp = base;
124             hdr = (u_int32_t *)curp;
125             next = sizeof(u_int32_t) * 2 + hdr[1];
126             next = roundup(next, sizeof(u_long));
127             curp += next;
128         } else
129             curp = preload_metadata;
130
131         for (;;) {
132             hdr = (u_int32_t *)curp;
133             if (hdr[0] == 0 && hdr[1] == 0)
134                 break;
135
136             /* Found a new record? */
137             if (hdr[0] == MODINFO_NAME)
138                 return curp;
139
140             /* skip to next field */
141             next = sizeof(u_int32_t) * 2 + hdr[1];
142             next = roundup(next, sizeof(u_long));
143             curp += next;
144         }
145     }
146     return(NULL);
147 }
148
149 /*
150  * Given a preloaded module handle (mod), return a pointer
151  * to the data for the attribute (inf).
152  */
153 caddr_t
154 preload_search_info(caddr_t mod, int inf)
155 {
156     caddr_t     curp;
157     u_int32_t   *hdr;
158     u_int32_t   type = 0;
159     int         next;
160
161     curp = mod;
162     for (;;) {
163         hdr = (u_int32_t *)curp;
164         /* end of module data? */
165         if (hdr[0] == 0 && hdr[1] == 0)
166             break;
167         /* 
168          * We give up once we've looped back to what we were looking at 
169          * first - this should normally be a MODINFO_NAME field.
170          */
171         if (type == 0) {
172             type = hdr[0];
173         } else {
174             if (hdr[0] == type)
175                 break;
176         }
177         
178         /* 
179          * Attribute match? Return pointer to data.
180          * Consumer may safely assume that size value preceeds  
181          * data.
182          */
183         if (hdr[0] == inf)
184             return(curp + (sizeof(u_int32_t) * 2));
185
186         /* skip to next field */
187         next = sizeof(u_int32_t) * 2 + hdr[1];
188         next = roundup(next, sizeof(u_long));
189         curp += next;
190     }
191     return(NULL);
192 }
193
194 /*
195  * Delete a preload record by name.
196  */
197 void
198 preload_delete_name(const char *name)
199 {
200     caddr_t     curp;
201     u_int32_t   *hdr;
202     int         next;
203     int         clearing;
204     
205     if (preload_metadata != NULL) {
206         
207         clearing = 0;
208         curp = preload_metadata;
209         for (;;) {
210             hdr = (u_int32_t *)curp;
211             if (hdr[0] == 0 && hdr[1] == 0)
212                 break;
213
214             /* Search for a MODINFO_NAME field */
215             if (hdr[0] == MODINFO_NAME) {
216                 if (!strcmp(name, curp + sizeof(u_int32_t) * 2))
217                     clearing = 1;       /* got it, start clearing */
218                 else if (clearing)
219                     clearing = 0;       /* at next one now.. better stop */
220             }
221             if (clearing)
222                 hdr[0] = MODINFO_EMPTY;
223
224             /* skip to next field */
225             next = sizeof(u_int32_t) * 2 + hdr[1];
226             next = roundup(next, sizeof(u_long));
227             curp += next;
228         }
229     }
230 }
231
232 /* Called from locore on i386.  Convert physical pointers to kvm. Sigh. */
233 void
234 preload_bootstrap_relocate(vm_offset_t offset)
235 {
236     caddr_t     curp;
237     u_int32_t   *hdr;
238     vm_offset_t *ptr;
239     int         next;
240     
241     if (preload_metadata != NULL) {
242         
243         curp = preload_metadata;
244         for (;;) {
245             hdr = (u_int32_t *)curp;
246             if (hdr[0] == 0 && hdr[1] == 0)
247                 break;
248
249             /* Deal with the ones that we know we have to fix */
250             switch (hdr[0]) {
251             case MODINFO_ADDR:
252             case MODINFO_METADATA|MODINFOMD_SSYM:
253             case MODINFO_METADATA|MODINFOMD_ESYM:
254                 ptr = (vm_offset_t *)(curp + (sizeof(u_int32_t) * 2));
255                 *ptr += offset;
256                 break;
257             }
258             /* The rest is beyond us for now */
259
260             /* skip to next field */
261             next = sizeof(u_int32_t) * 2 + hdr[1];
262             next = roundup(next, sizeof(u_long));
263             curp += next;
264         }
265     }
266 }