Back to home page

LXR

 
 

    


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

0001 /*
0002  *  head.S -- Bootloader Entry point
0003  *
0004  *  Copyright (C) 1998, 1999 Gabriel Paubert, paubert@iram.es
0005  *
0006  *  Modified to compile in RTEMS development environment
0007  *  by Eric Valette
0008  *
0009  *  Copyright (C) 1999 Eric Valette. valette@crf.canon.fr
0010  *
0011  *  The license and distribution terms for this file may be
0012  *  found in the file LICENSE in this distribution or at
0013  *  http://www.rtems.org/license/LICENSE.
0014  */
0015 
0016 #include <sys/param.h>
0017 #include <sys/types.h>
0018 #include <string.h>
0019 #include "bootldr.h"
0020 #include <libcpu/spr.h>
0021 #include "zlib.h"
0022 #include <libcpu/byteorder.h>
0023 #include <rtems/bspIo.h>
0024 #include <bsp.h>
0025 
0026 #include <rtems.h>
0027 
0028 /* to align the pointer to the (next) page boundary */
0029 #define PAGE_ALIGN(addr)    (((addr) + PAGE_MASK) & ~PAGE_MASK)
0030 
0031 SPR_RO(PPC_PVR)
0032 
0033 struct inode;
0034 struct wait_queue;
0035 struct buffer_head;
0036 typedef struct { int counter; } atomic_t;
0037 
0038 typedef struct page {
0039     /* these must be first (free area handling) */
0040     struct page *next;
0041     struct page *prev;
0042     struct inode *inode;
0043     unsigned long offset;
0044     struct page *next_hash;
0045     atomic_t count;
0046     unsigned long flags;    /* atomic flags, some possibly updated asynchronously */
0047     struct wait_queue *wait;
0048     struct page **pprev_hash;
0049     struct buffer_head * buffers;
0050 } mem_map_t;
0051 
0052 extern opaque mm_private, pci_private, v86_private, console_private;
0053 
0054 #define CONSOLE_ON_SERIAL   "console=ttyS0"
0055 
0056 extern struct console_io vacuum_console_functions;
0057 extern opaque log_console_setup, serial_console_setup, vga_console_setup;
0058 
0059 boot_data __bd = {0, 0, 0, 0, 0, 0, 0, 0,
0060           32, 0, 0, 0, 0, 0, 0,
0061           &mm_private,
0062           NULL,
0063           &pci_private,
0064           NULL,
0065           &v86_private,
0066           "root=/dev/hdc1"
0067          };
0068 
0069 static void exit(void) __attribute__((noreturn));
0070 
0071 static void exit(void) {
0072     printk("\nOnly way out is to press the reset button!\n");
0073     asm volatile("": : :"memory");
0074     while(1);
0075 }
0076 
0077 void hang(const char *s, u_long x, ctxt *p) {
0078     u_long *r1;
0079 #ifdef DEBUG
0080     print_all_maps("\nMemory mappings at exception time:\n");
0081 #endif
0082     printk("%s %lx NIP: %p LR: %p\n"
0083            "Callback trace (stack:return address)\n",
0084            s, x, (void *) p->nip, (void *) p->lr);
0085     asm volatile("lwz %0,0(1); lwz %0,0(%0); lwz %0,0(%0)": "=b" (r1));
0086     while(r1) {
0087         printk("  %p:%p\n", r1, (void *) r1[1]);
0088         r1 = (u_long *) *r1;
0089     }
0090     exit();
0091 };
0092 
0093 static void *zalloc(void *x, unsigned items, unsigned size)
0094 {
0095     void *p = salloc(items*size);
0096 
0097     if (!p) {
0098         printk("oops... not enough memory for gunzip\n");
0099     }
0100     return p;
0101 }
0102 
0103 static void zfree(void *x, void *addr, unsigned nb)
0104 {
0105     sfree(addr);
0106 }
0107 
0108 #define HEAD_CRC    2
0109 #define EXTRA_FIELD 4
0110 #define ORIG_NAME   8
0111 #define COMMENT     0x10
0112 #define RESERVED    0xe0
0113 
0114 #define DEFLATED    8
0115 
0116 void gunzip(void *dst, int dstlen, unsigned char *src, int *lenp)
0117 {
0118     z_stream s;
0119     int r, i, flags;
0120 
0121     /* skip header */
0122     i = 10;
0123     flags = src[3];
0124     if (src[2] != DEFLATED || (flags & RESERVED) != 0) {
0125         printk("bad gzipped data\n");
0126         exit();
0127     }
0128     if ((flags & EXTRA_FIELD) != 0)
0129         i = 12 + src[10] + (src[11] << 8);
0130     if ((flags & ORIG_NAME) != 0)
0131         while (src[i++] != 0)
0132             ;
0133     if ((flags & COMMENT) != 0)
0134         while (src[i++] != 0)
0135             ;
0136     if ((flags & HEAD_CRC) != 0)
0137         i += 2;
0138     if (i >= *lenp) {
0139         printk("gunzip: ran out of data in header\n");
0140         exit();
0141     }
0142 
0143     s.zalloc = zalloc;
0144     s.zfree = zfree;
0145     r = inflateInit2(&s, -MAX_WBITS);
0146     if (r != Z_OK) {
0147         printk("inflateInit2 returned %d\n", r);
0148         exit();
0149     }
0150     s.next_in = src + i;
0151     s.avail_in = *lenp - i;
0152     s.next_out = dst;
0153     s.avail_out = dstlen;
0154     r = inflate(&s, Z_FINISH);
0155     if (r != Z_OK && r != Z_STREAM_END) {
0156         printk("inflate returned %d\n", r);
0157         exit();
0158     }
0159     *lenp = s.next_out - (unsigned char *) dst;
0160     inflateEnd(&s);
0161 }
0162 
0163 void decompress_kernel(int kernel_size, void * zimage_start, int len,
0164                void * initrd_start, int initrd_len ) {
0165     u_char *parea;
0166     RESIDUAL* rescopy;
0167     int zimage_size= len;
0168 
0169     /* That's a mess, we have to copy the residual data twice just in
0170      * case it happens to be in the low memory area where the kernel
0171      * is going to be unpacked. Later we have to copy it back to
0172      * lower addresses because only the lowest part of memory is mapped
0173      * during boot.
0174      */
0175     parea=__palloc(kernel_size, PA_LOW);
0176     if(!parea) {
0177         printk("Not enough memory to uncompress the kernel.");
0178         exit();
0179     }
0180 
0181     rescopy=salloc(sizeof(RESIDUAL));
0182     /* Let us hope that residual data is aligned on word boundary */
0183     *rescopy =  *bd->residual;
0184     bd->residual = (void *)PAGE_ALIGN(kernel_size);
0185 
0186     /* Note that this clears the bss as a side effect, so some code
0187      * with ugly special case for SMP could be removed from the kernel!
0188      */
0189     memset(parea, 0, kernel_size);
0190     printk("\nUncompressing the kernel...\n");
0191 
0192     gunzip(parea, kernel_size, zimage_start, &zimage_size);
0193 
0194     bd->of_entry = 0;
0195     bd->load_address = 0;
0196     bd->r6 = (char *)bd->residual+PAGE_ALIGN(sizeof(RESIDUAL));
0197     bd->r7 = bd->r6+strlen(bd->cmd_line);
0198     if ( initrd_len ) {
0199         /* We have to leave some room for the hash table and for the
0200          * whole array of struct page. The hash table would be better
0201          * located at the end of memory if possible. With some bridges
0202          * DMA from the last pages of memory is slower because
0203          * prefetching from PCI has to be disabled to avoid accessing
0204          * non existing memory. So it is the ideal place to put the
0205          * hash table.
0206          */
0207             unsigned tmp = rescopy->TotalMemory;
0208         /* It's equivalent to tmp & (-tmp), but using the negation
0209          * operator on unsigned variables looks so ugly.
0210          */
0211         if ((tmp & (~tmp+1)) != tmp) tmp <<= 1; /* Next power of 2 */
0212         tmp /= 256; /* Size of hash table */
0213         if (tmp> (2<<20)) tmp=2<<20;
0214         tmp = tmp*2 + 0x40000; /* Alignment can double size + 256 kB */
0215         tmp += (rescopy->TotalMemory / PAGE_SIZE)
0216                    * sizeof(struct page);
0217         bd->load_address = (void *)PAGE_ALIGN((int)bd->r7 + tmp);
0218         bd->of_entry = (char *)bd->load_address+initrd_len;
0219     }
0220 #ifdef DEBUG
0221     printk("Kernel at 0x%p, size=0x%x\n", NULL, kernel_size);
0222     printk("Initrd at 0x%p, size=0x%x\n",bd->load_address, initrd_len);
0223     printk("Residual data at 0x%p\n", bd->residual);
0224     printk("Command line at 0x%p\n",bd->r6);
0225 #endif
0226     printk("done\nNow booting...\n");
0227     MMUoff();   /* We need to access address 0 ! */
0228     codemove(0, parea, kernel_size, bd->cache_lsize);
0229     codemove(bd->residual, rescopy, sizeof(RESIDUAL), bd->cache_lsize);
0230     codemove(bd->r6, bd->cmd_line, sizeof(bd->cmd_line), bd->cache_lsize);
0231     /* codemove checks for 0 length */
0232     codemove(bd->load_address, initrd_start, initrd_len, bd->cache_lsize);
0233 }
0234 
0235 static int ticks_per_ms=0;
0236 
0237 /*
0238  * This is based on rtems_bsp_delay from libcpu
0239  */
0240 void
0241 boot_udelay(uint32_t _microseconds)
0242 {
0243    uint32_t   start, ticks, now;
0244 
0245    ticks = _microseconds * ticks_per_ms / 1000;
0246    CPU_Get_timebase_low( start );
0247    do {
0248      CPU_Get_timebase_low( now );
0249    } while (now - start < ticks);
0250 }
0251 
0252 void
0253 setup_hw(void)
0254 {
0255     char *cp, ch;
0256     register RESIDUAL * res;
0257     /* PPC_DEVICE * nvram; */
0258     struct pci_dev *default_vga;
0259     int timer, err;
0260     u_short default_vga_cmd;
0261 
0262     res=bd->residual;
0263     default_vga=NULL;
0264     default_vga_cmd = 0;
0265 
0266 #define vpd res->VitalProductData
0267     if (_read_PPC_PVR()>>16 != 1) {
0268         if ( res && vpd.ProcessorBusHz ) {
0269             ticks_per_ms = vpd.ProcessorBusHz/
0270                 (vpd.TimeBaseDivisor ? vpd.TimeBaseDivisor : 4000);
0271         } else {
0272             ticks_per_ms = 16500; /* assume 66 MHz on bus */
0273         }
0274     }
0275 
0276     select_console(CONSOLE_LOG);
0277 
0278     /* We check that the keyboard is present and immediately
0279      * select the serial console if not.
0280      */
0281 #if defined(BSP_KBD_IOBASE)
0282     err = kbdreset();
0283         if (err) select_console(CONSOLE_SERIAL);
0284 #else
0285     err = 1;
0286     select_console(CONSOLE_SERIAL);
0287 #endif
0288 
0289     printk("\nModel: %s\nSerial: %s\n"
0290            "Processor/Bus frequencies (Hz): %ld/%ld\n"
0291            "Time Base Divisor: %ld\n"
0292            "Memory Size: %lx\n"
0293            "Residual: %lx (length %lu)\n",
0294            vpd.PrintableModel,
0295            vpd.Serial,
0296            vpd.ProcessorHz,
0297                vpd.ProcessorBusHz,
0298            (vpd.TimeBaseDivisor ? vpd.TimeBaseDivisor : 4000),
0299            res->TotalMemory,
0300            (unsigned long)res,
0301            res->ResidualLength);
0302 
0303     /* This reconfigures all the PCI subsystem */
0304         pci_init();
0305 
0306     /* The Motorola NT firmware does not set the correct mem size */
0307     if ( vpd.FirmwareSupplier == 0x10000 ) {
0308         int memsize;
0309         memsize = find_max_mem(bd->pci_devices);
0310         if ( memsize != res->TotalMemory ) {
0311             printk("Changed Memory size from %lx to %x\n",
0312                 res->TotalMemory, memsize);
0313             res->TotalMemory = memsize;
0314             res->GoodMemory = memsize;
0315         }
0316     }
0317 #define ENABLE_VGA_USAGE
0318 #undef ENABLE_VGA_USAGE
0319 #ifdef ENABLE_VGA_USAGE
0320     /* Find the primary VGA device, chosing the first one found
0321      * if none is enabled. The basic loop structure has been copied
0322      * from linux/drivers/char/bttv.c by Alan Cox.
0323      */
0324     for (p = bd->pci_devices; p; p = p->next) {
0325         u_short cmd;
0326         if (p->class != PCI_CLASS_NOT_DEFINED_VGA &&
0327             ((p->class) >> 16 != PCI_BASE_CLASS_DISPLAY))
0328             continue;
0329         if (p->bus->number != 0) {
0330             printk("VGA device not on bus 0 not initialized!\n");
0331             continue;
0332         }
0333         /* Only one can be active in text mode, which for now will
0334          * be assumed as equivalent to having I/O response enabled.
0335          */
0336         pci_bootloader_read_config_word(p, PCI_COMMAND, &cmd);
0337         if(cmd & PCI_COMMAND_IO || !default_vga) {
0338             default_vga=p;
0339             default_vga_cmd=cmd;
0340         }
0341     }
0342 
0343     /* Disable the enabled VGA device, if any. */
0344     if (default_vga)
0345         pci_bootloader_write_config_word(default_vga, PCI_COMMAND,
0346                       default_vga_cmd&
0347                       ~(PCI_COMMAND_IO|PCI_COMMAND_MEMORY));
0348     init_v86();
0349     /* Same loop copied from bttv.c, this time doing the serious work */
0350     for (p = bd->pci_devices; p; p = p->next) {
0351         u_short cmd;
0352         if (p->class != PCI_CLASS_NOT_DEFINED_VGA &&
0353             ((p->class) >> 16 != PCI_BASE_CLASS_DISPLAY))
0354             continue;
0355         if (p->bus->number != 0) continue;
0356         pci_bootloader_read_config_word(p, PCI_COMMAND, &cmd);
0357         pci_bootloader_write_config_word(p, PCI_COMMAND,
0358                       cmd|PCI_COMMAND_IO|PCI_COMMAND_MEMORY);
0359         printk("Calling the emulator.\n");
0360         em86_main(p);
0361         pci_bootloader_write_config_word(p, PCI_COMMAND, cmd);
0362     }
0363 
0364     cleanup_v86_mess();
0365 #endif
0366     /* Reenable the primary VGA device */
0367     if (default_vga) {
0368         pci_bootloader_write_config_word(default_vga, PCI_COMMAND,
0369                       default_vga_cmd|
0370                       (PCI_COMMAND_IO|PCI_COMMAND_MEMORY));
0371         if (err) {
0372             printk("Keyboard error %d, using serial console!\n",
0373                    err);
0374         } else {
0375             select_console(CONSOLE_VGA);
0376         }
0377     } else if (!err) {
0378         select_console(CONSOLE_SERIAL);
0379         if (bd->cmd_line[0] == '\0') {
0380           strcat(&bd->cmd_line[0], CONSOLE_ON_SERIAL);
0381         }
0382         else {
0383           int s = strlen (bd->cmd_line);
0384           bd->cmd_line[s + 1] = ' ';
0385           bd->cmd_line[s + 2] = '\0';
0386           strcat(&bd->cmd_line[0], CONSOLE_ON_SERIAL);
0387         }
0388     }
0389 #if 0
0390     /* In the future we may use the NVRAM to store default
0391      * kernel parameters.
0392      */
0393     nvram=residual_find_device(~0UL, NULL, SystemPeripheral, NVRAM,
0394                    ~0UL, 0);
0395     if (nvram) {
0396         PnP_TAG_PACKET * pkt;
0397         switch (nvram->DevId.Interface) {
0398         case IndirectNVRAM:
0399               pkt=PnP_find_packet(res->DevicePnpHeap
0400                       +nvram->AllocatedOffset,
0401                           )
0402         }
0403     }
0404 #endif
0405 
0406     printk("\nRTEMS " RTEMS_VERSION "/PPC load: ");
0407     timer = 0;
0408     cp = bd->cmd_line+strlen(bd->cmd_line);
0409     while (timer++ < 5*1000) {
0410         if (debug_tstc()) {
0411             while ((ch = debug_getc()) != '\n' && ch != '\r') {
0412                 if (ch == '\b' || ch == 0177) {
0413                     if (cp != bd->cmd_line) {
0414                         cp--;
0415                         printk("\b \b");
0416                     }
0417                 } else {
0418                     *cp++ = ch;
0419                     debug_putc(ch);
0420                 }
0421             }
0422             break;  /* Exit 'timer' loop */
0423         }
0424         boot_udelay(1000);  /* 1 msec */
0425     }
0426     *cp = 0;
0427 }
0428 
0429 /* Functions to deal with the residual data */
0430 static int same_DevID(unsigned short vendor,
0431            unsigned short Number,
0432            unsigned char * str)
0433 {
0434     static unsigned const char hexdigit[]="0123456789ABCDEF";
0435     if (strlen((char*)str)!=7) return 0;
0436     if ( ( ((vendor>>10)&0x1f)+'A'-1 == str[0])  &&
0437          ( ((vendor>>5)&0x1f)+'A'-1 == str[1])   &&
0438          ( (vendor&0x1f)+'A'-1 == str[2])        &&
0439          (hexdigit[(Number>>12)&0x0f] == str[3]) &&
0440          (hexdigit[(Number>>8)&0x0f] == str[4])  &&
0441          (hexdigit[(Number>>4)&0x0f] == str[5])  &&
0442          (hexdigit[Number&0x0f] == str[6]) ) return 1;
0443     return 0;
0444 }
0445 
0446 PPC_DEVICE *residual_find_device(unsigned long BusMask,
0447              unsigned char * DevID,
0448              int BaseType,
0449              int SubType,
0450              int Interface,
0451              int n)
0452 {
0453     int i;
0454     RESIDUAL *res = bd->residual;
0455     if ( !res || !res->ResidualLength ) return NULL;
0456     for (i=0; i<res->ActualNumDevices; i++) {
0457 #define Dev res->Devices[i].DeviceId
0458         if ( (Dev.BusId&BusMask)                                  &&
0459              (BaseType==-1 || Dev.BaseType==BaseType)             &&
0460              (SubType==-1 || Dev.SubType==SubType)                &&
0461              (Interface==-1 || Dev.Interface==Interface)          &&
0462              (DevID==NULL || same_DevID((Dev.DevId>>16)&0xffff,
0463                         Dev.DevId&0xffff, DevID)) &&
0464              !(n--) ) return res->Devices+i;
0465 #undef Dev
0466     }
0467     return 0;
0468 }
0469 
0470 PnP_TAG_PACKET *PnP_find_packet(unsigned char *p,
0471                 unsigned packet_tag,
0472                 int n)
0473 {
0474     unsigned mask, masked_tag, size;
0475     if(!p) return 0;
0476     if (tag_type(packet_tag)) mask=0xff; else mask=0xF8;
0477     masked_tag = packet_tag&mask;
0478     for(; *p != END_TAG; p+=size) {
0479         if ((*p & mask) == masked_tag && !(n--))
0480             return (PnP_TAG_PACKET *) p;
0481         if (tag_type(*p))
0482             size=ld_le16((unsigned short *)(p+1))+3;
0483         else
0484             size=tag_small_count(*p)+1;
0485     }
0486     return 0; /* not found */
0487 }
0488 
0489 PnP_TAG_PACKET *PnP_find_small_vendor_packet(unsigned char *p,
0490                          unsigned packet_type,
0491                          int n)
0492 {
0493     int next=0;
0494     while (p) {
0495         p = (unsigned char *) PnP_find_packet(p, 0x70, next);
0496         if (p && p[1]==packet_type && !(n--))
0497             return (PnP_TAG_PACKET *) p;
0498         next = 1;
0499     };
0500     return 0; /* not found */
0501 }
0502 
0503 PnP_TAG_PACKET *PnP_find_large_vendor_packet(unsigned char *p,
0504                        unsigned packet_type,
0505                        int n)
0506 {
0507     int next=0;
0508     while (p) {
0509         p = (unsigned char *) PnP_find_packet(p, 0x84, next);
0510         if (p && p[3]==packet_type && !(n--))
0511             return (PnP_TAG_PACKET *) p;
0512         next = 1;
0513     };
0514     return 0; /* not found */
0515 }
0516 
0517 /* Find out the amount of installed memory. For MPC105 and IBM 660 this
0518  * can be done by finding the bank with the highest memory ending address
0519  */
0520 int
0521 find_max_mem( struct pci_dev *dev )
0522 {
0523     u_char banks,tmp;
0524     int i, top, max;
0525 
0526     max = 0;
0527     for ( ; dev; dev = dev->next) {
0528         if ( ((dev->vendor == PCI_VENDOR_ID_MOTOROLA) &&
0529               (dev->device == PCI_DEVICE_ID_MOTOROLA_MPC105)) ||
0530              ((dev->vendor == PCI_VENDOR_ID_IBM) &&
0531               (dev->device == 0x0037/*IBM 660 Bridge*/)) ) {
0532             pci_bootloader_read_config_byte(dev, 0xa0, &banks);
0533             for (i = 0; i < 8; i++) {
0534                 if ( banks & (1<<i) ) {
0535                     pci_bootloader_read_config_byte(dev, 0x90+i, &tmp);
0536                     top = tmp;
0537                     pci_bootloader_read_config_byte(dev, 0x98+i, &tmp);
0538                     top |= (tmp&3)<<8;
0539                     if ( top > max ) max = top;
0540                 }
0541             }
0542             if ( max ) return ((max+1)<<20);
0543             else return(0);
0544         }
0545     }
0546     return(0);
0547 }