NetBSD/sys/arch/amiga/amiga/amiga_init.c

776 lines
22 KiB
C

/* Authors: Markus Wild, Bryan Ford, Niklas Hallqvist
* Michael L. Hitch - initial 68040 support
*
* $Id: amiga_init.c,v 1.12 1994/04/18 04:08:43 chopps Exp $
*/
#include <machine/pte.h>
#include <machine/cpu.h>
#include <sys/param.h>
#include <machine/vmparam.h>
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/proc.h>
#include <sys/user.h>
#include <vm/vm.h>
#include <sys/ioctl.h>
#include <sys/select.h>
#include <sys/tty.h>
#include <sys/proc.h>
#include <sys/buf.h>
#include <sys/msgbuf.h>
#include <sys/mbuf.h>
#include <sys/protosw.h>
#include <sys/domain.h>
#include <vm/pmap.h>
#include <sys/dkbad.h>
#include <sys/reboot.h>
#include <sys/exec.h>
#include <amiga/amiga/custom.h>
#include <amiga/amiga/cia.h>
#include <amiga/amiga/configdev.h>
#include <amiga/amiga/memlist.h>
#ifdef DEBUG
#include <amiga/amiga/color.h>
#define ROLLCOLOR(a) rollcolor(a)
void rollcolor (u_int);
#else
#define ROLLCOLOR(a)
#endif
extern int machineid, mmutype;
extern u_int lowram;
extern u_int Sysptmap, Sysptsize, Sysseg, Umap, proc0paddr;
extern u_int Sysseg1;
extern u_int virtual_avail;
/* virtual addresses specific to the AMIGA */
u_int CIAADDR, CUSTOMADDR; /* SCSIADDR;*/
/* virtual address space(s) allocated to boards */
caddr_t ZORRO2ADDR; /* add one for zorro3 if necessary */
u_int CHIPMEMADDR;
u_int Z2MEMADDR; /* XXX */
u_int Z2MEMSIZE; /* XXX */
/* some addresses used often, for performance */
caddr_t INTREQRaddr, INTREQWaddr;
/* pre-initialize these variables, so we can access the hardware while
running un-mapped. */
caddr_t CIAAbase = (caddr_t)0xbfe001, CIABbase = (caddr_t)0xbfd000;
volatile struct Custom *CUSTOMbase = (volatile struct Custom *) 0xdff000;
struct Mem_List *mem_list;
void *chipmem_start = (void *)0x400, *chipmem_end;
void *z2mem_start, *z2mem_end; /* XXX */
int use_z2_mem = 1; /* XXX */
int num_ConfigDev;
struct ConfigDev *ConfigDev;
/* Called by the console et al to steal chip memory during initialization */
void *
chipmem_steal(amount)
long amount;
{
/* steal from top of chipmem, so we don't collide with the kernel loaded
into chipmem in the not-yet-mapped state. */
void *ptr = chipmem_end - amount;
if ((long)ptr & 1)
ptr = (void *) ((long)ptr - 1);
chipmem_end = ptr;
if(chipmem_start > chipmem_end)
panic("not enough chip memory");
return(ptr);
}
/* Called to allocate 24-bit DMAable memory (ZorroII or chip). Used by
A2091 and GVP11 scsi driver as a dma bounce buffer. If use_z2_mem
is patched to 0, then only chip memory will be allocated. */
void *
alloc_z2mem(amount) /* XXX */
long amount;
{ /* XXX */
if (use_z2_mem && z2mem_end && (z2mem_end - amount) >= z2mem_start) {
z2mem_end -= amount;
return ((void *) z2mem_end);
}
return ((void *) alloc_chipmem(amount)); /* XXX */
} /* XXX */
/* This stuff is for reloading new kernels through /dev/reload. */
static struct exec kernel_exec;
static u_char *kernel_image;
static u_long kernel_text_size, kernel_load_ofs;
u_long orig_fastram_start, orig_fastram_size, orig_chipram_size;
/* this is the C-level entry function, it's called from locore.s.
Preconditions:
- Interrupts are disabled
- PA == VA, we don't have to relocate addresses before enabling
the MMU
- Exec is no longer available (because we're loaded all over
low memory, no ExecBase is available anymore)
It's purpose is:
- Do the things that are done in locore.s in the hp300 version,
this includes allocation of kernel maps and enabling the MMU.
Some of the code in here is `stolen' from Amiga MACH, and was
written by Bryan Ford and Niklas Hallqvist.
Very crude 68040 support by Michael L. Hitch.
*/
u_int cache_copyback = PG_CC; /* patchable to disable copyback cache */
void
start_c(id, fastram_start, fastram_size, chipram_size, esym_addr)
int id;
u_int fastram_start, fastram_size, chipram_size;
char *esym_addr;
{
extern char end[];
extern void etext();
extern u_int protorp[2];
extern char *esym;
u_int pstart, pend, vstart, vend, avail;
u_int Sysseg_pa, Sysptmap_pa, umap_pa;
u_int Sysseg1_pa, Sysptmap1_pa, umap1_pa;
u_int Sysptmap1, Umap1;
u_int pagetable, pagetable_pa, pagetable_size, pagetable_extra;
u_int sg_proto, pg_proto, *sg, *pg, *pg2, i;
u_int p0_pagetable_pa, p0_u_area_pa;
u_int tc;
u_int hw_va;
u_int chip_pt, cia_pt;
#if 0
u_int custom_pt, scsi_pt;
#else
u_int zorro2_pt;
#endif
u_int end_loaded;
orig_fastram_start = fastram_start;
orig_fastram_size = fastram_size;
orig_chipram_size = chipram_size;
machineid = id;
chipmem_end = (void *)chipram_size;
esym = esym_addr;
/* the kernel ends at end(), plus the ConfigDev structures we placed
there in the loader. Correct for this now. */
if (esym == NULL) {
num_ConfigDev = *(int *)end;
ConfigDev = (struct ConfigDev *) ((int)end + 4);
end_loaded = (u_int)end + 4 + num_ConfigDev * sizeof(struct ConfigDev);
} else {
num_ConfigDev = *(int *)esym;
ConfigDev = (struct ConfigDev *) ((int)esym + 4);
end_loaded = (u_int)esym + 4 + num_ConfigDev * sizeof(struct ConfigDev);
}
mem_list = (struct Mem_List *) end_loaded;
end_loaded = (u_int)&mem_list->mem_seg[mem_list->num_mem];
/* Get ZorroII (16-bit) memory if there is any and it's not where the
kernel is loaded. */
if (mem_list->num_mem > 0 && mem_list->num_mem < 16) {
for (i = 0; i < mem_list->num_mem; i++) {
if ((mem_list->mem_seg[i].mem_attrib & (MEMF_FAST|MEMF_24BITDMA)) !=
(MEMF_FAST|MEMF_24BITDMA))
continue;
if (mem_list->mem_seg[i].mem_start == fastram_start)
continue;
z2mem_start = (void *)mem_list->mem_seg[i].mem_start;
Z2MEMSIZE = mem_list->mem_seg[i].mem_size;
z2mem_end = z2mem_start + mem_list->mem_seg[i].mem_size;
break;
}
}
#if 0
/* XXX */
{
extern int boothowto;
boothowto = RB_SINGLE;
}
#endif
/* printf ("numCD=%d, end=0x%x, end_loaded=0x%x\n", num_ConfigDev, end, end_loaded);*/
/* update these as soon as possible! */
PAGE_SIZE = NBPG;
PAGE_MASK = NBPG-1;
PAGE_SHIFT = PG_SHIFT;
/* assume KVA_MIN == 0 */
vend = fastram_size;
avail = vend;
vstart = (u_int) end_loaded;
vstart = amiga_round_page (vstart);
pstart = vstart + fastram_start;
pend = vend + fastram_start;
avail -= vstart;
if (cpu040) {
/* allocate the kernel 1st level segment table */
Sysseg1 = vstart;
Sysseg1_pa = pstart;
vstart += AMIGA_PAGE_SIZE;
pstart += AMIGA_PAGE_SIZE;
avail -= AMIGA_PAGE_SIZE;
/* allocate the kernel segment table */
Sysseg = vstart;
Sysseg_pa = pstart;
vstart += AMIGA_PAGE_SIZE * 8;
pstart += AMIGA_PAGE_SIZE * 8;
avail -= AMIGA_PAGE_SIZE * 8;
}
else {
/* allocate the kernel segment table */
Sysseg = vstart;
Sysseg_pa = pstart;
vstart += AMIGA_PAGE_SIZE;
pstart += AMIGA_PAGE_SIZE;
avail -= AMIGA_PAGE_SIZE;
}
/* allocate initial page table pages */
pagetable = vstart;
pagetable_pa = pstart;
#if 0
pagetable_extra = CHIPMEMSIZE + CIASIZE + CUSTOMSIZE + SCSISIZE;
#else
pagetable_extra = CHIPMEMSIZE + CIASIZE + ZORRO2SIZE;
#endif
pagetable_extra += (Z2MEMSIZE) / AMIGA_PAGE_SIZE; /* XXX */
pagetable_size = (Sysptsize + (pagetable_extra + NPTEPG-1)/NPTEPG) << PGSHIFT;
vstart += pagetable_size;
pstart += pagetable_size;
avail -= pagetable_size;
/* allocate kernel page table map */
Sysptmap = vstart;
Sysptmap_pa = pstart;
vstart += AMIGA_PAGE_SIZE;
pstart += AMIGA_PAGE_SIZE;
avail -= AMIGA_PAGE_SIZE;
/* set Sysmap; mapped after page table pages */
Sysmap = (typeof (Sysmap)) (pagetable_size << (cpu040 ? 11 : (SEGSHIFT - PGSHIFT)));
/* initialize segment table and page table map */
if (cpu040) {
sg_proto = Sysseg_pa | SG_RW | SG_V;
/* map all level 1 entries to the segment table */
for (sg = (u_int *) Sysseg1_pa;
sg_proto < (u_int) pagetable_pa;
sg_proto += AMIGA_040RTSIZE)
{
*sg++ = sg_proto;
}
sg_proto = pagetable_pa | SG_RW | SG_V;
pg_proto = pagetable_pa | PG_RW | PG_CI | PG_V;
/* map so many segs */
for (sg = (u_int *) Sysseg_pa, pg = (u_int *) Sysptmap_pa;
sg_proto < (u_int) pstart;
sg_proto += AMIGA_040PTSIZE, pg_proto += AMIGA_PAGE_SIZE)
{
*sg++ = sg_proto;
if (pg_proto < pstart)
*pg++ = pg_proto;
else if (pg < (u_int *) (Sysptmap_pa + AMIGA_PAGE_SIZE))
*pg++ = PG_NV;
}
/* and invalidate the remainder of the table */
do
{
*sg++ = SG_NV;
if (pg < (u_int *) (Sysptmap_pa + AMIGA_PAGE_SIZE))
*pg++ = PG_NV;
}
while (sg < (u_int *) (Sysseg_pa + AMIGA_PAGE_SIZE * 8));
}
else {
sg_proto = pagetable_pa | SG_RW | SG_V;
pg_proto = pagetable_pa | PG_RW | PG_CI | PG_V;
/* map so many segs */
for (sg = (u_int *) Sysseg_pa, pg = (u_int *) Sysptmap_pa;
sg_proto < pstart;
sg_proto += AMIGA_PAGE_SIZE, pg_proto += AMIGA_PAGE_SIZE)
{
*sg++ = sg_proto;
*pg++ = pg_proto;
}
/* and invalidate the remainder of the tables (except last entry) */
do
{
*sg++ = SG_NV;
*pg++ = PG_NV;
}
while (sg < (u_int *) (Sysseg_pa + AMIGA_STSIZE-4));
}
if (cpu040) {
/* the end of the last segment (0xFFFC0000) of KVA space is used to
map the u-area of the current process (u + kernel stack). */
umap_pa = pstart;
sg_proto = (pstart + AMIGA_PAGE_SIZE - AMIGA_040PTSIZE) | SG_RW | SG_V; /* use next availabe PA */
umap_pa = pstart; /* remember for later map entry */
/* enter the page into the level 2 segment table */
for (sg = (u_int *) (Sysseg_pa + AMIGA_PAGE_SIZE * 8);
sg_proto > (u_int) pstart;
sg_proto -= AMIGA_040PTSIZE)
*--sg = sg_proto;
/* enter the page into the page table map */
pg_proto = pstart | PG_RW | PG_CI | PG_V;
pg = (u_int *) (Sysptmap_pa + 1024); /*** fix constant ***/
*--pg = pg_proto;
/* invalidate all pte's (will validate u-area afterwards) */
for (pg = (u_int *) pstart;
pg < (u_int *) (pstart + AMIGA_PAGE_SIZE);
)
*pg++ = PG_NV;
/* account for the allocated page */
pstart += AMIGA_PAGE_SIZE;
vstart += AMIGA_PAGE_SIZE;
avail -= AMIGA_PAGE_SIZE;
/* record KVA at which to access current u-area PTE(s) */
Umap = (u_int) Sysmap + AMIGA_MAX_PTSIZE - UPAGES*4;
}
else {
/* the end of the last segment (0xFF000000) of KVA space is used to
map the u-area of the current process (u + kernel stack). */
sg_proto = pstart | SG_RW | SG_V; /* use next availabe PA */
pg_proto = pstart | PG_RW | PG_CI | PG_V;
umap_pa = pstart; /* remember for later map entry */
/* enter the page into the segment table (and page table map) */
*sg++ = sg_proto;
*pg++ = pg_proto;
/* invalidate all pte's (will validate u-area afterwards) */
for (pg = (u_int *) pstart;
pg < (u_int *) (pstart + AMIGA_PAGE_SIZE);
)
*pg++ = PG_NV;
/* account for the allocated page */
pstart += AMIGA_PAGE_SIZE;
vstart += AMIGA_PAGE_SIZE;
avail -= AMIGA_PAGE_SIZE;
/* record KVA at which to access current u-area PTE(s) */
Umap = (u_int) Sysmap + AMIGA_MAX_PTSIZE - UPAGES*4;
}
/* initialize kernel page table page(s) (assume load at VA 0) */
pg_proto = fastram_start | PG_RO | PG_V; /* text pages are RO */
pg = (u_int *) pagetable_pa;
for (i = 0;
i < (u_int) etext;
i += AMIGA_PAGE_SIZE, pg_proto += AMIGA_PAGE_SIZE)
*pg++ = pg_proto;
/* data, bss and dynamic tables are read/write */
pg_proto = (pg_proto & PG_FRAME) | PG_RW | PG_V;
if (cpu040)
pg_proto |= cache_copyback;
/* go till end of data allocated so far plus proc0 PT/u-area (to be allocated) */
for (;
i < vstart + (UPAGES + 1)*AMIGA_PAGE_SIZE;
i += AMIGA_PAGE_SIZE, pg_proto += AMIGA_PAGE_SIZE)
*pg++ = pg_proto;
/* invalidate remainder of kernel PT */
while (pg < (u_int *) (pagetable_pa + pagetable_size))
*pg++ = PG_NV;
/* go back and validate internal IO PTEs at end of allocated PT space */
pg -= pagetable_extra;
chip_pt = (u_int) pg;
pg_proto = CHIPMEMBASE | PG_RW | PG_CI | PG_V; /* CI needed here?? */
while (pg_proto < CHIPMEMTOP)
{
*pg++ = pg_proto;
pg_proto += AMIGA_PAGE_SIZE;
}
if (z2mem_end) { /* XXX */
pg_proto = (u_int) z2mem_start | PG_RW | PG_V; /* XXX */
while (pg_proto < (u_int) z2mem_end) /* XXX */
{ /* XXX */
*pg++ = pg_proto; /* XXX */
pg_proto += AMIGA_PAGE_SIZE; /* XXX */
} /* XXX */
} /* XXX */
pg_proto = CIABASE | PG_RW | PG_CI | PG_V;
cia_pt = (u_int) pg;
while (pg_proto < CIATOP)
{
*pg++ = pg_proto;
pg_proto += AMIGA_PAGE_SIZE;
}
#if 0
pg_proto = CUSTOMBASE | PG_RW | PG_CI | PG_V;
custom_pt = (u_int) pg;
while (pg_proto < CUSTOMTOP)
{
*pg++ = pg_proto;
pg_proto += AMIGA_PAGE_SIZE;
}
pg_proto = SCSIBASE | PG_RW | PG_CI | PG_V;
scsi_pt = (u_int) pg;
while (pg_proto < SCSITOP)
{
*pg++ = pg_proto;
pg_proto += AMIGA_PAGE_SIZE;
}
#else
pg_proto = ZORRO2BASE | PG_RW | PG_CI | PG_V;
zorro2_pt = (u_int) pg;
while (pg_proto < ZORRO2TOP)
{
*pg++ = pg_proto;
pg_proto += AMIGA_PAGE_SIZE;
}
#endif
/* Setup page table for process 0.
We set up page table access for the kernel via Usrptmap (usrpt)
[no longer used?] and access to the u-area itself via Umap (u).
First available page (vstart/pstart) is used for proc0 page table.
Next UPAGES page(s) following are for u-area. */
p0_pagetable_pa = pstart;
pstart += AMIGA_PAGE_SIZE;
vstart += AMIGA_PAGE_SIZE; /* keep VA in sync */
avail -= AMIGA_PAGE_SIZE;
p0_u_area_pa = pstart; /* base of u-area and end of PT */
/* invalidate entire page table */
for (pg = (u_int *) p0_pagetable_pa; pg < (u_int *) p0_u_area_pa; )
*pg++ = PG_NV;
/* now go back and validate u-area PTE(s) in PT and in Umap */
pg -= UPAGES;
pg2 = (u_int *) (umap_pa + 4*(NPTEPG - UPAGES));
pg_proto = p0_u_area_pa | PG_RW | PG_V;
if (cpu040)
pg_proto |= cache_copyback;
for (i = 0; i < UPAGES; i++, pg_proto += AMIGA_PAGE_SIZE)
{
*pg++ = pg_proto;
*pg2++ = pg_proto;
}
bzero ((u_char *) p0_u_area_pa, UPAGES * AMIGA_PAGE_SIZE); /* clear process 0 u-area */
/* save KVA of proc0 u-area */
proc0paddr = vstart;
pstart += UPAGES * AMIGA_PAGE_SIZE;
vstart += UPAGES * AMIGA_PAGE_SIZE;
avail -= UPAGES * AMIGA_PAGE_SIZE;
/* init mem sizes */
maxmem = pend >> PGSHIFT;
lowram = fastram_start >> PGSHIFT;
physmem = fastram_size >> PGSHIFT;
/* get the pmap module in sync with reality. */
pmap_bootstrap (pstart, fastram_start);
/* record base KVA of IO spaces which are just before Sysmap */
CHIPMEMADDR = (u_int)Sysmap - pagetable_extra * AMIGA_PAGE_SIZE;
if (z2mem_end) { /* XXX */
Z2MEMADDR = CHIPMEMADDR + CHIPMEMSIZE*AMIGA_PAGE_SIZE;
CIAADDR = Z2MEMADDR + Z2MEMSIZE;
} /* XXX */
else /* XXX */
CIAADDR = CHIPMEMADDR + CHIPMEMSIZE*AMIGA_PAGE_SIZE;
ZORRO2ADDR = (caddr_t) CIAADDR + CIASIZE*AMIGA_PAGE_SIZE;
CIAADDR += AMIGA_PAGE_SIZE/2; /* not on 8k boundery :-( */
/* just setup the custom chips address, other addresses (like SCSI on
A3000, clock, etc.) moved to device drivers where they belong */
CUSTOMADDR = (u_int) ZORRO2ADDR - ZORRO2BASE + CUSTOMBASE;
#if 0
CUSTOMADDR = CIAADDR + CIASIZE*AMIGA_PAGE_SIZE;
SCSIADDR = CUSTOMADDR + CUSTOMSIZE*AMIGA_PAGE_SIZE;
CIAADDR += AMIGA_PAGE_SIZE/2; /* not on 8k boundery :-( */
CUSTOMADDR += AMIGA_PAGE_SIZE/2; /* not on 8k boundery */
#endif
/* set this before copying the kernel, so the variable is updated in
the `real' place too. protorp[0] is already preset to the CRP setting. */
protorp[1] = Sysseg_pa; /* + segtable address */
/* copy over the kernel (and all now initialized variables) to fastram.
DONT use bcopy(), this beast is much larger than 128k ! */
{
register u_int *lp = 0, *le = (u_int *) end_loaded, *fp = (u_int *) fastram_start;
while (lp < le)
*fp++ = *lp++;
}
/* prepare to enable the MMU */
if (cpu040) {
/* movel Sysseg1_pa,a0; movec a0,SRP; pflusha; movel #$0xc000,d0; movec d0,TC */
asm volatile ("movel %0,a0; .word 0x4e7b,0x8807" : : "a" (Sysseg1_pa));
asm volatile (".word 0xf518" : : );
asm volatile ("movel #0xc000,d0; .word 0x4e7b,0x0003" : : );
}
else {
/* create SRP */
protorp[0] = 0x80000202; /* nolimit + share global + 4 byte PTEs */
/*protorp[1] = Sysseg_pa;*/ /* + segtable address */
/* load SRP into MMU */
asm volatile ("pmove %0@,srp" : : "a" (protorp));
/* setup TC register. */
tc = 0x82d08b00; /* enable_cpr, enable_srp, pagesize=8k, A=8bits, B=11bits */
/* load it */
asm volatile ("pmove %0@,tc" : : "a" (&tc));
}
/* to make life easier in locore.s, set these addresses explicitly */
CIAAbase = (caddr_t) CIAADDR + 0x1001; /* CIA-A is at odd addresses ! */
CIABbase = (caddr_t) CIAADDR;
CUSTOMbase = (volatile struct Custom *) CUSTOMADDR;
INTREQRaddr = (caddr_t) & custom.intreqr;
INTREQWaddr = (caddr_t) & custom.intreq;
/* Get our chip memory allocation system working */
chipmem_start = (void *) (CHIPMEMADDR + (int) chipmem_start);
chipmem_end = (void *) (CHIPMEMADDR + (int) chipmem_end);
if (z2mem_end) { /* XXX */
z2mem_end = (void *) (Z2MEMADDR + Z2MEMSIZE);
z2mem_start = (void *) Z2MEMADDR; /* XXX */
} /* XXX */
i = *(int *)proc0paddr;
*(volatile int *)proc0paddr = i;
/* printf ("Running mapped now! Virtual_avail = $%lx\n", virtual_avail);*/
/* Do these things here, much easier than in assembly in locore.s ;-)
We shut off any interrupts, but allow interrupts in general (INTEN).
This way, drivers can enable those interrupts they want to have
enabled, without having to temper with the global interrupt
enable/disable bit. */
custom.intena = 0x7fff;
/* enable ints (none currently selected though) */
custom.intena = INTF_SETCLR | INTF_INTEN;
/* clear any possibly pending interrupts */
custom.intreq = 0x7fff;
/* really! (-> bloody keyboard!) */
ciaa.icr = 0x7f;
ciab.icr = 0x7f;
/* return to locore.s, and let BSD take over */
}
#ifdef DEBUG
void
rollcolor(color)
u_int color;
{
int s, i;
s = splhigh();
/* need to adjust count - too slow when cache off, too fast when cache on */
for (i = 0; i < 400000; i++)
CUSTOMbase->color[0] = color;
splx (s);
}
void
dump_segtable(ste)
struct ste *ste;
{
int i;
/* XXX need changes for 68040 */
for (i = 0; i < (cpu040 ? AMIGA_040STSIZE : AMIGA_STSIZE)>>2; i++, ste++)
{
if (ste->sg_v == SG_V)
{
printf ("$%08lx -> ", i << (cpu040 ? SG_040ISHIFT : SG_ISHIFT));
printf ("$%08lx\t", (*(u_int *)ste) & SG_FRAME);
}
}
printf ("\n");
}
void
dump_pagetable(voff, pte, num_pte)
caddr_t voff;
struct pte *pte;
int num_pte;
{
int i;
while (num_pte--)
{
if (pte->pg_v == PG_V)
{
printf ("$%08lx -> ", voff);
printf ("$%08lx\t", (*(u_int *)pte) & PG_FRAME);
}
}
printf ("\n");
}
u_int
vmtophys(ste, vm)
u_int *ste, vm;
{
u_int *s;
s = (u_int *)((*(ste + (vm >> SEGSHIFT))) & SG_FRAME);
s += (vm & (cpu040 ? SG_040PMASK : SG_PMASK)) >> PGSHIFT;
return (*s & (-AMIGA_PAGE_SIZE)) | (vm & (AMIGA_PAGE_SIZE-1));
}
#endif
/*** Kernel reloading code ***/
/* This supports the /dev/reload device, major 2, minor 20,
hooked into mem.c. Author: Bryan Ford. */
/* This is called below to find out how much magic storage
will be needed after a kernel image to be reloaded. */
static int
kernel_image_magic_size()
{
return 4 + num_ConfigDev * sizeof(struct ConfigDev)
+ mem_list->num_mem*sizeof(struct Mem_Seg) + 4;
}
/* This actually copies the magic information. */
static void
kernel_image_magic_copy(dest)
u_char *dest;
{
*((int*)dest) = num_ConfigDev;
dest += 4;
bcopy(ConfigDev, dest, num_ConfigDev * sizeof(struct ConfigDev)
+ mem_list->num_mem*sizeof(struct Mem_Seg) + 4);
}
#undef __LDPGSZ
#define __LDPGSZ 8192 /* XXX ??? */
int
kernel_reload_write(uio)
struct uio *uio;
{
struct iovec *iov;
int error;
iov = uio->uio_iov;
if (kernel_image == 0)
{
/* We have to get at least the whole exec header
in the first write. */
if (iov->iov_len < sizeof(kernel_exec))
return EFAULT; /* XXX */
/* Pull in the exec header and check it. */
error = uiomove(&kernel_exec, sizeof(kernel_exec), uio);
if (error == 0)
{
#if 0 /* XXX??? */
if (kernel_exec.a_magic != NMAGIC)
return EFAULT; /* XXX */
#endif
printf("loading kernel %d+%d+%d\n", kernel_exec.a_text, kernel_exec.a_data, kernel_exec.a_bss);
/* Looks good - allocate memory for a kernel image. */
kernel_text_size = (kernel_exec.a_text
+ __LDPGSZ - 1) & (-__LDPGSZ);
kernel_image = malloc(kernel_text_size + kernel_exec.a_data
+ kernel_exec.a_bss
+ kernel_image_magic_size(),
M_TEMP, M_WAITOK);
kernel_load_ofs = 0;
}
}
else
{
int c;
/* Continue loading in the kernel image. */
if (kernel_load_ofs < kernel_exec.a_text)
{
c = MIN(iov->iov_len, kernel_exec.a_text - kernel_load_ofs);
c = MIN(c, MAXPHYS);
}
else
{
if (kernel_load_ofs == kernel_exec.a_text)
kernel_load_ofs = kernel_text_size;
c = MIN(iov->iov_len,
kernel_text_size + kernel_exec.a_data - kernel_load_ofs);
c = MIN(c, MAXPHYS);
}
error = uiomove(kernel_image + kernel_load_ofs, (int)c, uio);
if (error == 0)
{
kernel_load_ofs += c;
if (kernel_load_ofs == kernel_text_size + kernel_exec.a_data)
{
/* Put the finishing touches on the kernel image. */
for(c = 0; c < kernel_exec.a_bss; c++)
kernel_image[kernel_text_size + kernel_exec.a_data + c] = 0;
kernel_image_magic_copy(kernel_image + kernel_text_size
+ kernel_exec.a_data
+ kernel_exec.a_bss);
/* Get everything in a clean state for rebooting. */
bootsync();
/* Start the new kernel with code in locore.s. */
kernel_reload(kernel_image,
(kernel_text_size + kernel_exec.a_data
+ kernel_exec.a_bss + kernel_image_magic_size()),
kernel_exec.a_entry,
orig_fastram_start, orig_fastram_size,
orig_chipram_size, NULL);
}
}
}
return error;
}