Back to home page

LXR

 
 

    


File indexing completed on 2025-05-11 08:23:54

0001 #include <bsp/residual.h>
0002 #include <stdint.h>
0003 
0004 /* Magic knowledge - qemu loads image here. 
0005  * However, we use the value from NVRAM if possible...
0006  */
0007 #define KERNELBASE 0x01000000
0008 
0009 /* When starting qemu make sure to give the correct
0010  * amount of memory!
0011  *
0012  * NOTE: Code now supports reading the actual memory
0013  *       amount from NVRAM. The residual copy in RAM
0014  *       is fixed-up accordingly.
0015  */
0016 #define MEM_MEGS 32
0017 
0018 /* Mock up a minimal/fake residual; just enough to make the
0019  * bootloader happy.
0020  */
0021 struct fake_data {
0022     unsigned long dat_len;
0023     unsigned long res_off;
0024     unsigned long cmd_off;
0025     unsigned long cmd_len;
0026     unsigned long img_adr;
0027     RESIDUAL      fake_residual;
0028     char          cmdline[1024];
0029 } fake_data = {
0030 dat_len: sizeof(fake_data),
0031 res_off: (unsigned long) &fake_data.fake_residual
0032         -(unsigned long) &fake_data,
0033 cmd_off: (unsigned long) &fake_data.cmdline
0034         -(unsigned long) &fake_data,
0035 cmd_len: sizeof(fake_data.cmdline),
0036 img_adr: KERNELBASE,
0037 fake_residual: 
0038 {
0039   ResidualLength: sizeof(RESIDUAL),
0040   Version:          0,
0041   Revision:         0,
0042   EC:               0,
0043   VitalProductData: {
0044     FirmwareSupplier:  QEMU,
0045     ProcessorHz:    300000000, /* fantasy */
0046     ProcessorBusHz: 100000000, /* qemu timebase clock */
0047     TimeBaseDivisor:1*1000,
0048   },
0049   MaxNumCpus:       1,
0050   ActualNumCpus:    1,
0051   Cpus: {
0052     {
0053     CpuType:        0x00040103, /* FIXME: fill from PVR */
0054     CpuNumber:      0,  
0055     CpuState:       0,
0056     },
0057   },
0058   /* Memory */
0059   TotalMemory:      1024*1024*MEM_MEGS,
0060   GoodMemory:       1024*1024*MEM_MEGS,
0061   ActualNumMemSegs: 13,
0062   Segs: {
0063     { 0x2000, 0xFFF00, 0x00100 },
0064     { 0x0020, MEM_MEGS*0x100, 0x80000 - MEM_MEGS*0x100 },
0065     { 0x0008, 0x00800, 0x00168 },
0066     { 0x0004, 0x00000, 0x00005 },
0067     { 0x0001, 0x006F1, 0x0010F },
0068     { 0x0002, 0x006AD, 0x00044 },
0069     { 0x0010, 0x00005, 0x006A8 },
0070     { 0x0010, 0x00968, MEM_MEGS*0x100 - 0x00968 },
0071     { 0x0800, 0xC0000, 0x3F000 },
0072     { 0x0600, 0xBF800, 0x00800 },
0073     { 0x0500, 0x81000, 0x3E800 },
0074     { 0x0480, 0x80800, 0x00800 },
0075     { 0x0440, 0x80000, 0x00800 }  
0076   },
0077   ActualNumMemories: 0,
0078   Memories: {
0079     {0},
0080   },
0081   /* Devices */
0082   ActualNumDevices:  1,
0083   Devices: {
0084     {
0085     DeviceId: {
0086         BusId:     PROCESSORDEVICE,
0087         BaseType:  BridgeController,
0088         SubType:   PCIBridge,
0089         Interface: PCIBridgeIndirect,
0090     },
0091     }
0092   },
0093   DevicePnPHeap: {0}
0094 },
0095 /* This is overwritten by command line passed by qemu. */
0096 cmdline: {
0097     '-','-','n','e','2','k','-','i','r','q','=','9',
0098     0,
0099 }
0100 };
0101 
0102 /* Read one byte from NVRAM */
0103 static inline uint8_t
0104 nvram_rd(void)
0105 {
0106 uint8_t rval = *(volatile uint8_t*)0x80000077;
0107     asm volatile("eieio");
0108     return rval;
0109 }
0110 
0111 /* Set NVRAM address pointer */
0112 static inline void
0113 nvram_addr(uint16_t addr)
0114 {
0115     *(volatile uint8_t*)0x80000074 = (addr & 0xff);
0116     asm volatile("eieio");
0117     *(volatile uint8_t*)0x80000075 = ((addr>>8) & 0xff);
0118     asm volatile("eieio");
0119 }
0120 
0121 /* Read a 32-bit (big-endian) work from NVRAM */
0122 static uint32_t
0123 nvram_rdl_be(uint16_t addr)
0124 {
0125 int i;
0126 uint32_t rval = 0;
0127     for ( i=0; i<sizeof(rval); i++ ) { 
0128         nvram_addr( addr + i );
0129         rval = (rval<<8) | nvram_rd();
0130     }
0131     return rval;
0132 }
0133 
0134 
0135 /* !!! NOTE !!!
0136  *
0137  * We use a special hack to propagate command-line info to the bootloader.
0138  * This is NOT PreP compliant (but who cares).
0139  * We set R6 and R7 to point to the start/end of the command line string
0140  * and hacked the bootloader so it uses R6/R7 (provided that the firmware
0141  * is detected as 'QEMU').
0142  *
0143  * (see bootloader/mm.c, bootloader/misc.c,  bootloader/bootldr.h, -- boot_data.cmd_line[])
0144  */
0145 uint32_t
0146 res_copy(void)
0147 {
0148 struct   fake_data *p;
0149 uint32_t addr, cmdl, l, imga;
0150 uint32_t mem_sz, pgs;
0151 int      i;
0152 int      have_nvram;
0153 
0154     /* Make sure we have a valid NVRAM -- just check for 'QEMU' at the
0155      * beginning 
0156      */
0157     have_nvram = ( (('Q'<<24) | ('E'<<16) | ('M'<< 8) | ('U'<< 0)) == nvram_rdl_be( 0x0000 ) );
0158 
0159     if ( !have_nvram ) {
0160         /* reading NVRAM failed - fall back to using the static residual copy;
0161          * this means no support for variable memory size or 'true' command line.
0162          */
0163         return (uint32_t)&fake_data;
0164     }
0165 
0166     /* Dilemma - we don't really know where to put the residual copy
0167      * (original is in ROM and cannot be modified).
0168      * We can't put it at the top of memory since the bootloader starts
0169      * allocating memory from there, before saving the residual, that is.
0170      * Too close to the final image might not work either because RTEMS
0171      * zeroes its BSS *before* making its copies of the residual and commandline.
0172      *
0173      * For now we hope that appending to the kernel image works (and that
0174      * the bootloader puts it somewhere safe).
0175      */
0176     imga  = nvram_rdl_be( 0x0038 );
0177     addr  = imga + nvram_rdl_be( 0x003c );
0178     addr += 0x1f;
0179     addr &= ~(0x1f);
0180 
0181     p     = (struct fake_data *)addr;
0182 
0183     /* commandline + length from NVRAM */
0184     cmdl  = nvram_rdl_be( 0x0040 );
0185     l     = nvram_rdl_be( 0x0044 );
0186 
0187     if ( l > 0 ) {
0188         /* have a command-line; copy it into our local buffer */
0189         if ( l > sizeof( p->cmdline ) - 1 ) {
0190             l = sizeof( p->cmdline ) - 1;
0191         }
0192         /* original may overlap our buffer; must safely move around */
0193         if ( p->cmdline < (char*)cmdl ) {
0194             for ( i=0; i<l; i++ ) {
0195                 p->cmdline[i] = ((char*)cmdl)[i];
0196             }
0197         } else {
0198             for ( i=l-1; i>=0; i-- ) {
0199                 p->cmdline[i] = ((char*)cmdl)[i];
0200             }
0201         }
0202     }
0203     p->cmdline[l]      = 0;
0204     /* Copy rest of residual */
0205     for ( i=0; i<sizeof(p->fake_residual); i++ )
0206         ((char*)&p->fake_residual)[i] = ((char*)&fake_data.fake_residual)[i];
0207     p->dat_len         = fake_data.dat_len;
0208     p->res_off         = fake_data.res_off;
0209     p->cmd_off         = fake_data.cmd_off;
0210     p->cmd_len         = l+1;
0211     p->img_adr         = imga;
0212 
0213     /* Fix up memory in residual from NVRAM settings */
0214 
0215     mem_sz = nvram_rdl_be( 0x0030 );
0216     pgs    = mem_sz >> 12;
0217 
0218     p->fake_residual.TotalMemory = mem_sz;
0219     p->fake_residual.GoodMemory  = mem_sz;
0220 
0221     p->fake_residual.Segs[1].BasePage  = pgs;
0222     p->fake_residual.Segs[1].PageCount = 0x80000 - pgs;
0223     p->fake_residual.Segs[7].PageCount = pgs - 0x00968;
0224 
0225     return (uint32_t)p;
0226 }