forked from Imagelibrary/rtems
Merged of mcp750 and mvme2307 BSP by Eric Valette <valette@crf.canon.fr>.
As part of this effort, the mpc750 libcpu code is now shared with the ppc6xx.
This commit is contained in:
528
c/src/lib/libbsp/powerpc/shared/bootloader/misc.c
Normal file
528
c/src/lib/libbsp/powerpc/shared/bootloader/misc.c
Normal file
@@ -0,0 +1,528 @@
|
||||
/*
|
||||
* head.S -- Bootloader Entry point
|
||||
*
|
||||
* Copyright (C) 1998, 1999 Gabriel Paubert, paubert@iram.es
|
||||
*
|
||||
* Modified to compile in RTEMS development environment
|
||||
* by Eric Valette
|
||||
*
|
||||
* Copyright (C) 1999 Eric Valette. valette@crf.canon.fr
|
||||
*
|
||||
* The license and distribution terms for this file may be
|
||||
* found in found in the file LICENSE in this distribution or at
|
||||
* http://www.OARcorp.com/rtems/license.html.
|
||||
*
|
||||
* $Id$
|
||||
*/
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <string.h>
|
||||
#include <libcpu/cpu.h>
|
||||
#include "bootldr.h"
|
||||
#include <libcpu/spr.h>
|
||||
#include "zlib.h"
|
||||
#include <libcpu/page.h>
|
||||
#include <libcpu/byteorder.h>
|
||||
|
||||
SPR_RW(DEC)
|
||||
SPR_RO(PVR)
|
||||
|
||||
struct inode;
|
||||
struct wait_queue;
|
||||
struct buffer_head;
|
||||
typedef struct { int counter; } atomic_t;
|
||||
|
||||
|
||||
typedef struct page {
|
||||
/* these must be first (free area handling) */
|
||||
struct page *next;
|
||||
struct page *prev;
|
||||
struct inode *inode;
|
||||
unsigned long offset;
|
||||
struct page *next_hash;
|
||||
atomic_t count;
|
||||
unsigned long flags; /* atomic flags, some possibly updated asynchronously */
|
||||
struct wait_queue *wait;
|
||||
struct page **pprev_hash;
|
||||
struct buffer_head * buffers;
|
||||
} mem_map_t;
|
||||
|
||||
|
||||
extern opaque mm_private, pci_private, v86_private, console_private;
|
||||
|
||||
#define CONSOLE_ON_SERIAL "console=ttyS0"
|
||||
|
||||
extern struct console_io vacuum_console_functions;
|
||||
extern opaque log_console_setup, serial_console_setup, vga_console_setup;
|
||||
|
||||
boot_data __bd = {0, 0, 0, 0, 0, 0, 0, 0,
|
||||
32, 0, 0, 0, 0, 0, 0,
|
||||
&mm_private,
|
||||
NULL,
|
||||
&pci_private,
|
||||
NULL,
|
||||
&v86_private,
|
||||
"root=/dev/hdc1"
|
||||
};
|
||||
|
||||
static void exit(void) __attribute__((noreturn));
|
||||
|
||||
static void exit(void) {
|
||||
printk("\nOnly way out is to press the reset button!\n");
|
||||
asm volatile("": : :"memory");
|
||||
while(1);
|
||||
}
|
||||
|
||||
|
||||
void hang(const char *s, u_long x, ctxt *p) {
|
||||
u_long *r1;
|
||||
#ifdef DEBUG
|
||||
print_all_maps("\nMemory mappings at exception time:\n");
|
||||
#endif
|
||||
printk("%s %lx NIP: %p LR: %p\n"
|
||||
"Callback trace (stack:return address)\n",
|
||||
s, x, (void *) p->nip, (void *) p->lr);
|
||||
asm volatile("lwz %0,0(1); lwz %0,0(%0); lwz %0,0(%0)": "=b" (r1));
|
||||
while(r1) {
|
||||
printk(" %p:%p\n", r1, (void *) r1[1]);
|
||||
r1 = (u_long *) *r1;
|
||||
}
|
||||
exit();
|
||||
};
|
||||
|
||||
|
||||
void *zalloc(void *x, unsigned items, unsigned size)
|
||||
{
|
||||
void *p = salloc(items*size);
|
||||
|
||||
if (!p) {
|
||||
printk("oops... not enough memory for gunzip\n");
|
||||
}
|
||||
return p;
|
||||
}
|
||||
|
||||
void zfree(void *x, void *addr, unsigned nb)
|
||||
{
|
||||
sfree(addr);
|
||||
}
|
||||
|
||||
#define HEAD_CRC 2
|
||||
#define EXTRA_FIELD 4
|
||||
#define ORIG_NAME 8
|
||||
#define COMMENT 0x10
|
||||
#define RESERVED 0xe0
|
||||
|
||||
#define DEFLATED 8
|
||||
|
||||
|
||||
void gunzip(void *dst, int dstlen, unsigned char *src, int *lenp)
|
||||
{
|
||||
z_stream s;
|
||||
int r, i, flags;
|
||||
|
||||
/* skip header */
|
||||
i = 10;
|
||||
flags = src[3];
|
||||
if (src[2] != DEFLATED || (flags & RESERVED) != 0) {
|
||||
printk("bad gzipped data\n");
|
||||
exit();
|
||||
}
|
||||
if ((flags & EXTRA_FIELD) != 0)
|
||||
i = 12 + src[10] + (src[11] << 8);
|
||||
if ((flags & ORIG_NAME) != 0)
|
||||
while (src[i++] != 0)
|
||||
;
|
||||
if ((flags & COMMENT) != 0)
|
||||
while (src[i++] != 0)
|
||||
;
|
||||
if ((flags & HEAD_CRC) != 0)
|
||||
i += 2;
|
||||
if (i >= *lenp) {
|
||||
printk("gunzip: ran out of data in header\n");
|
||||
exit();
|
||||
}
|
||||
|
||||
s.zalloc = zalloc;
|
||||
s.zfree = zfree;
|
||||
r = inflateInit2(&s, -MAX_WBITS);
|
||||
if (r != Z_OK) {
|
||||
printk("inflateInit2 returned %d\n", r);
|
||||
exit();
|
||||
}
|
||||
s.next_in = src + i;
|
||||
s.avail_in = *lenp - i;
|
||||
s.next_out = dst;
|
||||
s.avail_out = dstlen;
|
||||
r = inflate(&s, Z_FINISH);
|
||||
if (r != Z_OK && r != Z_STREAM_END) {
|
||||
printk("inflate returned %d\n", r);
|
||||
exit();
|
||||
}
|
||||
*lenp = s.next_out - (unsigned char *) dst;
|
||||
inflateEnd(&s);
|
||||
}
|
||||
|
||||
void decompress_kernel(int kernel_size, void * zimage_start, int len,
|
||||
void * initrd_start, int initrd_len ) {
|
||||
u_char *parea;
|
||||
RESIDUAL* rescopy;
|
||||
int zimage_size= len;
|
||||
|
||||
/* That's a mess, we have to copy the residual data twice just in
|
||||
* case it happens to be in the low memory area where the kernel
|
||||
* is going to be unpacked. Later we have to copy it back to
|
||||
* lower addresses because only the lowest part of memory is mapped
|
||||
* during boot.
|
||||
*/
|
||||
parea=__palloc(kernel_size, PA_LOW);
|
||||
if(!parea) {
|
||||
printk("Not enough memory to uncompress the kernel.");
|
||||
exit();
|
||||
}
|
||||
/* Note that this clears the bss as a side effect, so some code
|
||||
* with ugly special case for SMP could be removed from the kernel!
|
||||
*/
|
||||
memset(parea, 0, kernel_size);
|
||||
printk("\nUncompressing the kernel...\n");
|
||||
rescopy=salloc(sizeof(RESIDUAL));
|
||||
/* Let us hope that residual data is aligned on word boundary */
|
||||
*rescopy = *bd->residual;
|
||||
bd->residual = (void *)PAGE_ALIGN(kernel_size);
|
||||
|
||||
gunzip(parea, kernel_size, zimage_start, &zimage_size);
|
||||
|
||||
bd->of_entry = 0;
|
||||
bd->load_address = 0;
|
||||
bd->r6 = (char *)bd->residual+PAGE_ALIGN(sizeof(RESIDUAL));
|
||||
bd->r7 = bd->r6+strlen(bd->cmd_line);
|
||||
if ( initrd_len ) {
|
||||
/* We have to leave some room for the hash table and for the
|
||||
* whole array of struct page. The hash table would be better
|
||||
* located at the end of memory if possible. With some bridges
|
||||
* DMA from the last pages of memory is slower because
|
||||
* prefetching from PCI has to be disabled to avoid accessing
|
||||
* non existing memory. So it is the ideal place to put the
|
||||
* hash table.
|
||||
*/
|
||||
unsigned tmp = rescopy->TotalMemory;
|
||||
/* It's equivalent to tmp & (-tmp), but using the negation
|
||||
* operator on unsigned variables looks so ugly.
|
||||
*/
|
||||
if ((tmp & (~tmp+1)) != tmp) tmp <<= 1; /* Next power of 2 */
|
||||
tmp /= 256; /* Size of hash table */
|
||||
if (tmp> (2<<20)) tmp=2<<20;
|
||||
tmp = tmp*2 + 0x40000; /* Alignment can double size + 256 kB */
|
||||
tmp += (rescopy->TotalMemory / PAGE_SIZE)
|
||||
* sizeof(struct page);
|
||||
bd->load_address = (void *)PAGE_ALIGN((int)bd->r7 + tmp);
|
||||
bd->of_entry = (char *)bd->load_address+initrd_len;
|
||||
}
|
||||
#ifdef DEBUG
|
||||
printk("Kernel at 0x%p, size=0x%x\n", NULL, kernel_size);
|
||||
printk("Initrd at 0x%p, size=0x%x\n",bd->load_address, initrd_len);
|
||||
printk("Residual data at 0x%p\n", bd->residual);
|
||||
printk("Command line at 0x%p\n",bd->r6);
|
||||
#endif
|
||||
printk("done\nNow booting...\n");
|
||||
MMUoff(); /* We need to access address 0 ! */
|
||||
codemove(0, parea, kernel_size, bd->cache_lsize);
|
||||
codemove(bd->residual, rescopy, sizeof(RESIDUAL), bd->cache_lsize);
|
||||
codemove(bd->r6, bd->cmd_line, sizeof(bd->cmd_line), bd->cache_lsize);
|
||||
/* codemove checks for 0 length */
|
||||
codemove(bd->load_address, initrd_start, initrd_len, bd->cache_lsize);
|
||||
}
|
||||
|
||||
void
|
||||
setup_hw(void)
|
||||
{
|
||||
char *cp, ch;
|
||||
register RESIDUAL * res;
|
||||
/* PPC_DEVICE * nvram; */
|
||||
struct pci_dev *p, *default_vga;
|
||||
int timer, err;
|
||||
u_short default_vga_cmd;
|
||||
static unsigned int indic;
|
||||
|
||||
indic = 0;
|
||||
|
||||
res=bd->residual;
|
||||
default_vga=NULL;
|
||||
default_vga_cmd = 0;
|
||||
|
||||
#define vpd res->VitalProductData
|
||||
if (_read_PVR()>>16 != 1) {
|
||||
if ( res && vpd.ProcessorBusHz ) {
|
||||
ticks_per_ms = vpd.ProcessorBusHz/
|
||||
(vpd.TimeBaseDivisor ? vpd.TimeBaseDivisor : 4000);
|
||||
} else {
|
||||
ticks_per_ms = 16500; /* assume 66 MHz on bus */
|
||||
}
|
||||
}
|
||||
|
||||
select_console(CONSOLE_LOG);
|
||||
|
||||
/* We check that the keyboard is present and immediately
|
||||
* select the serial console if not.
|
||||
*/
|
||||
err = kbdreset();
|
||||
if (err) select_console(CONSOLE_SERIAL);
|
||||
|
||||
printk("\nModel: %s\nSerial: %s\n"
|
||||
"Processor/Bus frequencies (Hz): %ld/%ld\n"
|
||||
"Time Base Divisor: %ld\n"
|
||||
"Memory Size: %x\n",
|
||||
vpd.PrintableModel,
|
||||
vpd.Serial,
|
||||
vpd.ProcessorHz,
|
||||
vpd.ProcessorBusHz,
|
||||
(vpd.TimeBaseDivisor ? vpd.TimeBaseDivisor : 4000),
|
||||
res->TotalMemory);
|
||||
printk("Original MSR: %lx\nOriginal HID0: %lx\nOriginal R31: %lx\n",
|
||||
bd->o_msr, bd->o_hid0, bd->o_r31);
|
||||
|
||||
/* This reconfigures all the PCI subsystem */
|
||||
pci_init();
|
||||
|
||||
/* The Motorola NT firmware does not set the correct mem size */
|
||||
if ( vpd.FirmwareSupplier == 0x10000 ) {
|
||||
int memsize;
|
||||
memsize = find_max_mem(bd->pci_devices);
|
||||
if ( memsize != res->TotalMemory ) {
|
||||
printk("Changed Memory size from %lx to %x\n",
|
||||
res->TotalMemory, memsize);
|
||||
res->TotalMemory = memsize;
|
||||
res->GoodMemory = memsize;
|
||||
}
|
||||
}
|
||||
#define ENABLE_VGA_USAGE
|
||||
#undef ENABLE_VGA_USAGE
|
||||
#ifdef ENABLE_VGA_USAGE
|
||||
/* Find the primary VGA device, chosing the first one found
|
||||
* if none is enabled. The basic loop structure has been copied
|
||||
* from linux/drivers/char/bttv.c by Alan Cox.
|
||||
*/
|
||||
for (p = bd->pci_devices; p; p = p->next) {
|
||||
u_short cmd;
|
||||
if (p->class != PCI_CLASS_NOT_DEFINED_VGA &&
|
||||
((p->class) >> 16 != PCI_BASE_CLASS_DISPLAY))
|
||||
continue;
|
||||
if (p->bus->number != 0) {
|
||||
printk("VGA device not on bus 0 not initialized!\n");
|
||||
continue;
|
||||
}
|
||||
/* Only one can be active in text mode, which for now will
|
||||
* be assumed as equivalent to having I/O response enabled.
|
||||
*/
|
||||
pci_read_config_word(p, PCI_COMMAND, &cmd);
|
||||
if(cmd & PCI_COMMAND_IO || !default_vga) {
|
||||
default_vga=p;
|
||||
default_vga_cmd=cmd;
|
||||
}
|
||||
}
|
||||
|
||||
/* Disable the enabled VGA device, if any. */
|
||||
if (default_vga)
|
||||
pci_write_config_word(default_vga, PCI_COMMAND,
|
||||
default_vga_cmd&
|
||||
~(PCI_COMMAND_IO|PCI_COMMAND_MEMORY));
|
||||
init_v86();
|
||||
/* Same loop copied from bttv.c, this time doing the serious work */
|
||||
for (p = bd->pci_devices; p; p = p->next) {
|
||||
u_short cmd;
|
||||
if (p->class != PCI_CLASS_NOT_DEFINED_VGA &&
|
||||
((p->class) >> 16 != PCI_BASE_CLASS_DISPLAY))
|
||||
continue;
|
||||
if (p->bus->number != 0) continue;
|
||||
pci_read_config_word(p, PCI_COMMAND, &cmd);
|
||||
pci_write_config_word(p, PCI_COMMAND,
|
||||
cmd|PCI_COMMAND_IO|PCI_COMMAND_MEMORY);
|
||||
printk("Calling the emulator.\n");
|
||||
em86_main(p);
|
||||
pci_write_config_word(p, PCI_COMMAND, cmd);
|
||||
}
|
||||
|
||||
cleanup_v86_mess();
|
||||
#endif
|
||||
/* Reenable the primary VGA device */
|
||||
if (default_vga) {
|
||||
pci_write_config_word(default_vga, PCI_COMMAND,
|
||||
default_vga_cmd|
|
||||
(PCI_COMMAND_IO|PCI_COMMAND_MEMORY));
|
||||
if (err) {
|
||||
printk("Keyboard error %d, using serial console!\n",
|
||||
err);
|
||||
} else {
|
||||
select_console(CONSOLE_VGA);
|
||||
}
|
||||
} else if (!err) {
|
||||
select_console(CONSOLE_SERIAL);
|
||||
if (bd->cmd_line[0] == '\0') {
|
||||
strcat(&bd->cmd_line[0], CONSOLE_ON_SERIAL);
|
||||
}
|
||||
else {
|
||||
int s = strlen (bd->cmd_line);
|
||||
bd->cmd_line[s + 1] = ' ';
|
||||
bd->cmd_line[s + 2] = '\0';
|
||||
strcat(&bd->cmd_line[0], CONSOLE_ON_SERIAL);
|
||||
}
|
||||
}
|
||||
#if 0
|
||||
/* In the future we may use the NVRAM to store default
|
||||
* kernel parameters.
|
||||
*/
|
||||
nvram=residual_find_device(~0UL, NULL, SystemPeripheral, NVRAM,
|
||||
~0UL, 0);
|
||||
if (nvram) {
|
||||
PnP_TAG_PACKET * pkt;
|
||||
switch (nvram->DevId.Interface) {
|
||||
case IndirectNVRAM:
|
||||
pkt=PnP_find_packet(res->DevicePnpHeap
|
||||
+nvram->AllocatedOffset,
|
||||
)
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
printk("\nRTEMS 4.x/PPC load: ");
|
||||
timer = 0;
|
||||
cp = bd->cmd_line+strlen(bd->cmd_line);
|
||||
while (timer++ < 5*1000) {
|
||||
if (debug_tstc()) {
|
||||
while ((ch = debug_getc()) != '\n' && ch != '\r') {
|
||||
if (ch == '\b' || ch == 0177) {
|
||||
if (cp != bd->cmd_line) {
|
||||
cp--;
|
||||
printk("\b \b");
|
||||
}
|
||||
} else {
|
||||
*cp++ = ch;
|
||||
debug_putc(ch);
|
||||
}
|
||||
}
|
||||
break; /* Exit 'timer' loop */
|
||||
}
|
||||
udelay(1000); /* 1 msec */
|
||||
}
|
||||
*cp = 0;
|
||||
}
|
||||
|
||||
|
||||
/* Functions to deal with the residual data */
|
||||
static int same_DevID(unsigned short vendor,
|
||||
unsigned short Number,
|
||||
char * str)
|
||||
{
|
||||
static unsigned const char hexdigit[]="0123456789ABCDEF";
|
||||
if (strlen(str)!=7) return 0;
|
||||
if ( ( ((vendor>>10)&0x1f)+'A'-1 == str[0]) &&
|
||||
( ((vendor>>5)&0x1f)+'A'-1 == str[1]) &&
|
||||
( (vendor&0x1f)+'A'-1 == str[2]) &&
|
||||
(hexdigit[(Number>>12)&0x0f] == str[3]) &&
|
||||
(hexdigit[(Number>>8)&0x0f] == str[4]) &&
|
||||
(hexdigit[(Number>>4)&0x0f] == str[5]) &&
|
||||
(hexdigit[Number&0x0f] == str[6]) ) return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
PPC_DEVICE *residual_find_device(unsigned long BusMask,
|
||||
unsigned char * DevID,
|
||||
int BaseType,
|
||||
int SubType,
|
||||
int Interface,
|
||||
int n)
|
||||
{
|
||||
int i;
|
||||
RESIDUAL *res = bd->residual;
|
||||
if ( !res || !res->ResidualLength ) return NULL;
|
||||
for (i=0; i<res->ActualNumDevices; i++) {
|
||||
#define Dev res->Devices[i].DeviceId
|
||||
if ( (Dev.BusId&BusMask) &&
|
||||
(BaseType==-1 || Dev.BaseType==BaseType) &&
|
||||
(SubType==-1 || Dev.SubType==SubType) &&
|
||||
(Interface==-1 || Dev.Interface==Interface) &&
|
||||
(DevID==NULL || same_DevID((Dev.DevId>>16)&0xffff,
|
||||
Dev.DevId&0xffff, DevID)) &&
|
||||
!(n--) ) return res->Devices+i;
|
||||
#undef Dev
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
PnP_TAG_PACKET *PnP_find_packet(unsigned char *p,
|
||||
unsigned packet_tag,
|
||||
int n)
|
||||
{
|
||||
unsigned mask, masked_tag, size;
|
||||
if(!p) return 0;
|
||||
if (tag_type(packet_tag)) mask=0xff; else mask=0xF8;
|
||||
masked_tag = packet_tag&mask;
|
||||
for(; *p != END_TAG; p+=size) {
|
||||
if ((*p & mask) == masked_tag && !(n--))
|
||||
return (PnP_TAG_PACKET *) p;
|
||||
if (tag_type(*p))
|
||||
size=ld_le16((unsigned short *)(p+1))+3;
|
||||
else
|
||||
size=tag_small_count(*p)+1;
|
||||
}
|
||||
return 0; /* not found */
|
||||
}
|
||||
|
||||
PnP_TAG_PACKET *PnP_find_small_vendor_packet(unsigned char *p,
|
||||
unsigned packet_type,
|
||||
int n)
|
||||
{
|
||||
int next=0;
|
||||
while (p) {
|
||||
p = (unsigned char *) PnP_find_packet(p, 0x70, next);
|
||||
if (p && p[1]==packet_type && !(n--))
|
||||
return (PnP_TAG_PACKET *) p;
|
||||
next = 1;
|
||||
};
|
||||
return 0; /* not found */
|
||||
}
|
||||
|
||||
PnP_TAG_PACKET *PnP_find_large_vendor_packet(unsigned char *p,
|
||||
unsigned packet_type,
|
||||
int n)
|
||||
{
|
||||
int next=0;
|
||||
while (p) {
|
||||
p = (unsigned char *) PnP_find_packet(p, 0x84, next);
|
||||
if (p && p[3]==packet_type && !(n--))
|
||||
return (PnP_TAG_PACKET *) p;
|
||||
next = 1;
|
||||
};
|
||||
return 0; /* not found */
|
||||
}
|
||||
|
||||
/* Find out the amount of installed memory. For MPC105 and IBM 660 this
|
||||
* can be done by finding the bank with the highest memory ending address
|
||||
*/
|
||||
int
|
||||
find_max_mem( struct pci_dev *dev )
|
||||
{
|
||||
u_char banks,tmp;
|
||||
int i, top, max;
|
||||
|
||||
max = 0;
|
||||
for ( ; dev; dev = dev->next) {
|
||||
if ( ((dev->vendor == PCI_VENDOR_ID_MOTOROLA) &&
|
||||
(dev->device == PCI_DEVICE_ID_MOTOROLA_MPC105)) ||
|
||||
((dev->vendor == PCI_VENDOR_ID_IBM) &&
|
||||
(dev->device == 0x0037/*IBM 660 Bridge*/)) ) {
|
||||
pci_read_config_byte(dev, 0xa0, &banks);
|
||||
for (i = 0; i < 8; i++) {
|
||||
if ( banks & (1<<i) ) {
|
||||
pci_read_config_byte(dev, 0x90+i, &tmp);
|
||||
top = tmp;
|
||||
pci_read_config_byte(dev, 0x98+i, &tmp);
|
||||
top |= (tmp&3)<<8;
|
||||
if ( top > max ) max = top;
|
||||
}
|
||||
}
|
||||
if ( max ) return ((max+1)<<20);
|
||||
else return(0);
|
||||
}
|
||||
}
|
||||
return(0);
|
||||
}
|
||||
Reference in New Issue
Block a user