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

Last change on this file since 79d45cbd was 79d45cbd, checked in by Joel Sherrill <joel@…>, on Apr 24, 2017 at 1:05:03 AM

shared/bootloader/misc.c: Fix printf() format warnings

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