summaryrefslogtreecommitdiffstats
path: root/bsps/powerpc/motorola_powerpc/bootloader/qemu_fakeres.c
diff options
context:
space:
mode:
Diffstat (limited to 'bsps/powerpc/motorola_powerpc/bootloader/qemu_fakeres.c')
-rw-r--r--bsps/powerpc/motorola_powerpc/bootloader/qemu_fakeres.c226
1 files changed, 226 insertions, 0 deletions
diff --git a/bsps/powerpc/motorola_powerpc/bootloader/qemu_fakeres.c b/bsps/powerpc/motorola_powerpc/bootloader/qemu_fakeres.c
new file mode 100644
index 0000000000..51f03a070f
--- /dev/null
+++ b/bsps/powerpc/motorola_powerpc/bootloader/qemu_fakeres.c
@@ -0,0 +1,226 @@
+#include <bsp/residual.h>
+#include <stdint.h>
+
+/* Magic knowledge - qemu loads image here.
+ * However, we use the value from NVRAM if possible...
+ */
+#define KERNELBASE 0x01000000
+
+/* When starting qemu make sure to give the correct
+ * amount of memory!
+ *
+ * NOTE: Code now supports reading the actual memory
+ * amount from NVRAM. The residual copy in RAM
+ * is fixed-up accordingly.
+ */
+#define MEM_MEGS 32
+
+/* Mock up a minimal/fake residual; just enough to make the
+ * bootloader happy.
+ */
+struct fake_data {
+ unsigned long dat_len;
+ unsigned long res_off;
+ unsigned long cmd_off;
+ unsigned long cmd_len;
+ unsigned long img_adr;
+ RESIDUAL fake_residual;
+ char cmdline[1024];
+} fake_data = {
+dat_len: sizeof(fake_data),
+res_off: (unsigned long) &fake_data.fake_residual
+ -(unsigned long) &fake_data,
+cmd_off: (unsigned long) &fake_data.cmdline
+ -(unsigned long) &fake_data,
+cmd_len: sizeof(fake_data.cmdline),
+img_adr: KERNELBASE,
+fake_residual:
+{
+ ResidualLength: sizeof(RESIDUAL),
+ Version: 0,
+ Revision: 0,
+ EC: 0,
+ VitalProductData: {
+ FirmwareSupplier: QEMU,
+ ProcessorHz: 300000000, /* fantasy */
+ ProcessorBusHz: 100000000, /* qemu timebase clock */
+ TimeBaseDivisor:1*1000,
+ },
+ MaxNumCpus: 1,
+ ActualNumCpus: 1,
+ Cpus: {
+ {
+ CpuType: 0x00040103, /* FIXME: fill from PVR */
+ CpuNumber: 0,
+ CpuState: 0,
+ },
+ },
+ /* Memory */
+ TotalMemory: 1024*1024*MEM_MEGS,
+ GoodMemory: 1024*1024*MEM_MEGS,
+ ActualNumMemSegs: 13,
+ Segs: {
+ { 0x2000, 0xFFF00, 0x00100 },
+ { 0x0020, MEM_MEGS*0x100, 0x80000 - MEM_MEGS*0x100 },
+ { 0x0008, 0x00800, 0x00168 },
+ { 0x0004, 0x00000, 0x00005 },
+ { 0x0001, 0x006F1, 0x0010F },
+ { 0x0002, 0x006AD, 0x00044 },
+ { 0x0010, 0x00005, 0x006A8 },
+ { 0x0010, 0x00968, MEM_MEGS*0x100 - 0x00968 },
+ { 0x0800, 0xC0000, 0x3F000 },
+ { 0x0600, 0xBF800, 0x00800 },
+ { 0x0500, 0x81000, 0x3E800 },
+ { 0x0480, 0x80800, 0x00800 },
+ { 0x0440, 0x80000, 0x00800 }
+ },
+ ActualNumMemories: 0,
+ Memories: {
+ {0},
+ },
+ /* Devices */
+ ActualNumDevices: 1,
+ Devices: {
+ {
+ DeviceId: {
+ BusId: PROCESSORDEVICE,
+ BaseType: BridgeController,
+ SubType: PCIBridge,
+ Interface: PCIBridgeIndirect,
+ },
+ }
+ },
+ DevicePnPHeap: {0}
+},
+/* This is overwritten by command line passed by qemu. */
+cmdline: {
+ '-','-','n','e','2','k','-','i','r','q','=','9',
+ 0,
+}
+};
+
+/* Read one byte from NVRAM */
+static inline uint8_t
+nvram_rd(void)
+{
+uint8_t rval = *(volatile uint8_t*)0x80000077;
+ asm volatile("eieio");
+ return rval;
+}
+
+/* Set NVRAM address pointer */
+static inline void
+nvram_addr(uint16_t addr)
+{
+ *(volatile uint8_t*)0x80000074 = (addr & 0xff);
+ asm volatile("eieio");
+ *(volatile uint8_t*)0x80000075 = ((addr>>8) & 0xff);
+ asm volatile("eieio");
+}
+
+/* Read a 32-bit (big-endian) work from NVRAM */
+static uint32_t
+nvram_rdl_be(uint16_t addr)
+{
+int i;
+uint32_t rval = 0;
+ for ( i=0; i<sizeof(rval); i++ ) {
+ nvram_addr( addr + i );
+ rval = (rval<<8) | nvram_rd();
+ }
+ return rval;
+}
+
+
+/* !!! NOTE !!!
+ *
+ * We use a special hack to propagate command-line info to the bootloader.
+ * This is NOT PreP compliant (but who cares).
+ * We set R6 and R7 to point to the start/end of the command line string
+ * and hacked the bootloader so it uses R6/R7 (provided that the firmware
+ * is detected as 'QEMU').
+ *
+ * (see bootloader/mm.c, bootloader/misc.c, bootloader/bootldr.h, -- boot_data.cmd_line[])
+ */
+uint32_t
+res_copy(void)
+{
+struct fake_data *p;
+uint32_t addr, cmdl, l, imga;
+uint32_t mem_sz, pgs;
+int i;
+int have_nvram;
+
+ /* Make sure we have a valid NVRAM -- just check for 'QEMU' at the
+ * beginning
+ */
+ have_nvram = ( (('Q'<<24) | ('E'<<16) | ('M'<< 8) | ('U'<< 0)) == nvram_rdl_be( 0x0000 ) );
+
+ if ( !have_nvram ) {
+ /* reading NVRAM failed - fall back to using the static residual copy;
+ * this means no support for variable memory size or 'true' command line.
+ */
+ return (uint32_t)&fake_data;
+ }
+
+ /* Dilemma - we don't really know where to put the residual copy
+ * (original is in ROM and cannot be modified).
+ * We can't put it at the top of memory since the bootloader starts
+ * allocating memory from there, before saving the residual, that is.
+ * Too close to the final image might not work either because RTEMS
+ * zeroes its BSS *before* making its copies of the residual and commandline.
+ *
+ * For now we hope that appending to the kernel image works (and that
+ * the bootloader puts it somewhere safe).
+ */
+ imga = nvram_rdl_be( 0x0038 );
+ addr = imga + nvram_rdl_be( 0x003c );
+ addr += 0x1f;
+ addr &= ~(0x1f);
+
+ p = (struct fake_data *)addr;
+
+ /* commandline + length from NVRAM */
+ cmdl = nvram_rdl_be( 0x0040 );
+ l = nvram_rdl_be( 0x0044 );
+
+ if ( l > 0 ) {
+ /* have a command-line; copy it into our local buffer */
+ if ( l > sizeof( p->cmdline ) - 1 ) {
+ l = sizeof( p->cmdline ) - 1;
+ }
+ /* original may overlap our buffer; must safely move around */
+ if ( p->cmdline < (char*)cmdl ) {
+ for ( i=0; i<l; i++ ) {
+ p->cmdline[i] = ((char*)cmdl)[i];
+ }
+ } else {
+ for ( i=l-1; i>=0; i-- ) {
+ p->cmdline[i] = ((char*)cmdl)[i];
+ }
+ }
+ }
+ p->cmdline[l] = 0;
+ /* Copy rest of residual */
+ for ( i=0; i<sizeof(p->fake_residual); i++ )
+ ((char*)&p->fake_residual)[i] = ((char*)&fake_data.fake_residual)[i];
+ p->dat_len = fake_data.dat_len;
+ p->res_off = fake_data.res_off;
+ p->cmd_off = fake_data.cmd_off;
+ p->cmd_len = l+1;
+ p->img_adr = imga;
+
+ /* Fix up memory in residual from NVRAM settings */
+
+ mem_sz = nvram_rdl_be( 0x0030 );
+ pgs = mem_sz >> 12;
+
+ p->fake_residual.TotalMemory = mem_sz;
+ p->fake_residual.GoodMemory = mem_sz;
+
+ p->fake_residual.Segs[1].BasePage = pgs;
+ p->fake_residual.Segs[1].PageCount = 0x80000 - pgs;
+ p->fake_residual.Segs[7].PageCount = pgs - 0x00968;
+
+ return (uint32_t)p;
+}