1 /* $NetBSD: zbsdmod.c,v 1.3 2008/11/12 12:36:09 ad Exp $ */
2 /* $OpenBSD: zbsdmod.c,v 1.7 2005/05/02 02:45:29 uwe Exp $ */
5 * Copyright (c) 2005 Uwe Stuehler <uwe@bsdx.de>
7 * Permission to use, copy, modify, and distribute this software for any
8 * purpose with or without fee is hereby granted, provided that the above
9 * copyright notice and this permission notice appear in all copies.
11 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
12 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
13 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
14 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
15 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
16 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
17 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
21 * Zaurus NetBSD bootstrap loader.
24 #include "compat_linux.h"
26 #include <machine/bootinfo.h>
28 #define ZBOOTDEV_MAJOR 99
29 #define ZBOOTDEV_MODE 0222
30 #define ZBOOTDEV_NAME "zboot"
31 #define ZBOOTMOD_NAME "zbsdmod"
34 int init_module(void);
35 void cleanup_module(void);
37 static ssize_t
zbsdmod_write(struct file
*, const char *, size_t, loff_t
*);
38 static int zbsdmod_open(struct inode
*, struct file
*);
39 static int zbsdmod_close(struct inode
*, struct file
*);
41 static void elf32bsdboot(void);
43 static struct file_operations fops
= {
44 0, /* struct module *owner */
47 zbsdmod_write
, /* write */
52 zbsdmod_open
, /* open */
54 zbsdmod_close
, /* release */
57 0, /* check media change */
63 static loff_t position
;
65 /* Outcast local variables to avoid stack usage in elf32bsdboot(). */
67 static unsigned int sz
;
69 static vaddr_t minv
, maxv
, posv
;
70 static vaddr_t elfv
, shpv
;
72 static vaddr_t
*esymp
;
77 /* The maximum size of a kernel image is restricted to 10MB. */
78 static u_int bsdimage
[10485760/sizeof(u_int
)]; /* XXX use kmalloc() */
79 static char bootargs
[BOOTARGS_BUFSIZ
];
82 * Boot the loaded BSD kernel image, or return if an error is found.
83 * Part of this routine is borrowed from sys/lib/libsa/loadfile.c.
89 #define elf ((Elf32_Ehdr *)bsdimage)
90 #define phdr ((Elf32_Phdr *)((char *)elf + elf->e_phoff))
92 if (memcmp(elf
->e_ident
, ELFMAG
, SELFMAG
) != 0 ||
93 elf
->e_ident
[EI_CLASS
] != ELFCLASS32
)
102 * Get min and max addresses used by the loaded kernel.
104 for (i
= 0; i
< elf
->e_phnum
; i
++) {
106 if (phdr
[i
].p_type
!= PT_LOAD
||
107 (phdr
[i
].p_flags
& (PF_W
|PF_R
|PF_X
)) == 0)
110 #define IS_TEXT(p) (p.p_flags & PF_X)
111 #define IS_DATA(p) ((p.p_flags & PF_X) == 0)
112 #define IS_BSS(p) (p.p_filesz < p.p_memsz)
114 * XXX: Assume first address is lowest
116 if (IS_TEXT(phdr
[i
]) || IS_DATA(phdr
[i
])) {
117 posv
= phdr
[i
].p_vaddr
;
120 posv
+= phdr
[i
].p_filesz
;
124 if (IS_DATA(phdr
[i
]) && IS_BSS(phdr
[i
])) {
125 posv
+= phdr
[i
].p_memsz
;
130 * 'esym' is the first word in the .data section,
131 * and marks the end of the symbol table.
133 if (IS_DATA(phdr
[i
]) && !IS_BSS(phdr
[i
]))
134 esymp
= (vaddr_t
*)phdr
[i
].p_vaddr
;
137 __asm
volatile ("mrs %0, cpsr_all" : "=r" (cpsr
));
138 cpsr
|= 0xc0; /* set FI */
139 __asm
volatile ("msr cpsr_all, %0" :: "r" (cpsr
));
142 * Copy the boot arguments.
144 sz
= BOOTARGS_BUFSIZ
;
147 ((char *)minv
- BOOTARGS_BUFSIZ
)[sz
] = bootargs
[sz
];
151 * Set up pointers to copied ELF and section headers.
153 #define roundup(x, y) ((((x)+((y)-1))/(y))*(y))
154 elfv
= maxv
= roundup(maxv
, sizeof(long));
155 maxv
+= sizeof(Elf_Ehdr
);
157 sz
= elf
->e_shnum
* sizeof(Elf_Shdr
);
158 shp
= (Elf_Shdr
*)((vaddr_t
)elf
+ elf
->e_shoff
);
160 maxv
+= roundup(sz
, sizeof(long));
163 * Now load the symbol sections themselves. Make sure the
164 * sections are aligned, and offsets are relative to the
165 * copied ELF header. Don't bother with string tables if
166 * there are no symbol sections.
168 off
= roundup((sizeof(Elf_Ehdr
) + sz
), sizeof(long));
169 for (havesyms
= i
= 0; i
< elf
->e_shnum
; i
++)
170 if (shp
[i
].sh_type
== SHT_SYMTAB
)
172 for (i
= 0; i
< elf
->e_shnum
; i
++) {
173 if (shp
[i
].sh_type
== SHT_SYMTAB
||
174 shp
[i
].sh_type
== SHT_STRTAB
) {
181 shp
[i
].sh_offset
)[sz
];
184 maxv
+= roundup(shp
[i
].sh_size
, sizeof(long));
185 shp
[i
].sh_offset
= off
;
186 off
+= roundup(shp
[i
].sh_size
, sizeof(long));
191 * Copy the ELF and section headers.
193 sz
= sizeof(Elf_Ehdr
);
196 ((char *)elfv
)[sz
] = ((char *)elf
)[sz
];
198 sz
= elf
->e_shnum
* sizeof(Elf_Shdr
);
201 ((char *)shpv
)[sz
] = ((char *)shp
)[sz
];
205 * Frob the copied ELF header to give information relative
208 ((Elf_Ehdr
*)elfv
)->e_phoff
= 0;
209 ((Elf_Ehdr
*)elfv
)->e_shoff
= sizeof(Elf_Ehdr
);
210 ((Elf_Ehdr
*)elfv
)->e_phentsize
= 0;
211 ((Elf_Ehdr
*)elfv
)->e_phnum
= 0;
214 * Tell locore.S where the symbol table ends, and arrange
215 * to skip esym when loading the data section.
218 *esymp
= (vaddr_t
)maxv
;
219 for (i
= 0; esymp
!= 0 && i
< elf
->e_phnum
; i
++) {
220 if (phdr
[i
].p_type
!= PT_LOAD
||
221 (phdr
[i
].p_flags
& (PF_W
|PF_R
|PF_X
)) == 0)
223 if (phdr
[i
].p_vaddr
== (vaddr_t
)esymp
) {
224 phdr
[i
].p_vaddr
= (vaddr_t
)((char *)phdr
[i
].p_vaddr
+ sizeof(long));
225 phdr
[i
].p_offset
= (vaddr_t
)((char *)phdr
[i
].p_offset
+ sizeof(long));
226 phdr
[i
].p_filesz
-= sizeof(long);
232 * Load text and data.
234 for (i
= 0; i
< elf
->e_phnum
; i
++) {
235 if (phdr
[i
].p_type
!= PT_LOAD
||
236 (phdr
[i
].p_flags
& (PF_W
|PF_R
|PF_X
)) == 0)
239 if (IS_TEXT(phdr
[i
]) || IS_DATA(phdr
[i
])) {
240 sz
= phdr
[i
].p_filesz
;
243 ((char *)phdr
[i
].p_vaddr
)[sz
] =
244 (((char *)elf
) + phdr
[i
].p_offset
)[sz
];
249 addr
= (int *)(elf
->e_entry
);
253 "mcr p15, 0, r2, c7, c7, 0;"
256 "mov r1, #(0x00000010 | 0x00000020);"
257 "mcr p15, 0, r1, c1, c0, 0;"
258 "mcr p15, 0, r2, c8, c7, 0;"
261 "mov pc, r0" :: "r"(addr
) : "r0","r1","r2");
265 * Initialize the module.
270 struct proc_dir_entry
*entry
;
273 rc
= register_chrdev(ZBOOTDEV_MAJOR
, ZBOOTDEV_NAME
, &fops
);
275 printk("%s: register_chrdev(%d, ...): error %d\n",
280 entry
= proc_mknod(ZBOOTDEV_NAME
, ZBOOTDEV_MODE
| S_IFCHR
,
281 &proc_root
, MKDEV(ZBOOTDEV_MAJOR
, 0));
282 if (entry
== (struct proc_dir_entry
*)0) {
283 (void)unregister_chrdev(ZBOOTDEV_MAJOR
, ZBOOTDEV_NAME
);
287 printk("%s: NetBSD/" MACHINE
" bootstrap device is %d,0\n",
288 ZBOOTMOD_NAME
, ZBOOTDEV_MAJOR
);
294 * Cleanup - undo whatever init_module did.
300 (void)unregister_chrdev(ZBOOTDEV_MAJOR
, ZBOOTDEV_NAME
);
301 remove_proc_entry(ZBOOTDEV_NAME
, &proc_root
);
303 printk("%s: NetBSD/" MACHINE
" bootstrap device unloaded\n",
308 zbsdmod_write(struct file
*f
, const char *buf
, size_t len
, loff_t
*offp
)
314 if (*offp
+ len
>= sizeof(bsdimage
))
317 memcpy(((char *)bsdimage
) + *offp
, buf
, len
);
320 if (*offp
> position
)
327 zbsdmod_open(struct inode
*ino
, struct file
*f
)
330 /* XXX superuser check */
342 zbsdmod_close(struct inode
*ino
, struct file
*f
)
349 printk("%s: loaded %d bytes\n", ZBOOTDEV_NAME
,
352 if (position
< BOOTINFO_MAXSIZE
) {
353 *(u_int
*)bootargs
= BOOTARGS_MAGIC
;
354 memcpy(bootargs
+ sizeof(u_int
), bsdimage
, position
);
357 printk("%s: boot failed\n", ZBOOTDEV_NAME
);