4 * Loads a RAM build of u-boot and starts it
5 * The load address is hardcoded to 0x03f00000 (for LS HLAN)
7 * Copyright (C) 2006 Mihai Georgian <u-boot@linuxnotincluded.org.uk>
9 * This program is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU General Public License as
11 * published by the Free Software Foundation; either version 2 of
12 * the License, or (at your option) any later version.
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
25 * loader_mod.c by Chih-Chung Chang <jochang@gmail.com>
27 #include <linux/module.h>
28 #include <linux/kernel.h>
29 #include <asm/uaccess.h>
30 #include <linux/file.h>
32 #include <linux/vmalloc.h>
33 #include <linux/slab.h>
34 #include <linux/reboot.h>
36 MODULE_LICENSE("GPL");
37 MODULE_AUTHOR("Mihai Georgian <u-boot@linuxnotincluded.org.uk>");
38 MODULE_PARM(uboot, "s");
39 MODULE_PARM(laddr, "l");
40 MODULE_PARM_DESC(uboot, "u-boot file name (must be binary)");
41 MODULE_PARM_DESC(laddr, "u-boot load address");
43 static char* uboot = "u-boot.bin";
44 static unsigned long laddr = 0x03f00000;
46 #define LOW_MEM 0x800000 /* no smaller than kernel + 1M (bss) + initrd */
48 void load_uboot(unsigned long pa_load_uboot,
49 unsigned long pa_uboot_buf,
52 struct indirect_buffer {
54 unsigned long paddr[1]; /* physical address of each 4K page */
55 /* terminate with zero */
57 static struct indirect_buffer *uboot_buf;
59 static int uloader_notify_reboot (struct notifier_block *this, \
60 unsigned long event, void *x);
61 static struct notifier_block uloader_notifier = {
62 uloader_notify_reboot,
67 #define MAX_INDIRECT_BUFFER_SIZE ((PAGE_SIZE/4-1)*PAGE_SIZE)
70 * Allocate a page with physical address >= LOWMEM
73 static int saved_pages;
74 static void *alloc_high_page(void)
79 save = vmalloc(((LOW_MEM+PAGE_SIZE-1)/PAGE_SIZE)*4);
85 ptr = kmalloc(PAGE_SIZE, GFP_KERNEL);
87 if(__pa(ptr) >= LOW_MEM) break;
88 save[saved_pages++] = ptr;
93 static void free_saved_pages(void)
98 for(i=0;i<saved_pages;i++)
104 static void free_ibuffer(struct indirect_buffer *ibuf);
107 * Read input file into an indirect buffer
109 static int read_file(char *filename, struct indirect_buffer **indirect_buf)
113 struct indirect_buffer *ibuf;
118 file = filp_open(filename, O_RDONLY, 0);
120 return PTR_ERR(file);
123 if(!file->f_op || !file->f_op->read)
127 inode = file->f_dentry->d_inode;
128 if(!S_ISREG(inode->i_mode))
132 ibuf = (struct indirect_buffer*)alloc_high_page();
134 memset(ibuf, 0, PAGE_SIZE);
136 if(inode->i_size > MAX_INDIRECT_BUFFER_SIZE) goto out2;
137 size = (size_t)inode->i_size;
140 for(i=0;i<size;i+=PAGE_SIZE)
142 size_t todo = min(size-i, (size_t)PAGE_SIZE);
146 buf = alloc_high_page();
148 ibuf->paddr[i/PAGE_SIZE] = __pa(buf);
154 got = file->f_op->read(file, buf, todo, &file->f_pos);
156 if(got != todo) goto out2;
159 *indirect_buf = ibuf;
163 filp_close(file, NULL);
170 static void free_ibuffer(struct indirect_buffer *ibuf)
173 for(i=0;ibuf->paddr[i];i++)
174 kfree((void *)__va(ibuf->paddr[i]));
178 /* convert vmalloc'ed memory to physical address */
179 static unsigned long va2pa(void *p)
181 return iopa((unsigned long)p);
184 static int uloader_notify_reboot (struct notifier_block *this, \
185 unsigned long event, void *x)
194 printk(KERN_INFO "uloader module booting u-boot\n");
196 load_uboot(va2pa(load_uboot), va2pa(uboot_buf), laddr);
198 return NOTIFY_DONE; /* This should never be reached */
201 int init_module(void)
205 printk(KERN_INFO "uloader module loaded\n");
206 printk(KERN_INFO "uboot=%s\n", uboot);
208 if((err = read_file(uboot, &uboot_buf)))
210 register_reboot_notifier(&uloader_notifier);
217 void cleanup_module(void)
219 printk(KERN_INFO "uloader module unloaded\n");