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

5
Last change on this file since eb36d11 was 03e1d837, checked in by Sebastian Huber <sebastian.huber@…>, on 04/24/18 at 05:06:36

bsps/powerpc: Move bootloader to bsps

This bootloader is only used by the motorola_powerpc BSP.

This patch is a part of the BSP source reorganization.

Update #3285.

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