added UART init and progress while booting kernel.
[uloader.git] / uloader_mod.c
1 /*
2  * uloader_mod.c
3  *
4  * Loads a RAM build of u-boot and starts it
5  * The load address is hardcoded to 0x03f00000 (for LS HLAN)
6  *
7  * Copyright (C) 2006 Mihai Georgian <u-boot@linuxnotincluded.org.uk>
8  *
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.
13  *
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.
18  *
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,
22  * MA 02111-1307 USA
23  *
24  * Based on:
25  *   loader_mod.c by Chih-Chung Chang <jochang@gmail.com>
26  */
27 #include <linux/module.h>
28 #include <linux/kernel.h>
29 #include <asm/uaccess.h>
30 #include <linux/file.h>
31 #include <linux/mm.h>
32 #include <linux/vmalloc.h>
33 #include <linux/slab.h>
34 #include <linux/reboot.h>
35
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");
42
43 static char* uboot = "u-boot.bin";
44 // 0x01f00000
45 // 0x07f00000
46 static unsigned long laddr = 0x01f00000;
47
48 #define LOW_MEM ( 8 * 1024 * 1024 )  /* no smaller than kernel + 1M (bss) + initrd */
49 #define MAX_INDIRECT_BUFFER_SIZE ((PAGE_SIZE/4-1)*PAGE_SIZE)
50 #define VMALLOC_SIZE ((LOW_MEM+PAGE_SIZE-1)/PAGE_SIZE)*4
51
52 void load_uboot(unsigned long pa_load_uboot,
53                 unsigned long pa_uboot_buf,
54                 unsigned long laddr);
55
56 struct indirect_buffer {
57   int size;
58   unsigned long paddr[1]; /* physical address of each 4K page */
59                           /* terminate with zero */
60 };
61 static struct indirect_buffer *uboot_buf;
62
63 static int uloader_notify_reboot (struct notifier_block *this, \
64                                   unsigned long event, void *x);
65 static struct notifier_block uloader_notifier = {
66   uloader_notify_reboot,
67   NULL,
68   0
69 };
70
71 #define MAX_INDIRECT_BUFFER_SIZE ((PAGE_SIZE/4-1)*PAGE_SIZE)
72
73 #define VMALLOC_SIZE ((LOW_MEM+PAGE_SIZE-1)/PAGE_SIZE)*4
74
75 /*
76  *  Allocate a page with physical address >= LOWMEM
77  */
78 static void **save;
79 static int saved_pages = 0;
80 static void *alloc_high_page(void)
81 {
82   void *ptr;
83   if(!save)
84   {
85     save = vmalloc( VMALLOC_SIZE );
86     if(!save) {
87         printk(KERN_INFO "can't vmalloc(%lu)\n", VMALLOC_SIZE );
88         return 0;
89     } else {
90         //printk(KERN_INFO "vmalloc(%lu) = %08x\n", VMALLOC_SIZE, save );
91     }
92   }
93
94   while(1)
95   {
96     ptr = kmalloc(PAGE_SIZE, GFP_KERNEL);
97     if(!ptr) {
98         printk(KERN_INFO "can't kmalloc(%lu)\n", PAGE_SIZE);
99         return 0;
100     }
101     if( __pa(ptr) >= LOW_MEM ) {
102         //printk(KERN_INFO "kmalloc(%lu) = %08x __pa: %08x >= %08x got %d pages before this\n", PAGE_SIZE, ptr, __pa(ptr), LOW_MEM, saved_pages );
103         break;
104     }
105     //printk(KERN_INFO "%d: kmalloc(%lu) = %08x __pa: %08x\n", saved_pages, PAGE_SIZE, ptr, __pa(ptr) );
106     save[saved_pages++] = ptr;
107   }
108   printk(KERN_INFO "alloc_high_page %08x __pa: %08x\n", ptr, __pa(ptr) );
109   return ptr;
110 }
111
112 static void free_saved_pages(void)
113 {
114   if(save)
115   {
116     int i;
117     for(i=0;i<saved_pages;i++)
118       kfree(save[i]);
119     vfree(save);
120   }
121 }
122
123 static void free_ibuffer(struct indirect_buffer *ibuf);
124
125 /*
126  *  Read input file into an indirect buffer
127  */
128 static int read_file(char *filename, struct indirect_buffer **indirect_buf)
129 {
130   struct file* file;
131   struct inode* inode;
132   struct indirect_buffer *ibuf;
133   size_t size, got, i;
134   mm_segment_t fs;
135   int err;
136
137   file = filp_open(filename, O_RDONLY, 0);
138   if(IS_ERR(file)) {
139     printk(KERN_INFO "can't open filename %s\n", filename);
140     return PTR_ERR(file);
141   }
142
143   err = -EIO;
144   if(!file->f_op || !file->f_op->read) {
145     printk(KERN_INFO "EIO\n");
146     goto out;
147   }
148
149   err = -EACCES;
150   inode = file->f_dentry->d_inode;
151   if(!S_ISREG(inode->i_mode)) {
152     printk(KERN_INFO "EACCES\n");
153     goto out;
154   }
155
156   err = -ENOMEM;
157   ibuf = (struct indirect_buffer*)alloc_high_page();
158   if(!ibuf) {
159     printk(KERN_INFO "ENOMEM\n");
160     goto out;
161   }
162   memset(ibuf, 0, PAGE_SIZE);
163
164   if(inode->i_size > MAX_INDIRECT_BUFFER_SIZE) {
165         printk(KERN_INFO "## %8x > %8x\n", inode->i_size, MAX_INDIRECT_BUFFER_SIZE);
166         goto out2;
167   }
168   size = (size_t)inode->i_size;
169   ibuf->size = size;
170   printk(KERN_INFO "loading %s %d bytes\n", filename, size);
171
172   for(i=0;i<size;i+=PAGE_SIZE)
173   {
174     size_t todo = min(size-i, (size_t)PAGE_SIZE);
175     void *buf;
176
177     err = -ENOMEM;
178     buf = alloc_high_page();
179     if(!buf) {
180       printk(KERN_INFO "can't allocate page %d\n", i);
181       goto out2;
182     }
183     ibuf->paddr[i/PAGE_SIZE] = __pa(buf);
184
185     err = -EIO;
186     file->f_pos = i;
187     fs = get_fs();
188     set_fs(KERNEL_DS);
189     got = file->f_op->read(file, buf, todo, &file->f_pos);
190     set_fs(fs);
191     if(got != todo) {
192       printk(KERN_INFO "for block %d got %d expected %8x\n", i, got, todo);
193       goto out2;
194     }
195   }
196
197   *indirect_buf = ibuf;
198   err = 0;
199
200   printk(KERN_INFO "loaded %s\n", filename);
201 out:
202   filp_close(file, NULL);
203   printk(KERN_INFO "return code %d\n", err);
204
205   return err;
206 out2:
207   printk(KERN_INFO "failed loading %s\n", filename);
208   free_ibuffer(ibuf);
209   goto out;
210 }
211
212 static void free_ibuffer(struct indirect_buffer *ibuf)
213 {
214   int i;
215   for(i=0;ibuf->paddr[i];i++)
216     kfree((void *)__va(ibuf->paddr[i]));
217   kfree(ibuf);
218 }
219
220 /* convert vmalloc'ed memory to physical address */
221 static unsigned long va2pa(void *p)
222 {
223   return iopa((unsigned long)p);
224 }
225
226 static int uloader_notify_reboot (struct notifier_block *this, \
227                                   unsigned long event, void *x)
228 {
229   switch (event) {
230     case SYS_RESTART:
231       break;
232     default:
233       return NOTIFY_DONE;
234   }
235
236   //printk(KERN_INFO "load_uboot(%8x,%8x,%8x)\n",va2pa(load_uboot), va2pa(uboot_buf), laddr);
237   printk(KERN_INFO "A");
238   load_uboot(va2pa(load_uboot), va2pa(uboot_buf), laddr);
239
240   return NOTIFY_DONE;  /* This should never be reached */
241 }
242
243 int init_module(void)
244 {
245   int err;
246
247   printk(KERN_INFO "uloader module loaded\n");
248   printk(KERN_INFO "uboot=%s<--\n", uboot);
249
250   if((err = read_file(uboot, &uboot_buf))) {
251     printk(KERN_INFO "Error loading %s\n", uboot);
252     goto out;
253   }
254   register_reboot_notifier(&uloader_notifier);
255   return 0;
256 out:
257   free_saved_pages();
258   return err;
259 }
260
261 void cleanup_module(void)
262 {
263   printk(KERN_INFO "uloader module unloaded\n");
264 }