Annotation of sys/arch/zaurus/stand/zbsdmod/zbsdmod.c, Revision 1.1.1.1
1.1 nbrk 1: /* $OpenBSD: zbsdmod.c,v 1.7 2005/05/02 02:45:29 uwe Exp $ */
2:
3: /*
4: * Copyright (c) 2005 Uwe Stuehler <uwe@bsdx.de>
5: *
6: * Permission to use, copy, modify, and distribute this software for any
7: * purpose with or without fee is hereby granted, provided that the above
8: * copyright notice and this permission notice appear in all copies.
9: *
10: * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11: * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12: * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13: * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14: * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15: * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16: * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17: *
18: * Zaurus OpenBSD bootstrap loader.
19: */
20:
21: #include "compat_linux.h"
22:
23: #define BOOTARGS_BUFSIZ 256
24: #define BOOTARGS_MAGIC 0x4f425344
25:
26: #define ZBOOTDEV_MAJOR 99
27: #define ZBOOTDEV_MODE 0222
28: #define ZBOOTDEV_NAME "zboot"
29: #define ZBOOTMOD_NAME "zbsdmod"
30:
31: /* Prototypes */
32: void elf32bsdboot(void);
33: int init_module(void);
34: void cleanup_module(void);
35:
36: ssize_t zbsdmod_write(struct file *, const char *, size_t, loff_t *);
37: int zbsdmod_open(struct inode *, struct file *);
38: int zbsdmod_close(struct inode *, struct file *);
39:
40: static struct file_operations fops = {
41: 0, /* struct module *owner */
42: 0, /* lseek */
43: 0, /* read */
44: zbsdmod_write, /* write */
45: 0, /* readdir */
46: 0, /* poll */
47: 0, /* ioctl */
48: 0, /* mmap */
49: zbsdmod_open, /* open */
50: 0, /* flush */
51: zbsdmod_close, /* release */
52: 0, /* sync */
53: 0, /* async */
54: 0, /* check media change */
55: 0, /* revalidate */
56: 0, /* lock */
57: };
58:
59: static int isopen;
60: static loff_t position;
61:
62: /* Outcast local variables to avoid stack usage in elf32bsdboot(). */
63: static int cpsr;
64: static unsigned int sz;
65: static int i;
66: static vaddr_t minv, maxv, posv;
67: static vaddr_t elfv, shpv;
68: static int *addr;
69: static vaddr_t *esymp;
70: static Elf_Shdr *shp;
71: static Elf_Off off;
72: static int havesyms;
73:
74: /* The maximum size of a kernel image is restricted to 5MB. */
75: static int bsdimage[1310720]; /* XXX use kmalloc() */
76: static char bootargs[BOOTARGS_BUFSIZ];
77:
78: /*
79: * Boot the loaded BSD kernel image, or return if an error is found.
80: * Part of this routine is borrowed from sys/lib/libsa/loadfile.c.
81: */
82: void
83: elf32bsdboot(void)
84: {
85:
86: #define elf ((Elf32_Ehdr *)bsdimage)
87: #define phdr ((Elf32_Phdr *)((char *)elf + elf->e_phoff))
88:
89: if (memcmp(elf->e_ident, ELFMAG, SELFMAG) != 0 ||
90: elf->e_ident[EI_CLASS] != ELFCLASS32)
91: return;
92:
93: minv = (vaddr_t)~0;
94: maxv = (vaddr_t)0;
95: posv = (vaddr_t)0;
96: esymp = 0;
97:
98: /*
99: * Get min and max addresses used by the loaded kernel.
100: */
101: for (i = 0; i < elf->e_phnum; i++) {
102:
103: if (phdr[i].p_type != PT_LOAD ||
104: (phdr[i].p_flags & (PF_W|PF_R|PF_X)) == 0)
105: continue;
106:
107: #define IS_TEXT(p) (p.p_flags & PF_X)
108: #define IS_DATA(p) ((p.p_flags & PF_X) == 0)
109: #define IS_BSS(p) (p.p_filesz < p.p_memsz)
110: /*
111: * XXX: Assume first address is lowest
112: */
113: if (IS_TEXT(phdr[i]) || IS_DATA(phdr[i])) {
114: posv = phdr[i].p_vaddr;
115: if (minv > posv)
116: minv = posv;
117: posv += phdr[i].p_filesz;
118: if (maxv < posv)
119: maxv = posv;
120: }
121: if (IS_DATA(phdr[i]) && IS_BSS(phdr[i])) {
122: posv += phdr[i].p_memsz;
123: if (maxv < posv)
124: maxv = posv;
125: }
126: /*
127: * 'esym' is the first word in the .data section,
128: * and marks the end of the symbol table.
129: */
130: if (IS_DATA(phdr[i]) && !IS_BSS(phdr[i]))
131: esymp = (vaddr_t *)phdr[i].p_vaddr;
132: }
133:
134: __asm__ volatile ("mrs %0, cpsr_all" : "=r" (cpsr));
135: cpsr |= 0xc0; /* set FI */
136: __asm__ volatile ("msr cpsr_all, %0" :: "r" (cpsr));
137:
138: /*
139: * Copy the boot arguments.
140: */
141: sz = BOOTARGS_BUFSIZ;
142: while (sz > 0) {
143: sz--;
144: ((char *)minv - BOOTARGS_BUFSIZ)[sz] = bootargs[sz];
145: }
146:
147: /*
148: * Set up pointers to copied ELF and section headers.
149: */
150: #define roundup(x, y) ((((x)+((y)-1))/(y))*(y))
151: elfv = maxv = roundup(maxv, sizeof(long));
152: maxv += sizeof(Elf_Ehdr);
153:
154: sz = elf->e_shnum * sizeof(Elf_Shdr);
155: shp = (Elf_Shdr *)((vaddr_t)elf + elf->e_shoff);
156: shpv = maxv;
157: maxv += roundup(sz, sizeof(long));
158:
159: /*
160: * Now load the symbol sections themselves. Make sure the
161: * sections are aligned, and offsets are relative to the
162: * copied ELF header. Don't bother with string tables if
163: * there are no symbol sections.
164: */
165: off = roundup((sizeof(Elf_Ehdr) + sz), sizeof(long));
166: for (havesyms = i = 0; i < elf->e_shnum; i++)
167: if (shp[i].sh_type == SHT_SYMTAB)
168: havesyms = 1;
169: for (i = 0; i < elf->e_shnum; i++) {
170: if (shp[i].sh_type == SHT_SYMTAB ||
171: shp[i].sh_type == SHT_STRTAB) {
172: if (havesyms) {
173: sz = shp[i].sh_size;
174: while (sz > 0) {
175: sz--;
176: ((char *)maxv)[sz] =
177: ((char *)elf +
178: shp[i].sh_offset)[sz];
179: }
180: }
181: maxv += roundup(shp[i].sh_size, sizeof(long));
182: shp[i].sh_offset = off;
183: off += roundup(shp[i].sh_size, sizeof(long));
184: }
185: }
186:
187: /*
188: * Copy the ELF and section headers.
189: */
190: sz = sizeof(Elf_Ehdr);
191: while (sz > 0) {
192: sz--;
193: ((char *)elfv)[sz] = ((char *)elf)[sz];
194: }
195: sz = elf->e_shnum * sizeof(Elf_Shdr);
196: while (sz > 0) {
197: sz--;
198: ((char *)shpv)[sz] = ((char *)shp)[sz];
199: }
200:
201: /*
202: * Frob the copied ELF header to give information relative
203: * to elfv.
204: */
205: ((Elf_Ehdr *)elfv)->e_phoff = 0;
206: ((Elf_Ehdr *)elfv)->e_shoff = sizeof(Elf_Ehdr);
207: ((Elf_Ehdr *)elfv)->e_phentsize = 0;
208: ((Elf_Ehdr *)elfv)->e_phnum = 0;
209:
210: /*
211: * Tell locore.S where the symbol table ends, and arrange
212: * to skip esym when loading the data section.
213: */
214: if (esymp != 0)
215: *esymp = (vaddr_t)maxv;
216: for (i = 0; esymp != 0 && i < elf->e_phnum; i++) {
217: if (phdr[i].p_type != PT_LOAD ||
218: (phdr[i].p_flags & (PF_W|PF_R|PF_X)) == 0)
219: continue;
220: if (phdr[i].p_vaddr == (vaddr_t)esymp) {
221: phdr[i].p_vaddr = (vaddr_t)((char *)phdr[i].p_vaddr + sizeof(long));
222: phdr[i].p_offset = (vaddr_t)((char *)phdr[i].p_offset + sizeof(long));
223: phdr[i].p_filesz -= sizeof(long);
224: break;
225: }
226: }
227:
228: /*
229: * Load text and data.
230: */
231: for (i = 0; i < elf->e_phnum; i++) {
232:
233: if (phdr[i].p_type != PT_LOAD ||
234: (phdr[i].p_flags & (PF_W|PF_R|PF_X)) == 0)
235: continue;
236:
237: if (IS_TEXT(phdr[i]) || IS_DATA(phdr[i])) {
238: sz = phdr[i].p_filesz;
239: while (sz > 0) {
240: sz--;
241: ((char *)phdr[i].p_vaddr)[sz] =
242: (((char *)elf) + phdr[i].p_offset)[sz];
243: }
244: }
245: }
246:
247: addr = (int *)(elf->e_entry);
248: __asm__ volatile (
249: "mov r0, %0;"
250: "mov r2, #0;"
251: "mov r1, #(0x00000010 | 0x00000020);"
252: "mcr 15, 0, r1, c1, c0, 0;"
253: "mcr 15, 0, r2, c8, c7, 0 /* nail I+D TLB on ARMv4 and greater */;"
254: "mov pc, r0" :: "r"(addr) : "r0","r1","r2");
255: }
256:
257: /*
258: * Initialize the LKM.
259: */
260: int
261: init_module()
262: {
263: struct proc_dir_entry *entry;
264: int rc;
265:
266: rc = register_chrdev(ZBOOTDEV_MAJOR, ZBOOTDEV_NAME, &fops);
267: if (rc != 0) {
268: printk("%s: register_chrdev(%d, ...): error %d\n",
269: ZBOOTMOD_NAME, -rc);
270: return 1;
271: }
272:
273: entry = proc_mknod(ZBOOTDEV_NAME, ZBOOTDEV_MODE | S_IFCHR,
274: &proc_root, MKDEV(ZBOOTDEV_MAJOR, 0));
275: if (entry == (struct proc_dir_entry *)0) {
276: (void)unregister_chrdev(ZBOOTDEV_MAJOR, ZBOOTDEV_NAME);
277: return 1;
278: }
279:
280: printk("%s: OpenBSD/" MACHINE " bootstrap device is %d,0\n",
281: ZBOOTMOD_NAME, ZBOOTDEV_MAJOR);
282:
283: return 0;
284: }
285:
286: /*
287: * Cleanup - undo whatever init_module did.
288: */
289: void
290: cleanup_module()
291: {
292:
293: (void)unregister_chrdev(ZBOOTDEV_MAJOR, ZBOOTDEV_NAME);
294: remove_proc_entry(ZBOOTDEV_NAME, &proc_root);
295:
296: printk("%s: OpenBSD/" MACHINE " bootstrap device unloaded\n",
297: ZBOOTMOD_NAME);
298: }
299:
300:
301: ssize_t
302: zbsdmod_write(struct file *f, const char *buf, size_t len, loff_t *offp)
303: {
304:
305: if (len < 1)
306: return 0;
307:
308: if (*offp + len >= sizeof(bsdimage))
309: return EFBIG;
310:
311: memcpy(((char *)bsdimage) + *offp, buf, len);
312:
313: *offp += len;
314: if (*offp > position)
315: position = *offp;
316:
317: return len;
318: }
319:
320: int
321: zbsdmod_open(struct inode *ino, struct file *f)
322: {
323:
324: /* XXX superuser check */
325:
326: if (isopen)
327: return -EBUSY;
328:
329: isopen = 1;
330: position = 0;
331:
332: return 0;
333: }
334:
335: int
336: zbsdmod_close(struct inode *ino, struct file *f)
337: {
338:
339: if (isopen) {
340: if (position > 0) {
341: printk("%s: loaded %d bytes\n", ZBOOTDEV_NAME,
342: position);
343:
344: if (position < BOOTARGS_BUFSIZ) {
345: *(int *)bootargs = BOOTARGS_MAGIC;
346: bootargs[position + sizeof(int)] = '\0';
347: memcpy(bootargs + sizeof(int), bsdimage,
348: position);
349: } else {
350: #ifndef _TEST
351: elf32bsdboot();
352: printk("%s: boot failed\n", ZBOOTDEV_NAME);
353: #else
354: printk("/* boot() */\n");
355: #endif
356: }
357: }
358: isopen = 0;
359: return 0;
360: }
361:
362: return -EBUSY;
363: }
CVSweb