source: rtems/bsps/powerpc/motorola_powerpc/bootloader/misc.c

Last change on this file was ee14fdf, checked in by Chris Johns <chrisj@…>, on 10/14/20 at 06:14:21

bsp/motorola_powerp: Print RTEMS_VERSION from the bootloader

  • Property mode set to 100644
File size: 14.4 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 <sys/param.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/byteorder.h>
23#include <rtems/bspIo.h>
24#include <bsp.h>
25
26#include <rtems.h>
27
28/* to align the pointer to the (next) page boundary */
29#define PAGE_ALIGN(addr)        (((addr) + PAGE_MASK) & ~PAGE_MASK)
30
31SPR_RO(PPC_PVR)
32
33struct inode;
34struct wait_queue;
35struct buffer_head;
36typedef struct { int counter; } atomic_t;
37
38typedef struct page {
39        /* these must be first (free area handling) */
40        struct page *next;
41        struct page *prev;
42        struct inode *inode;
43        unsigned long offset;
44        struct page *next_hash;
45        atomic_t count;
46        unsigned long flags;    /* atomic flags, some possibly updated asynchronously */
47        struct wait_queue *wait;
48        struct page **pprev_hash;
49        struct buffer_head * buffers;
50} mem_map_t;
51
52extern opaque mm_private, pci_private, v86_private, console_private;
53
54#define CONSOLE_ON_SERIAL       "console=ttyS0"
55
56extern struct console_io vacuum_console_functions;
57extern opaque log_console_setup, serial_console_setup, vga_console_setup;
58
59boot_data __bd = {0, 0, 0, 0, 0, 0, 0, 0,
60                  32, 0, 0, 0, 0, 0, 0,
61                  &mm_private,
62                  NULL,
63                  &pci_private,
64                  NULL,
65                  &v86_private,
66                  "root=/dev/hdc1"
67                 };
68
69static void exit(void) __attribute__((noreturn));
70
71static void exit(void) {
72        printk("\nOnly way out is to press the reset button!\n");
73        asm volatile("": : :"memory");
74        while(1);
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
93static void *zalloc(void *x, unsigned items, unsigned size)
94{
95        void *p = salloc(items*size);
96
97        if (!p) {
98                printk("oops... not enough memory for gunzip\n");
99        }
100        return p;
101}
102
103static void zfree(void *x, void *addr, unsigned nb)
104{
105        sfree(addr);
106}
107
108#define HEAD_CRC        2
109#define EXTRA_FIELD     4
110#define ORIG_NAME       8
111#define COMMENT         0x10
112#define RESERVED        0xe0
113
114#define DEFLATED        8
115
116void gunzip(void *dst, int dstlen, unsigned char *src, int *lenp)
117{
118        z_stream s;
119        int r, i, flags;
120
121        /* skip header */
122        i = 10;
123        flags = src[3];
124        if (src[2] != DEFLATED || (flags & RESERVED) != 0) {
125                printk("bad gzipped data\n");
126                exit();
127        }
128        if ((flags & EXTRA_FIELD) != 0)
129                i = 12 + src[10] + (src[11] << 8);
130        if ((flags & ORIG_NAME) != 0)
131                while (src[i++] != 0)
132                        ;
133        if ((flags & COMMENT) != 0)
134                while (src[i++] != 0)
135                        ;
136        if ((flags & HEAD_CRC) != 0)
137                i += 2;
138        if (i >= *lenp) {
139                printk("gunzip: ran out of data in header\n");
140                exit();
141        }
142
143        s.zalloc = zalloc;
144        s.zfree = zfree;
145        r = inflateInit2(&s, -MAX_WBITS);
146        if (r != Z_OK) {
147                printk("inflateInit2 returned %d\n", r);
148                exit();
149        }
150        s.next_in = src + i;
151        s.avail_in = *lenp - i;
152        s.next_out = dst;
153        s.avail_out = dstlen;
154        r = inflate(&s, Z_FINISH);
155        if (r != Z_OK && r != Z_STREAM_END) {
156                printk("inflate returned %d\n", r);
157                exit();
158        }
159        *lenp = s.next_out - (unsigned char *) dst;
160        inflateEnd(&s);
161}
162
163void decompress_kernel(int kernel_size, void * zimage_start, int len,
164                       void * initrd_start, int initrd_len ) {
165        u_char *parea;
166        RESIDUAL* rescopy;
167        int zimage_size= len;
168
169        /* That's a mess, we have to copy the residual data twice just in
170         * case it happens to be in the low memory area where the kernel
171         * is going to be unpacked. Later we have to copy it back to
172         * lower addresses because only the lowest part of memory is mapped
173         * during boot.
174         */
175        parea=__palloc(kernel_size, PA_LOW);
176        if(!parea) {
177                printk("Not enough memory to uncompress the kernel.");
178                exit();
179        }
180
181        rescopy=salloc(sizeof(RESIDUAL));
182        /* Let us hope that residual data is aligned on word boundary */
183        *rescopy =  *bd->residual;
184        bd->residual = (void *)PAGE_ALIGN(kernel_size);
185
186        /* Note that this clears the bss as a side effect, so some code
187         * with ugly special case for SMP could be removed from the kernel!
188         */
189        memset(parea, 0, kernel_size);
190        printk("\nUncompressing the kernel...\n");
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
235static int ticks_per_ms=0;
236
237/*
238 * This is based on rtems_bsp_delay from libcpu
239 */
240void
241boot_udelay(uint32_t _microseconds)
242{
243   uint32_t   start, ticks, now;
244
245   ticks = _microseconds * ticks_per_ms / 1000;
246   CPU_Get_timebase_low( start );
247   do {
248     CPU_Get_timebase_low( now );
249   } while (now - start < ticks);
250}
251
252void
253setup_hw(void)
254{
255        char *cp, ch;
256        register RESIDUAL * res;
257        /* PPC_DEVICE * nvram; */
258        struct pci_dev *default_vga;
259        int timer, err;
260        u_short default_vga_cmd;
261
262        res=bd->residual;
263        default_vga=NULL;
264        default_vga_cmd = 0;
265
266#define vpd res->VitalProductData
267        if (_read_PPC_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 %lu)\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,
301               res->ResidualLength);
302
303        /* This reconfigures all the PCI subsystem */
304        pci_init();
305
306        /* The Motorola NT firmware does not set the correct mem size */
307        if ( vpd.FirmwareSupplier == 0x10000 ) {
308                int memsize;
309                memsize = find_max_mem(bd->pci_devices);
310                if ( memsize != res->TotalMemory ) {
311                        printk("Changed Memory size from %lx to %x\n",
312                                res->TotalMemory, memsize);
313                        res->TotalMemory = memsize;
314                        res->GoodMemory = memsize;
315                }
316        }
317#define ENABLE_VGA_USAGE
318#undef ENABLE_VGA_USAGE
319#ifdef ENABLE_VGA_USAGE
320        /* Find the primary VGA device, chosing the first one found
321         * if none is enabled. The basic loop structure has been copied
322         * from linux/drivers/char/bttv.c by Alan Cox.
323         */
324        for (p = bd->pci_devices; p; p = p->next) {
325                u_short cmd;
326                if (p->class != PCI_CLASS_NOT_DEFINED_VGA &&
327                    ((p->class) >> 16 != PCI_BASE_CLASS_DISPLAY))
328                        continue;
329                if (p->bus->number != 0) {
330                        printk("VGA device not on bus 0 not initialized!\n");
331                        continue;
332                }
333                /* Only one can be active in text mode, which for now will
334                 * be assumed as equivalent to having I/O response enabled.
335                 */
336                pci_bootloader_read_config_word(p, PCI_COMMAND, &cmd);
337                if(cmd & PCI_COMMAND_IO || !default_vga) {
338                        default_vga=p;
339                        default_vga_cmd=cmd;
340                }
341        }
342
343        /* Disable the enabled VGA device, if any. */
344        if (default_vga)
345                pci_bootloader_write_config_word(default_vga, PCI_COMMAND,
346                                      default_vga_cmd&
347                                      ~(PCI_COMMAND_IO|PCI_COMMAND_MEMORY));
348        init_v86();
349        /* Same loop copied from bttv.c, this time doing the serious work */
350        for (p = bd->pci_devices; p; p = p->next) {
351                u_short cmd;
352                if (p->class != PCI_CLASS_NOT_DEFINED_VGA &&
353                    ((p->class) >> 16 != PCI_BASE_CLASS_DISPLAY))
354                        continue;
355                if (p->bus->number != 0) continue;
356                pci_bootloader_read_config_word(p, PCI_COMMAND, &cmd);
357                pci_bootloader_write_config_word(p, PCI_COMMAND,
358                                      cmd|PCI_COMMAND_IO|PCI_COMMAND_MEMORY);
359                printk("Calling the emulator.\n");
360                em86_main(p);
361                pci_bootloader_write_config_word(p, PCI_COMMAND, cmd);
362        }
363
364        cleanup_v86_mess();
365#endif
366        /* Reenable the primary VGA device */
367        if (default_vga) {
368                pci_bootloader_write_config_word(default_vga, PCI_COMMAND,
369                                      default_vga_cmd|
370                                      (PCI_COMMAND_IO|PCI_COMMAND_MEMORY));
371                if (err) {
372                        printk("Keyboard error %d, using serial console!\n",
373                               err);
374                } else {
375                        select_console(CONSOLE_VGA);
376                }
377        } else if (!err) {
378                select_console(CONSOLE_SERIAL);
379                if (bd->cmd_line[0] == '\0') {
380                  strcat(&bd->cmd_line[0], CONSOLE_ON_SERIAL);
381                }
382                else {
383                  int s = strlen (bd->cmd_line);
384                  bd->cmd_line[s + 1] = ' ';
385                  bd->cmd_line[s + 2] = '\0';
386                  strcat(&bd->cmd_line[0], CONSOLE_ON_SERIAL);
387                }
388        }
389#if 0
390        /* In the future we may use the NVRAM to store default
391         * kernel parameters.
392         */
393        nvram=residual_find_device(~0UL, NULL, SystemPeripheral, NVRAM,
394                                   ~0UL, 0);
395        if (nvram) {
396                PnP_TAG_PACKET * pkt;
397                switch (nvram->DevId.Interface) {
398                case IndirectNVRAM:
399                          pkt=PnP_find_packet(res->DevicePnpHeap
400                                      +nvram->AllocatedOffset,
401                                              )
402                }
403        }
404#endif
405
406        printk("\nRTEMS " RTEMS_VERSION "/PPC load: ");
407        timer = 0;
408        cp = bd->cmd_line+strlen(bd->cmd_line);
409        while (timer++ < 5*1000) {
410                if (debug_tstc()) {
411                        while ((ch = debug_getc()) != '\n' && ch != '\r') {
412                                if (ch == '\b' || ch == 0177) {
413                                        if (cp != bd->cmd_line) {
414                                                cp--;
415                                                printk("\b \b");
416                                        }
417                                } else {
418                                        *cp++ = ch;
419                                        debug_putc(ch);
420                                }
421                        }
422                        break;  /* Exit 'timer' loop */
423                }
424                boot_udelay(1000);  /* 1 msec */
425        }
426        *cp = 0;
427}
428
429/* Functions to deal with the residual data */
430static int same_DevID(unsigned short vendor,
431               unsigned short Number,
432               unsigned char * str)
433{
434        static unsigned const char hexdigit[]="0123456789ABCDEF";
435        if (strlen((char*)str)!=7) return 0;
436        if ( ( ((vendor>>10)&0x1f)+'A'-1 == str[0])  &&
437             ( ((vendor>>5)&0x1f)+'A'-1 == str[1])   &&
438             ( (vendor&0x1f)+'A'-1 == str[2])        &&
439             (hexdigit[(Number>>12)&0x0f] == str[3]) &&
440             (hexdigit[(Number>>8)&0x0f] == str[4])  &&
441             (hexdigit[(Number>>4)&0x0f] == str[5])  &&
442             (hexdigit[Number&0x0f] == str[6]) ) return 1;
443        return 0;
444}
445
446PPC_DEVICE *residual_find_device(unsigned long BusMask,
447                         unsigned char * DevID,
448                         int BaseType,
449                         int SubType,
450                         int Interface,
451                         int n)
452{
453        int i;
454        RESIDUAL *res = bd->residual;
455        if ( !res || !res->ResidualLength ) return NULL;
456        for (i=0; i<res->ActualNumDevices; i++) {
457#define Dev res->Devices[i].DeviceId
458                if ( (Dev.BusId&BusMask)                                  &&
459                     (BaseType==-1 || Dev.BaseType==BaseType)             &&
460                     (SubType==-1 || Dev.SubType==SubType)                &&
461                     (Interface==-1 || Dev.Interface==Interface)          &&
462                     (DevID==NULL || same_DevID((Dev.DevId>>16)&0xffff,
463                                                Dev.DevId&0xffff, DevID)) &&
464                     !(n--) ) return res->Devices+i;
465#undef Dev
466        }
467        return 0;
468}
469
470PnP_TAG_PACKET *PnP_find_packet(unsigned char *p,
471                                unsigned packet_tag,
472                                int n)
473{
474        unsigned mask, masked_tag, size;
475        if(!p) return 0;
476        if (tag_type(packet_tag)) mask=0xff; else mask=0xF8;
477        masked_tag = packet_tag&mask;
478        for(; *p != END_TAG; p+=size) {
479                if ((*p & mask) == masked_tag && !(n--))
480                        return (PnP_TAG_PACKET *) p;
481                if (tag_type(*p))
482                        size=ld_le16((unsigned short *)(p+1))+3;
483                else
484                        size=tag_small_count(*p)+1;
485        }
486        return 0; /* not found */
487}
488
489PnP_TAG_PACKET *PnP_find_small_vendor_packet(unsigned char *p,
490                                             unsigned packet_type,
491                                             int n)
492{
493        int next=0;
494        while (p) {
495                p = (unsigned char *) PnP_find_packet(p, 0x70, next);
496                if (p && p[1]==packet_type && !(n--))
497                        return (PnP_TAG_PACKET *) p;
498                next = 1;
499        };
500        return 0; /* not found */
501}
502
503PnP_TAG_PACKET *PnP_find_large_vendor_packet(unsigned char *p,
504                                           unsigned packet_type,
505                                           int n)
506{
507        int next=0;
508        while (p) {
509                p = (unsigned char *) PnP_find_packet(p, 0x84, next);
510                if (p && p[3]==packet_type && !(n--))
511                        return (PnP_TAG_PACKET *) p;
512                next = 1;
513        };
514        return 0; /* not found */
515}
516
517/* Find out the amount of installed memory. For MPC105 and IBM 660 this
518 * can be done by finding the bank with the highest memory ending address
519 */
520int
521find_max_mem( struct pci_dev *dev )
522{
523        u_char banks,tmp;
524        int i, top, max;
525
526        max = 0;
527        for ( ; dev; dev = dev->next) {
528                if ( ((dev->vendor == PCI_VENDOR_ID_MOTOROLA) &&
529                      (dev->device == PCI_DEVICE_ID_MOTOROLA_MPC105)) ||
530                     ((dev->vendor == PCI_VENDOR_ID_IBM) &&
531                      (dev->device == 0x0037/*IBM 660 Bridge*/)) ) {
532                        pci_bootloader_read_config_byte(dev, 0xa0, &banks);
533                        for (i = 0; i < 8; i++) {
534                                if ( banks & (1<<i) ) {
535                                        pci_bootloader_read_config_byte(dev, 0x90+i, &tmp);
536                                        top = tmp;
537                                        pci_bootloader_read_config_byte(dev, 0x98+i, &tmp);
538                                        top |= (tmp&3)<<8;
539                                        if ( top > max ) max = top;
540                                }
541                        }
542                        if ( max ) return ((max+1)<<20);
543                        else return(0);
544                }
545        }
546        return(0);
547}
Note: See TracBrowser for help on using the repository browser.