--- /dev/null
+# Makefile for uloader.o
+#
+# Copyright (C) 2006 Mihai Georgian <u-boot@linuxnotincluded.org.uk>
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License as
+# published by the Free Software Foundation; either version 2 of
+# the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+# MA 02111-1307 USA
+#
+# Based on:
+# Makefile for loader.o by Chih-Chung Chang <jochang@gmail.com>
+# CFLAGS taken from linux-2.4.17_mvl21-sandpoint
+#
+# To compile this module you will need a fully configured kernel
+# 2.4.17_mvl21-sandpoint and gcc 2.95
+
+# Change INCLUDE to match your environment
+INCLUDE = -nostdinc -I/opt/embedded/ppc/list/linux-2.4.17_mvl21-sandpoint.ref/include -I/opt/embedded/ppc/list/linux-2.4.17_mvl21-sandpoint.ref/arch/ppc -I/opt/embedded/ppc/toolchain/usr/lib/gcc-lib/powerpc-linux/2.95.3/include
+
+CFLAGS = -D__KERNEL__ -Wall -Wstrict-prototypes -Wno-trigraphs -O2 -fomit-frame-pointer -fno-strict-aliasing -fno-common -fsigned-char -msoft-float -pipe -ffixed-r2 -Wno-uninitialized -mmultiple -mstring -DMODULE
+
+CC = $(CROSS_COMPILE)gcc
+LD = $(CROSS_COMPILE)ld
+
+uloader.o: uloader_mod.o uloader_boot.o
+ $(LD) -r uloader_mod.o uloader_boot.o -o uloader.o
+uloader_mod.o: uloader_mod.c
+ $(CC) -c $(INCLUDE) $(CFLAGS) uloader_mod.c
+uloader_boot.o: uloader_boot.S
+ $(CC) -c -mregnames uloader_boot.S
+clean:
+ rm -f uloader.o uloader_mod.o uloader_boot.o
--- /dev/null
+* Introduction
+
+Here is a small kernel module for booting new kernels on Kuro Box without
+flashing. It loads a new kernel into memory and jumps to it directly.
+
+You need kernel header files to build the module.
+I put the kernel source came with my Kuro Box in
+
+http://jan.csie.ntu.edu.tw/~jo/kuro/CD2/linux-2.4.17_kuro-box.tar.gz
+
+You also need a configuration file to build the kernel,
+I use the one in
+
+ftp://linkstation.yi.org/pub/linkstation/kernel/config_kurobox.040630
+
+* Building the new kernel
+
+cd /usr/src
+tar xzvf ~/linux-2.4.17_kuro-box.tar.gz
+cd linux-2.4.17_kuro-box
+cp ~/config_kurobox.040630 .config
+make oldconfig
+make dep
+make
+# the loader need the kernel to be in binary format
+objcopy -O binary vmlinux
+
+* Building the loader module
+
+tar xzvf loader.tar.gz
+cd loader
+# change Makefile for your kernel source directory
+make
+
+* Loading the new kernel
+
+sync;insmod loader.o kernel=/usr/src/linux-2.4.17_kuro-box/vmlinux
+
+About one minute later or so, you can again telnet in your kuro box
+and verify it is running the new kernel by typing "uname -a".
+
+There are three parameters for this module:
+
+kernel: kernel file name (the kernel must be in binary format)
+initrd: initrd file name (it can be a gzip'ed file)
+cmdline: kernel command line
+
+For example you can use an ramdisk as your root filesystem:
+
+sync;insmod loader.o kernel=/usr/src/linux-2.4.17_kuro-box/vmlinux \
+initrd=/root/initrd.gz cmdline="root=/dev/ram0"
+
+The cmdline parameter doesn't work unless a small patch is applied
+to the kernel:
+
+--- arch/ppc/platforms/sandpoint_setup.c.orig Mon Mar 15 00:15:01 2004
++++ arch/ppc/platforms/sandpoint_setup.c Sun Jan 9 20:54:55 2005
+@@ -666,6 +666,12 @@
+ }
+ #endif
+
++ if ( r6 )
++ {
++ *(char *)(r7+KERNELBASE) = 0;
++ strcpy(cmd_line, (char *)(r6+KERNELBASE));
++ }
++
+ #ifdef NAS_DEBUG
+ printk("initrd_start: %08X\n",initrd_start);
+ printk("initrd_end: %08X\n",initrd_end);
+
+--
+Chih-Chung Chang <jochang@gmail.com>
+
+P.S. This module works for me most of the time, but sometimes it
+just crashes. I'd be glad to hear if you have any idea why :)
--- /dev/null
+#!/bin/bash
+sync;sync;insmod /mnt/share/uloader.o uboot=/mnt/share/u-boot-hd.ram.bin
+init 6
--- /dev/null
+/*
+ * uloader_boot.S
+ *
+ * Copyright (C) 2006 Mihai Georgian <u-boot@linuxnotincluded.org.uk>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ *
+ * Based on: arch/ppc/boot/sandpoint/head.S
+ * arch/ppc/kernel/head.S
+ * http://www-106.ibm.com/developerworks/library/pa-ppccache.html
+ */
+
+#define HID0 0x3F0 /* Hardware Implementation Register 0 */
+#define HID0_ICE (1<<15) /* Instruction Cache Enable */
+#define HID0_DCE (1<<14) /* Data Cache Enable */
+
+.section ".text"
+.globl load_uboot
+
+load_uboot:
+ /* save parameters */
+ mr r31,r3 /* pa_load_uboot */
+ mr r30,r4 /* pa_uboot_buf */
+ mr r29,r5 /* load_address */
+
+ /* disable interrupts */
+ mfmsr r0
+ rlwinm r0,r0,0,17,15 /* clear MSR_EE in r0 */
+ sync
+ mtmsr r0
+ sync
+
+ /* disable cache */
+ bl disable_cache
+
+ /* jump to after_mmu_off */
+ addi r4,r31,after_mmu_off-load_uboot
+ li r3,0
+ mtspr SRR0,r4
+ mtspr SRR1,r3
+ isync
+ sync
+ rfi
+
+after_mmu_off:
+
+ /* copy uboot image */
+ mr r4,r29 /* load address */
+ addi r30,r30,4 /* skip size */
+
+2: li r0,1024
+ lwz r9,0(r30)
+
+ mtctr r0
+1: lwz r0,0(r9)
+ addi r9,r9,4
+ stw r0,0(r4)
+ addi r4,r4,4
+ bdnz 1b
+
+ addi r30,r30,4
+ lwz r0,0(r30)
+ cmpwi r0,0
+ bne 2b
+
+ /* jump to uboot */
+ lis r1,0x100 /* put stack at 16M */
+ li r3,0
+ mr r9,r29
+ /* u-boot entry point is u-boot base + 0x100 */
+ addi r9,r9,0x100
+ mtlr r9
+ blr
+
+disable_cache:
+ li r2,1024 /* flush 16K cache */
+ mtctr r2
+ mr r3,r2
+ lis r4,0xC000
+loop1:
+ lwz r6,0(r4)
+ addi r4,r4,16
+ bdnz loop1
+
+ lis r4,0xC000
+ mtctr r3
+loop2:
+ dcbf r0,r4
+ addi r4,r4,16
+ bdnz loop2
+
+ mfspr r4,HID0
+ li r3,0
+ ori r3,r3,HID0_ICE|HID0_DCE
+ andc r4,r4,r3
+ mtspr HID0,r4
+ isync
+ blr
--- /dev/null
+/*
+ * uloader_mod.c
+ *
+ * Loads a RAM build of u-boot and starts it
+ * The load address is hardcoded to 0x03f00000 (for LS HLAN)
+ *
+ * Copyright (C) 2006 Mihai Georgian <u-boot@linuxnotincluded.org.uk>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ *
+ * Based on:
+ * loader_mod.c by Chih-Chung Chang <jochang@gmail.com>
+ */
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <asm/uaccess.h>
+#include <linux/file.h>
+#include <linux/mm.h>
+#include <linux/vmalloc.h>
+#include <linux/slab.h>
+#include <linux/reboot.h>
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Mihai Georgian <u-boot@linuxnotincluded.org.uk>");
+MODULE_PARM(uboot, "s");
+MODULE_PARM(laddr, "l");
+MODULE_PARM_DESC(uboot, "u-boot file name (must be binary)");
+MODULE_PARM_DESC(laddr, "u-boot load address");
+
+static char* uboot = "u-boot.bin";
+static unsigned long laddr = 0x03f00000;
+
+#define LOW_MEM 0x800000 /* no smaller than kernel + 1M (bss) + initrd */
+
+void load_uboot(unsigned long pa_load_uboot,
+ unsigned long pa_uboot_buf,
+ unsigned long laddr);
+
+struct indirect_buffer {
+ int size;
+ unsigned long paddr[1]; /* physical address of each 4K page */
+ /* terminate with zero */
+};
+static struct indirect_buffer *uboot_buf;
+
+static int uloader_notify_reboot (struct notifier_block *this, \
+ unsigned long event, void *x);
+static struct notifier_block uloader_notifier = {
+ uloader_notify_reboot,
+ NULL,
+ 0
+};
+
+#define MAX_INDIRECT_BUFFER_SIZE ((PAGE_SIZE/4-1)*PAGE_SIZE)
+
+/*
+ * Allocate a page with physical address >= LOWMEM
+ */
+static void **save;
+static int saved_pages;
+static void *alloc_high_page(void)
+{
+ void *ptr;
+ if(!save)
+ {
+ save = vmalloc(((LOW_MEM+PAGE_SIZE-1)/PAGE_SIZE)*4);
+ if(!save) return 0;
+ }
+
+ while(1)
+ {
+ ptr = kmalloc(PAGE_SIZE, GFP_KERNEL);
+ if(!ptr) return 0;
+ if(__pa(ptr) >= LOW_MEM) break;
+ save[saved_pages++] = ptr;
+ }
+ return ptr;
+}
+
+static void free_saved_pages(void)
+{
+ if(save)
+ {
+ int i;
+ for(i=0;i<saved_pages;i++)
+ kfree(save[i]);
+ vfree(save);
+ }
+}
+
+static void free_ibuffer(struct indirect_buffer *ibuf);
+
+/*
+ * Read input file into an indirect buffer
+ */
+static int read_file(char *filename, struct indirect_buffer **indirect_buf)
+{
+ struct file* file;
+ struct inode* inode;
+ struct indirect_buffer *ibuf;
+ size_t size, got, i;
+ mm_segment_t fs;
+ int err;
+
+ file = filp_open(filename, O_RDONLY, 0);
+ if(IS_ERR(file))
+ return PTR_ERR(file);
+
+ err = -EIO;
+ if(!file->f_op || !file->f_op->read)
+ goto out;
+
+ err = -EACCES;
+ inode = file->f_dentry->d_inode;
+ if(!S_ISREG(inode->i_mode))
+ goto out;
+
+ err = -ENOMEM;
+ ibuf = (struct indirect_buffer*)alloc_high_page();
+ if(!ibuf) goto out;
+ memset(ibuf, 0, PAGE_SIZE);
+
+ if(inode->i_size > MAX_INDIRECT_BUFFER_SIZE) goto out2;
+ size = (size_t)inode->i_size;
+ ibuf->size = size;
+
+ for(i=0;i<size;i+=PAGE_SIZE)
+ {
+ size_t todo = min(size-i, (size_t)PAGE_SIZE);
+ void *buf;
+
+ err = -ENOMEM;
+ buf = alloc_high_page();
+ if(!buf) goto out2;
+ ibuf->paddr[i/PAGE_SIZE] = __pa(buf);
+
+ err = -EIO;
+ file->f_pos = i;
+ fs = get_fs();
+ set_fs(KERNEL_DS);
+ got = file->f_op->read(file, buf, todo, &file->f_pos);
+ set_fs(fs);
+ if(got != todo) goto out2;
+ }
+
+ *indirect_buf = ibuf;
+ err = 0;
+
+out:
+ filp_close(file, NULL);
+ return err;
+out2:
+ free_ibuffer(ibuf);
+ goto out;
+}
+
+static void free_ibuffer(struct indirect_buffer *ibuf)
+{
+ int i;
+ for(i=0;ibuf->paddr[i];i++)
+ kfree((void *)__va(ibuf->paddr[i]));
+ kfree(ibuf);
+}
+
+/* convert vmalloc'ed memory to physical address */
+static unsigned long va2pa(void *p)
+{
+ return iopa((unsigned long)p);
+}
+
+static int uloader_notify_reboot (struct notifier_block *this, \
+ unsigned long event, void *x)
+{
+ switch (event) {
+ case SYS_RESTART:
+ break;
+ default:
+ return NOTIFY_DONE;
+ }
+
+ printk(KERN_INFO "uloader module booting u-boot\n");
+
+ load_uboot(va2pa(load_uboot), va2pa(uboot_buf), laddr);
+
+ return NOTIFY_DONE; /* This should never be reached */
+}
+
+int init_module(void)
+{
+ int err;
+
+ printk(KERN_INFO "uloader module loaded\n");
+ printk(KERN_INFO "uboot=%s\n", uboot);
+
+ if((err = read_file(uboot, &uboot_buf)))
+ goto out;
+ register_reboot_notifier(&uloader_notifier);
+ return 0;
+out:
+ free_saved_pages();
+ return err;
+}
+
+void cleanup_module(void)
+{
+ printk(KERN_INFO "uloader module unloaded\n");
+}