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

4.115
Last change on this file since 1d367a49 was 9c39236d, checked in by Till Straumann <strauman@…>, on 07/16/11 at 01:21:36

2011-07-15 Till Straumann <strauman@…>

  • shared/bootloader/misc.c: Copy residual data _before_ decompressing the kernel since the firmware may have stored it in an area that is overwritten by decompress_kernel().
  • Property mode set to 100644
File size: 14.3 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 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
180        rescopy=salloc(sizeof(RESIDUAL));
181        /* Let us hope that residual data is aligned on word boundary */
182        *rescopy =  *bd->residual;
183        bd->residual = (void *)PAGE_ALIGN(kernel_size);
184
185        /* Note that this clears the bss as a side effect, so some code
186         * with ugly special case for SMP could be removed from the kernel!
187         */
188        memset(parea, 0, kernel_size);
189        printk("\nUncompressing the kernel...\n");
190
191        gunzip(parea, kernel_size, zimage_start, &zimage_size);
192
193        bd->of_entry = 0;
194        bd->load_address = 0;
195        bd->r6 = (char *)bd->residual+PAGE_ALIGN(sizeof(RESIDUAL));
196        bd->r7 = bd->r6+strlen(bd->cmd_line);
197        if ( initrd_len ) {
198                /* We have to leave some room for the hash table and for the
199                 * whole array of struct page. The hash table would be better
200                 * located at the end of memory if possible. With some bridges
201                 * DMA from the last pages of memory is slower because
202                 * prefetching from PCI has to be disabled to avoid accessing
203                 * non existing memory. So it is the ideal place to put the
204                 * hash table.
205                 */
206                unsigned tmp = rescopy->TotalMemory;
207                /* It's equivalent to tmp & (-tmp), but using the negation
208                 * operator on unsigned variables looks so ugly.
209                 */
210                if ((tmp & (~tmp+1)) != tmp) tmp <<= 1; /* Next power of 2 */
211                tmp /= 256; /* Size of hash table */
212                if (tmp> (2<<20)) tmp=2<<20;
213                tmp = tmp*2 + 0x40000; /* Alignment can double size + 256 kB */
214                tmp += (rescopy->TotalMemory / PAGE_SIZE)
215                               * sizeof(struct page);
216                bd->load_address = (void *)PAGE_ALIGN((int)bd->r7 + tmp);
217                bd->of_entry = (char *)bd->load_address+initrd_len;
218        }
219#ifdef DEBUG
220        printk("Kernel at 0x%p, size=0x%x\n", NULL, kernel_size);
221        printk("Initrd at 0x%p, size=0x%x\n",bd->load_address, initrd_len);
222        printk("Residual data at 0x%p\n", bd->residual);
223        printk("Command line at 0x%p\n",bd->r6);
224#endif
225        printk("done\nNow booting...\n");
226        MMUoff();       /* We need to access address 0 ! */
227        codemove(0, parea, kernel_size, bd->cache_lsize);
228        codemove(bd->residual, rescopy, sizeof(RESIDUAL), bd->cache_lsize);
229        codemove(bd->r6, bd->cmd_line, sizeof(bd->cmd_line), bd->cache_lsize);
230        /* codemove checks for 0 length */
231        codemove(bd->load_address, initrd_start, initrd_len, bd->cache_lsize);
232}
233
234static int ticks_per_ms=0;
235
236/* this is from rtems_bsp_delay from libcpu */
237void
238boot_udelay(uint32_t   _microseconds)
239{
240   uint32_t   start, ticks, now;
241
242   ticks = _microseconds * ticks_per_ms / 1000;
243   CPU_Get_timebase_low( start );
244   do {
245     CPU_Get_timebase_low( now );
246   } while (now - start < ticks);
247}
248
249void
250setup_hw(void)
251{
252        char *cp, ch;
253        register RESIDUAL * res;
254        /* PPC_DEVICE * nvram; */
255        struct pci_dev *default_vga;
256        int timer, err;
257        u_short default_vga_cmd;
258        static unsigned int indic;
259
260        indic = 0;
261
262        res=bd->residual;
263        default_vga=NULL;
264        default_vga_cmd = 0;
265
266#define vpd res->VitalProductData
267        if (_read_PVR()>>16 != 1) {
268                if ( res && vpd.ProcessorBusHz ) {
269                        ticks_per_ms = vpd.ProcessorBusHz/
270                            (vpd.TimeBaseDivisor ? vpd.TimeBaseDivisor : 4000);
271                } else {
272                        ticks_per_ms = 16500; /* assume 66 MHz on bus */
273                }
274        }
275
276        select_console(CONSOLE_LOG);
277
278        /* We check that the keyboard is present and immediately
279         * select the serial console if not.
280         */
281#if defined(BSP_KBD_IOBASE)
282        err = kbdreset();
283        if (err) select_console(CONSOLE_SERIAL);
284#else
285        err = 1;
286        select_console(CONSOLE_SERIAL);
287#endif
288
289        printk("\nModel: %s\nSerial: %s\n"
290               "Processor/Bus frequencies (Hz): %ld/%ld\n"
291               "Time Base Divisor: %ld\n"
292               "Memory Size: %lx\n"
293                   "Residual: %lx (length %u)\n",
294               vpd.PrintableModel,
295               vpd.Serial,
296               vpd.ProcessorHz,
297               vpd.ProcessorBusHz,
298               (vpd.TimeBaseDivisor ? vpd.TimeBaseDivisor : 4000),
299               res->TotalMemory,
300                   (unsigned long)res, res->ResidualLength);
301
302        /* This reconfigures all the PCI subsystem */
303        pci_init();
304
305        /* The Motorola NT firmware does not set the correct mem size */
306        if ( vpd.FirmwareSupplier == 0x10000 ) {
307                int memsize;
308                memsize = find_max_mem(bd->pci_devices);
309                if ( memsize != res->TotalMemory ) {
310                        printk("Changed Memory size from %lx to %x\n",
311                                res->TotalMemory, memsize);
312                        res->TotalMemory = memsize;
313                        res->GoodMemory = memsize;
314                }
315        }
316#define ENABLE_VGA_USAGE
317#undef ENABLE_VGA_USAGE
318#ifdef ENABLE_VGA_USAGE
319        /* Find the primary VGA device, chosing the first one found
320         * if none is enabled. The basic loop structure has been copied
321         * from linux/drivers/char/bttv.c by Alan Cox.
322         */
323        for (p = bd->pci_devices; p; p = p->next) {
324                u_short cmd;
325                if (p->class != PCI_CLASS_NOT_DEFINED_VGA &&
326                    ((p->class) >> 16 != PCI_BASE_CLASS_DISPLAY))
327                        continue;
328                if (p->bus->number != 0) {
329                        printk("VGA device not on bus 0 not initialized!\n");
330                        continue;
331                }
332                /* Only one can be active in text mode, which for now will
333                 * be assumed as equivalent to having I/O response enabled.
334                 */
335                pci_bootloader_read_config_word(p, PCI_COMMAND, &cmd);
336                if(cmd & PCI_COMMAND_IO || !default_vga) {
337                        default_vga=p;
338                        default_vga_cmd=cmd;
339                }
340        }
341
342        /* Disable the enabled VGA device, if any. */
343        if (default_vga)
344                pci_bootloader_write_config_word(default_vga, PCI_COMMAND,
345                                      default_vga_cmd&
346                                      ~(PCI_COMMAND_IO|PCI_COMMAND_MEMORY));
347        init_v86();
348        /* Same loop copied from bttv.c, this time doing the serious work */
349        for (p = bd->pci_devices; p; p = p->next) {
350                u_short cmd;
351                if (p->class != PCI_CLASS_NOT_DEFINED_VGA &&
352                    ((p->class) >> 16 != PCI_BASE_CLASS_DISPLAY))
353                        continue;
354                if (p->bus->number != 0) continue;
355                pci_bootloader_read_config_word(p, PCI_COMMAND, &cmd);
356                pci_bootloader_write_config_word(p, PCI_COMMAND,
357                                      cmd|PCI_COMMAND_IO|PCI_COMMAND_MEMORY);
358                printk("Calling the emulator.\n");
359                em86_main(p);
360                pci_bootloader_write_config_word(p, PCI_COMMAND, cmd);
361        }
362
363        cleanup_v86_mess();
364#endif
365        /* Reenable the primary VGA device */
366        if (default_vga) {
367                pci_bootloader_write_config_word(default_vga, PCI_COMMAND,
368                                      default_vga_cmd|
369                                      (PCI_COMMAND_IO|PCI_COMMAND_MEMORY));
370                if (err) {
371                        printk("Keyboard error %d, using serial console!\n",
372                               err);
373                } else {
374                        select_console(CONSOLE_VGA);
375                }
376        } else if (!err) {
377                select_console(CONSOLE_SERIAL);
378                if (bd->cmd_line[0] == '\0') {
379                  strcat(&bd->cmd_line[0], CONSOLE_ON_SERIAL);
380                }
381                else {
382                  int s = strlen (bd->cmd_line);
383                  bd->cmd_line[s + 1] = ' ';
384                  bd->cmd_line[s + 2] = '\0';
385                  strcat(&bd->cmd_line[0], CONSOLE_ON_SERIAL);
386                }
387        }
388#if 0
389        /* In the future we may use the NVRAM to store default
390         * kernel parameters.
391         */
392        nvram=residual_find_device(~0UL, NULL, SystemPeripheral, NVRAM,
393                                   ~0UL, 0);
394        if (nvram) {
395                PnP_TAG_PACKET * pkt;
396                switch (nvram->DevId.Interface) {
397                case IndirectNVRAM:
398                          pkt=PnP_find_packet(res->DevicePnpHeap
399                                      +nvram->AllocatedOffset,
400                                              )
401                }
402        }
403#endif
404
405        printk("\nRTEMS 4.x/PPC load: ");
406        timer = 0;
407        cp = bd->cmd_line+strlen(bd->cmd_line);
408        while (timer++ < 5*1000) {
409                if (debug_tstc()) {
410                        while ((ch = debug_getc()) != '\n' && ch != '\r') {
411                                if (ch == '\b' || ch == 0177) {
412                                        if (cp != bd->cmd_line) {
413                                                cp--;
414                                                printk("\b \b");
415                                        }
416                                } else {
417                                        *cp++ = ch;
418                                        debug_putc(ch);
419                                }
420                        }
421                        break;  /* Exit 'timer' loop */
422                }
423                boot_udelay(1000);  /* 1 msec */
424        }
425        *cp = 0;
426}
427
428/* Functions to deal with the residual data */
429static int same_DevID(unsigned short vendor,
430               unsigned short Number,
431               unsigned char * str)
432{
433        static unsigned const char hexdigit[]="0123456789ABCDEF";
434        if (strlen((char*)str)!=7) return 0;
435        if ( ( ((vendor>>10)&0x1f)+'A'-1 == str[0])  &&
436             ( ((vendor>>5)&0x1f)+'A'-1 == str[1])   &&
437             ( (vendor&0x1f)+'A'-1 == str[2])        &&
438             (hexdigit[(Number>>12)&0x0f] == str[3]) &&
439             (hexdigit[(Number>>8)&0x0f] == str[4])  &&
440             (hexdigit[(Number>>4)&0x0f] == str[5])  &&
441             (hexdigit[Number&0x0f] == str[6]) ) return 1;
442        return 0;
443}
444
445PPC_DEVICE *residual_find_device(unsigned long BusMask,
446                         unsigned char * DevID,
447                         int BaseType,
448                         int SubType,
449                         int Interface,
450                         int n)
451{
452        int i;
453        RESIDUAL *res = bd->residual;
454        if ( !res || !res->ResidualLength ) return NULL;
455        for (i=0; i<res->ActualNumDevices; i++) {
456#define Dev res->Devices[i].DeviceId
457                if ( (Dev.BusId&BusMask)                                  &&
458                     (BaseType==-1 || Dev.BaseType==BaseType)             &&
459                     (SubType==-1 || Dev.SubType==SubType)                &&
460                     (Interface==-1 || Dev.Interface==Interface)          &&
461                     (DevID==NULL || same_DevID((Dev.DevId>>16)&0xffff,
462                                                Dev.DevId&0xffff, DevID)) &&
463                     !(n--) ) return res->Devices+i;
464#undef Dev
465        }
466        return 0;
467}
468
469PnP_TAG_PACKET *PnP_find_packet(unsigned char *p,
470                                unsigned packet_tag,
471                                int n)
472{
473        unsigned mask, masked_tag, size;
474        if(!p) return 0;
475        if (tag_type(packet_tag)) mask=0xff; else mask=0xF8;
476        masked_tag = packet_tag&mask;
477        for(; *p != END_TAG; p+=size) {
478                if ((*p & mask) == masked_tag && !(n--))
479                        return (PnP_TAG_PACKET *) p;
480                if (tag_type(*p))
481                        size=ld_le16((unsigned short *)(p+1))+3;
482                else
483                        size=tag_small_count(*p)+1;
484        }
485        return 0; /* not found */
486}
487
488PnP_TAG_PACKET *PnP_find_small_vendor_packet(unsigned char *p,
489                                             unsigned packet_type,
490                                             int n)
491{
492        int next=0;
493        while (p) {
494                p = (unsigned char *) PnP_find_packet(p, 0x70, next);
495                if (p && p[1]==packet_type && !(n--))
496                        return (PnP_TAG_PACKET *) p;
497                next = 1;
498        };
499        return 0; /* not found */
500}
501
502PnP_TAG_PACKET *PnP_find_large_vendor_packet(unsigned char *p,
503                                           unsigned packet_type,
504                                           int n)
505{
506        int next=0;
507        while (p) {
508                p = (unsigned char *) PnP_find_packet(p, 0x84, next);
509                if (p && p[3]==packet_type && !(n--))
510                        return (PnP_TAG_PACKET *) p;
511                next = 1;
512        };
513        return 0; /* not found */
514}
515
516/* Find out the amount of installed memory. For MPC105 and IBM 660 this
517 * can be done by finding the bank with the highest memory ending address
518 */
519int
520find_max_mem( struct pci_dev *dev )
521{
522        u_char banks,tmp;
523        int i, top, max;
524
525        max = 0;
526        for ( ; dev; dev = dev->next) {
527                if ( ((dev->vendor == PCI_VENDOR_ID_MOTOROLA) &&
528                      (dev->device == PCI_DEVICE_ID_MOTOROLA_MPC105)) ||
529                     ((dev->vendor == PCI_VENDOR_ID_IBM) &&
530                      (dev->device == 0x0037/*IBM 660 Bridge*/)) ) {
531                        pci_bootloader_read_config_byte(dev, 0xa0, &banks);
532                        for (i = 0; i < 8; i++) {
533                                if ( banks & (1<<i) ) {
534                                        pci_bootloader_read_config_byte(dev, 0x90+i, &tmp);
535                                        top = tmp;
536                                        pci_bootloader_read_config_byte(dev, 0x98+i, &tmp);
537                                        top |= (tmp&3)<<8;
538                                        if ( top > max ) max = top;
539                                }
540                        }
541                        if ( max ) return ((max+1)<<20);
542                        else return(0);
543                }
544        }
545        return(0);
546}
Note: See TracBrowser for help on using the repository browser.