Initial import from FreeBSD RELENG_4:
[games.git] / sys / boot / common / load_aout.c
1 /*-
2  * Copyright (c) 1998 Michael Smith <msmith@freebsd.org>
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/boot/common/load_aout.c,v 1.16.2.2 2000/12/28 13:12:35 ps Exp $
27  */
28
29 #include <sys/param.h>
30 #include <sys/exec.h>
31 #include <sys/imgact_aout.h>
32 #include <sys/reboot.h>
33 #include <sys/linker.h>
34 #include <string.h>
35 #include <machine/bootinfo.h>
36 #include <stand.h>
37 #include <a.out.h>
38 #define FREEBSD_AOUT
39 #include <link.h>
40
41 #include "bootstrap.h"
42
43 static int              aout_loadimage(struct loaded_module *mp, int fd, vm_offset_t loadaddr, struct exec *ehdr, int kernel);
44
45 #if 0
46 static vm_offset_t      aout_findkldident(struct loaded_module *mp, struct exec *ehdr);
47 static int              aout_fixupkldmod(struct loaded_module *mp, struct exec *ehdr);
48 #endif
49
50 const char      *aout_kerneltype = "a.out kernel";
51 const char      *aout_moduletype = "a.out module";
52
53 /*
54  * Attempt to load the file (file) as an a.out module.  It will be stored at
55  * (dest), and a pointer to a module structure describing the loaded object
56  * will be saved in (result).
57  */
58 int
59 aout_loadmodule(char *filename, vm_offset_t dest, struct loaded_module **result)
60 {
61     struct loaded_module        *mp, *kmp;
62     struct exec                 ehdr;
63     int                         fd;
64     vm_offset_t                 addr;
65     int                         err, kernel;
66     u_int                       pad;
67     char                        *s;
68
69     mp = NULL;
70     
71     /*
72      * Open the image, read and validate the a.out header 
73      */
74     if (filename == NULL)       /* can't handle nameless */
75         return(EFTYPE);
76     if ((fd = open(filename, O_RDONLY)) == -1)
77         return(errno);
78     if (read(fd, &ehdr, sizeof(ehdr)) != sizeof(ehdr)) {
79         err = EFTYPE;           /* could be EIO, but may be small file */
80         goto oerr;
81     }
82     if (N_BADMAG(ehdr)) {
83         err = EFTYPE;
84         goto oerr;
85     }
86
87     /*
88      * Check to see what sort of module we are.
89      *
90      * XXX should check N_GETMID()
91      */
92     kmp = mod_findmodule(NULL, NULL);
93     if ((N_GETFLAG(ehdr)) & EX_DYNAMIC) {
94         /* Looks like a kld module */
95         if (kmp == NULL) {
96             printf("aout_loadmodule: can't load module before kernel\n");
97             err = EPERM;
98             goto oerr;
99         }
100         if (strcmp(aout_kerneltype, kmp->m_type)) {
101             printf("aout_loadmodule: can't load module with kernel type '%s'\n", kmp->m_type);
102             err = EPERM;
103             goto oerr;
104         }
105         /* Looks OK, got ahead */
106         kernel = 0;
107
108     } else if (N_GETFLAG(ehdr) == 0) {
109         /* Looks like a kernel */
110         if (kmp != NULL) {
111             printf("aout_loadmodule: kernel already loaded\n");
112             err = EPERM;
113             goto oerr;
114         }
115         /* 
116          * Calculate destination address based on kernel entrypoint     
117          * XXX this is i386-freebsd-aout specific
118          */
119         dest = ehdr.a_entry & 0x100000;
120         if (dest == 0) {
121             printf("aout_loadmodule: not a kernel (maybe static binary?)\n");
122             err = EPERM;
123             goto oerr;
124         }
125         kernel = 1;
126     } else {
127         err = EFTYPE;
128         goto oerr;
129     }
130
131     /* 
132      * Ok, we think we should handle this.
133      */
134     mp = mod_allocmodule();
135     if (kernel)
136         setenv("kernelname", filename, 1);
137     s = strrchr(filename, '/');
138     if (s)
139         mp->m_name = strdup(s + 1); 
140     else
141         mp->m_name = strdup(filename);
142     mp->m_type = strdup(kernel ? aout_kerneltype : aout_moduletype);
143
144     /* Page-align the load address */
145     addr = dest;
146     pad = (u_int)addr & PAGE_MASK;
147     if (pad != 0) {
148         pad = PAGE_SIZE - pad;
149         addr += pad;
150     }
151     mp->m_addr = addr;                                  /* save the aligned load address */
152     if (kernel)
153         printf("%s at %p\n", filename, (void *) addr);
154
155     mp->m_size = aout_loadimage(mp, fd, addr, &ehdr, kernel);
156     if (mp->m_size == 0)
157         goto ioerr;
158
159 #if 0
160     /* Handle KLD module data */
161     if (!kernel && ((err = aout_fixupkldmod(mp, &ehdr)) != 0))
162         goto oerr;
163 #endif
164
165     /* save exec header as metadata */
166     mod_addmetadata(mp, MODINFOMD_AOUTEXEC, sizeof(struct exec), &ehdr);
167
168     /* Load OK, return module pointer */
169     *result = (struct loaded_module *)mp;
170     err = 0;
171     goto out;
172     
173  ioerr:
174     err = EIO;
175  oerr:
176     mod_discard(mp);
177  out:
178     close(fd);
179     return(err);
180 }
181
182 /*
183  * With the file (fd) open on the image, and (ehdr) containing
184  * the exec header, load the image at (addr)
185  *
186  * Fixup the a_bss field in (ehdr) to reflect the padding added to
187  * align the symbol table.
188  */
189 static int
190 aout_loadimage(struct loaded_module *mp, int fd, vm_offset_t loadaddr, struct exec *ehdr, int kernel)
191 {
192     u_int               pad;
193     vm_offset_t         addr;
194     size_t              ss;
195     ssize_t             result;
196     vm_offset_t         ssym, esym;
197     
198     addr = loadaddr;
199     lseek(fd, (off_t)N_TXTOFF(*ehdr), SEEK_SET);
200
201     /* text segment */
202     printf("  text=0x%lx ", ehdr->a_text);
203     result = archsw.arch_readin(fd, addr, ehdr->a_text);
204     if (result < 0 || (size_t)result != ehdr->a_text)
205         return(0);
206     addr += ehdr->a_text;
207
208     /* data segment */
209     printf("data=0x%lx ", ehdr->a_data);
210     result = archsw.arch_readin(fd, addr, ehdr->a_data);
211     if (result < 0 || (size_t)result != ehdr->a_data)
212         return(0);
213     addr += ehdr->a_data;
214
215     /* For kernels, we pad the BSS to a page boundary */
216     if (kernel) {
217         pad = (u_int)ehdr->a_bss & PAGE_MASK;
218         if (pad != 0) {
219             pad = PAGE_SIZE - pad;
220             ehdr->a_bss += pad;
221         }
222     }
223     printf("bss=0x%lx ", ehdr->a_bss);
224     addr += ehdr->a_bss;
225
226     /* symbol table size */
227     ssym = esym = addr;
228     if(ehdr->a_syms!=NULL) {
229         archsw.arch_copyin(&ehdr->a_syms, addr, sizeof(ehdr->a_syms));
230         addr += sizeof(ehdr->a_syms);
231
232         /* symbol table */
233         printf("symbols=[0x%lx+0x%lx", (long)sizeof(ehdr->a_syms),ehdr->a_syms);
234         result = archsw.arch_readin(fd, addr, ehdr->a_syms);
235         if (result < 0 || (size_t)result != ehdr->a_syms)
236                 return(0);
237         addr += ehdr->a_syms;
238
239         /* string table */
240         read(fd, &ss, sizeof(ss));
241         archsw.arch_copyin(&ss, addr, sizeof(ss));
242         addr += sizeof(ss);
243         ss -= sizeof(ss);
244         printf("+0x%lx+0x%x]", (long)sizeof(ss), ss);
245         result = archsw.arch_readin(fd, addr, ss);
246         if (result < 0 || (size_t)result != ss)
247                 return(0);
248         addr += ss;
249         esym = addr;
250
251         mod_addmetadata(mp, MODINFOMD_SSYM, sizeof(ssym), &ssym);
252         mod_addmetadata(mp, MODINFOMD_ESYM, sizeof(esym), &esym);
253     } else {
254         printf("symbols=[none]");
255     }
256     printf("\n");
257
258     return(addr - loadaddr);
259 }
260
261