1
0
Files
irix-657m-src/stand/arcs/IP21prom/transfer.c
2022-09-29 17:59:04 +03:00

172 lines
4.8 KiB
C

/***********************************************************************\
* File: transfer.c *
* *
* Attempts to read the IO4 Flash EPROM, transfer it into main *
* memory, and then execute it. The master IO4 must have been *
* initialized before this routine is called. The code assumes *
* that the flash EPROM is in the standard location in *
* IO window 1. *
* *
\***********************************************************************/
#include <sys/types.h>
#include <sys/sbd.h>
#include <sys/cpu.h>
#include <sys/loaddrs.h>
#include <sys/EVEREST/epc.h>
#include <sys/EVEREST/promhdr.h>
#include <setjmp.h>
#include "pod.h"
#include "prom_leds.h"
#include "prom_externs.h"
#include "pod_failure.h"
#define PROM_OFF 4096 /* PROM starts at offset 4096 in Flash PROM */
/*
* copy_prom(__scunsigned_t src, __scunsigned_t dest, uint numbytes)
* Copies the requested number of bytes from the
* flash eprom to the specified memory address.
* As the copy is performed, a checksum is calculated
* and is returned on completion.
*/
#define SPLIT (512 * 1024)
#define MEG (1024 * 1024)
int jump_addr(__psunsigned_t, uint, uint, struct flag_struct *);
uint load_lwin_half_store_mult(int, int, __scunsigned_t, int);
uint
copy_prom(register __scunsigned_t src,
register __scunsigned_t dest,
uint numbytes)
{
register __scunsigned_t offset = (master_epc_adap()<<LWIN_PADAPSHIFT) + src;
register uint cksum = 0;
register uint numtocopy;
while (numbytes) {
/* We can't allow the transfer to cross the boundary between
* Flash PROM windows 0 and 1, so we break up the transfer into
* two pieces if necessary and select the proper window.
*/
if (src < SPLIT) {
numtocopy = ((numbytes < (SPLIT - src)) ? numbytes : (SPLIT - src));
offset += EPC_LWIN_LOPROM;
} else {
numtocopy = numbytes;
offset += EPC_LWIN_HIPROM - SPLIT;
}
cksum += load_lwin_half_store_mult(EPC_REGION, offset, dest, numtocopy);
dest += numtocopy;
offset += numtocopy;
src += numtocopy;
numbytes -= numtocopy;
}
return cksum;
}
/*
* load_io4prom()
* Copies the IO4 PROM out of the Flash EPROM and loads it
* into memory.
*/
int
load_io4prom()
{
evpromhdr_t promhdr;
seginfo_t seginfo;
uint cksum;
struct flag_struct flags;
jmp_buf fault_buf; /* Fault status buffer */
unsigned *old_buf; /* Previous fault handler buf ptr */
__psunsigned_t startaddr, entry;
sysctlr_message("Loading IO4 PROM...");
/*
* Pull in the PROM header and check it
*/
if (setfault(fault_buf, &old_buf)) {
loprintf("*** A bus error occurred while downloading IO4 PROM.\n");
restorefault(old_buf);
return EVDIAG_DLBUSERR;
}
/* Set the LEDs appropriately */
set_cc_leds(PLED_LOADPROM);
loprintf("Downloading PROM header information...");
(void) copy_prom(0, (__scunsigned_t)&promhdr, sizeof(promhdr));
(void) copy_prom(SEGINFO_OFFSET, (__scunsigned_t)&seginfo, sizeof(seginfo_t));
if (promhdr.prom_magic != PROM_MAGIC) {
loprintf("*** ERROR: Invalid magic number (%x) for IO4 PROM.\n",
promhdr.prom_magic);
restorefault(old_buf);
return EVDIAG_BADMAGIC;
}
if (seginfo.si_magic != SI_MAGIC) {
loprintf("*** ERROR: Invalid segment magic number (%x) for IO4 PROM.\n",
seginfo.si_magic);
restorefault(old_buf);
return EVDIAG_BADMAGIC;
}
startaddr = seginfo.si_segs[0].seg_startaddr;
entry = seginfo.si_segs[0].seg_entry;
if (! IS_KSEGDM(startaddr)) {
loprintf("*** ERROR: IO4 PROM start address 0x%x is invalid\n",
startaddr);
restorefault(old_buf);
return EVDIAG_BADSTART;
}
if (promhdr.prom_length > MEG) {
loprintf("*** ERROR: IO4 PROM length 0x%x is excessive.\n",
promhdr.prom_length);
restorefault(old_buf);
return EVDIAG_TOOLONG;
}
/*
* Actually copy the bulk of the PROM into main memory UNCACHED
*/
loprintf("\nDownloading PROM code...");
cksum = copy_prom(PROM_OFF, startaddr, promhdr.prom_length);
loprintf("\n");
if (cksum != promhdr.prom_cksum) {
loprintf("*** WARNING: IO4 PROM checksums don't match.\n");
loprintf("\t Calculated 0x%x != stored 0x%x\n", cksum,
promhdr.prom_cksum);
restorefault(old_buf);
return EVDIAG_BADCKSUM;
}
if ((entry < startaddr) || (entry > startaddr + promhdr.prom_length)) {
loprintf("*** ERROR: IO4 PROM entry point (0x%x) is outside of PROM\n",
entry);
restorefault(old_buf);
return EVDIAG_BADENTRY;
}
/* Let the world know we're about to jump. */
set_cc_leds(PLED_PROMJUMP);
loprintf("Jumping into IO4 PROM.\n");
flags.mem = 1; /* Yes, we have memory */
flags.silent = 1; /* Don't squawk about clearing cache, jumping to... */
setfault(0, &old_buf);
jump_addr(entry, 0, 0, &flags);
loprintf("IO4 PROM returned. Weird.\n");
return 0;
}