source: rtems/c/src/lib/libbsp/powerpc/shared/bootloader/misc.c @ e79a1947

4.104.114.84.95
Last change on this file since e79a1947 was e79a1947, checked in by Joel Sherrill <joel.sherrill@…>, on 11/10/04 at 23:51:17

2004-11-10 Richard Campbell <richard.campbell@…>

  • Makefile.am, bootloader/misc.c, bootloader/pci.c, bootloader/pci.h, console/console.c, console/inch.c, console/reboot.c, console/uart.c, console/uart.h, irq/irq.c, irq/irq.h, irq/irq_init.c, motorola/motorola.c, motorola/motorola.h, openpic/openpic.c, openpic/openpic.h, pci/detect_raven_bridge.c, pci/pci.c, start/start.S, startup/bspstart.c, vectors/vectors_init.c, vme/vmeconfig.c: Add MVME2100 BSP and MPC8240 support. There was also a significant amount of spelling and whitespace cleanup.
  • tod/todcfg.c: New file.
  • Property mode set to 100644
File size: 14.1 KB
Line 
1/*
2 *  head.S -- Bootloader Entry point
3 *
4 *  Copyright (C) 1998, 1999 Gabriel Paubert, paubert@iram.es
5 *
6 *  Modified to compile in RTEMS development environment
7 *  by Eric Valette
8 *
9 *  Copyright (C) 1999 Eric Valette. valette@crf.canon.fr
10 *
11 *  The license and distribution terms for this file may be
12 *  found in found in the file LICENSE in this distribution or at
13 *  http://www.rtems.com/license/LICENSE.
14 *
15 * $Id$
16 */
17
18#include <rtems/system.h>
19#include <sys/types.h>
20#include <string.h>
21#include "bootldr.h"
22#include <libcpu/spr.h>
23#include "zlib.h"
24#include <libcpu/page.h>
25#include <libcpu/byteorder.h>
26#include <rtems/bspIo.h>
27#include <bsp.h>
28
29SPR_RW(DEC)
30SPR_RO(PVR)
31
32struct inode;
33struct wait_queue;
34struct buffer_head;
35typedef struct { int counter; } atomic_t;
36
37typedef struct page {
38        /* these must be first (free area handling) */
39        struct page *next;
40        struct page *prev;
41        struct inode *inode;
42        unsigned long offset;
43        struct page *next_hash;
44        atomic_t count;
45        unsigned long flags;    /* atomic flags, some possibly updated asynchronously */
46        struct wait_queue *wait;
47        struct page **pprev_hash;
48        struct buffer_head * buffers;
49} mem_map_t;
50
51extern opaque mm_private, pci_private, v86_private, console_private;
52
53#define CONSOLE_ON_SERIAL       "console=ttyS0"
54
55extern struct console_io vacuum_console_functions;
56extern opaque log_console_setup, serial_console_setup, vga_console_setup;
57
58boot_data __bd = {0, 0, 0, 0, 0, 0, 0, 0,
59                  32, 0, 0, 0, 0, 0, 0,
60                  &mm_private,
61                  NULL,
62                  &pci_private,
63                  NULL,
64                  &v86_private,
65                  "root=/dev/hdc1"
66                 };
67
68static void exit(void) __attribute__((noreturn));
69
70static void exit(void) {
71        printk("\nOnly way out is to press the reset button!\n");
72        asm volatile("": : :"memory");
73        while(1);
74}
75
76void hang(const char *s, u_long x, ctxt *p) {
77        u_long *r1;
78#ifdef DEBUG
79        print_all_maps("\nMemory mappings at exception time:\n");
80#endif
81        printk("%s %lx NIP: %p LR: %p\n"
82               "Callback trace (stack:return address)\n",
83               s, x, (void *) p->nip, (void *) p->lr);
84        asm volatile("lwz %0,0(1); lwz %0,0(%0); lwz %0,0(%0)": "=b" (r1));
85        while(r1) {
86                printk("  %p:%p\n", r1, (void *) r1[1]);
87                r1 = (u_long *) *r1;
88        }
89        exit();
90};
91
92void *zalloc(void *x, unsigned items, unsigned size)
93{
94        void *p = salloc(items*size);
95
96        if (!p) {
97                printk("oops... not enough memory for gunzip\n");
98        }
99        return p;
100}
101
102void zfree(void *x, void *addr, unsigned nb)
103{
104        sfree(addr);
105}
106
107#define HEAD_CRC        2
108#define EXTRA_FIELD     4
109#define ORIG_NAME       8
110#define COMMENT         0x10
111#define RESERVED        0xe0
112
113#define DEFLATED        8
114
115void gunzip(void *dst, int dstlen, unsigned char *src, int *lenp)
116{
117        z_stream s;
118        int r, i, flags;
119
120        /* skip header */
121        i = 10;
122        flags = src[3];
123        if (src[2] != DEFLATED || (flags & RESERVED) != 0) {
124                printk("bad gzipped data\n");
125                exit();
126        }
127        if ((flags & EXTRA_FIELD) != 0)
128                i = 12 + src[10] + (src[11] << 8);
129        if ((flags & ORIG_NAME) != 0)
130                while (src[i++] != 0)
131                        ;
132        if ((flags & COMMENT) != 0)
133                while (src[i++] != 0)
134                        ;
135        if ((flags & HEAD_CRC) != 0)
136                i += 2;
137        if (i >= *lenp) {
138                printk("gunzip: ran out of data in header\n");
139                exit();
140        }
141
142        s.zalloc = zalloc;
143        s.zfree = zfree;
144        r = inflateInit2(&s, -MAX_WBITS);
145        if (r != Z_OK) {
146                printk("inflateInit2 returned %d\n", r);
147                exit();
148        }
149        s.next_in = src + i;
150        s.avail_in = *lenp - i;
151        s.next_out = dst;
152        s.avail_out = dstlen;
153        r = inflate(&s, Z_FINISH);
154        if (r != Z_OK && r != Z_STREAM_END) {
155                printk("inflate returned %d\n", r);
156                exit();
157        }
158        *lenp = s.next_out - (unsigned char *) dst;
159        inflateEnd(&s);
160}
161
162void decompress_kernel(int kernel_size, void * zimage_start, int len,
163                       void * initrd_start, int initrd_len ) {
164        u_char *parea;
165        RESIDUAL* rescopy;
166        int zimage_size= len;
167
168        /* That's a mess, we have to copy the residual data twice just in
169         * case it happens to be in the low memory area where the kernel
170         * is going to be unpacked. Later we have to copy it back to
171         * lower addresses because only the lowest part of memory is mapped
172         * during boot.
173         */
174        parea=__palloc(kernel_size, PA_LOW);
175        if(!parea) {
176                printk("Not enough memory to uncompress the kernel.");
177                exit();
178        }
179        /* Note that this clears the bss as a side effect, so some code
180         * with ugly special case for SMP could be removed from the kernel!
181         */
182        memset(parea, 0, kernel_size);
183        printk("\nUncompressing the kernel...\n");
184        rescopy=salloc(sizeof(RESIDUAL));
185        /* Let us hope that residual data is aligned on word boundary */
186        *rescopy =  *bd->residual;
187        bd->residual = (void *)PAGE_ALIGN(kernel_size);
188
189        gunzip(parea, kernel_size, zimage_start, &zimage_size);
190
191        bd->of_entry = 0;
192        bd->load_address = 0;
193        bd->r6 = (char *)bd->residual+PAGE_ALIGN(sizeof(RESIDUAL));
194        bd->r7 = bd->r6+strlen(bd->cmd_line);
195        if ( initrd_len ) {
196                /* We have to leave some room for the hash table and for the
197                 * whole array of struct page. The hash table would be better
198                 * located at the end of memory if possible. With some bridges
199                 * DMA from the last pages of memory is slower because
200                 * prefetching from PCI has to be disabled to avoid accessing
201                 * non existing memory. So it is the ideal place to put the
202                 * hash table.
203                 */
204                unsigned tmp = rescopy->TotalMemory;
205                /* It's equivalent to tmp & (-tmp), but using the negation
206                 * operator on unsigned variables looks so ugly.
207                 */
208                if ((tmp & (~tmp+1)) != tmp) tmp <<= 1; /* Next power of 2 */
209                tmp /= 256; /* Size of hash table */
210                if (tmp> (2<<20)) tmp=2<<20;
211                tmp = tmp*2 + 0x40000; /* Alignment can double size + 256 kB */
212                tmp += (rescopy->TotalMemory / PAGE_SIZE)
213                               * sizeof(struct page);
214                bd->load_address = (void *)PAGE_ALIGN((int)bd->r7 + tmp);
215                bd->of_entry = (char *)bd->load_address+initrd_len;
216        }
217#ifdef DEBUG
218        printk("Kernel at 0x%p, size=0x%x\n", NULL, kernel_size);
219        printk("Initrd at 0x%p, size=0x%x\n",bd->load_address, initrd_len);
220        printk("Residual data at 0x%p\n", bd->residual);
221        printk("Command line at 0x%p\n",bd->r6);
222#endif
223        printk("done\nNow booting...\n");
224        MMUoff();       /* We need to access address 0 ! */
225        codemove(0, parea, kernel_size, bd->cache_lsize);
226        codemove(bd->residual, rescopy, sizeof(RESIDUAL), bd->cache_lsize);
227        codemove(bd->r6, bd->cmd_line, sizeof(bd->cmd_line), bd->cache_lsize);
228        /* codemove checks for 0 length */
229        codemove(bd->load_address, initrd_start, initrd_len, bd->cache_lsize);
230}
231
232static int ticks_per_ms=0;
233
234/* this is from rtems_bsp_delay from libcpu */
235void
236boot_udelay(uint32_t   _microseconds)
237{
238   uint32_t   start, ticks, now;
239
240   ticks = _microseconds * ticks_per_ms / 1000;
241   CPU_Get_timebase_low( start );
242   do {
243     CPU_Get_timebase_low( now );
244   } while (now - start < ticks);
245}
246
247void
248setup_hw(void)
249{
250        char *cp, ch;
251        register RESIDUAL * res;
252        /* PPC_DEVICE * nvram; */
253        struct pci_dev *default_vga;
254        int timer, err;
255        u_short default_vga_cmd;
256        static unsigned int indic;
257
258        indic = 0;
259
260        res=bd->residual;
261        default_vga=NULL;
262        default_vga_cmd = 0;
263
264#define vpd res->VitalProductData
265        if (_read_PVR()>>16 != 1) {
266                if ( res && vpd.ProcessorBusHz ) {
267                        ticks_per_ms = vpd.ProcessorBusHz/
268                            (vpd.TimeBaseDivisor ? vpd.TimeBaseDivisor : 4000);
269                } else {
270                        ticks_per_ms = 16500; /* assume 66 MHz on bus */
271                }
272        }
273
274        select_console(CONSOLE_LOG);
275
276        /* We check that the keyboard is present and immediately
277         * select the serial console if not.
278         */
279#if defined(BSP_KBD_IOBASE)
280        err = kbdreset();
281        if (err) select_console(CONSOLE_SERIAL);
282#else
283        err = 1;
284        select_console(CONSOLE_SERIAL);
285#endif
286
287        printk("\nModel: %s\nSerial: %s\n"
288               "Processor/Bus frequencies (Hz): %ld/%ld\n"
289               "Time Base Divisor: %ld\n"
290               "Memory Size: %lx\n",
291               vpd.PrintableModel,
292               vpd.Serial,
293               vpd.ProcessorHz,
294               vpd.ProcessorBusHz,
295               (vpd.TimeBaseDivisor ? vpd.TimeBaseDivisor : 4000),
296               res->TotalMemory);
297
298        /* This reconfigures all the PCI subsystem */
299        pci_init();
300
301        /* The Motorola NT firmware does not set the correct mem size */
302        if ( vpd.FirmwareSupplier == 0x10000 ) {
303                int memsize;
304                memsize = find_max_mem(bd->pci_devices);
305                if ( memsize != res->TotalMemory ) {
306                        printk("Changed Memory size from %lx to %x\n",
307                                res->TotalMemory, memsize);
308                        res->TotalMemory = memsize;
309                        res->GoodMemory = memsize;
310                }
311        }
312#define ENABLE_VGA_USAGE
313#undef ENABLE_VGA_USAGE
314#ifdef ENABLE_VGA_USAGE
315        /* Find the primary VGA device, chosing the first one found
316         * if none is enabled. The basic loop structure has been copied
317         * from linux/drivers/char/bttv.c by Alan Cox.
318         */
319        for (p = bd->pci_devices; p; p = p->next) {
320                u_short cmd;
321                if (p->class != PCI_CLASS_NOT_DEFINED_VGA &&
322                    ((p->class) >> 16 != PCI_BASE_CLASS_DISPLAY))
323                        continue;
324                if (p->bus->number != 0) {
325                        printk("VGA device not on bus 0 not initialized!\n");
326                        continue;
327                }
328                /* Only one can be active in text mode, which for now will
329                 * be assumed as equivalent to having I/O response enabled.
330                 */
331                pci_read_config_word(p, PCI_COMMAND, &cmd);
332                if(cmd & PCI_COMMAND_IO || !default_vga) {
333                        default_vga=p;
334                        default_vga_cmd=cmd;
335                }
336        }
337
338        /* Disable the enabled VGA device, if any. */
339        if (default_vga)
340                pci_write_config_word(default_vga, PCI_COMMAND,
341                                      default_vga_cmd&
342                                      ~(PCI_COMMAND_IO|PCI_COMMAND_MEMORY));
343        init_v86();
344        /* Same loop copied from bttv.c, this time doing the serious work */
345        for (p = bd->pci_devices; p; p = p->next) {
346                u_short cmd;
347                if (p->class != PCI_CLASS_NOT_DEFINED_VGA &&
348                    ((p->class) >> 16 != PCI_BASE_CLASS_DISPLAY))
349                        continue;
350                if (p->bus->number != 0) continue;
351                pci_read_config_word(p, PCI_COMMAND, &cmd);
352                pci_write_config_word(p, PCI_COMMAND,
353                                      cmd|PCI_COMMAND_IO|PCI_COMMAND_MEMORY);
354                printk("Calling the emulator.\n");
355                em86_main(p);
356                pci_write_config_word(p, PCI_COMMAND, cmd);
357        }
358
359        cleanup_v86_mess();
360#endif
361        /* Reenable the primary VGA device */
362        if (default_vga) {
363                pci_write_config_word(default_vga, PCI_COMMAND,
364                                      default_vga_cmd|
365                                      (PCI_COMMAND_IO|PCI_COMMAND_MEMORY));
366                if (err) {
367                        printk("Keyboard error %d, using serial console!\n",
368                               err);
369                } else {
370                        select_console(CONSOLE_VGA);
371                }
372        } else if (!err) {
373                select_console(CONSOLE_SERIAL);
374                if (bd->cmd_line[0] == '\0') {
375                  strcat(&bd->cmd_line[0], CONSOLE_ON_SERIAL);
376                }
377                else {
378                  int s = strlen (bd->cmd_line);
379                  bd->cmd_line[s + 1] = ' ';
380                  bd->cmd_line[s + 2] = '\0';
381                  strcat(&bd->cmd_line[0], CONSOLE_ON_SERIAL);
382                }
383        }
384#if 0
385        /* In the future we may use the NVRAM to store default
386         * kernel parameters.
387         */
388        nvram=residual_find_device(~0UL, NULL, SystemPeripheral, NVRAM,
389                                   ~0UL, 0);
390        if (nvram) {
391                PnP_TAG_PACKET * pkt;
392                switch (nvram->DevId.Interface) {
393                case IndirectNVRAM:
394                          pkt=PnP_find_packet(res->DevicePnpHeap
395                                      +nvram->AllocatedOffset,
396                                              )
397                }
398        }
399#endif
400
401        printk("\nRTEMS 4.x/PPC load: ");
402        timer = 0;
403        cp = bd->cmd_line+strlen(bd->cmd_line);
404        while (timer++ < 5*1000) {
405                if (debug_tstc()) {
406                        while ((ch = debug_getc()) != '\n' && ch != '\r') {
407                                if (ch == '\b' || ch == 0177) {
408                                        if (cp != bd->cmd_line) {
409                                                cp--;
410                                                printk("\b \b");
411                                        }
412                                } else {
413                                        *cp++ = ch;
414                                        debug_putc(ch);
415                                }
416                        }
417                        break;  /* Exit 'timer' loop */
418                }
419                boot_udelay(1000);  /* 1 msec */
420        }
421        *cp = 0;
422}
423
424/* Functions to deal with the residual data */
425static int same_DevID(unsigned short vendor,
426               unsigned short Number,
427               char * str)
428{
429        static unsigned const char hexdigit[]="0123456789ABCDEF";
430        if (strlen(str)!=7) return 0;
431        if ( ( ((vendor>>10)&0x1f)+'A'-1 == str[0])  &&
432             ( ((vendor>>5)&0x1f)+'A'-1 == str[1])   &&
433             ( (vendor&0x1f)+'A'-1 == str[2])        &&
434             (hexdigit[(Number>>12)&0x0f] == str[3]) &&
435             (hexdigit[(Number>>8)&0x0f] == str[4])  &&
436             (hexdigit[(Number>>4)&0x0f] == str[5])  &&
437             (hexdigit[Number&0x0f] == str[6]) ) return 1;
438        return 0;
439}
440
441PPC_DEVICE *residual_find_device(unsigned long BusMask,
442                         unsigned char * DevID,
443                         int BaseType,
444                         int SubType,
445                         int Interface,
446                         int n)
447{
448        int i;
449        RESIDUAL *res = bd->residual;
450        if ( !res || !res->ResidualLength ) return NULL;
451        for (i=0; i<res->ActualNumDevices; i++) {
452#define Dev res->Devices[i].DeviceId
453                if ( (Dev.BusId&BusMask)                                  &&
454                     (BaseType==-1 || Dev.BaseType==BaseType)             &&
455                     (SubType==-1 || Dev.SubType==SubType)                &&
456                     (Interface==-1 || Dev.Interface==Interface)          &&
457                     (DevID==NULL || same_DevID((Dev.DevId>>16)&0xffff,
458                                                Dev.DevId&0xffff, DevID)) &&
459                     !(n--) ) return res->Devices+i;
460#undef Dev
461        }
462        return 0;
463}
464
465PnP_TAG_PACKET *PnP_find_packet(unsigned char *p,
466                                unsigned packet_tag,
467                                int n)
468{
469        unsigned mask, masked_tag, size;
470        if(!p) return 0;
471        if (tag_type(packet_tag)) mask=0xff; else mask=0xF8;
472        masked_tag = packet_tag&mask;
473        for(; *p != END_TAG; p+=size) {
474                if ((*p & mask) == masked_tag && !(n--))
475                        return (PnP_TAG_PACKET *) p;
476                if (tag_type(*p))
477                        size=ld_le16((unsigned short *)(p+1))+3;
478                else
479                        size=tag_small_count(*p)+1;
480        }
481        return 0; /* not found */
482}
483
484PnP_TAG_PACKET *PnP_find_small_vendor_packet(unsigned char *p,
485                                             unsigned packet_type,
486                                             int n)
487{
488        int next=0;
489        while (p) {
490                p = (unsigned char *) PnP_find_packet(p, 0x70, next);
491                if (p && p[1]==packet_type && !(n--))
492                        return (PnP_TAG_PACKET *) p;
493                next = 1;
494        };
495        return 0; /* not found */
496}
497
498PnP_TAG_PACKET *PnP_find_large_vendor_packet(unsigned char *p,
499                                           unsigned packet_type,
500                                           int n)
501{
502        int next=0;
503        while (p) {
504                p = (unsigned char *) PnP_find_packet(p, 0x84, next);
505                if (p && p[3]==packet_type && !(n--))
506                        return (PnP_TAG_PACKET *) p;
507                next = 1;
508        };
509        return 0; /* not found */
510}
511
512/* Find out the amount of installed memory. For MPC105 and IBM 660 this
513 * can be done by finding the bank with the highest memory ending address
514 */
515int
516find_max_mem( struct pci_dev *dev )
517{
518        u_char banks,tmp;
519        int i, top, max;
520
521        max = 0;
522        for ( ; dev; dev = dev->next) {
523                if ( ((dev->vendor == PCI_VENDOR_ID_MOTOROLA) &&
524                      (dev->device == PCI_DEVICE_ID_MOTOROLA_MPC105)) ||
525                     ((dev->vendor == PCI_VENDOR_ID_IBM) &&
526                      (dev->device == 0x0037/*IBM 660 Bridge*/)) ) {
527                        pci_read_config_byte(dev, 0xa0, &banks);
528                        for (i = 0; i < 8; i++) {
529                                if ( banks & (1<<i) ) {
530                                        pci_read_config_byte(dev, 0x90+i, &tmp);
531                                        top = tmp;
532                                        pci_read_config_byte(dev, 0x98+i, &tmp);
533                                        top |= (tmp&3)<<8;
534                                        if ( top > max ) max = top;
535                                }
536                        }
537                        if ( max ) return ((max+1)<<20);
538                        else return(0);
539                }
540        }
541        return(0);
542}
Note: See TracBrowser for help on using the repository browser.