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

4.104.114.84.95
Last change on this file since eba2e4f was df49c60, checked in by Joel Sherrill <joel.sherrill@…>, on 06/12/00 at 15:00:15

Merged from 4.5.0-beta3a

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