diff options
125 files changed, 27517 insertions, 1190 deletions
diff --git a/sys/arch/mvme88k/conf/GENERIC b/sys/arch/mvme88k/conf/GENERIC new file mode 100644 index 00000000000..959af6779af --- /dev/null +++ b/sys/arch/mvme88k/conf/GENERIC @@ -0,0 +1,100 @@ +# +# This configuration file contains all possible options +# + +machine m88k + +options TIMEZONE=300, DST=1 + +# +# processors this kernel should support +# +options "M88000" # support for 88K +options MVME187 # support for 187 + +options SWAPPAGER # Pager for processes (Required) +options VNODEPAGER # Pager for vnodes (Required) +options DEVPAGER # Pager for devices (Required) + +# +# Networking options +# + +# +# File system related options +# +#options QUOTA # Disk quotas for local disks +#options NFSSERVER # Network File System server side code +#options NFSCLIENT # Network File System client side code + +# +# File systems +# +options FFS # Berkeley fast file system +options MFS # Memory based filesystem +options FIFO # FIFO operations on vnodes (Recommended) + +# +# Compatability options for various existing systems +# +#options "COMPAT_43" # 4.3 BSD compatible system calls +#options "TCP_COMPAT_42" # Use 4.2 BSD style TCP +#options "COMPAT_NOMID" # allow nonvalid machine id executables + +# +# Support for System V IPC facilities. +# + +# +# Support for various kernel options +# +options GENERIC # Mini-root boot support +options DIAGNOSTIC # Add additional error checking code +options "NKMEMCLUSTERS=256" # Size of kernel malloc area + +# +# Misc. debuging options +# +options PANICWAIT # Require keystroke to dump/reboot +options DEBUG # Add debugging statements +options DDB # Kernel debugger +options SYSCALL_DEBUG # debug all syscalls. + +# +# devices +# +mainbus0 at root +# mainbus devices +#sram0 at mainbus0 addr 0xffe00000 +vme0 at mainbus0 addr 0xfff40000 +pcctwo0 at mainbus0 addr 0xfff42000 +# pcctwo devices +clock0 at pcctwo0 addr 0xfff42000 ipl 5 +nvram0 at pcctwo0 addr 0xfffc0000 size 0x10000 +#ie0 at pcctwo0 addr 0xfff46000 ipl 1 size +#siop0 at pcctwo0 addr 0xfff47000 ipl 2 #size +cl0 at pcctwo0 addr 0xfff45000 ipl 3 size 0x512 +#lptwo0 at pcctwo0 addr 0xfff45000 ipl 1 size +#mcecc0 at pcctwo0 addr 0xfff43000 +#mcecc1 at pcctwo0 addr 0xfff43100 +#memc0 at pcctwo0 addr 0xfff43000 +#memc1 at pcctwo0 addr 0xfff43100 + +#bugtty0 at mainbus0 + +#vme0 devices +vmes0 at vme0 +vmel0 at vme0 + +#scsibus* at siop? +# +#sd* at scsibus? target ? lun ? +#st* at scsibus? target ? lun ? +#cd* at scsibus? target ? lun ? + +#pseudo-device sl # slip +#pseudo-device ppp # ppp +pseudo-device pty 16 # pseudo terminals +pseudo-device loop # network loopback + +config netbsd swap on generic diff --git a/sys/arch/mvme88k/conf/MYBOX b/sys/arch/mvme88k/conf/MYBOX new file mode 100644 index 00000000000..1876913aa34 --- /dev/null +++ b/sys/arch/mvme88k/conf/MYBOX @@ -0,0 +1,73 @@ +# $Id: MYBOX,v 1.4 1997/03/03 20:20:30 rahnds Exp $ + +include "std.mvme88k" + +maxusers 8 +options TIMEZONE=300, DST=1 +options BYTE_MSF +options SWAPPAGER, VNODEPAGER, DEVPAGER +#options INET +options FFS, MFS, FDESC +#options "COMPAT_42", "COMPAT_43" +options GENERIC, KTRACE, DIAGNOSTIC, "NKMEMCLUSTERS=256" +#options PANICWAIT, DEBUG, DDB +options PANICWAIT, DEBUG, DDB + +#options "CD9660", PORTAL, MSDOSFS, PROCFS, NULLFS, FIFO, KERNFS +#options NFSSERVER, NFSCLIENT +#options SYSVSHM, SYSVMSG, SYSVSEM +#options SYSCALL_DEBUG, SCSIDEBUG, KGDB + +mainbus0 at root + +pcctwo0 at mainbus0 addr 0xfff00000 +clock0 at pcctwo0 ipl 5 +#nvram0 at pcctwo0 offset 0xc0000 +#ie0 at pcctwo0 offset 0x46000 ipl 1 +#siop0 at pcctwo0 offset 0x47000 ipl 2 +#cl0 at pcctwo0 offset 0x45000 ipl 4 +vme0 at pcctwo0 offset 0x40000 +#lptwo0 at pcctwo0 ipl 1 +#mcecc0 at pcctwo0 offset 0x43000 +#mcecc1 at pcctwo0 offset 0x43100 +#memc0 at pcctwo0 offset 0x43000 +#memc1 at pcctwo0 offset 0x43100 +#sram0 at mainbus0 addr 0xffe00000 + +bugtty0 at mainbus0 # bug tty + +# scsi stuff, all possible +#m187scsi0 at mainbus0 +#bugscsi0 at mainbus0 +#bugscsi0 at pcc0 + +#scsibus0 at m187scsi0 +#scsibus0 at bugscsi0 +#scsibus0 at scsi0 +# +# compat. +# +#sd0 at scsibus? target 0 lun 0 +#sd1 at scsibus? target 1 lun 0 +#sd2 at scsibus? target 2 lun 0 +#sd3 at scsibus? target 3 lun 0 +#sd4 at scsibus? target 4 lun 0 +#sd5 at scsibus? target 5 lun 0 +#sd6 at scsibus? target 6 lun 0 + +# +# This is nicer however many amiga setups expect sd units to refer to +# scsi target numbers. If this is not the case, you can remove the +# specific sdx lines above and each hard drive from low target to high +# will configure to the next available sd unit number + +#sd* at scsibus? target ? lun ? # scsi disks +#st* at scsibus? target ? lun ? # scsi tapes +#cd* at scsibus? target ? lun ? # scsi cd's + +#pseudo-device sl # slip +#pseudo-device ppp # ppp +#pseudo-device pty 16 # pseudo terminals +#pseudo-device loop # network loopback +# +config netbsd swap on generic diff --git a/sys/arch/mvme88k/ddb/db_disasm.c b/sys/arch/mvme88k/ddb/db_disasm.c new file mode 100644 index 00000000000..81cf53a4103 --- /dev/null +++ b/sys/arch/mvme88k/ddb/db_disasm.c @@ -0,0 +1,608 @@ +/* + * Mach Operating System + * Copyright (c) 1993-1991 Carnegie Mellon University + * Copyright (c) 1991 OMRON Corporation + * All Rights Reserved. + * + * Permission to use, copy, modify and distribute this software and its + * documentation is hereby granted, provided that both the copyright + * notice and this permission notice appear in all copies of the + * software, derivative works or modified versions, and any portions + * thereof, and that both notices appear in supporting documentation. + * + * CARNEGIE MELLON AND OMRON ALLOW FREE USE OF THIS SOFTWARE IN ITS "AS IS" + * CONDITION. CARNEGIE MELLON AND OMRON DISCLAIM ANY LIABILITY OF ANY KIND + * FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. + * + * Carnegie Mellon requests users of this software to return to + * + * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU + * School of Computer Science + * Carnegie Mellon University + * Pittsburgh PA 15213-3890 + * + * any improvements or extensions that they make and grant Carnegie the + * rights to redistribute these changes. + */ + +/* + * m88k disassembler for use in ddb + */ + +#include <machine/db_machdep.h> +#include <ddb/db_sym.h> /* DB_STGY_PROC, db_printsym() */ +#include <ddb/db_access.h> /* db_get_value() */ +#include <ddb/db_output.h> /* db_printf() */ + +static char *instwidth[4] = { + ".d", " ", ".h", ".b" +}; + +static char *condname[6] = { + "gt0 ", "eq0 ", "ge0 ", "lt0 ", "ne0 ", "le0 " +}; + +static char *ctrlreg[64] = { + "cr0(PID) ", + "cr1(PSR) ", + "cr2(EPSR) ", + "cr3(SSBR) ", + "cr4(SXIP) ", + "cr5(SNIP) ", + "cr6(SFIP) ", + "cr7(VBR) ", + "cr8(DMT0) ", + "cr9(DMD0) ", + "cr10(DMA0) ", + "cr11(DMT1) ", + "cr12(DMD1) ", + "cr13(DMA1) ", + "cr14(DMT2) ", + "cr15(DMD2) ", + "cr16(DMA2) ", + "cr17(SR0) ", + "cr18(SR1) ", + "cr19(SR2) ", + "cr20(SR3) ", + "fcr0(FPECR)", + "fcr1(FPHS1)", + "fcr2(FPLS1)", + "fcr3(FPHS2)", + "fcr4(FPLS2)", + "fcr5(FPPT) ", + "fcr6(FPRH) ", + "fcr7(FPRL) ", + "fcr8(FPIT) ", + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + "fcr62(FPSR)", + "fcr63(FPCR)" +}; + +#define printval(x) if (x<0) db_printf ("-0x%X", -x); else db_printf("0x%X",x) + +/* Handlers immediate integer arithmetic instructions */ +static void +oimmed(long inst, char *opcode, long iadr) +{ + register int Linst = inst & 0177777; + register int Hinst = inst >> 16; + register int H6inst = Hinst >> 10; + register int rs1 = Hinst & 037; + register int rd = ( Hinst >> 5 ) & 037; + + if (( H6inst > 017 ) && ( H6inst < 030 ) && ( H6inst & 01) == 1 ) + db_printf("\t%s.u",opcode); + else { + db_printf("\t%s",opcode); + db_printf(" "); + } + db_printf("\t\tr%-3d,r%-3d,", rd, rs1); + printval(Linst); +} + + +/* Handles instructions dealing with control registers */ +static void +ctrlregs(long inst, char *opcode, long iadr) +{ + register int L6inst = (inst >> 11) & 037; + register int creg = (inst >> 5) & 077; + register int rd = (inst >> 21) & 037; + register int rs1 = (inst >> 16) & 037; + + db_printf("\t%s",opcode); + + if ( L6inst == 010 || L6inst == 011 ) + db_printf("\t\tr%-3d,%s", rd, ctrlreg[creg]); + else if ( L6inst == 020 || L6inst == 021 ) + db_printf("\t\tr%-3d,%s", rs1, ctrlreg[creg]); + else + db_printf("\t\tr%-3d,r%-3d,%s", rd, rs1, ctrlreg[creg]); +} + + +static void +printsod(int t) +{ + if ( t == 0 ) + db_printf("s"); + else + db_printf("d"); +} + +/* Handles floating point instructions */ +static void +sindou(int inst, char *opcode, long iadr) +{ + register int rs2 = inst & 037; + register int td = ( inst >> 5 ) & 03; + register int t2 = ( inst >> 7 ) & 03; + register int t1 = ( inst >> 9 ) & 03; + register int rs1 = ( inst >> 16 ) & 037; + register int rd = ( inst >> 21 ) & 037; + register int checkbits = ( inst >> 11 ) & 037; + + db_printf("\t%s.",opcode); + printsod(td); + if (( checkbits > 010 && checkbits < 014 ) || ( checkbits == 04 )) { + printsod(t2); + db_printf(" "); + if ( checkbits == 012 || checkbits == 013 ) + db_printf("\t\tr%-3d,r%-3d", rd, rs2); + else + db_printf("\t\tr%-3d,r%-3d", rd, rs2); + } + else{ + printsod(t1);printsod(t2); + db_printf("\t\tr%-3d,r%-3d,r%-3d", rd, rs1, rs2); + } +} + + +static void +jump(long inst, char *opcode, long iadr) +{ + register int rs2 = inst & 037; + register int Nbit = ( inst >> 10 ) & 01; + + db_printf("\t%s",opcode); + if ( Nbit == 1 ) + db_printf(".n"); + else + db_printf(" "); + db_printf("\t\tr%-3d",rs2); +} + + +/* Handles ff1, ff0, tbnd and rte instructions */ +static void +instset(long inst, char *opcode, long iadr) +{ + register int rs2 = inst & 037; + register int rs1 = ( inst >> 16 ) & 037; + register int rd = ( inst >> 21 ) & 037; + register int checkbits = ( inst >> 10 ) & 077; + register int H6inst = ( inst >> 26 ) & 077; + + db_printf("\t%s",opcode); + if ( H6inst == 076 ) { + db_printf("\t\tr%-3d,",rs1); + printval(inst & 0177777); + } + else if (( checkbits == 072 ) || ( checkbits == 073 )) + db_printf("\t\tr%-3d,r%-3d", rd, rs2); + else if ( checkbits == 076 ) + db_printf("\t\tr%-3d,r%-3d",rs1,rs2); +} + +static void +symofset(int disp, int bit, int iadr) +{ + long addr; + + if ( disp & (1 << (bit-1)) ) { + /* negative value */ + addr = iadr + ((disp << 2) | (~0 << bit)); + } + else { + addr = iadr + (disp << 2); + } + db_printsym(addr,DB_STGY_PROC); + return; +} + +static void +obranch(int inst, char *opcode, long iadr) +{ + int cond = ( inst >> 26 ) & 01; + int disp = inst &0377777777; + + if ( cond == 0 ) { + db_printf("\t%s\t\t",opcode); + symofset(disp, 26, iadr); + } + else { + db_printf("\t%s.n\t\t",opcode); + symofset(disp, 26, iadr); + } +} + + +/* Handles branch on conditions instructions */ +static void +brcond(int inst, char *opcode, long iadr) +{ + int cond = ( inst >> 26 ) & 1; + int match = ( inst >> 21 ) & 037; + int rs = ( inst >> 16 ) & 037; + int disp = ( inst & 0177777 ); + + if ( cond == 0 ) + db_printf("\t%s\t\t", opcode); + else + db_printf("\t%s.n\t\t", opcode); + if ( ( ( inst >> 27 ) & 03 ) == 1 ) + switch (match) { + case 1 : db_printf("%s,", condname[0]); break; + case 2 : db_printf("%s,", condname[1]); break; + case 3 : db_printf("%s,", condname[2]); break; + case 12: db_printf("%s,", condname[3]); break; + case 13: db_printf("%s,", condname[4]); break; + case 14: db_printf("%s,", condname[5]); break; + default: printval(match); + db_printf(","); + } + else { + printval(match); + db_printf(","); + } + + db_printf("r%-3d,", rs); + symofset(disp,16, iadr); +} + + +static void +otrap(int inst, char *opcode, long iadr) +{ + int vecno = inst & 0777; + int match = ( inst >> 21 ) & 037; + int rs = ( inst >> 16 ) & 037; + + db_printf("\t%s\t",opcode); + if ( ( ( inst >> 12 ) & 017 ) == 0xe ) + switch (match) { + case 1 : db_printf("%s,", condname[0]);break; + case 2 : db_printf("%s,", condname[1]);break; + case 3 : db_printf("%s,", condname[2]);break; + case 12: db_printf("%s,", condname[3]);break; + case 13: db_printf("%s,", condname[4]);break; + case 14: db_printf("%s,", condname[5]);break; + default: printval(match); + db_printf(","); + } + else { + printval(match); + db_printf(","); + } + db_printf("\tr%-3d,", rs); + printval(vecno); +} + + +/* Handles 10 bit immediate bit field operations */ +static void +obit(int inst, char *opcode, long iadr) +{ + int rs = ( inst >> 16 ) & 037; + int rd = ( inst >> 21 ) & 037; + int width = ( inst >> 5 ) & 037; + int offset = ( inst & 037 ); + + db_printf("\t%s\t\tr%-3d,r%-3d,", opcode, rd, rs); + if ( ( ( inst >> 10 ) & 077 ) == 052 ) { + db_printf("<"); + printval(offset); + db_printf(">"); + } + else + { + printval(width); + db_printf("<"); + printval(offset); + db_printf(">"); + } +} + + +/* Handles triadic mode bit field instructions */ +static void +bitman(int inst, char *opcode, long iadr) +{ + + int rs1 = ( inst >> 16 ) & 037; + int rd = ( inst >> 21 ) & 037; + int rs2 = inst & 037; + + db_printf("\t%s\t\tr%-3d,r%-3d,r%-3d", opcode, rd, rs1, rs2); +} + + +/* Handles immediate load/store/exchange instructions */ +static void +immem(int inst, char *opcode, long iadr) +{ + register int immed = inst & 0xFFFF; + register int rd = (inst >> 21) & 037; + register int rs = (inst >> 16) & 037; + register int st_lda = (inst >> 28) & 03; + register int aryno = (inst >> 26) & 03; + char c = ' '; + + if (!st_lda) { + if ((aryno == 0) || (aryno == 01)) + opcode = "xmem"; + else + opcode = "ld"; + if (aryno == 0) + aryno = 03; + if (!(aryno == 01)) + c = 'u'; + } + else + if (st_lda == 01) + opcode = "ld"; + + db_printf("\t%s%s%c\t\tr%-3d,r%-3d,", opcode, instwidth[aryno], + c, rd, rs); + printval(immed); +} + + +/* Handles triadic mode load/store/exchange instructions */ +static void +nimmem(int inst, char *opcode, long iadr) +{ + register int scaled = (inst >> 9) & 01; + register int rd = (inst >> 21) & 037; + register int rs1 = (inst >> 16) & 037; + register int rs2 = inst & 037; + register int st_lda = (inst >> 12) & 03; + register int aryno = (inst >> 10) & 03; + register int user_bit = 0; + int signed_fg = 1; + char *user = " "; + char c = ' '; + + if (!st_lda) { + if ((aryno == 0) || (aryno == 01)) + opcode = "xmem"; + else + opcode = "ld"; + if (aryno == 0) + aryno = 03; + if (!(aryno == 01)) { + c = 'u'; + signed_fg = 0; + } + } + else + if (st_lda == 01) + opcode = "ld"; + + if (!(st_lda == 03)) { + user_bit = (inst >> 8) & 01; + if (user_bit) + user = ".usr"; + } + + if (user_bit && signed_fg && (aryno == 01)) { + if (st_lda) + db_printf("\t%s%s\tr%-3d,r%-3d", opcode, + user, rd, rs1); + else + db_printf("\t%s%s\tr%-3d,r%-3d", opcode, + user, rd, rs1); + } + else + if (user_bit && signed_fg) + db_printf("\t%s%s%s\tr%-3d,r%-3d", opcode, + instwidth[aryno], user, rd, rs1); + else + db_printf("\t%s%s%c%s\tr%-3d,r%-3d", opcode, + instwidth[aryno], c, user, rd, rs1); + + if (scaled) + db_printf("[r%-3d]", rs2); + else + db_printf(",r%-3d", rs2); +} + + +/* Handles triadic mode logical instructions */ +static void +lognim(int inst, char *opcode, long iadr) +{ + register int rd = (inst >> 21) & 037; + register int rs1 = (inst >> 16) & 037; + register int rs2 = inst & 037; + register int complemt = (inst >> 10) & 01; + char *c = " "; + + if (complemt) + c = ".c"; + + db_printf("\t%s%s\t\tr%-3d,r%-3d,r%-3d", opcode, c, rd, rs1, rs2); +} + + +/* Handles triadic mode arithmetic instructions */ +static void +onimmed(int inst, char *opcode, long iadr) +{ + register int rd = (inst >> 21) & 037; + register int rs1 = (inst >> 16) & 037; + register int rs2 = inst & 037; + register int carry = (inst >> 8) & 03; + register int nochar = (inst >> 10) & 07; + register int nodecode = (inst >> 11) & 01; + char *tab, *c ; + + if (nochar > 02) + tab = "\t\t"; + else + tab = "\t"; + + if (!nodecode) { + if (carry == 01) + c = ".co "; + else + if (carry == 02) + c = ".ci "; + else + if (carry == 03) + c = ".cio"; + else + c = " "; + } + else + c = " "; + + db_printf("\t%s%s%sr%-3d,r%-3d,r%-3d", opcode, c, + tab, rd, rs1, rs2); +} + +static struct opdesc { + unsigned mask, match; + void (*opfun) (); + char *farg; +} opdecode[] = { + + /* ORDER IS IMPORTANT BELOW */ + + { 0xF0000000U, 0x00000000U, immem, 0, }, + { 0xF0000000U, 0x10000000U, immem, 0, }, + { 0xF0000000U, 0x20000000U, immem, "st" }, + { 0xF0000000U, 0x30000000U, immem, "lda" }, + + { 0xF8000000U, 0x40000000U, oimmed, "and" }, + { 0xF8000000U, 0x48000000U, oimmed, "mask" }, + { 0xF8000000U, 0x50000000U, oimmed, "xor" }, + { 0xF8000000U, 0x58000000U, oimmed, "or" }, + { 0xFC000000U, 0x60000000U, oimmed, "addu" }, + { 0xFC000000U, 0x64000000U, oimmed, "subu" }, + { 0xFC000000U, 0x68000000U, oimmed, "divu" }, + { 0xFC000000U, 0x6C000000U, oimmed, "mul" }, + { 0xFC000000U, 0x70000000U, oimmed, "add" }, + { 0xFC000000U, 0x74000000U, oimmed, "sub" }, + { 0xFC000000U, 0x78000000U, oimmed, "div" }, + { 0xFC000000U, 0x7C000000U, oimmed, "cmp" }, + + { 0xFC00F800U, 0x80004000U, ctrlregs, "ldcr" }, + { 0xFC00F800U, 0x80004800U, ctrlregs, "fldcr" }, + { 0xFC00F800U, 0x80008000U, ctrlregs, "stcr" }, + { 0xFC00F800U, 0x80008800U, ctrlregs, "fstcr" }, + { 0xFC00F800U, 0x8000C000U, ctrlregs, "xcr" }, + { 0xFC00F800U, 0x8000C800U, ctrlregs, "fxcr" }, + + { 0xFC00F800U, 0x84000000U, sindou, "fmul" }, + { 0xFC1FFF80U, 0x84002000U, sindou, "flt" }, + { 0xFC00F800U, 0x84002800U, sindou, "fadd" }, + { 0xFC00F800U, 0x84003000U, sindou, "fsub" }, + { 0xFC00F860U, 0x84003800U, sindou, "fcmp" }, + { 0xFC1FFE60U, 0x84004800U, sindou, "int" }, + { 0xFC1FFE60U, 0x84005000U, sindou, "nint" }, + { 0xFC1FFE60U, 0x84005800U, sindou, "trnc" }, + { 0xFC00F800U, 0x84007000U, sindou, "fdiv" }, + + { 0xF8000000U, 0xC0000000U, obranch, "br" }, + { 0xF8000000U, 0xC8000000U, obranch, "bsr" }, + + { 0xF8000000U, 0xD0000000U, brcond, "bb0" }, + { 0xF8000000U, 0xD8000000U, brcond, "bb1" }, + { 0xF8000000U, 0xE8000000U, brcond, "bcnd" }, + + { 0xFC00FC00U, 0xF0008000U, obit, "clr" }, + { 0xFC00FC00U, 0xF0008800U, obit, "set" }, + { 0xFC00FC00U, 0xF0009000U, obit, "ext" }, + { 0xFC00FC00U, 0xF0009800U, obit, "extu" }, + { 0xFC00FC00U, 0xF000A000U, obit, "mak" }, + { 0xFC00FC00U, 0xF000A800U, obit, "rot" }, + + { 0xFC00FE00U, 0xF000D000U, otrap, "tb0" }, + { 0xFC00FE00U, 0xF000D800U, otrap, "tb1" }, + { 0xFC00FE00U, 0xF000E800U, otrap, "tcnd" }, + + { 0xFC00F2E0U, 0xF4000000U, nimmem, 0, }, + { 0xFC00F2E0U, 0xF4000200U, nimmem, 0, }, + { 0xFC00F2E0U, 0xF4001000U, nimmem, 0, }, + { 0xFC00F2E0U, 0xF4001200U, nimmem, 0, }, + { 0xFC00F2E0U, 0xF4002000U, nimmem, "st" }, + { 0xFC00F2E0U, 0xF4002200U, nimmem, "st" }, + { 0xFC00F2E0U, 0xF4003000U, nimmem, "lda" }, + { 0xFC00F2E0U, 0xF4003200U, nimmem, "lda" }, + + { 0xFC00FBE0U, 0xF4004000U, lognim, "and" }, + { 0xFC00FBE0U, 0xF4005000U, lognim, "xor" }, + { 0xFC00FBE0U, 0xF4005800U, lognim, "or" }, + + { 0xFC00FCE0U, 0xF4006000U, onimmed, "addu" }, + { 0xFC00FCE0U, 0xF4006400U, onimmed, "subu" }, + { 0xFC00FCE0U, 0xF4006800U, onimmed, "divu" }, + { 0xFC00FCE0U, 0xF4006C00U, onimmed, "mul" }, + { 0xFC00FCE0U, 0xF4007000U, onimmed, "add" }, + { 0xFC00FCE0U, 0xF4007400U, onimmed, "sub" }, + { 0xFC00FCE0U, 0xF4007800U, onimmed, "div" }, + { 0xFC00FCE0U, 0xF4007C00U, onimmed, "cmp" }, + + { 0xFC00FFE0U, 0xF4008000U, bitman, "clr" }, + { 0xFC00FFE0U, 0xF4008800U, bitman, "set" }, + { 0xFC00FFE0U, 0xF4009000U, bitman, "ext" }, + { 0xFC00FFE0U, 0xF4009800U, bitman, "extu" }, + { 0xFC00FFE0U, 0xF400A000U, bitman, "mak" }, + { 0xFC00FFE0U, 0xF400A800U, bitman, "rot" }, + + { 0xFC00FBE0U, 0xF400C000U, jump, "jmp" }, + { 0xFC00FBE0U, 0xF400C800U, jump, "jsr" }, + + { 0xFC00FFE0U, 0xF400E800U, instset, "ff1" }, + { 0xFC00FFE0U, 0xF400EC00U, instset, "ff0" }, + { 0xFC00FFE0U, 0xF400F800U, instset, "tbnd" }, + { 0xFC00FFE0U, 0xF400FC00U, instset, "rte" }, + { 0xFC000000U, 0xF8000000U, instset, "tbnd" }, + { 0,0,0,0 } +}; + +static char *badop = "\t???"; + +int +m88k_print_instruction(unsigned iadr, long inst) +{ + register struct opdesc *p; + + /* this messes up "orb" instructions ever so slightly, */ + /* but keeps us in sync between routines... */ + if (inst == 0) { + db_printf ("\t.word 0"); + } + else + { + for (p = opdecode; p->mask; p++) + if ((inst & p->mask) == p->match) { + (*p->opfun) (inst, p->farg, iadr); + break; + } + if (!p->mask) + db_printf (badop); + } + + return iadr+4; +} + +db_addr_t +db_disasm(db_addr_t loc, boolean_t altfmt) +{ + m88k_print_instruction(loc, db_get_value(loc, 4, FALSE)); + db_printf ("\n"); + return loc+4; +} diff --git a/sys/arch/mvme88k/ddb/db_interface.c b/sys/arch/mvme88k/ddb/db_interface.c new file mode 100644 index 00000000000..771736702e8 --- /dev/null +++ b/sys/arch/mvme88k/ddb/db_interface.c @@ -0,0 +1,848 @@ +/* + * Mach Operating System + * Copyright (c) 1993-1991 Carnegie Mellon University + * Copyright (c) 1991 OMRON Corporation + * All Rights Reserved. + * + * Permission to use, copy, modify and distribute this software and its + * documentation is hereby granted, provided that both the copyright + * notice and this permission notice appear in all copies of the + * software, derivative works or modified versions, and any portions + * thereof, and that both notices appear in supporting documentation. + * + * CARNEGIE MELLON AND OMRON ALLOW FREE USE OF THIS SOFTWARE IN ITS "AS IS" + * CONDITION. CARNEGIE MELLON AND OMRON DISCLAIM ANY LIABILITY OF ANY KIND + * FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. + * + * Carnegie Mellon requests users of this software to return to + * + * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU + * School of Computer Science + * Carnegie Mellon University + * Pittsburgh PA 15213-3890 + * + * any improvements or extensions that they make and grant Carnegie the + * rights to redistribute these changes. + */ + +/* + * m88k interface to ddb debugger + */ + +#include <sys/param.h> +#include <sys/proc.h> +#include <sys/reboot.h> +#include <sys/systm.h> /* just for boothowto --eichin */ + +#include <vm/vm.h> + +#include <machine/m882xx.h> /* CMMU defs */ +#include <machine/trap.h> /* current_thread() */ +#include <machine/db_machdep.h> /* local ddb stuff */ +#include <machine/bug.h> /* bug routines */ +#include <machine/mmu.h> + +#include <ddb/db_command.h> +#include <ddb/db_sym.h> + +extern label_t *db_recover; +extern unsigned int db_maxoff; + +int db_active = 0; +int db_noisy = 0; +int quiet_db_read_bytes = 0; + +/* + * Received keyboard interrupt sequence. + */ +kdb_kintr(regs) + register struct m88100_saved_state *regs; +{ + if (db_active == 0 && (boothowto & RB_KDB)) { + printf("\n\nkernel: keyboard interrupt\n"); + m88k_db_trap(-1, regs); + } +} + +/************************/ +/* PRINTING *************/ +/************************/ + +static void +m88k_db_str(char *str) +{ + db_printf(str); +} + +static void +m88k_db_str1(char *str, int arg1) +{ + db_printf(str, arg1); +} + +static void +m88k_db_str2(char *str, int arg1, int arg2) +{ + db_printf(str, arg1, arg2); +} + +/************************/ +/* DB_REGISTERS ****/ +/************************/ + +/* + * + * If you really feel like understanding the following procedure and + * macros, see pages 6-22 to 6-30 (Section 6.7.3) of + * + * MC881000 RISC Microprocessor User's Manual Second Edition + * (Motorola Order: MC88100UM/AD REV 1) + * + * and ERRATA-5 (6-23, 6-24, 6-24) of + * + * Errata to MC88100 User's Manual Second Edition MC88100UM/AD Rev 1 + * (Oct 2, 1990) + * (Motorola Order: MC88100UMAD/AD) + * + */ + +/* macros for decoding dmt registers */ + +#define XMEM(x) ((x) & (1<<12)) +#define XMEM_MODE(x) ((((x)>>2 & 0xf) == 0xf) ? "" : ".bu") +#define MODE(x) ((x)>>2 & 0xf) +#define DOUB(x) ((x) & (1<<13)) +#define SIGN(x) ((x) & (1<<6)) +#define DAS(x) (((x) & (1<<14)) ? "" : ".usr") +#define REG(x) (((x)>>7) & 0x1f) +#define STORE(x) ((x) & 0x2) + +/* + * return 1 if the printing of the next stage should be surpressed + */ +static int +m88k_dmx_print(unsigned t, unsigned d, unsigned a, unsigned no) +{ + static unsigned addr_mod[16] = { 0, 3, 2, 2, 1, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0}; + static char *mode[16] = { "?", ".b", ".b", ".h", ".b", "?", "?", "?", + ".b", ".h", "?" , "?" , "?" , "?", "?", ""}; + static unsigned mask[16] = { 0, 0xff, 0xff00, 0xffff, + 0xff0000, 0, 0, 0, + 0xff000000U, 0xffff0000U, 0, 0, + 0, 0, 0, 0xffffffffU}; + static unsigned shift[16] = { 0, 0, 8, 0, 16, 0, 0, 0, + 24, 16, 0, 0, 0, 0, 0, 0}; + int reg = REG(t); + + if (XMEM(t)) + { + db_printf("xmem%s%s r%d(0x%x) <-> mem(0x%x),", + XMEM_MODE(t), DAS(t), reg, + (((t)>>2 & 0xf) == 0xf) ? d : (d & 0xff), a ); + return 1; + } + else + { + if (MODE(t) == 0xf) + { + /* full or double word */ + if (STORE(t)) + if (DOUB(t) && no == 2) + db_printf("st.d%s -> mem(0x%x) (** restart sxip **)", + DAS(t), a); + else + db_printf("st%s (0x%x) -> mem(0x%x)", DAS(t), d, a); + else /* load */ + if (DOUB(t) && no == 2) + db_printf("ld.d%s r%d <- mem(0x%x), r%d <- mem(0x%x)", + DAS(t), reg, a, reg+1, a+4); + else + db_printf("ld%s r%d <- mem(0x%x)", DAS(t), reg, a); + } + else + { + /* fractional word - check if load or store */ + a += addr_mod[MODE(t)]; + if (STORE(t)) + db_printf("st%s%s (0x%x) -> mem(0x%x)", mode[MODE(t)], DAS(t), + (d & mask[MODE(t)]) >> shift[MODE(t)], a); + else + db_printf("ld%s%s%s r%d <- mem(0x%x)", + mode[MODE(t)], SIGN(t) ? "" : "u", DAS(t), reg, a); + } + } + return 0; +} + +static void +m88k_db_print_frame(db_expr_t addr, int have_addr, int count, char *modif) +{ + struct m88100_saved_state *s = (struct m88100_saved_state *)addr; + char *name; + db_expr_t offset; + int surpress1 = 0, surpress2 = 0; + int c, force = 0, help = 0; + + if (!have_addr) { + db_printf("requires address of frame\n"); + help = 1; + } + + while (modif && *modif) { + switch (c = *modif++, c) { + case 'f': force = 1; break; + case 'h': help = 1; break; + default: + db_printf("unknown modifier [%c]\n", c); + help = 1; + break; + } + } + + if (help) { + db_printf("usage: mach frame/[f] ADDRESS\n"); + db_printf(" /f force printing of insane frames.\n"); + return; + } + + if (badwordaddr((vm_offset_t)s) || + badwordaddr((vm_offset_t)(&((db_regs_t*)s)->mode))) { + db_printf("frame at 0x%08x is unreadable\n", s); + return; + } + + if (!frame_is_sane(s)) /* see db_trace.c */ + { + db_printf("frame seems insane ("); + + if (force) + db_printf("forging ahead anyway...)\n"); + else { + db_printf("use /f to force)\n"); + return; + } + } + +#define R(i) s->r[i] +#define IPMASK(x) ((x) & ~(3)) + db_printf("R00-05: 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x\n", + R(0),R(1),R(2),R(3),R(4),R(5)); + db_printf("R06-11: 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x\n", + R(6),R(7),R(8),R(9),R(10),R(11)); + db_printf("R12-17: 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x\n", + R(12),R(13),R(14),R(15),R(16),R(17)); + db_printf("R18-23: 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x\n", + R(18),R(19),R(20),R(21),R(22),R(23)); + db_printf("R24-29: 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x\n", + R(24),R(25),R(26),R(27),R(28),R(29)); + db_printf("R30-31: 0x%08x 0x%08x\n",R(30),R(31)); + + db_printf("sxip: 0x%08x ",s->sxip & ~3); + db_find_xtrn_sym_and_offset((db_addr_t) IPMASK(s->sxip),&name,&offset); + if (name!= 0 && (unsigned)offset <= db_maxoff) + db_printf("%s+0x%08x",name,(unsigned)offset); + db_printf("\n"); + if (s->snip != s->sxip+4) + { + db_printf("snip: 0x%08x ",s->snip); + db_find_xtrn_sym_and_offset((db_addr_t) IPMASK(s->snip),&name,&offset); + if (name!= 0 && (unsigned)offset <= db_maxoff) + db_printf("%s+0x%08x",name,(unsigned)offset); + db_printf("\n"); + } + if (s->sfip != s->snip+4) + { + db_printf("sfip: 0x%08x ",s->sfip); + db_find_xtrn_sym_and_offset((db_addr_t) IPMASK(s->sfip),&name,&offset); + if (name!= 0 && (unsigned)offset <= db_maxoff) + db_printf("%s+0x%08x",name,(unsigned)offset); + db_printf("\n"); + } + + db_printf("vector: 0x%02x interrupt mask: 0x%08x\n", + s->vector, s->mask); + db_printf("epsr: 0x%08x current process: 0x%x\n", + s->epsr, curproc); + + /* + * If the vector indicates trap, instead of an exception or + * interrupt, skip the check of dmt and fp regs. + * + * Interrupt and exceptions are vectored at 0-10 and 114-127. + */ + + if (!(s->vector <= 10 || (114 <= s->vector && s->vector <= 127))) + { + db_printf("\n\n"); + return; + } + + if (s->vector == /*data*/3 || s->dmt0 & 1) + { + db_printf("dmt,d,a0: 0x%08x 0x%08x 0x%08x ",s->dmt0,s->dmd0,s->dma0); + db_find_xtrn_sym_and_offset((db_addr_t) s->dma0,&name,&offset); + if (name!= 0 && (unsigned)offset <= db_maxoff) + db_printf("%s+0x%08x",name,(unsigned)offset); + db_printf("\n "); + surpress1 = m88k_dmx_print(s->dmt0|0x01, s->dmd0, s->dma0, 0); + db_printf("\n"); + + if ((s->dmt1 & 1) && (!surpress1)) + { + db_printf("dmt,d,a1: 0x%08x 0x%08x 0x%08x ",s->dmt1, s->dmd1,s->dma1); + db_find_xtrn_sym_and_offset((db_addr_t) s->dma1,&name,&offset); + if (name!= 0 && (unsigned)offset <= db_maxoff) + db_printf("%s+0x%08x",name,(unsigned)offset); + db_printf("\n "); + surpress2 = m88k_dmx_print(s->dmt1, s->dmd1, s->dma1, 1); + db_printf("\n"); + + if ((s->dmt2 & 1) && (!surpress2)) + { + db_printf("dmt,d,a2: 0x%08x 0x%08x 0x%08x ",s->dmt2, s->dmd2,s->dma2); + db_find_xtrn_sym_and_offset((db_addr_t) s->dma2,&name,&offset); + if (name!= 0 && (unsigned)offset <= db_maxoff) + db_printf("%s+0x%08x",name,(unsigned)offset); + db_printf("\n "); + (void) m88k_dmx_print(s->dmt2, s->dmd2, s->dma2, 2); + db_printf("\n"); + } + } + } + + if (s->fpecr & 255) /* floating point error occured */ + { + db_printf("fpecr: 0x%08x fpsr: 0x%08x fpcr: 0x%08x\n", + s->fpecr,s->fpsr,s->fpcr); + db_printf("fcr1-4: 0x%08x 0x%08x 0x%08x 0x%08x\n", + s->fphs1, s->fpls1, s->fphs2, s->fpls2); + db_printf("fcr5-8: 0x%08x 0x%08x 0x%08x 0x%08x\n", + s->fppt, s->fprh, s->fprl, s->fpit); + } + db_printf("\n\n"); +} + +static void +m88k_db_registers(db_expr_t addr, int have_addr, int count, char *modif) +{ + if (modif && *modif) { + db_printf("usage: mach regs\n"); + return; + } + + m88k_db_print_frame((db_expr_t)DDB_REGS, TRUE,0,0); + return; +} + +/************************/ +/* PAUSE ****************/ +/************************/ + +/* + * pause for 2*ticks many cycles + */ +static void +m88k_db_pause(unsigned volatile ticks) +{ + while (ticks) + ticks -= 1; + return; +} + +/* + * m88k_db_trap - field a TRACE or BPT trap + */ + +m88k_db_trap( + int type, + register struct m88100_saved_state *regs) +{ + + int i; + +#if 0 + if ((i = db_spl()) != 7) + m88k_db_str1("WARNING: spl is not high in m88k_db_trap (spl=%x)\n", i); +#endif /* 0 */ + + if (db_are_interrupts_disabled()) + m88k_db_str("WARNING: entered debugger with interrupts disabled\n"); + + switch(type) { + + case T_KDB_BREAK: + case T_KDB_TRACE: + case T_KDB_ENTRY: + break; + case -1: + break; + default: + kdbprinttrap(type, 0); + if (db_recover != 0) { + db_error("Caught exception in ddb.\n"); + /*NOTREACHED*/ + } + } + + ddb_regs = *regs; + + db_active++; + cnpollc(TRUE); + db_trap(type, 0); + cnpollc(FALSE); + db_active--; + + *regs = ddb_regs; + +#if 0 + (void) spl7(); +#endif + return(1); +} + +extern char *trap_type[]; +extern int trap_types; + +/* + * Print trap reason. + */ +kdbprinttrap(type, code) + int type, code; +{ + printf("kernel: "); + if (type >= trap_types || type < 0) + printf("type %d", type); + else + printf("%s", trap_type[type]); + printf(" trap\n"); +} + +void +Debugger(void) +{ + asm (ENTRY_ASM); /* entry trap */ + /* ends up at ddb_entry_trap below */ +} + +/* gimmeabreak - drop execute the ENTRY trap */ +void +gimmeabreak(void) +{ + asm (ENTRY_ASM); /* entry trap */ + /* ends up at ddb_entry_trap below */ +} + +/* fielded a non maskable interrupt */ +int +ddb_nmi_trap(int level, db_regs_t *eframe) +{ + NOISY(m88k_db_str("kernel: nmi interrupt\n");) + m88k_db_trap(T_KDB_ENTRY, eframe); + + return 0; +} + +/* + * When the below routine is entered interrupts should be on + * but spl should be high + * + * The following routine is for breakpoint and watchpoint entry. + */ + +/* breakpoint/watchpoint entry */ +int +ddb_break_trap(int type, db_regs_t *eframe) +{ + m88k_db_trap(type, eframe); + + if (type == T_KDB_BREAK) { + /* back up an instruction and retry the instruction at the + breakpoint address */ + eframe->sfip = eframe->snip; + eframe->snip = eframe->sxip; + } + + return 0; +} + +/* enter at splhigh */ +int +ddb_entry_trap(int level, db_regs_t *eframe) +{ + m88k_db_trap(T_KDB_ENTRY, eframe); + + return 0; +} + +/* + * When the below routine is entered interrupts should be on + * but spl should be high + */ +/* error trap - unreturnable */ +void +ddb_error_trap(char *error, db_regs_t *eframe) +{ + + m88k_db_str1("KERNEL: terminal error [%s]\n",(int)error); + m88k_db_str ("KERNEL: Exiting debugger will cause abort to rom\n"); + m88k_db_str1("at 0x%x ", eframe->sxip & ~3); + m88k_db_str2("dmt0 0x%x dma0 0x%x", eframe->dmt0, eframe->dma0); + m88k_db_pause(1000000); + m88k_db_trap(T_KDB_BREAK, eframe); +} + +/* + * Read bytes from kernel address space for debugger. + */ +void +db_read_bytes(addr, size, data) + vm_offset_t addr; + register int size; + register char *data; +{ + register char *src; + + src = (char *)addr; + + while(--size >= 0) { + *data++ = *src++; + } +} + +/* + * Write bytes to kernel address space for debugger. + * This should make a text page writable to be able + * to plant a break point (right now text is mapped with + * write access in pmap_bootstrap()). XXX nivas + */ +void +db_write_bytes(char *addr, int size, char *data) +{ + + register char *dst; + int i = size; + vm_offset_t physaddr; + pte_template_t *pte; + + dst = (char *)addr; + + while(--size >= 0) { +#if 0 + db_printf("byte %x\n", *data); +#endif /* 0 */ + *dst++ = *data++; + } + physaddr = pmap_extract(kernel_pmap, (vm_offset_t)addr); + cmmu_flush_cache(physaddr, i); +} + +/* to print a character to the console */ +void +db_putc(int c) +{ + bugoutchr(c & 0xff); +} + +/* to peek at the console; returns -1 if no character is there */ +int +db_getc(void) +{ + if (buginstat()) + return (buginchr()); + else + return -1; +} + +/* display where all the cpus are stopped at */ +static void +m88k_db_where(db_expr_t addr, int have_addr, db_expr_t count, char *modif) +{ + struct m88100_saved_state *s; + char *name; + int *offset; + int i; + int l; + + s = DDB_REGS; + + l = m88k_pc(s); /* clear low bits */ + + db_find_xtrn_sym_and_offset((db_addr_t) l,&name, (db_expr_t*)&offset); + if (name && (unsigned)offset <= db_maxoff) + db_printf("stopped at 0x%x (%s+0x%x)\n", + l, name, offset); + else + db_printf("stopped at 0x%x\n", l); +} + +/* + * Walk back a stack, looking for exception frames. + * These frames are recognized by the routine frame_is_sane. Frames + * only start with zero, so we only call frame_is_sane if the + * current address contains zero. + * + * If addr is given, it is assumed to an address on the stack to be + * searched. Otherwise, r31 of the current cpu is used. + */ +static void +m88k_db_frame_search(db_expr_t addr, int have_addr, db_expr_t count, char *modif) +{ +#if 1 + db_printf("sorry, frame search currently disabled.\n"); +#else + if (have_addr) + addr &= ~3; /* round to word */ + else + addr = (DDB_REGS -> r[31]); + + /* walk back up stack until 8k boundry, looking for 0 */ + while (addr & ((8*1024)-1)) + { + int i; + db_read_bytes(addr, 4, &i); + if (i == 0 && frame_is_sane(i)) + db_printf("frame found at 0x%x\n", i); + addr += 4; + } + + db_printf("(Walked back until 0x%x)\n",addr); +#endif +} + +/* flush icache */ +static void +m88k_db_iflush(db_expr_t addr, int have_addr, db_expr_t count, char *modif) +{ + addr = 0; + cmmu_remote_set(addr, CMMU_SCR, 0, CMMU_FLUSH_CACHE_CBI_ALL); +} + +/* flush dcache */ + +static void +m88k_db_dflush(db_expr_t addr, int have_addr, db_expr_t count, char *modif) +{ + addr = 0; + + cmmu_remote_set(addr, CMMU_SCR, 1, CMMU_FLUSH_CACHE_CBI_ALL); +} + +/* probe my cache */ +static void +m88k_db_peek(db_expr_t addr, int have_addr, int count, char *modif) +{ + int pa12; + int valmask; + + pa12 = addr & ~((1<<12) -1); + + /* probe dcache */ + cmmu_remote_set(0, CMMU_SAR, 1, addr); + + valmask = cmmu_remote_get(0, CMMU_CSSP, 1); + db_printf("dcache valmask 0x%x\n", (unsigned)valmask); + db_printf("dcache tag ports 0x%x 0x%x 0x%x 0x%x\n", + (unsigned)cmmu_remote_get(0, CMMU_CTP0, 1), + (unsigned)cmmu_remote_get(0, CMMU_CTP1, 1), + (unsigned)cmmu_remote_get(0, CMMU_CTP2, 1), + (unsigned)cmmu_remote_get(0, CMMU_CTP3, 1)); + + /* probe icache */ + cmmu_remote_set(0, CMMU_SAR, 0, addr); + + valmask = cmmu_remote_get(0, CMMU_CSSP, 0); + db_printf("icache valmask 0x%x\n", (unsigned)valmask); + db_printf("icache tag ports 0x%x 0x%x 0x%x 0x%x\n", + (unsigned)cmmu_remote_get(0, CMMU_CTP0, 0), + (unsigned)cmmu_remote_get(0, CMMU_CTP1, 0), + (unsigned)cmmu_remote_get(0, CMMU_CTP2, 0), + (unsigned)cmmu_remote_get(0, CMMU_CTP3, 0)); + +} + + +/* + * control how much info the debugger prints about itself + */ +static void +m88k_db_noise(db_expr_t addr, int have_addr, db_expr_t count, char *modif) +{ + if (!have_addr) + { + /* if off make noisy; if noisy or very noisy turn off */ + if (db_noisy) + { + db_printf("changing debugger status from %s to quiet\n", + db_noisy == 1 ? "noisy" : + db_noisy == 2 ? "very noisy" : "violent"); + db_noisy = 0; + } + else + { + db_printf("changing debugger status from quiet to noisy\n"); + db_noisy = 1; + } + } + else + if (addr < 0 || addr > 3) + db_printf("invalid noise level to m88k_db_noisy; should be 0, 1, 2, or 3\n"); + else + { + db_noisy = addr; + db_printf("debugger noise level set to %s\n", + db_noisy == 0 ? "quiet" : + (db_noisy == 1 ? "noisy" : + db_noisy==2 ? "very noisy" : "violent")); + } +} + +/* + * See how a virtual address translates. + * Must have an address. + */ +static void +m88k_db_translate(db_expr_t addr, int have_addr, db_expr_t count, char *modif) +{ +#if 0 + char c; + int verbose_flag = 0; + int supervisor_flag = 1; + int wanthelp = 0; + + if (!have_addr) + wanthelp = 1; + else { + while (c = *modif++, c != 0) { + switch (c) { + default: + db_printf("bad modifier [%c]\n", c); + wanthelp = 1; + break; + case 'h': + wanthelp = 1; + break; + case 'v': + verbose_flag++; + break; + case 's': + supervisor_flag = 1; + break; + case 'u': + supervisor_flag = 0; + break; + } + } + } + if (wanthelp) { + db_printf("usage: translate[/vvsu] address\n"); + db_printf("flags: v - be verbose (vv - be very verbose)\n"); + db_printf(" s - use cmmu's supervisor area pointer (default)\n"); + db_printf(" u - use cmmu's user area pointer\n"); + return; + } + + cmmu_show_translation(addr, supervisor_flag, verbose_flag); +#endif /* 0 */ +} + +void cpu_interrupt_to_db(int cpu_no) +{} + + +/************************/ +/* COMMAND TABLE / INIT */ +/************************/ + +static struct db_command m88k_cache_cmds[] = +{ + { "iflush", m88k_db_iflush, 0, 0}, + { "dflush", m88k_db_dflush, 0, 0}, + { "peek", m88k_db_peek, 0, 0}, + { (char *) 0,} +}; + +struct db_command db_machine_cmds[] = +{ + {"cache", 0, 0, m88k_cache_cmds}, + {"frame", m88k_db_print_frame, 0, 0}, + {"noise", m88k_db_noise, 0, 0}, + {"regs", m88k_db_registers, 0, 0}, + {"searchframe", m88k_db_frame_search, 0, 0}, + {"translate", m88k_db_translate, 0, 0}, + {"where", m88k_db_where, 0, 0}, + {(char *) 0,} +}; + +/* + * Called from "m88k/m1x7_init.c" + */ +void +kdb_init(void) +{ +#ifdef DB_MACHINE_COMMANDS + db_machine_commands_install(db_machine_cmds); +#endif + ddb_init(); + + db_printf("ddb enabled\n"); +} + +/* + * Attempt to figure out the UX name of the task. + * This is kludgy at best... we can't even be sure the task is a UX task... + */ +#define TOP_OF_USER_STACK USRSTACK +#define MAX_DISTANCE_TO_LOOK (1024 * 10) + +#define DB_TASK_NAME_LEN 50 + +char +*db_task_name() +{ + static unsigned buffer[(DB_TASK_NAME_LEN + 5)/sizeof(unsigned)]; + unsigned ptr = (vm_offset_t)(TOP_OF_USER_STACK - 4); + unsigned limit = ptr - MAX_DISTANCE_TO_LOOK; + unsigned word; + int i; + + /* skip zeros at the end */ + while (ptr > limit && + (i = db_trace_get_val((vm_offset_t)ptr, &word)) + && (word == 0)) + { + ptr -= 4; /* continue looking for a non-null word */ + } + + if (ptr <= limit) { + db_printf("bad name at line %d\n", __LINE__); + return "<couldn't find 1>"; + } else if (i != 1) { + return "<nostack>"; + } + + /* skip looking for null before all the text */ + while (ptr > limit + &&(i = db_trace_get_val(ptr, &word)) + && (word != 0)) + { + ptr -= 4; /* continue looking for a null word */ + } + + if (ptr <= limit) { + db_printf("bad name at line %d\n", __LINE__); + return "<couldn't find 2>"; + } else if (i != 1) { + db_printf("bad name read of %x " + "at line %d\n", ptr, __LINE__); + return "<bad read 2>"; + } + + ptr += 4; /* go back to the non-null word after this one */ + + for (i = 0; i < sizeof(buffer); i++, ptr+=4) { + buffer[i] = 0; /* just in case it's not read */ + db_trace_get_val((vm_offset_t)ptr, &buffer[i]); + } + return (char*)buffer; +} diff --git a/sys/arch/mvme88k/ddb/db_sstep.c b/sys/arch/mvme88k/ddb/db_sstep.c new file mode 100644 index 00000000000..db4115b55ea --- /dev/null +++ b/sys/arch/mvme88k/ddb/db_sstep.c @@ -0,0 +1,268 @@ +/* + * Mach Operating System + * Copyright (c) 1993-1991 Carnegie Mellon University + * Copyright (c) 1991 OMRON Corporation + * All Rights Reserved. + * + * Permission to use, copy, modify and distribute this software and its + * documentation is hereby granted, provided that both the copyright + * notice and this permission notice appear in all copies of the + * software, derivative works or modified versions, and any portions + * thereof, and that both notices appear in supporting documentation. + * + * CARNEGIE MELLON AND OMRON ALLOW FREE USE OF THIS SOFTWARE IN ITS "AS IS" + * CONDITION. CARNEGIE MELLON AND OMRON DISCLAIM ANY LIABILITY OF ANY KIND + * FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. + * + * Carnegie Mellon requests users of this software to return to + * + * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU + * School of Computer Science + * Carnegie Mellon University + * Pittsburgh PA 15213-3890 + * + * any improvements or extensions that they make and grant Carnegie the + * rights to redistribute these changes. + */ + +#include <machine/db_machdep.h> +#include <ddb/db_access.h> /* db_get_value() */ + +/* + * Support routines for software single step. + * + * Author: Daniel Stodolsky (danner@cs.cmu.edu) + * + */ + +/* is the instruction a branch or jump instruction (br, bb0, bb1, bcnd, jmp) + but not a function call (bsr or jsr) */ + +boolean_t +inst_branch(unsigned ins) +{ + /* check high five bits */ + + switch (ins >> (32-5)) + { + case 0x18: /* br */ + case 0x1a: /* bb0 */ + case 0x1b: /* bb1 */ + case 0x1d: /* bcnd */ + return TRUE; + break; + case 0x1e: /* could be jmp */ + if ((ins & 0xfffffbe0U) == 0xf400c000U) + return TRUE; + } + + return FALSE; +} + +/* inst_load(ins) - returns the number of words the instruction loads. byte, + half and word count as 1; double word as 2 */ + +unsigned +inst_load(unsigned ins) +{ + /* look at the top six bits, for starters */ + + switch (ins >> (32-6)) + { + case 0x0: /* xmem byte imm */ + case 0x1: /* xmem word imm */ + + case 0x2: /* unsigned half-word load imm */ + case 0x3: /* unsigned byte load imm */ + case 0x5: /* signed word load imm */ + case 0x6: /* signed half-word load imm */ + case 0x7: /* signed byte load imm */ + return 1; + + case 0x4: /* signed double word load imm */ + return 2; + + case 0x3d: /* load/store/xmem scaled/unscaled instruction */ + if ((ins & 0xf400c0e0U) == 0xf4000000U) /* is load/xmem */ + switch ((ins & 0x0000fce0)>>5) /* look at bits 15-5, but mask bits 8-9 */ + { + case 0x0: /* xmem byte */ + case 0x1: /* xmem word */ + case 0x2: /* unsigned half word */ + case 0x3: /* unsigned byte load */ + case 0x5: /* signed word load */ + case 0x6: /* signed half-word load */ + case 0x7: /* signed byte load */ + return 1; + + case 0x4: /* signed double word load */ + return 2; + } /* end switch load/xmem */ + break; + } /* end switch 32-6 */ + + return 0; +} + +/* inst_store - like inst_load, except for store instructions. */ + +unsigned +inst_store(unsigned ins) +{ + /* decode top 6 bits again */ + switch (ins >> (32-6)) + { + case 0x0: /* xmem byte imm */ + case 0x1: /* xmem word imm */ + case 0x9: /* store word imm */ + case 0xa: /* store half-word imm */ + case 0xb: /* store byte imm */ + return 1; + + case 0x8: /* store double word */ + return 2; + case 0x3d: /* load/store/xmem scaled/unscaled instruction */ + /* check bits 15,14,12,7,6,5 are all 0 */ + if ((ins & 0x0000d0e0U) == 0) + switch ((ins & 0x00003c00U) >> 10 ) /* decode bits 10-13 */ + { + case 0x0: /* xmem byte imm */ + case 0x1: /* xmem word imm */ + case 0x9: /* store word */ + case 0xa: /* store half-word */ + case 0xb: /* store byte */ + return 1; + + case 0x8: /* store double word */ + return 2; + } /* end switch store/xmem */ + break; + } /* end switch 32-6 */ + + return 0; +} + +/* inst_delayed - this instruction is followed by a delay slot. Could be + br.n, bsr.n bb0.n, bb1.n, bcnd.n or jmp.n or jsr.n */ + +boolean_t +inst_delayed(unsigned ins) +{ + /* check the br, bsr, bb0, bb1, bcnd cases */ + switch ((ins & 0xfc000000U)>>(32-6)) + { + case 0x31: /* br */ + case 0x33: /* bsr */ + case 0x35: /* bb0 */ + case 0x37: /* bb1 */ + case 0x3b: /* bcnd */ + return TRUE; + } + + /* check the jmp, jsr cases */ + /* mask out bits 0-4, bit 11 */ + return ((ins & 0xfffff7e0U) == 0xf400c400U) ? TRUE : FALSE; +} + + +/* + * next_instr_address(pc,delay_slot,task) has the following semantics. + * Let inst be the instruction at pc. + * If delay_slot = 1, next_instr_address should return + * the address of the instruction in the delay slot; if this instruction + * does not have a delay slot, it should return pc. + * If delay_slot = 0, next_instr_address should return the + * address of next sequential instruction, or pc if the instruction is + * followed by a delay slot. + * + * 91-11-28 jfriedl: I think the above is wrong. I think it should be: + * if delay_slot true, return address of the delay slot if there is one, + * return pc otherwise. + * if delay_slot false, return (pc + 4) regardless. + * + */ +db_addr_t +next_instr_address(db_addr_t pc, unsigned delay_slot) +{ + if (delay_slot == 0) + return pc + 4; + else + { + if (inst_delayed(db_get_value(pc,sizeof(int),FALSE))) + return pc + 4; + else + return pc; + } +} + + +/* + * branch_taken(instruction, program counter, func, func_data) + * + * instruction will be a control flow instruction location at address pc. + * Branch taken is supposed to return the address to which the instruction + * would jump if the branch is taken. Func can be used to get the current + * register values when invoked with a register number and func_data as + * arguments. + * + * If the instruction is not a control flow instruction, panic. + */ +unsigned +branch_taken( + unsigned inst, + unsigned pc, + db_expr_t (*func)(unsigned int, db_regs_t *), + db_regs_t *func_data) /* 'opaque' */ +{ + + /* check if br/bsr */ + if ((inst & 0xf0000000U) == 0xc0000000U) + { + /* signed 26 bit pc relative displacement, shift left two bits */ + inst = (inst & 0x03ffffffU)<<2; + /* check if sign extension is needed */ + if (inst & 0x08000000U) + inst |= 0xf0000000U; + return pc + inst; + } + + /* check if bb0/bb1/bcnd case */ + switch ((inst & 0xf8000000U)) + { + case 0xd0000000U: /* bb0 */ + case 0xd8000000U: /* bb1 */ + case 0xe8000000U: /* bcnd */ + /* signed 16 bit pc relative displacement, shift left two bits */ + inst = (inst & 0x0000ffffU)<<2; + /* check if sign extension is needed */ + if (inst & 0x00020000U) + inst |= 0xfffc0000U; + return pc + inst; + } + + /* check jmp/jsr case */ + /* check bits 5-31, skipping 10 & 11 */ + if ((inst & 0xfffff3e0U) == 0xf400c000U) + return (*func)(inst & 0x1f, func_data); /* the register value */ + + panic("branch_taken"); + return 0; /* keeps compiler happy */ +} + +/* + * getreg_val - handed a register number and an exception frame. + * Returns the value of the register in the specified + * frame. Only makes sense for general registers. + */ +db_expr_t +getreg_val(unsigned regno, db_regs_t *frame) +{ + if (regno == 0) + return 0; + else if (regno < 31) + return frame->r[regno]; + else { + panic("bad register number to getreg_val."); + return 0;/*to make compiler happy */ + } +} diff --git a/sys/arch/mvme88k/ddb/db_trace.c b/sys/arch/mvme88k/ddb/db_trace.c new file mode 100644 index 00000000000..9af1296fda6 --- /dev/null +++ b/sys/arch/mvme88k/ddb/db_trace.c @@ -0,0 +1,1145 @@ +/* + * Mach Operating System + * Copyright (c) 1993-1991 Carnegie Mellon University + * Copyright (c) 1991 OMRON Corporation + * All Rights Reserved. + * + * Permission to use, copy, modify and distribute this software and its + * documentation is hereby granted, provided that both the copyright + * notice and this permission notice appear in all copies of the + * software, derivative works or modified versions, and any portions + * thereof, and that both notices appear in supporting documentation. + * + * CARNEGIE MELLON AND OMRON ALLOW FREE USE OF THIS SOFTWARE IN ITS "AS IS" + * CONDITION. CARNEGIE MELLON AND OMRON DISCLAIM ANY LIABILITY OF ANY KIND + * FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. + * + * Carnegie Mellon requests users of this software to return to + * + * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU + * School of Computer Science + * Carnegie Mellon University + * Pittsburgh PA 15213-3890 + * + * any improvements or extensions that they make and grant Carnegie the + * rights to redistribute these changes. + */ + +union instruction { + unsigned rawbits; + + struct { + unsigned int : 5; + unsigned int n: 1; + signed int d26:26; + } br; + + struct { + unsigned int : 4; + unsigned int isbb1: 1; /* isbb1==0 means bb0, isbb1==1 means bb1 */ + unsigned int n : 1; + unsigned int b5 : 5; + unsigned int s1 : 5; + signed int d16 :16; + } bb; /* bcnd too, except "isbb1" makes no sense for bcnd */ + + struct { + unsigned int : 6; + unsigned int b5 : 5; + unsigned int s1 : 5; + unsigned int : 7; + unsigned int vec9 : 9; + } tb; /* tcnd too */ + + struct { + unsigned int :21; + unsigned int n : 1; + unsigned int : 5; + unsigned int s2 : 5; + } jump; /* jmp, jsr */ + + struct { + unsigned int : 6; + unsigned int d : 5; + unsigned int s1 : 5; + unsigned int i16 :16; + } diatic; /* general reg/reg/i16 instructions */ + + struct { + unsigned int : 6; + unsigned int d : 5; + unsigned int s1 : 5; + unsigned int :11; + unsigned int s2 : 5; + } triatic; /* general reg/reg/reg instructions */ + +}; + +static inline unsigned br_dest(unsigned addr, union instruction inst) +{ + return addr + inst.br.d26 * 4; +} + + +#define TRACE_DEBUG /* undefine to disable debugging */ + +#include <machine/db_machdep.h> /* lots of stuff */ +#include <ddb/db_variables.h> /* db_variable, DB_VAR_GET, etc. */ +#include <ddb/db_output.h> /* db_printf */ +#include <ddb/db_sym.h> /* DB_STGY_PROC, etc. */ +#include <ddb/db_command.h> /* db_recover */ + +/* + * Some macros to tell if the given text is the instruction. + */ +#define JMPN_R1(I) ( (I) == 0xf400c401U) /* jmp.n r1 */ +#define JMP_R1(I) ( (I) == 0xf400c001U) /* jmp r1 */ + +/* gets the IMM16 value from an instruction */ +#define IMM16VAL(I) (((union instruction)(I)).diatic.i16) + +/* subu r31, r31, IMM */ +#define SUBU_R31_R31_IMM(I) (((I) & 0xffff0000U) == 0x67ff0000U) + +/* st r1, r31, IMM */ +#define ST_R1_R31_IMM(I) (((I) & 0xffff0000U) == 0x243f0000U) + +static trace_flags = 0; +#define TRACE_DEBUG_FLAG 0x01 +#define TRACE_SHOWCALLPRESERVED_FLAG 0x02 +#define TRACE_SHOWADDRESS_FLAG 0x04 +#define TRACE_SHOWFRAME_FLAG 0x08 +#define TRACE_USER_FLAG 0x10 + +#ifdef TRACE_DEBUG + #define DEBUGGING_ON (trace_flags & TRACE_DEBUG_FLAG) +#endif + +#ifndef TRACE_DEBUG + #define SHOW_INSTRUCTION(Addr, Inst, Note) { /*nothing*/ } +#else + #define SHOW_INSTRUCTION(Addr, Inst, Note) if (DEBUGGING_ON) { \ + db_printf("%s0x%x: (0x%08x) ", Note, (unsigned)(Addr), (Inst)); \ + m88k_print_instruction((unsigned)(Addr), (Inst)); \ + db_printf("\n"); \ + } +#endif + +extern label_t *db_recover; +extern int quiet_db_read_bytes; +/* + * m88k trace/register state interface for ddb. + */ + +/* lifted from mips */ +static int +db_setf_regs( + struct db_variable *vp, + db_expr_t *valuep, + int op) /* read/write */ +{ + register int *regp = (int *) ((char *) DDB_REGS + (int) (vp->valuep)); + + if (op == DB_VAR_GET) + *valuep = *regp; + else if (op == DB_VAR_SET) + *regp = *valuep; +} + +#define N(s, x) {s, (int *)&(((db_regs_t *) 0)->x), db_setf_regs} + +struct db_variable db_regs[] = { + N("r1", r[1]), N("r2", r[2]), N("r3", r[3]), N("r4", r[4]), + N("r5", r[5]), N("r6", r[6]), N("r7", r[7]), N("r8", r[8]), + N("r9", r[9]), N("r10", r[10]), N("r11", r[11]), N("r12", r[12]), + N("r13", r[13]), N("r14", r[14]), N("r15", r[15]), N("r16", r[16]), + N("r17", r[17]), N("r18", r[18]), N("r19", r[19]), N("r20", r[20]), + N("r21", r[21]), N("r22", r[22]), N("r23", r[23]), N("r24", r[24]), + N("r25", r[25]), N("r26", r[26]), N("r27", r[27]), N("r28", r[28]), + N("r29", r[29]), N("r30", r[30]), N("r31", r[31]), N("epsr", epsr), + N("sxip", sxip), N("snip", snip), N("sfip", sfip), N("ssbr", ssbr), + N("dmt0", dmt0), N("dmd0", dmd0), N("dma0", dma0), N("dmt1", dmt1), + N("dmd1", dmd1), N("dma1", dma1), N("dmt2", dmt2), N("dmd2", dmd2), + N("dma2", dma2), N("fpecr", fpecr),N("fphs1", fphs1),N("fpls1", fpls1), + N("fphs2", fphs2), N("fpls2", fpls2),N("fppt", fppt), N("fprh", fprh), + N("fprl", fprl), N("fpit", fpit), N("fpsr", fpsr), N("fpcr", fpcr), + N("mask", mask), /* interrupt mask */ + N("mode", mode), /* interrupt mode */ + N("exvc", vector), /* exception vector */ +}; +#undef N + +struct db_variable *db_eregs = db_regs + sizeof(db_regs)/sizeof(db_regs[0]); + + +#define TRASHES 0x001 /* clobbers instruction field D */ +#define STORE 0x002 /* does a store to S1+IMM16 */ +#define LOAD 0x004 /* does a load from S1+IMM16 */ +#define DOUBLE 0x008 /* double-register */ +#define FLOW_CTRL 0x010 /* flow-control instruction */ +#define DELAYED 0x020 /* delayed flow control */ +#define JSR 0x040 /* flow-control is a jsr[.n] */ +#define BSR 0x080 /* flow-control is a bsr[.n] */ + +/* + * Given a word of instruction text, return some flags about that + * instruction (flags defined above). + */ +static unsigned +m88k_instruction_info(unsigned instruction) +{ + static struct { unsigned mask, value, flags; } *ptr, control[] = + { + /* runs in the same order as 2nd Ed 88100 manual Table 3-14 */ + { 0xf0000000U, 0x00000000U, /* xmem */ TRASHES | STORE | LOAD }, + { 0xec000000U, 0x00000000U, /* ld.d */ TRASHES | LOAD | DOUBLE }, + { 0xe0000000U, 0x00000000U, /* load */ TRASHES | LOAD }, + { 0xfc000000U, 0x20000000U, /* st.d */ STORE | DOUBLE }, + { 0xf0000000U, 0x20000000U, /* store */ STORE }, + { 0xc0000000U, 0x40000000U, /* arith */ TRASHES }, + { 0xfc004000U, 0x80004000U, /* ld cr */ TRASHES }, + { 0xfc004000U, 0x80000000U, /* st cr */ 0 }, + { 0xfc008060U, 0x84000000U, /* f */ TRASHES }, + { 0xfc008060U, 0x84000020U, /* f.d */ TRASHES | DOUBLE }, + { 0xfc000000U, 0xcc000000U, /* bsr.n */ FLOW_CTRL | DELAYED | BSR }, + { 0xfc000000U, 0xc8000000U, /* bsr */ FLOW_CTRL | BSR }, + { 0xe4000000U, 0xc4000000U, /* br/bb.n */ FLOW_CTRL | DELAYED }, + { 0xe4000000U, 0xc0000000U, /* br/bb */ FLOW_CTRL }, + { 0xfc000000U, 0xec000000U, /* bcnd.n */ FLOW_CTRL | DELAYED }, + { 0xfc000000U, 0xe8000000U, /* bcnd */ FLOW_CTRL }, + { 0xfc00c000U, 0xf0008000U, /* bits */ TRASHES }, + { 0xfc00c000U, 0xf000c000U, /* trap */ 0 }, + { 0xfc00f0e0U, 0xf4002000U, /* st */ 0 }, + { 0xfc00cce0U, 0xf4000000U, /* ld.d */ TRASHES | DOUBLE }, + { 0xfc00c0e0U, 0xf4000000U, /* ld */ TRASHES }, + { 0xfc00c0e0U, 0xf4004000U, /* arith */ TRASHES }, + { 0xfc00c3e0U, 0xf4008000U, /* bits */ TRASHES }, + { 0xfc00ffe0U, 0xf400cc00U, /* jsr.n */ FLOW_CTRL | DELAYED | JSR }, + { 0xfc00ffe0U, 0xf400c800U, /* jsr */ FLOW_CTRL | JSR }, + { 0xfc00ffe0U, 0xf400c400U, /* jmp.n */ FLOW_CTRL | DELAYED }, + { 0xfc00ffe0U, 0xf400c000U, /* jmp */ FLOW_CTRL }, + { 0xfc00fbe0U, 0xf400e800U, /* ff */ TRASHES }, + { 0xfc00ffe0U, 0xf400f800U, /* tbnd */ 0 }, + { 0xfc00ffe0U, 0xf400fc00U, /* rte */ FLOW_CTRL }, + { 0xfc000000U, 0xf8000000U, /* tbnd */ 0 }, + }; + #define ctrl_count (sizeof(control)/sizeof(control[0])) + for (ptr = &control[0]; ptr < &control[ctrl_count]; ptr++) + if ((instruction & ptr->mask) == ptr->value) + return ptr->flags; + SHOW_INSTRUCTION(0, instruction, "bad m88k_instruction_info"); + return 0; +} + +static int +hex_value_needs_0x(unsigned value) +{ + int i; + unsigned last = 0; + unsigned char c; + unsigned have_a_hex_digit = 0; + + if (value <= 9) + return 0; + + for (i = 0; i < 8; i++) { + c = value & 0xf; + value >>= 4; + if (c) + last = c; + if (c > 9) + have_a_hex_digit = 1; + } + if (have_a_hex_digit == 0) + return 1; + if (last > 9) + return 1; + return 0; +} + + +/* + * returns + * 1 if regs seems to be a reasonable kernel exception frame. + * 2 if regs seems to be a reasonable user exception frame + * (in the current task). + * 0 if this looks like neither. + */ +int +frame_is_sane(db_regs_t *regs) +{ + /* no good if we can't read the whole frame */ + if (badwordaddr((vm_offset_t)regs) || badwordaddr((vm_offset_t)®s->mode)) + return 0; + +#ifndef DIAGNOSTIC + /* disabled for now -- see fpu_enable in luna88k/eh.s */ + /* r0 must be 0 (obviously) */ + if (regs->r[0] != 0) + return 0; +#endif + + /* stack sanity ... r31 must be nonzero, but must be word aligned */ + if (regs->r[31] == 0 || (regs->r[31] & 3) != 0) + return 0; + + /* sxip is reasonable */ +#if 0 + if ((regs->sxip & 1) == 1) + return 0; +#endif + /* snip is reasonable */ + if ((regs->snip & 3) != 2) + return 0; + /* sfip is reasonable */ + if ((regs->sfip & 3) != 2) + return 0; + + /* epsr sanity */ + if ((regs->epsr & 0x8FFFFFF5U) == 0x800003f0U) /* kernel mode */ + { + if (regs->epsr & 0x40000000) + db_printf("[WARNING: byte order in kernel frame at %x " + "is little-endian!]\n", regs); + return 1; + } + if ((regs->epsr & 0x8FFFFFFFU) == 0x000003f0U) /* user mode */ + { + if (regs->epsr & 0x40000000) + db_printf("[WARNING: byte order in user frame at %x " + "is little-endian!]\n", regs); + return 2; + } + return 0; +} + +char +*m88k_exception_name(unsigned vector) +{ + switch (vector) + { + default: + case 0: return "Reset"; + case 1: return "Interrupt"; + case 2: return "Instruction Access Exception"; + case 3: return "Data Access Exception"; + case 4: return "Misaligned Access Exception"; + case 5: return "Unimplemented Opcode Exception"; + case 6: return "Privilege Violation"; + case 7: return "Bounds Check"; + case 8: return "Integer Divide Exception"; + case 9: return "Integer Overflow Exception"; + case 10: return "Error Exception"; + case 114: return "FPU precise"; + case 115: return "FPU imprecise"; + case 130: return "Ddb break"; + case 131: return "Ddb trace"; + case 132: return "Ddb trap"; + case 451: return "Syscall"; + } +} + +/* + * Read a word at address addr. + * Return 1 if was able to read, 0 otherwise. + */ +unsigned +db_trace_get_val(vm_offset_t addr, unsigned *ptr) +{ + label_t db_jmpbuf; + label_t *prev = db_recover; + boolean_t old_quiet_db_read_bytes = quiet_db_read_bytes; + + quiet_db_read_bytes = 1; + + if (setjmp(*(db_recover = &db_jmpbuf)) != 0) { + db_recover = prev; + quiet_db_read_bytes = old_quiet_db_read_bytes; + return 0; + } else { + db_read_bytes((char*)addr, 4, (char*)ptr); + db_recover = prev; + quiet_db_read_bytes = old_quiet_db_read_bytes; + return 1; + } +} + + +#define FIRST_CALLPRESERVED_REG 14 +#define LAST_CALLPRESERVED_REG 29 +#define FIRST_ARG_REG 2 +#define LAST_ARG_REG 9 +#define RETURN_VAL_REG 1 + +static unsigned global_saved_list = 0x0; /* one bit per register */ +static unsigned local_saved_list = 0x0; /* one bit per register */ +static unsigned trashed_list = 0x0; /* one bit per register */ +static unsigned saved_reg[32]; /* one value per register */ + +#define reg_bit(reg) (1<<((reg)%32)) + +static void +save_reg(int reg, unsigned value) +{ + #ifdef TRACE_DEBUG + if (DEBUGGING_ON) db_printf("save_reg(%d, %x)\n", reg, value); + #endif + if (trashed_list & reg_bit(reg)) { + #ifdef TRACE_DEBUG + if (DEBUGGING_ON) db_printf("<trashed>\n"); + #endif + return; /* don't save trashed registers */ + } + saved_reg[(reg%32)] = value; + global_saved_list |= reg_bit(reg); + local_saved_list |= reg_bit(reg); +} + +#define mark_reg_trashed(reg) (trashed_list |= reg_bit(reg)) + +#define have_global_reg(reg) (global_saved_list & (1<<(reg))) +#define have_local_reg(reg) (local_saved_list & (1<<(reg))) + +#define clear_local_saved_regs() { local_saved_list = trashed_list = 0; } +#define clear_global_saved_regs() { local_saved_list = global_saved_list = 0; } + +#define saved_reg_value(reg) (saved_reg[(reg)]) + +/* + * Show any arguments that we might have been able to determine. + */ +static void +print_args(void) +{ + int reg, last_arg; + + /* find the highest argument register saved */ + for (last_arg = LAST_ARG_REG; last_arg >= FIRST_ARG_REG; last_arg--) + if (have_local_reg(last_arg)) + break; + if (last_arg < FIRST_ARG_REG) + return; /* none were saved */ + + db_printf("("); + + /* print each one, up to the highest */ + for (reg = FIRST_ARG_REG; /*nothing */; reg++) + { + if (!have_local_reg(reg)) + db_printf("?"); + else { + unsigned value = saved_reg_value(reg); + db_printf("%s%x", hex_value_needs_0x(value) ? "0x" : "", value); + } + if (reg == last_arg) + break; + else + db_printf(", "); + } + db_printf(")"); +} + + +#define JUMP_SOURCE_IS_BAD 0 +#define JUMP_SOURCE_IS_OK 1 +#define JUMP_SOURCE_IS_UNLIKELY 2 + +/* + * Give an address to where we return, and an address to where we'd jumped, + * Decided if it all makes sense. + * + * Gcc sometimes optimized something like + * if (condition) + * func1(); + * else + * OtherStuff... + * to + * bcnd !condition mark + * bsr.n func1 + * or r1, r0, mark2 + * mark: + * OtherStuff... + * mark2: + * + * So RETURN_TO will be MARK2, even though we really did branch via + * 'bsr.n func1', so this makes it difficult to be certaian about being + * wrong. + */ +static int +is_jump_source_ok(unsigned return_to, unsigned jump_to) +{ + unsigned flags; + union instruction instruction; + + /* + * Delayed branches are most common... look two instructions before + * where we were going to return to to see if it's a delayed branch. + */ + if (!db_trace_get_val(return_to - 8, &instruction.rawbits)) + return JUMP_SOURCE_IS_BAD; + flags = m88k_instruction_info(instruction.rawbits); + + if ((flags & FLOW_CTRL) && (flags & DELAYED) && (flags & (JSR|BSR))) { + if (flags & JSR) + return JUMP_SOURCE_IS_OK; /* have to assume it's correct */ + /* calculate the offset */ + if (br_dest(return_to - 8, instruction) == jump_to) + return JUMP_SOURCE_IS_OK; /* exactamundo! */ + else + return JUMP_SOURCE_IS_UNLIKELY; /* seems wrong */ + } + + /* + * Try again, looking for a non-delayed jump one back. + */ + if (!db_trace_get_val(return_to - 4, &instruction.rawbits)) + return JUMP_SOURCE_IS_BAD; + flags = m88k_instruction_info(instruction.rawbits); + + if ((flags & FLOW_CTRL) && !(flags & DELAYED) && (flags & (JSR|BSR))) { + if (flags & JSR) + return JUMP_SOURCE_IS_OK; /* have to assume it's correct */ + /* calculate the offset */ + if (br_dest(return_to - 4, instruction) == jump_to) + return JUMP_SOURCE_IS_OK; /* exactamundo! */ + else + return JUMP_SOURCE_IS_UNLIKELY; /* seems wrong */ + } + + return JUMP_SOURCE_IS_UNLIKELY; +} + +static char *note = 0; +static int next_address_likely_wrong = 0; + +/* How much slop we expect in the stack trace */ +#define FRAME_PLAY 8 + +/* + * Stack decode - + * unsigned addr; program counter + * unsigned *stack; IN/OUT stack pointer + * + * given an address within a function and a stack pointer, + * try to find the function from which this one was called + * and the stack pointer for that function. + * + * The return value is zero (if we get confused) or + * we determine that the return address has not yet + * been saved (early in the function prologue). Otherwise + * the return value is the address from which this function + * was called. + * + * Note that even is zero is returned (the second case) the + * stack pointer can be adjusted. + * + */ +static int +stack_decode(unsigned addr, unsigned *stack) +{ + db_sym_t proc; + unsigned offset_from_proc; + unsigned instructions_to_search; + unsigned check_addr; + unsigned function_addr; /* start of function */ + unsigned r31 = *stack; /* the r31 of the function */ + unsigned inst; /* text of an instruction */ + unsigned ret_addr; /* address to which we return */ + unsigned tried_to_save_r1 = 0; + + #ifdef TRACE_DEBUG + if (DEBUGGING_ON) + db_printf("\n>>>stack_decode(addr=%x, stack=%x)\n", + addr, *stack); + #endif + + /* get what we hope will be the db_sym_t for the function name */ + proc = db_search_symbol(addr, DB_STGY_PROC, &offset_from_proc); + if (offset_from_proc == addr) /* i.e. no symbol found */ + proc = DB_SYM_NULL; + + /* + * Somehow, find the start of this function. + * If we found a symbol above, it'll have the address. + * Otherwise, we've got to search for it.... + */ + if (proc != DB_SYM_NULL) + { + char *names; + db_symbol_values(proc, &names, &function_addr); + if (names == 0) + return 0; + #ifdef TRACE_DEBUG + if (DEBUGGING_ON) db_printf("name %s address 0x%x\n", + names, function_addr); + #endif + } + else + { + int instructions_to_check = 400; + /* + * hmm - unable to find symbol. Search back + * looking for a function prolog. + */ + for (check_addr = addr; instructions_to_check-- > 0; check_addr -= 4) + { + if (!db_trace_get_val(check_addr, &inst)) + break; + + if (SUBU_R31_R31_IMM(inst)) + { + #if 0 + /* + * If the next instruction is "st r1, r31, ####" + * then we can feel safe we have the start of + * a function. + */ + if (!db_trace_get_val(check_addr + 4, &inst)) + continue; + if (ST_R1_R31_IMM(instr)) + break; /* sucess */ + #else + /* + * Latest GCC optimizer is just too good... the store + * of r1 might come much later... so we'll have to + * settle for just the "subr r31, r31, ###" to mark + * the start.... + */ + break; + #endif + } + /* + * if we come across a [jmp r1] or [jmp.n r1] assume we have hit + * the previous functions epilogue and stop our search. + * Since we know we would have hit the "subr r31, r31" if it was + * right in front of us, we know this doesn't have one so + * we just return failure.... + */ + if (JMP_R1(inst) || JMPN_R1(inst)) { + #ifdef TRACE_DEBUG + if (DEBUGGING_ON) + db_printf("ran into a [jmp r1] at %x (addr=%x)\n", + check_addr, addr); + #endif + return 0; + } + } + if (instructions_to_check < 0) { + #ifdef TRACE_DEBUG + if (DEBUGGING_ON) + db_printf("couldn't find func start (addr=%x)\n", addr); + #endif + return 0; /* bummer, couldn't find it */ + } + function_addr = check_addr; + } + + /* + * We now know the start of the function (function_addr). + * If we're stopped right there, or if it's not a + * subu r31, r31, #### + * then we're done. + */ + if (addr == function_addr) { + #ifdef TRACE_DEBUG + if (DEBUGGING_ON) db_printf("at start of func\n"); + #endif + return 0; + } + if (!db_trace_get_val(function_addr, &inst)) { + #ifdef TRACE_DEBUG + if (DEBUGGING_ON) db_printf("couldn't read %x at line %d\n", + function_addr, __LINE__); + #endif + return 0; + } + SHOW_INSTRUCTION(function_addr, inst, "start of function: "); + if (!SUBU_R31_R31_IMM(inst)) { + #ifdef TRACE_DEBUG + if (DEBUGGING_ON) db_printf("<not subu,r31,r31,imm>\n"); + #endif + return 0; + } + + /* add the size of this frame to the stack (for the next frame) */ + *stack += IMM16VAL(inst); + + /* + * Search from the beginning of the function (funstart) to where we are + * in the function (addr) looking to see what kind of registers have + * been saved on the stack. + * + * We'll stop looking before we get to ADDR if we hit a branch. + */ + clear_local_saved_regs(); + check_addr = function_addr + 4; /* we know the first inst isn't a store */ + + for (instructions_to_search = (addr - check_addr)/sizeof(long); + instructions_to_search-- > 0; + check_addr += 4) + { + union instruction instruction; + unsigned flags; + + /* read the instruction */ + if (!db_trace_get_val(check_addr, &instruction.rawbits)) { + #ifdef TRACE_DEBUG + if (DEBUGGING_ON) db_printf("couldn't read %x at line %d\n", + check_addr, __LINE__); + #endif + break; + } + + SHOW_INSTRUCTION(check_addr, instruction.rawbits, "prolog: "); + + /* find out the particulars about this instruction */ + flags = m88k_instruction_info(instruction.rawbits); + + /* if a store to something off the stack pointer, note the value */ + if ((flags & STORE) && instruction.diatic.s1 == /*stack pointer*/31) + { + unsigned value; + if (!have_local_reg(instruction.diatic.d)) { + if (instruction.diatic.d == 1) + tried_to_save_r1 = r31 + instruction.diatic.i16 ; + if (db_trace_get_val(r31 + instruction.diatic.i16, &value)) + save_reg(instruction.diatic.d, value); + } + if ((flags & DOUBLE) && !have_local_reg(instruction.diatic.d + 1)) { + if (instruction.diatic.d == 0) + tried_to_save_r1 = r31+instruction.diatic.i16 +4; + if (db_trace_get_val(r31+instruction.diatic.i16 +4, &value)) + save_reg(instruction.diatic.d + 1, value); + } + } + + /* if an inst that kills D (and maybe D+1), note that */ + if (flags & TRASHES) { + mark_reg_trashed(instruction.diatic.d); + if (flags & DOUBLE) + mark_reg_trashed(instruction.diatic.d + 1); + } + + /* if a flow control instruction, stop now (or next if delayed) */ + if ((flags & FLOW_CTRL) && instructions_to_search != 0) + instructions_to_search = (flags & DELAYED) ? 1 : 0; + } + + /* + * If we didn't save r1 at some point, we're hosed. + */ + if (!have_local_reg(1)) { + if (tried_to_save_r1) { + db_printf(" <return value of next fcn unreadable in %08x>\n", + tried_to_save_r1); + } + #ifdef TRACE_DEBUG + if (DEBUGGING_ON) db_printf("didn't save r1\n"); + #endif + return 0; + } + + ret_addr = saved_reg_value(1); + + #ifdef TRACE_DEBUG + if (DEBUGGING_ON) + db_printf("Return value is = %x, function_addr is %x.\n", + ret_addr, function_addr); + #endif + + /* + * In support of this, continuation.s puts the low bit on the + * return address for continuations (the return address will never + * be used, so it's ok to do anything you want to it). + */ + if (ret_addr & 1) { + note = "<<can not trace past a continuation>>"; + ret_addr = 0; + } else if (ret_addr != 0x00) { + switch(is_jump_source_ok(ret_addr, function_addr)) { + case JUMP_SOURCE_IS_OK: + break; /* excellent */ + + case JUMP_SOURCE_IS_BAD: + #ifdef TRACE_DEBUG + if (DEBUGGING_ON) db_printf("jump is bad\n"); + #endif + return 0; /* bummer */ + + case JUMP_SOURCE_IS_UNLIKELY: + next_address_likely_wrong = 1;; + break; + } + } + + return ret_addr; +} + +static void +db_stack_trace_cmd2(db_regs_t *regs) +{ + unsigned stack; + unsigned depth=1; + unsigned where; + unsigned ft; + unsigned pair[2]; + int i; + + /* + * Frame_is_sane returns: + * 1 if regs seems to be a reasonable kernel exception frame. + * 2 if regs seems to be a reasonable user exception frame + * (in the current task). + * 0 if this looks like neither. + */ + if (ft = frame_is_sane(regs), ft == 0) + { + db_printf("Register frame 0x%x is suspicous; skipping trace\n", regs); + return; + } + + /* if user space and no user space trace specified, puke */ + if (ft == 2 && !(trace_flags & TRACE_USER_FLAG)) + return; + + /* fetch address */ + /* use sxip if valid, otherwise try snip or sfip */ + where = ((regs->sxip & 2) ? regs->sxip : + ((regs->snip & 2) ? regs->snip : + regs->sfip) ) & ~3; + stack = regs->r[31]; + db_printf("stack base = 0x%x\n", stack); + db_printf("(0) "); /*depth of trace */ + if (trace_flags & TRACE_SHOWADDRESS_FLAG) + db_printf("%08x ", where); + db_printsym(where, DB_STGY_PROC); + clear_global_saved_regs(); + + /* see if this routine had a stack frame */ + if ((where=stack_decode(where, &stack))==0) + { + where = regs->r[1]; + db_printf("(stackless)"); + } + else + { + print_args(); + if (trace_flags & TRACE_SHOWFRAME_FLAG) + db_printf(" [frame 0x%x]", stack); + } + db_printf("\n"); + if (note) { + db_printf(" %s\n", note); + note = 0; + } + + do + { + /* + * If requested, show preserved registers at the time + * the next-shown call was made. Only registers known to have + * changed from the last exception frame are shown, as others + * can be gotten at by looking at the exception frame. + */ + if (trace_flags & TRACE_SHOWCALLPRESERVED_FLAG) + { + int r, title_printed = 0; + + for (r = FIRST_CALLPRESERVED_REG; r<=LAST_CALLPRESERVED_REG; r++) { + if (have_global_reg(r)) { + unsigned value = saved_reg_value(r); + if (title_printed == 0) { + title_printed = 1; + db_printf("[in next func:"); + } + if (value == 0) + db_printf(" r%d", r); + else if (value <= 9) + db_printf(" r%d=%x", r, value); + else + db_printf(" r%d=x%x", r, value); + } + } + if (title_printed) + db_printf("]\n"); + } + + db_printf("(%d)%c", depth++, next_address_likely_wrong ? '?':' '); + next_address_likely_wrong = 0; + + if (trace_flags & TRACE_SHOWADDRESS_FLAG) + db_printf("%08x ", where); + db_printsym(where, DB_STGY_PROC); + where = stack_decode(where, &stack); + print_args(); + if (trace_flags & TRACE_SHOWFRAME_FLAG) + db_printf(" [frame 0x%x]", stack); + db_printf("\n"); + if (note) { + db_printf(" %s\n", note); + note = 0; + } + } while (where); + + /* try to trace back over trap/exception */ + + stack &= ~7; /* double word aligned */ + /* take last top of stack, and try to find an exception frame near it */ + + i = FRAME_PLAY; + + #ifdef TRACE_DEBUG + if (DEBUGGING_ON) + db_printf("(searching for exception frame at 0x%x)\n", stack); + #endif + + while (i) + { + /* + * On the stack, a pointer to the exception frame is written + * in two adjacent words. In the case of a fault from the kernel, + * this should point to the frame right above them: + * + * Exception Frame Top + * .. + * Exception Frame Bottom <-- frame addr + * frame addr + * frame addr <-- stack pointer + * + * In the case of a fault from user mode, the top of stack + * will just have the address of the frame + * replicated twice. + * + * frame addr <-- top of stack + * frame addr + * + * Here we are just looking for kernel exception frames. + */ + + if (badwordaddr((vm_offset_t)stack) || + badwordaddr((vm_offset_t)(stack+4))) + break; + + db_read_bytes((char*)stack, 2*sizeof(int), (char*)pair); + + /* the pairs should match and equal stack+8 */ + if (pair[0] == pair[1]) + { + if (pair[0] != stack+8) + { + /* + if (!badwordaddr((vm_offset_t)pair[0]) && (pair[0]!=0)) + db_printf("stack_trace:found pair 0x%x but != to stack+8\n", + pair[0]); + */ + } + else if (frame_is_sane((db_regs_t*)pair[0])) + { + db_regs_t *frame = (db_regs_t *) pair[0]; + char *cause = m88k_exception_name(frame -> vector); + + db_printf("-------------- %s [EF: 0x%x] -------------\n", + cause, frame); + db_stack_trace_cmd2(frame); + return; + } + #ifdef TRACE_DEBUG + else if (DEBUGGING_ON) + db_printf("pair matched, but frame at 0x%x looks insane\n", + stack+8); + #endif + } + stack += 8; + i--; + } + + /* + * If we go here, crawling back on the stack failed to find us + * a previous exception frame. Look for a user frame pointer + * pointed to by a word 8 bytes off of the top of the stack + * if the "u" option was specified. + */ + if (trace_flags & TRACE_USER_FLAG) + { + db_regs_t *user; + + /* Make sure we are back on the right page */ + stack -= 4*FRAME_PLAY; + stack = stack & ~(KERNEL_STACK_SIZE-1); /* point to the bottom */ + stack += KERNEL_STACK_SIZE - 8; + + if (badwordaddr((vm_offset_t)stack) || + badwordaddr((vm_offset_t)stack)) + return; + + db_read_bytes((char*)stack, 2*sizeof(int), (char*)pair); + if (pair[0] != pair[1]) + return; + + /* have a hit */ + user = *((db_regs_t **) stack); + + if (frame_is_sane(user) == 2) + { + db_printf("---------------- %s [EF : 0x%x] -------------\n", + m88k_exception_name(user->vector), user); + db_stack_trace_cmd2(user); + } + } +} + +/* + * stack trace - needs a pointer to a m88k saved state. + * + * If argument f is given, the stack pointer of each call frame is + * printed. + */ +void +db_stack_trace_cmd( + db_regs_t *addr, + int have_addr, + db_expr_t count, + char *modif) +{ + enum { Default, Stack, Proc, Frame } style = Default; + db_regs_t frame; /* a m88100_saved_state */ + db_regs_t *regs; + union { + db_regs_t *frame; + struct proc *proc; + unsigned num; + } arg; + arg.frame = addr; + + trace_flags = 0; /* flags will be set via modifers */ + + while (modif && *modif) { + switch (*modif++) + { + case 'd': + #ifdef TRACE_DEBUG + trace_flags |= TRACE_DEBUG_FLAG; + #else + db_printtf("<debug trace not compiled in, ignoring>\n"); + #endif + break; + + case 's': style = Stack ; break; + case 'f': style = Frame ; break; + case 'p': trace_flags |= TRACE_SHOWCALLPRESERVED_FLAG; break; + case 'a': trace_flags |= TRACE_SHOWADDRESS_FLAG; break; + case 'F': trace_flags |= TRACE_SHOWFRAME_FLAG; break; + case 'u': trace_flags |= TRACE_USER_FLAG; break; + default: + db_printf("unknown trace modifier [%c]\n", modif[-1]); + /*FALLTHROUGH*/ + case 'h': + db_printf("usage: trace/[MODIFIER] [ARG]\n"); + db_printf(" u = include user trace\n"); + db_printf(" F = print stack frames\n"); + db_printf(" a = show return addresses\n"); + db_printf(" p = show call-preserved registers\n"); + db_printf(" s = ARG is a stack pointer\n"); + db_printf(" f = ARG is a frame pointer\n"); + #ifdef TRACE_DEBUG + db_printf(" d = trace-debugging output\n"); + #endif + return; + } + } + + if (!have_addr && style != Default) { + db_printf("expecting argument with /s or /f\n"); + return; + } + if (have_addr && style == Default) + style = Proc; + + switch(style) + { + case Default: + regs = DDB_REGS; + break; + + case Frame: + regs = arg.frame; + break; + + case Stack: + { + unsigned val1, val2, sxip; + unsigned ptr; + bzero((void*)&frame, sizeof(frame)); + #define REASONABLE_FRAME_DISTANCE 2048 + + /* + * We've got to find the top of a stack frame so we can get both + * a PC and and real SP. + */ + for (ptr = arg.num;/**/; ptr += 4) { + /* Read a word from the named stack */ + if (db_trace_get_val(ptr, &val1) == 0) { + db_printf("can't read from %x, aborting.\n", ptr); + return; + } + + /* + * See if it's a frame pointer.... if so it will be larger than + * the address it was taken from (i.e. point back up the stack) + * and we'll be able to read where it points. + */ + if (val1 <= ptr || + (val1 & 3) || + val1 > (ptr + REASONABLE_FRAME_DISTANCE)) + continue; + + /* peek at the next word to see if it could be a return address */ + if (db_trace_get_val(ptr, &sxip) == 0) { + db_printf("can't read from %x, aborting.\n", ptr); + return; + } + if (sxip == 0 || !db_trace_get_val(sxip, &val2)) + continue; + + if (db_trace_get_val(val1, &val2) == 0) { + db_printf("can't read from %x, aborting.\n", val1); + continue; + } + + /* + * The value we've just read will be either another frame pointer, + * or the start of another exception frame. + */ + if ( + #ifdef JEFF_DEBUG + val2 == 0 + #else + val2 == 0x12345678 + #endif + && db_trace_get_val(val1-4, &val2) && val2 == val1 + && db_trace_get_val(val1-8, &val2) && val2 == val1) + { + /* we've found a frame, so the stack must have been good */ + db_printf("%x looks like a frame, accepting %x\n",val1,ptr); + break; + } + + if (val2 > val1 && (val2 & 3) == 0) { + /* well, looks close enough to be another frame pointer */ + db_printf("*%x = %x looks like a stack frame pointer, accepting %x\n", val1, val2, ptr); + break; + } + } + + frame.r[31] = ptr; + frame.epsr = 0x800003f0U; + frame.sxip = sxip | 2; + frame.snip = frame.sxip + 4; + frame.sfip = frame.snip + 4; +db_printf("[r31=%x, sxip=%x]\n", frame.r[31], frame.sxip); + regs = &frame; + } + } + + db_stack_trace_cmd2(regs); +} diff --git a/sys/arch/mvme88k/dev/bugtty.c b/sys/arch/mvme88k/dev/bugtty.c new file mode 100644 index 00000000000..0eeafd308c7 --- /dev/null +++ b/sys/arch/mvme88k/dev/bugtty.c @@ -0,0 +1,502 @@ +/* $NetBSD$ */ + +/* + * Copyright (c) 1995 Dale Rahn. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by Dale Rahn. + * 4. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/ioctl.h> +#include <sys/device.h> +#include <sys/tty.h> +#include <sys/proc.h> +#include <sys/conf.h> +#include <sys/uio.h> +#include <sys/queue.h> +#include <dev/cons.h> + +#include <machine/autoconf.h> +#include <machine/cpu.h> + +#include "bugtty.h" + +int bugttymatch __P((struct device *parent, void *self, void *aux)); +void bugttyattach __P((struct device *parent, struct device *self, void *aux)); + +struct cfattach bugtty_ca = { + sizeof(struct device), bugttymatch, bugttyattach +}; + +struct cfdriver bugtty_cd = { + NULL, "bugtty", DV_TTY, 0 +}; + +/* prototypes */ +int bugttycnprobe __P((struct consdev *cp)); +int bugttycninit __P((struct consdev *cp)); +int bugttycngetc __P((dev_t dev)); +int bugttycnputc __P((dev_t dev, char c)); + +int bugttyopen __P((dev_t dev, int flag, int mode, struct proc *p)); +int bugttyclose __P((dev_t dev, int flag, int mode, struct proc *p)); +int bugttyread __P((dev_t dev, struct uio *uio, int flag)); +int bugttywrite __P((dev_t dev, struct uio *uio, int flag)); +int bugttyioctl __P((dev_t dev, int cmd, caddr_t data, int flag, struct proc *p)); +int bugttystop __P((struct tty *tp, int flag)); + +#define DIALOUT(x) ((x) & 0x80) +#define SWFLAGS(dev) (bugttyswflags | (DIALOUT(dev) ? TIOCFLAG_SOFTCAR : 0)) + +#define BUGBUF 80 +char bugtty_ibuffer[BUGBUF+1]; +volatile char *pinchar = bugtty_ibuffer; +char bug_obuffer[BUGBUF+1]; + +#define bugtty_tty bugttytty +struct tty *bugtty_tty[NBUGTTY]; +int needprom = 1; + +int +bugttymatch(parent, self, aux) + struct device *parent; + void *self; + void *aux; +{ + extern int needprom; + struct confargs *ca = aux; + + if (needprom == 0) + return (0); + /* + * tell our parent our requirements + */ + ca->ca_paddr = (caddr_t)0xfff45000; + ca->ca_size = 0x200; + ca->ca_ipl = IPL_TTY; + return (1); +} + +void +bugttyattach(parent, self, aux) + struct device *parent; + struct device *self; + void *aux; +{ + printf("\n"); +} + +#define BUGTTYUNIT(x) ((x) & (0x7f)) +void bugttyoutput __P((struct tty *tp)); + +int bugttydefaultrate = TTYDEF_SPEED; +int bugttyswflags; + +int +bugttymctl(dev, bits, how) + dev_t dev; + int bits, how; +{ + static int settings = TIOCM_DTR | TIOCM_RTS | + TIOCM_CTS | TIOCM_CD | TIOCM_DSR; + int s; + + /*printf("mctl: dev %x, bits %x, how %x,",dev, bits, how);*/ + + /* settings are currently ignored */ + s = spltty(); + switch (how) { + case DMSET: + break; + case DMBIC: + break; + case DMBIS: + break; + case DMGET: + break; + } + (void)splx(s); + + bits = 0; + /* proper defaults? */ + bits |= TIOCM_DTR; + bits |= TIOCM_RTS; + bits |= TIOCM_CTS; + bits |= TIOCM_CD; + /* bits |= TIOCM_RI; */ + bits |= TIOCM_DSR; + + /* printf("retbits %x\n", bits); */ + return (bits); +} + +int +bugttyopen(dev, flag, mode, p) + dev_t dev; + int flag, mode; + struct proc *p; +{ + int s, unit = BUGTTYUNIT(dev); + struct tty *tp; + extern int needprom; + + if (needprom == 0) + return (ENODEV); + + s = spltty(); + if (bugtty_tty[unit]) { + tp = bugtty_tty[unit]; + } else { + tp = bugtty_tty[unit] = ttymalloc(); + } + tp->t_oproc = bugttyoutput; + tp->t_param = NULL; + tp->t_dev = dev; + + if ((tp->t_state & TS_ISOPEN) == 0) { + tp->t_state |= TS_WOPEN; + ttychars(tp); + if (tp->t_ispeed == 0) { + /* + * only when cleared do we reset to defaults. + */ + tp->t_iflag = TTYDEF_IFLAG; + tp->t_oflag = TTYDEF_OFLAG; + tp->t_cflag = TTYDEF_CFLAG; + tp->t_lflag = TTYDEF_LFLAG; + tp->t_ispeed = tp->t_ospeed = bugttydefaultrate; + } + /* bugtty does not have carrier */ + tp->t_cflag |= CLOCAL; + /* + * do these all the time + */ + if (bugttyswflags & TIOCFLAG_CLOCAL) + tp->t_cflag |= CLOCAL; + if (bugttyswflags & TIOCFLAG_CRTSCTS) + tp->t_cflag |= CRTSCTS; + if (bugttyswflags & TIOCFLAG_MDMBUF) + tp->t_cflag |= MDMBUF; + bugttyparam(tp, &tp->t_termios); + ttsetwater(tp); + + (void)bugttymctl(dev, TIOCM_DTR | TIOCM_RTS, DMSET); + /* + if ((SWFLAGS(dev) & TIOCFLAG_SOFTCAR) || + (bugttymctl(dev, 0, DMGET) & TIOCM_CD)) + tp->t_state |= TS_CARR_ON; + else + tp->t_state &= ~TS_CARR_ON; + */ + tp->t_state |= TS_CARR_ON; + } else if (tp->t_state & TS_XCLUDE && p->p_ucred->cr_uid != 0) { + splx(s); + return (EBUSY); + } + + /* + * if NONBLOCK requested, ignore carrier + */ +/* + if (flag & O_NONBLOCK) + goto done; +*/ + + splx(s); + /* + * Reset the tty pointer, as there could have been a dialout + * use of the tty with a dialin open waiting. + */ + tp->t_dev = dev; + return ((*linesw[tp->t_line].l_open)(dev, tp)); +} + +int +bugttyparam() +{ + return (0); +} + +void +bugttyoutput(tp) + struct tty *tp; +{ + int cc, s, unit, cnt ; + + /* only supports one unit */ + + if ((tp->t_state & TS_ISOPEN) == 0) + return; + + s = spltty(); + cc = tp->t_outq.c_cc; + while (cc > 0) { + cnt = min(BUGBUF, cc); + cnt = q_to_b(&tp->t_outq, bug_obuffer, cnt); + bugoutstr(bug_obuffer, &bug_obuffer[cnt]); + cc -= cnt; + } + splx(s); +} + +int +bugttyclose(dev, flag, mode, p) + dev_t dev; + int flag, mode; + struct proc *p; +{ + int unit = BUGTTYUNIT(dev); + struct tty *tp = bugtty_tty[unit]; + + (*linesw[tp->t_line].l_close)(tp, flag); + + ttyclose(tp); +#if 0 + bugtty_tty[unit] = NULL; +#endif + return (0); +} + +int +bugttyread(dev, uio, flag) + dev_t dev; + struct uio *uio; + int flag; +{ + struct tty *tp; + + if ((tp = bugtty_tty[BUGTTYUNIT(dev)]) == NULL) + return (ENXIO); + return ((*linesw[tp->t_line].l_read)(tp, uio, flag)); +} + +#if 1 +/* only to be called at splclk() */ +bugtty_chkinput() +{ + struct tty *tp; + + tp = bugtty_tty[0]; /* Kinda ugly hack */ + if (tp == NULL ) + return; + + if (buginstat()) { + while (buginstat()) { + u_char c = buginchr() & 0xff; + (*linesw[tp->t_line].l_rint)(c, tp); + } + /* + wakeup(tp); + */ + } +} +#endif + +int +bugttywrite(dev, uio, flag) + dev_t dev; + struct uio *uio; + int flag; +{ +#if 0 + /* bypass tty output routines. */ + int i, cnt, s; + int oldoff; + + s = spltty(); + oldoff = uio->uio_offset; + do { + uiomove(bug_obuffer, BUGBUF, uio); + bugoutstr(bug_obuffer, &bug_obuffer[uio->uio_offset - oldoff]); + oldoff = uio->uio_offset; + } while (uio->uio_resid != 0); + splx(s); + + return (0); +#else + struct tty *tp; + if((tp = bugtty_tty[BUGTTYUNIT(dev)]) == NULL) + return (ENXIO); + return ((*linesw[tp->t_line].l_write)(tp, uio, flag)); +#endif +} + +int +bugttyioctl(dev, cmd, data, flag, p) + dev_t dev; + int cmd; + caddr_t data; + int flag; + struct proc *p; +{ + int unit = BUGTTYUNIT(dev); + struct tty *tp = bugtty_tty[unit]; + int error; + + if (!tp) + return (ENXIO); + + error = (*linesw[tp->t_line].l_ioctl)(tp, cmd, data, flag, p); + if (error >= 0) + return (error); + + error = ttioctl(tp, cmd, data, flag, p); + if (error >= 0) + return (error); + + switch (cmd) { + case TIOCSBRK: + /* */ + break; + + case TIOCCBRK: + /* */ + break; + + case TIOCSDTR: + (void) bugttymctl(dev, TIOCM_DTR | TIOCM_RTS, DMBIS); + break; + + case TIOCCDTR: + (void) bugttymctl(dev, TIOCM_DTR | TIOCM_RTS, DMBIC); + break; + + case TIOCMSET: + (void) bugttymctl(dev, *(int *) data, DMSET); + break; + + case TIOCMBIS: + (void) bugttymctl(dev, *(int *) data, DMBIS); + break; + + case TIOCMBIC: + (void) bugttymctl(dev, *(int *) data, DMBIC); + break; + + case TIOCMGET: + *(int *)data = bugttymctl(dev, 0, DMGET); + break; + case TIOCGFLAGS: + *(int *)data = SWFLAGS(dev); + break; + case TIOCSFLAGS: + error = suser(p->p_ucred, &p->p_acflag); + if (error != 0) + return (EPERM); + + bugttyswflags = *(int *)data; + bugttyswflags &= /* only allow valid flags */ + (TIOCFLAG_SOFTCAR | TIOCFLAG_CLOCAL | TIOCFLAG_CRTSCTS); + break; + default: + return (ENOTTY); + } + + return (0); +} + +int +bugttystop(tp, flag) + struct tty *tp; + int flag; +{ + int s; + + s = spltty(); + if (tp->t_state & TS_BUSY) { + if ((tp->t_state & TS_TTSTOP) == 0) + tp->t_state |= TS_FLUSH; + } + splx(s); + return (0); +} + +/* + * bugtty is the last possible choice for a console device. + */ +int +bugttycnprobe(cp) + struct consdev *cp; +{ + int maj; + extern int needprom; + + if (needprom == 0) { + cp->cn_pri = CN_DEAD; + return (0); + } + +#if 0 + switch (cputyp) { + case CPU_147: + case CPU_162: + cp->cn_pri = CN_NORMAL; + return (0); + default: + break; + } +#else + cp->cn_pri = CN_NORMAL; + return (0); +#endif /* 0 */ + + /* locate the major number */ + for (maj = 0; maj < nchrdev; maj++) + if (cdevsw[maj].d_open == bugttyopen) + break; + + cp->cn_dev = makedev(maj, 0); + cp->cn_pri = CN_NORMAL; + + return (1); +} + +int +bugttycninit(cp) + struct consdev *cp; +{ +} + +int +bugttycngetc(dev) + dev_t dev; +{ + return (buginchr()); +} + +int +bugttycnputc(dev, c) + dev_t dev; + char c; +{ + int s; + + if (c == '\n') + bugoutchr('\r'); + bugoutchr(c); +} diff --git a/sys/arch/mvme88k/dev/clock.c b/sys/arch/mvme88k/dev/clock.c new file mode 100644 index 00000000000..352bc426dfc --- /dev/null +++ b/sys/arch/mvme88k/dev/clock.c @@ -0,0 +1,371 @@ +/* $NetBSD: clock.c,v 1.22 1995/05/29 23:57:15 pk Exp $ */ + +/* + * Copyright (c) 1992, 1993 + * The Regents of the University of California. All rights reserved. + * Copyright (c) 1995 Nivas Madhur + * Copyright (c) 1994 Gordon W. Ross + * Copyright (c) 1993 Adam Glass + * + * This software was developed by the Computer Systems Engineering group + * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and + * contributed to Berkeley. + * + * All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Lawrence Berkeley Laboratory. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)clock.c 8.1 (Berkeley) 6/11/93 + */ + +/* + * Clock driver. Has both interval timer as well as statistics timer. + */ + +#include <sys/param.h> +#include <sys/kernel.h> +#include <sys/device.h> +#ifdef GPROF +#include <sys/gmon.h> +#endif + +#include <machine/autoconf.h> +#include <machine/cpu.h> + +#include <mvme88k/dev/pcctworeg.h> + +/* + * Statistics clock interval and variance, in usec. Variance must be a + * power of two. Since this gives us an even number, not an odd number, + * we discard one case and compensate. That is, a variance of 4096 would + * give us offsets in [0..4095]. Instead, we take offsets in [1..4095]. + * This is symmetric about the point 2048, or statvar/2, and thus averages + * to that value (assuming uniform random numbers). + */ +int statvar = 8192; +int statmin; /* statclock interval - 1/2*variance */ +int timerok; + +u_long delay_factor = 1; + +static int clockmatch __P((struct device *, void *, void *)); +static void clockattach __P((struct device *, struct device *, void *)); +int clockintr __P((void *, void *)); +int statintr __P((void *, void *)); + +struct clocksoftc { + struct device sc_dev; + volatile struct pcc2reg *sc_pcc2reg; +}; + +struct cfattach clock_ca = { + sizeof(struct clocksoftc), clockmatch, clockattach +}; + +struct cfdriver clock_cd = { + NULL, "clock", DV_DULL, 0 +}; + +struct intrhand clockintrhand, statintrhand; + +static int +clockmatch(struct device *parent, void *self, void *aux) +{ + register struct confargs *ca = aux; + register struct cfdata *cf = self; + + if (ca->ca_bustype != BUS_PCCTWO || + strcmp(cf->cf_driver->cd_name, "clock")) { + return (0); + } + + /* + * clock has to be at ipl 5 + * We return the ipl here so that the parent can print + * a message if it is different from what ioconf.c says. + */ + ca->ca_ipl = IPL_CLOCK; + /* set size to 0 - see pcctwo.c:match for details */ + ca->ca_size = 0; + + return 1; +} + +/* ARGSUSED */ +static void +clockattach(struct device *parent, struct device *self, void *aux) +{ + struct confargs *ca = aux; + struct clocksoftc *sc = (struct clocksoftc *)self; + u_long elapsedtime; + + extern void delay(u_long); + extern int cpuspeed; + + /* + * save virtual address of the pcc2 block since our + * registers are in that block. + */ + sc->sc_pcc2reg = (struct pcc2reg *)ca->ca_vaddr; + + /* + * calibrate for delay() calls. + * We do this by using tick timer1 in free running mode before + * cpu_initclocks() is called so turn on clock interrupts etc. + * + * the approach is: + * set count in timer to 0 + * call delay(1000) for a 1000 us delay + * after return, stop count and figure out + * how many us went by (call it x) + * now the factor to multiply the arg. passed to + * delay would be (x/1000) rounded up to an int. + */ + printf("\n"); + sc->sc_pcc2reg->pcc2_t1ctl &= ~PCC2_TICTL_CEN; + sc->sc_pcc2reg->pcc2_psclkadj = 256 - cpuspeed; + sc->sc_pcc2reg->pcc2_t1irq &= ~PCC2_TTIRQ_IEN; + sc->sc_pcc2reg->pcc2_t1cntr = 0; + sc->sc_pcc2reg->pcc2_t1ctl |= PCC2_TICTL_CEN; + delay(1000); /* delay for 1 ms */ + sc->sc_pcc2reg->pcc2_t1ctl &= ~PCC2_TICTL_CEN; + elapsedtime = sc->sc_pcc2reg->pcc2_t1cntr; + + delay_factor = (u_long)(elapsedtime / 1000 + 1); + + /* + * program clock to interrupt at IPL_CLOCK. Set everything + * except compare registers, interrupt enable and counter + * enable registers. + */ + sc->sc_pcc2reg->pcc2_t1ctl &= ~(PCC2_TICTL_CEN); + sc->sc_pcc2reg->pcc2_t1cntr= 0; + sc->sc_pcc2reg->pcc2_t1ctl |= (PCC2_TICTL_COC|PCC2_TICTL_COVF); + sc->sc_pcc2reg->pcc2_t1irq = (PCC2_TTIRQ_ICLR|IPL_CLOCK); + + sc->sc_pcc2reg->pcc2_t2ctl &= ~(PCC2_TICTL_CEN); + sc->sc_pcc2reg->pcc2_t2cntr= 0; + sc->sc_pcc2reg->pcc2_t2ctl |= (PCC2_TICTL_COC|PCC2_TICTL_COVF); + sc->sc_pcc2reg->pcc2_t2irq = (PCC2_TTIRQ_ICLR|IPL_CLOCK); + + /* + * Establish inerrupt handlers. + */ + clockintrhand.ih_fn = clockintr; + clockintrhand.ih_arg = 0; /* don't want anything */ + clockintrhand.ih_ipl = IPL_CLOCK; + clockintrhand.ih_wantframe = 1; + intr_establish(PCC2_VECT+9, &clockintrhand); + + statintrhand.ih_fn = statintr; + statintrhand.ih_arg = 0; /* don't want anything */ + statintrhand.ih_ipl = IPL_CLOCK; + statintrhand.ih_wantframe = 1; + intr_establish(PCC2_VECT+8, &statintrhand); + + timerok = 1; +} + +/* + * Set up the real-time and statistics clocks. Leave stathz 0 only if + * no alternative timer is available. mvme167/mvme187 has 2 tick timers + * in pcc2 - we are using timer 1 for clock interrupt and timer 2 for + * statistics. + * + * The frequencies of these clocks must be an even number of microseconds. + */ +cpu_initclocks() +{ + register int statint, minint; + volatile struct pcc2reg *pcc2reg; + + pcc2reg = ((struct clocksoftc *)clock_cd.cd_devs[0])->sc_pcc2reg; + + if (1000000 % hz) { + printf("cannot get %d Hz clock; using 100 Hz\n", hz); + hz = 100; + tick = 1000000 / hz; + } + if (stathz == 0) + stathz = hz; + if (1000000 % stathz) { + printf("cannot get %d Hz statclock; using 100 Hz\n", stathz); + stathz = 100; + } + profhz = stathz; /* always */ + + statint = 1000000 / stathz; + minint = statint / 2 + 100; + while (statvar > minint) + statvar >>= 1; + /* + * hz value 100 means we want the clock to interrupt 100 + * times a sec or 100 times in 1000000 us ie, 1 interrupt + * every 10000 us. Program the tick timer compare register + * to this value. + */ + pcc2reg->pcc2_t1cmp = tick; + pcc2reg->pcc2_t2cmp = statint; + statmin = statint - (statvar >> 1); + + /* start the clocks ticking */ + pcc2reg->pcc2_t1ctl = (PCC2_TICTL_CEN|PCC2_TICTL_COC|PCC2_TICTL_COVF); + pcc2reg->pcc2_t2ctl = (PCC2_TICTL_CEN|PCC2_TICTL_COC|PCC2_TICTL_COVF); + /* and enable those interrupts */ + pcc2reg->pcc2_t1irq |= (PCC2_TTIRQ_IEN|PCC2_TTIRQ_ICLR); + pcc2reg->pcc2_t2irq |= (PCC2_TTIRQ_IEN|PCC2_TTIRQ_ICLR); +} + +/* + * Dummy setstatclockrate(), since we know profhz==hz. + */ +/* ARGSUSED */ +void +setstatclockrate(int newhz) +{ + /* nothing */ +} + +/* + * Delay: wait for `about' n microseconds to pass. + */ +void +delay(volatile u_long n) +{ + volatile u_long cnt = n * delay_factor; + + while (cnt-- > 0) { + asm volatile(""); + } +} + +/* + * Clock interrupt handler. Calls hardclock() after setting up a + * clockframe. + */ +int +clockintr(void *cap, void *frame) +{ + volatile struct pcc2reg *reg; + + reg = ((struct clocksoftc *)clock_cd.cd_devs[0])->sc_pcc2reg; + + /* Clear the interrupt */ + reg->pcc2_t1irq = (PCC2_TTIRQ_IEN|PCC2_TTIRQ_ICLR|IPL_CLOCK); +#if 0 + reg->pcc2_t1irq |= PCC2_TTIRQ_ICLR; +#endif /* 0 */ + + hardclock((struct clockframe *)frame); +#include "bugtty.h" +#if NBUGTTY > 0 + bugtty_chkinput(); +#endif /* NBUGTTY */ + + return (1); +} + +/* + * Stat clock interrupt handler. + */ +int +statintr(void *cap, void *frame) +{ + volatile struct pcc2reg *reg; + register u_long newint, r, var; + + reg = ((struct clocksoftc *)clock_cd.cd_devs[0])->sc_pcc2reg; + + /* Clear the interrupt */ +#if 0 + reg->pcc2_t2irq |= PCC2_TTIRQ_ICLR; +#endif /* 0 */ + reg->pcc2_t2irq = (PCC2_TTIRQ_IEN|PCC2_TTIRQ_ICLR|IPL_CLOCK); + + statclock((struct clockframe *)frame); + + /* + * Compute new randomized interval. The intervals are uniformly + * distributed on [statint - statvar / 2, statint + statvar / 2], + * and therefore have mean statint, giving a stathz frequency clock. + */ + var = statvar; + do { + r = random() & (var - 1); + } while (r == 0); + newint = statmin + r; + + /* + * reprogram statistics timer to interrupt at + * newint us intervals. + */ + reg->pcc2_t2ctl = ~(PCC2_TICTL_CEN); + reg->pcc2_t2cntr = 0; + reg->pcc2_t2cmp = newint; + reg->pcc2_t2ctl = (PCC2_TICTL_CEN|PCC2_TICTL_COC|PCC2_TICTL_COVF); + reg->pcc2_t2irq |= (PCC2_TTIRQ_ICLR|PCC2_TTIRQ_IEN); + + return (1); +} + +/* + * Return the best possible estimate of the time in the timeval + * to which tvp points. We do this by returning the current time + * plus the amount of time since the last clock interrupt. + * + * Check that this time is no less than any previously-reported time, + * which could happen around the time of a clock adjustment. Just for + * fun, we guarantee that the time will be greater than the value + * obtained by a previous call. + */ +void +microtime(tvp) + register struct timeval *tvp; +{ + int s; + static struct timeval lasttime; + + s = splhigh(); + *tvp = time; + while (tvp->tv_usec > 1000000) { + tvp->tv_sec++; + tvp->tv_usec -= 1000000; + } + if (tvp->tv_sec == lasttime.tv_sec && + tvp->tv_usec <= lasttime.tv_usec && + (tvp->tv_usec = lasttime.tv_usec + 1) > 1000000) { + tvp->tv_sec++; + tvp->tv_usec -= 1000000; + } + lasttime = *tvp; + splx(s); +} diff --git a/sys/arch/mvme88k/dev/pcc2.c b/sys/arch/mvme88k/dev/pcc2.c new file mode 100644 index 00000000000..c78cbb24a81 --- /dev/null +++ b/sys/arch/mvme88k/dev/pcc2.c @@ -0,0 +1,253 @@ +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/device.h> +#include <machine/cpu.h> +#include <machine/pcc2.h> + +int m1x7pccprobe(struct device *parent, struct cfdata *self, void *aux); +void m1x7pccattach(struct device *parent, struct device *self, void *aux); + +int abort_handler(); +extern void abort_intrv(); +extern void pcc_intrv(); +extern int intrh_debug; +extern int machineid; +extern void badtrap(); +extern int submatch( struct device *parent, struct cfdata *self, void *aux); +/* static */ u_int *pcc_io_base; +static u_int *pcc_vector_base; + +static void abort_setup(); +void timer2_intr(); + +struct pcctwosoftc { + struct device sc_dev; + caddr_t sc_vaddr; + caddr_t sc_paddr; + struct pcctworeg *sc_pcc2; +}; + +void pcctwoattach __P((struct device *, struct device *, void *)); +int pcctwoprobe __P((struct device *, void *, void *)); +int pcctwoabort __P((struct frame *)); + +struct cfdriver pcctwocd = { + NULL, "pcctwo", pcctwomatch, pcctwoattach, + DV_DULL, sizeof(struct pcctwosoftc), 0 +}; + +struct pcctworeg *sys_pcc2 = NULL; + +int +pcctwomatch(struct device *parent, struct cfdata *self, void *aux) +{ +#if defined(__m88k__) + if (machineid == 0x187) { + return 1; + } +#endif + return 0; +} + +void +pcctwoattach(struct device *parent, struct device *self, void *aux) +{ + struct cfdata *cf; + volatile char *ibvr; /* Interrupt Base Vector Register */ + u_int ibv; /* Interrupt Base Vector, offset from vbr */ + u_int *iv; /* interupt vector */ + int i; + u_int vector_base; + + /* attach memory mapped io space */ + /* map 0xfffe1000 - 0xfffe102f, 0xfffe2800 */ + /* ppc_io_base = mmio(0xfffe1000, 1800, PG_RW|PG_CI); */ + pcc_io_base = 0xfffe1000; /* should really be return of virtmem alloc */ + /* set PCC vector base */ + ibv = PCC_IBVR(pcc_io_base) & 0xf0; + ibvr = &PCC_IBVR(pcc_io_base); + printf("pcc:ibvr %x *ibvr %x ibv %x\n",ibvr,*ibvr, ibv); + pcc_vector_base = (u_int *)ibv; + asm volatile ("movec vbr,%0": "=d" (vector_base)); + printf("pcc:vector_base %x\n",vector_base); + /* register "standard interupt handlers */ + + abort_setup(); + iv = (u_int *)(vector_base + (ibv * 4)); +printf("iv %x\n",iv); + for (i = 0; i <= SOFT2_VECTOR; i++) { + iv[i] = (u_int)pcc_intrv; + } + /* + timer2_setup(); + */ + iv = (u_int *)(vector_base + (ibv + TICK2_VECTOR) * 4); + *iv = (u_int)&pcc_intrv; + +#ifdef DEBUG + if (intrh_debug) + pr_intrh(); +#endif + if ((cf = config_search(submatch, self, aux)) != NULL) { + return; + } + return ; +} +asm (" .text"); +asm (" .global _pcc_intrv"); +asm ("_pcc_intrv:"); +asm (" link a6,#0"); +asm (" movml a0/a1/d0/d1,sp@-"); +asm (" movel a6,a0"); +asm (" addql #4,a0"); +asm (" movel a0,sp@-"); +asm (" jbsr _pcc_handler"); +asm (" addql #4,sp"); +asm (" movml sp@+,a0/a1/d0/d1"); +asm (" unlk a6"); +asm (" jra rei"); + +asm (" .global _abort_intrv"); +asm ("_abort_intrv:"); +asm (" movml a0/a1/d0/d1,sp@-"); +asm (" jbsr _abort_handler"); +asm (" movml sp@+,a0/a1/d0/d1"); +asm (" jra rei"); +/* asm (" .previous"); */ + +void *m147le_arg; +void +pcc_handler(struct exception_frame *except) +{ + u_int vector; + int handled = 0; + +#if 0 + printf("except %x\n",except); + printf("sr %x\n",except->sr); + printf("pc %x\n",except->pc); + printf("type %x\n",except->type); +#endif + vector = except->vo; +/* printf("vector %x\n",vector); */ + vector = (vector/4 - (u_int)pcc_vector_base); +/* printf("vector %x\n",vector); */ + + switch (vector) { + case AC_FAIL_VECTOR: + printf("ac_fail vector\n"); + break; + case BERR_VECTOR: + printf("berr vector\n"); + printf("pcc_handler:invalid vector %x\n",vector); + break; + case ABORT_VECTOR: + printf("abort vector\n"); + abort_handler(); + handled = 1; + break; + case SERIAL_VECTOR: + printf("serial vector\n"); + PCC_SERIAL_ICR(0xfffe1000) = 0; + break; + case LANCE_VECTOR: + leintr(m147le_arg); + handled = 1; + break; + case SCSIPORT_VECTOR: + printf("scsiport vector\n"); + m147sc_scintr(); + break; + case SCSIDMA_VECTOR: + printf("scsidma vector\n"); + m147sc_dmaintr(); + break; + case PRINTER_VECTOR: + printf("printer vector\n"); + break; + case TICK1_VECTOR: + printf("tick1 vector\n"); + printf("pcc_handler:invalid vector %x\n",vector); + break; + case TICK2_VECTOR: + timer2_intr(except); + handled = 1; + break; + case SOFT1_VECTOR: + printf("soft1 vector\n"); + break; + case SOFT2_VECTOR: + printf("soft2 vector\n"); + break; + default: + printf("pcc_handler:invalid vector %x\n",vector); + } + + if (handled == 0) { + printf("except %x\n",except); + printf("sr %x\n",except->sr); + printf("pc %x\n",except->pc); + printf("type %x\n",except->type); + } +} + + +int +abort_handler() +{ + printf("aicr = 0x%x\n",PCC_ABRT_ICR(pcc_io_base)); + PCC_ABRT_ICR(pcc_io_base) = 0x88; + printf("aicr = 0x%x\n",PCC_ABRT_ICR(pcc_io_base)); + Debugger(); + return 0; +} +static void abort_setup() +{ + printf("PCC_ABRT_ICR %x\n",&PCC_ABRT_ICR(pcc_io_base)); + printf("aicr = 0x%x\n",PCC_ABRT_ICR(pcc_io_base)); + PCC_ABRT_ICR(pcc_io_base) = 0x88; + printf("aicr = 0x%x\n",PCC_ABRT_ICR(pcc_io_base)); +} + +/* timer2 (clock) driver */ + +/*const u_int timer_reload = 0; /* .4096 sec ? */ +/* const u_int timer_reload = 62870; 1/60 sec ? */ +const u_int timer_reload = 63936; /* 1/100 sec ? */ + +#if 0 +void +timer2_setup() +{ + u_int *io_base; + pcc_io_base = 0xfffe1000; /* should really be return of virtmem alloc */ + io_base = pcc_io_base; + printf("pcc_io_base %x io_base %x\n",pcc_io_base, io_base); + printf("PCC_TIMER2_PRE %x\n",&PCC_TIMER2_PRE(io_base)); + printf("PCC_TIMER2_CTR %x\n",&PCC_TIMER2_CTR(io_base)); + printf("PCC_TIMER2_ICR %x\n",&PCC_TIMER2_ICR(io_base)); + PCC_TIMER2_PRE(io_base) = timer_reload; + PCC_TIMER2_CTR(io_base) = 0x7; + PCC_TIMER2_ICR(io_base) = 0x8e; +} +#endif +void +timer2_intr(struct exception_frame *except) +{ + u_int *io_base; + pcc_io_base = 0xfffe1000; /* should really be return of virtmem alloc */ + io_base = pcc_io_base; + + if (0x80 && PCC_TIMER2_ICR(io_base)) { + PCC_TIMER2_ICR(io_base) = 0x8e; + /* hardclock(); */ + hardclock(except); + + } else { + printf("timer2_intr: vector called without interrupt\n"); + } + /* REALLY UGLY HACK */ + bugtty_chkinput(); + + return; +} diff --git a/sys/arch/mvme88k/dev/pcctwo.c b/sys/arch/mvme88k/dev/pcctwo.c new file mode 100644 index 00000000000..7ad4c3abee1 --- /dev/null +++ b/sys/arch/mvme88k/dev/pcctwo.c @@ -0,0 +1,210 @@ +#include <sys/param.h> +#include <sys/uio.h> +#include <sys/systm.h> +#include <sys/device.h> +#include <machine/cpu.h> +#include <machine/autoconf.h> + +#include <mvme88k/dev/pcctworeg.h> + +struct pcctwosoftc { + struct device sc_dev; + volatile struct pcc2reg *sc_pcc2reg; +}; + +int pcctwomatch __P((struct device *, void *, void *)); +int pcctwoscan __P((struct device *, void *, void *)); +void pcctwoattach __P((struct device *, struct device *, void *)); + +#ifdef MVME187 +void setupiackvectors __P((void)); +#endif /* MVME187 */ + +struct cfattach pcctwo_ca = { + sizeof(struct pcctwosoftc), pcctwomatch, pcctwoattach +}; + +struct cfdriver pcctwo_cd = { + NULL, "pcctwo", DV_DULL, 0 +}; + +/*ARGSUSED*/ +int +pcctwomatch(struct device *parent, void *self, void *aux) +{ + int ret; + u_char id, rev; + caddr_t base; + struct confargs *ca = aux; + struct cfdata *cf = self; + +#if 0 + if (cputyp != CPU_167 && cputyp != CPU_166 +#ifdef MVME187 + && cputyp != CPU_187 +#endif + ) + { + return 0; + } +#endif /* 0 */ + if (cputyp != CPU_187) { + return 0; + } + + /* + * If bus or name do not match, fail. + */ + if (ca->ca_bustype != BUS_MAIN || + strcmp(cf->cf_driver->cd_name, "pcctwo")) { + return 0; + } + + if ((base = (caddr_t)cf->cf_loc[0]) == (caddr_t)-1) { + return 0; + } + + id = badpaddr(base, 1); + rev = badpaddr(base + 1, 1); + + if (id != PCC2_CHIP_ID || rev != PCC2_CHIP_REV) { + return 0; + } + + ca->ca_size = PCC2_SIZE; + ca->ca_paddr = base; + + return 1; +} + +int +pcctwoprint(void *aux, char *parent) +{ + struct confargs *ca = aux; + + /* + * We call pcctwoprint() via config_attach(). Parent + * will always be null and config_attach() would have already + * printed "nvram0 at pcctwo0". + */ + printf(" addr %x size %x", ca->ca_paddr, ca->ca_size); + if (ca->ca_ipl != -1) { + printf(" ipl %x", ca->ca_ipl); + } + + return (UNCONF); +} + +/*ARGSUSED*/ +int +pcctwoscan(struct device *parent, void *self, void *aux) +{ + struct confargs ca; + struct cfdata *cf = self; + struct pcctwosoftc *sc = (struct pcctwosoftc *)parent; + + /* + * Pcctwoscan gets called by config_search() for each + * child of parent (pcctwo) specified in ioconf.c. + * Fill in the bus type to be PCCTWO and call the child's + * match routine. If the child's match returns 1, then + * we need to allocate device memory, set it in confargs + * and call config_attach(). This, in turn, will call the + * child's attach. + */ + + ca.ca_bustype = BUS_PCCTWO; + + if ((*cf->cf_attach->ca_match)(parent, cf, &ca) == 0) + return 0; + + /* + * The child would have fixed up ca to reflect what its + * requirements are. + */ + + if (cf->cf_loc[2] != ca.ca_ipl) { + printf("Changing ipl %x specified in ioconf.c to %x for %s\n", + cf->cf_loc[2], ca.ca_ipl, cf->cf_driver->cd_name); + } + + /* + * If the size specified by the child is 0, don't map + * any IO space, but pass in the address of pcc2reg as vaddr. + * This is for clock and parallel port which don't have a + * separate address space by themselves but use pcc2's register + * block. + */ + if (ca.ca_size == 0) { + /* + * pcc2regs addr + */ +#if 0 + ca.ca_vaddr = ((struct confargs *)aux)->ca_vaddr; +#endif /* 0 */ + ca.ca_vaddr = (caddr_t)sc->sc_pcc2reg; + + } else { + ca.ca_vaddr = ca.ca_paddr; + } + +#if 0 + ca.ca_parent = ((struct confargs *)aux)->ca_vaddr; +#endif /* 0 */ + ca.ca_parent = (caddr_t)sc->sc_pcc2reg; + + /* + * Call child's attach using config_attach(). + */ + config_attach(parent, cf, &ca, pcctwoprint); + return 1; +} + +/* + * This function calls the match routine of the configured children + * in turn. For each configured child, map the device address into + * iomap space and then call config_attach() to attach the child. + */ + +/* ARGSUSED */ +void +pcctwoattach(struct device *parent, struct device *self, void *aux) +{ + struct pcctwosoftc *sc = (struct pcctwosoftc *)self; + struct confargs *ca = aux; + caddr_t base; + + if (self->dv_unit > 0) { + printf(" unsupported\n"); + return; + } + + base = ca->ca_vaddr; + + printf(": PCCTWO id 0x%2x rev 0x%2x\n", + *(u_char *)base, *((u_char *)base + 1)); + + /* + * mainbus driver would have mapped Pcc2 at base. Save + * the address in pcctwosoftc. + */ + sc->sc_pcc2reg = (struct pcc2reg *)base; + + /* + * Set pcc2intr_mask and pcc2intr_ipl. + */ + pcc2intr_ipl = (u_char *)&(sc->sc_pcc2reg->pcc2_ipl); + pcc2intr_mask = (u_char *)&(sc->sc_pcc2reg->pcc2_imask); + +#ifdef MVME187 + /* + * Get mappings for iack vectors. This doesn't belong here + * but is more closely related to pcc than anything I can + * think of. (could probably do it in locore.s). + */ + + setupiackvectors(); +#endif /* MVME187 */ + + (void)config_search(pcctwoscan, self, aux); +} diff --git a/sys/arch/mvme88k/include/ansi.h b/sys/arch/mvme88k/include/ansi.h new file mode 100644 index 00000000000..a1d9d668c93 --- /dev/null +++ b/sys/arch/mvme88k/include/ansi.h @@ -0,0 +1,76 @@ +/*- + * Copyright (c) 1990, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * from: @(#)ansi.h 8.2 (Berkeley) 1/4/94 + * $Id: ansi.h,v 1.3 1997/03/03 20:20:43 rahnds Exp $ + */ + +#ifndef _ANSI_H_ +#define _ANSI_H_ + +/* + * Types which are fundamental to the implementation and may appear in + * more than one standard header are defined here. Standard headers + * then use: + * #ifdef _BSD_SIZE_T_ + * typedef _BSD_SIZE_T_ size_t; + * #undef _BSD_SIZE_T_ + * #endif + */ +#define _BSD_CLOCK_T_ unsigned long /* clock() */ +#define _BSD_PTRDIFF_T_ int /* ptr1 - ptr2 */ +#define _BSD_SIZE_T_ unsigned int /* sizeof() */ +#define _BSD_SSIZE_T_ int /* byte count or error */ +#define _BSD_TIME_T_ long /* time() */ + +#include "va-m88k.h" + +#define _BSD_VA_LIST_ __gnuc_va_list + +/* + * Runes (wchar_t) is declared to be an ``int'' instead of the more natural + * ``unsigned long'' or ``long''. Two things are happening here. It is not + * unsigned so that EOF (-1) can be naturally assigned to it and used. Also, + * it looks like 10646 will be a 31 bit standard. This means that if your + * ints cannot hold 32 bits, you will be in trouble. The reason an int was + * chosen over a long is that the is*() and to*() routines take ints (says + * ANSI C), but they use _RUNE_T_ instead of int. By changing it here, you + * lose a bit of ANSI conformance, but your programs will still work. + * + * Note that _WCHAR_T_ and _RUNE_T_ must be of the same type. When wchar_t + * and rune_t are typedef'd, _WCHAR_T_ will be undef'd, but _RUNE_T remains + * defined for ctype.h. + */ +#define _BSD_WCHAR_T_ int /* wchar_t */ +#define _BSD_RUNE_T_ int /* rune_t */ + +#endif /* _ANSI_H_ */ diff --git a/sys/arch/mvme88k/include/asm.h b/sys/arch/mvme88k/include/asm.h new file mode 100644 index 00000000000..2c89b9e2191 --- /dev/null +++ b/sys/arch/mvme88k/include/asm.h @@ -0,0 +1,249 @@ +/* + * Mach Operating System + * Copyright (c) 1993-1992 Carnegie Mellon University + * Copyright (c) 1991 OMRON Corporation + * All Rights Reserved. + * + * Permission to use, copy, modify and distribute this software and its + * documentation is hereby granted, provided that both the copyright + * notice and this permission notice appear in all copies of the + * software, derivative works or modified versions, and any portions + * thereof, and that both notices appear in supporting documentation. + * + * CARNEGIE MELLON AND OMRON ALLOW FREE USE OF THIS SOFTWARE IN ITS "AS IS" + * CONDITION. CARNEGIE MELLON AND OMRON DISCLAIM ANY LIABILITY OF ANY KIND + * FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. + * + * Carnegie Mellon requests users of this software to return to + * + * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU + * School of Computer Science + * Carnegie Mellon University + * Pittsburgh PA 15213-3890 + * + * any improvements or extensions that they make and grant Carnegie the + * rights to redistribute these changes. + */ + +#ifndef __M88K_ASM_H__ +#define __M88K_ASM_H__ + +#ifdef __STDC__ +# define FUNC(NAME) _##NAME +#else +# define FUNC(NAME) _/**/NAME +#endif + +/* Define EH_DEBUG to be non-zero to compile-in various debugging things */ +#ifndef EH_DEBUG +#define EH_DEBUG 0 +#endif EH_DEBUG + +/* this gives the offsets into various structures of various elements, etc */ +#include "assym.s" + +#define ENTRY(NAME) \ + .align 8; .globl FUNC(NAME); FUNC(NAME): + + +#define LABEL(name) name:; .globl name ; +/* + * _LABEL(name) + * Defines one visible only to the file, unless debugging + * is enabled, in which case it's visible to the world (and + * hence to debuggers, and such). + */ +#if EH_DEBUG +# define _LABEL(name) name: .globl name ; +#else +# define _LABEL(name) name: ; +#endif + +#define RTE NOP ; rte + +#define PID cr0 +#define PSR cr1 +#define EPSR cr2 +#define SSBR cr3 +#define SXIP cr4 +#define SNIP cr5 +#define SFIP cr6 +#define VBR cr7 +#define DMT0 cr8 +#define DMD0 cr9 +#define DMA0 cr10 +#define DMT1 cr11 +#define DMD1 cr12 +#define DMA1 cr13 +#define DMT2 cr14 +#define DMD2 cr15 +#define DMA2 cr16 +#define SR0 cr17 +#define SR1 cr18 +#define SR2 cr19 +#define SR3 cr20 +#define FPECR fcr0 +#define FPHS1 fcr1 +#define FPLS1 fcr2 +#define FPHS2 fcr3 +#define FPLS2 fcr4 +#define FPPT fcr5 +#define FPRH fcr6 +#define FPRL fcr7 +#define FPIT fcr8 +#define FPSR fcr62 +#define FPCR fcr63 + +/* + * At various times, there is the need to clear the pipeline (i.e. + * synchronize). A "tb1 0, r0, foo" will do that (because a trap + * instruction always synchronizes, and this particular instruction + * will never actually take the trap). + */ +#define FLUSH_PIPELINE tb1 0, r0, 0 +#define NOP or r0, r0, r0 + +/* + * Useful in some situations. + * NOTE: If ARG1 or ARG2 are r2 or r3, strange things may happen. Watch out! + */ +#define CALL(NAME, ARG1, ARG2) \ + subu r31, r31, 32 ; \ + or r2, r0, ARG1 ; \ + bsr.n NAME ; \ + or r3, r0, ARG2 ; \ + addu r31, r31, 32 + +/* + * SR1 - CPU FLAGS REGISTER + * XXX clean this when the trap handler is reworked. Among the things + * I like to see is having the trap frame on the kernel stack instead + * of putting in the PCB. If done properly, we don't need SR1 for doing + * anything special. nivas + * + * SR1 contains flags about the current CPU status. + * + * The bit FLAG_IGNORE_DATA_EXCEPTION indicates that any data exceptions + * should be ignored (well, at least treated in a special way). + * The bit FLAG_INTERRUPT_EXCEPTION indicates that the current exception + * is the interrupt exception. Such information can be gotten + * in other ways, but having it in the flags makes it easy for the + * exception handler to check quickly. + * The bit FLAG_ENABLING_FPU indicates that the exception handler is + * in the process of enabling the FPU (so that an exception can + * be serviced). This is needed because enabling the FPU can + * cause other exceptions to happen, and the whole system is + * in a rather precarious state and so special cautions must + * be taken. + */ +#define FLAG_CPU_FIELD_WIDTH 4 /* must be <= 12 */ + +#define FLAG_IGNORE_DATA_EXCEPTION 5 /* bit number 5 */ +#define FLAG_INTERRUPT_EXCEPTION 6 /* bit number 6 */ +#define FLAG_ENABLING_FPU 7 /* bit number 7 */ + + +/* REGister OFFset into the E.F. (exception frame) */ +#define REG_OFF(reg_num) ((reg_num) * 4) /* (num * sizeof(register int)) */ +#define GENREG_OFF(num) (REG_OFF(EF_R0 + (num))) /* GENeral REGister OFFset */ + + +#define GENERAL_BREATHING_ROOM /* arbitrarily */ 200 +#define KERNEL_STACK_BREATHING_ROOM \ + (GENERAL_BREATHING_ROOM + SIZEOF_STRUCT_PCB + SIZEOF_STRUCT_UTHREAD) + +/* + * Some registers used during the setting up of the new exception frame. + * Don't choose r1, r30, or r31 for any of them. + * + * Also, if any are 'r2' or 'r3', be careful using with CALL above! + */ +#define FLAGS r2 +#define TMP r3 +#define TMP2 r10 +#define TMP3 r11 +#define SAVE_TMP2 st r10, r31, GENREG_OFF(10) +#define SAVE_TMP3 st r11, r31, GENREG_OFF(11) +#define RESTORE_TMP2 ld r10, r31, GENREG_OFF(10) +#define RESTORE_TMP3 ld r11, r31, GENREG_OFF(11) + +/* + * Info about the PSR + */ +#define PSR_SHADOW_FREEZE_BIT 0 +#define PSR_INTERRUPT_DISABLE_BIT 1 +#define PSR_FPU_DISABLE_BIT 3 +#define PSR_BIG_ENDIAN_MODE 30 +#define PSR_SUPERVISOR_MODE_BIT 31 + +/* + * Status bits for an SXIP/SNIP/SFIP address. + */ +#define RTE_VALID_BIT 1 +#define RTE_ERROR_BIT 0 + +/* + * Info about DMT0/DMT1/DMT2 + */ +#define DMT_VALID_BIT 0 +#define DMT_WRITE_BIT 1 +#define DMT_LOCK_BIT 12 +#define DMT_DOUBLE_BIT 13 +#define DMT_DAS_BIT 14 +#define DMT_DREG_OFFSET 7 +#define DMT_DREG_WIDTH 5 + +/* + * Bits for eh_debug. + */ +#define DEBUG_INTERRUPT_BIT 0 +#define DEBUG_DATA_BIT 1 +#define DEBUG_INSTRUCTION_BIT 2 +#define DEBUG_MISALIGN_BIT 3 +#define DEBUG_UNIMP_BIT 4 +#define DEBUG_DIVIDE_BIT 5 +#define DEBUG_OF_BIT 6 +#define DEBUG_FPp_BIT 7 +#define DEBUG_FPi_BIT 8 +#define DEBUG_SYSCALL_BIT 9 +#define DEBUG_MACHSYSCALL_BIT 10 +#define DEBUG_UNIMPLEMENTED_BIT 11 +#define DEBUG_PRIVILEGE_BIT 12 +#define DEBUG_BOUNDS_BIT 13 +#define DEBUG_OVERFLOW_BIT 14 +#define DEBUG_ERROR_BIT 15 +#define DEBUG_SIGSYS_BIT 16 +#define DEBUG_SIGTRAP_BIT 17 +#define DEBUG_BREAK_BIT 18 +#define DEBUG_TRACE_BIT 19 +#define DEBUG_KDB_BIT 20 +#define DEBUG_JKDB_BIT 21 +#define DEBUG_BUGCALL_BIT 22 + +#define DEBUG_UNKNOWN_BIT 31 + +/* + * These things for vector_init.c and locore.c + */ +#if defined(ASSEMBLER) +# define PREDEFINED_BY_ROM 0xffffffff +# define END_OF_VECTOR_LIST 0xfffffffe +#else +# define PREDEFINED_BY_ROM 0xffffffffU +# define END_OF_VECTOR_LIST 0xfffffffeU +#endif + +/* + * Define ERROR__XXX_USR if the xxx.usr bug (mask C82N) is present. + * This implements the workaround. + */ +#define ERRATA__XXX_USR 1 + +#if !defined(CMMU_I) +#define CMMU_I 0xFFF77000 +#endif +#if !defined(CMMU_D) +#define CMMU_D 0xFFF7F000 +#endif + +#endif /* __M88K_ASM_H__ */ diff --git a/sys/arch/mvme88k/include/asm_macro.h b/sys/arch/mvme88k/include/asm_macro.h new file mode 100644 index 00000000000..87aac4b3276 --- /dev/null +++ b/sys/arch/mvme88k/include/asm_macro.h @@ -0,0 +1,119 @@ +/* + * Mach Operating System + * Copyright (c) 1993-1991 Carnegie Mellon University + * Copyright (c) 1991 OMRON Corporation + * All Rights Reserved. + * + * Permission to use, copy, modify and distribute this software and its + * documentation is hereby granted, provided that both the copyright + * notice and this permission notice appear in all copies of the + * software, derivative works or modified versions, and any portions + * thereof, and that both notices appear in supporting documentation. + * + * CARNEGIE MELLON AND OMRON ALLOW FREE USE OF THIS SOFTWARE IN ITS "AS IS" + * CONDITION. CARNEGIE MELLON AND OMRON DISCLAIM ANY LIABILITY OF ANY KIND + * FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. + * + * Carnegie Mellon requests users of this software to return to + * + * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU + * School of Computer Science + * Carnegie Mellon University + * Pittsburgh PA 15213-3890 + * + * any improvements or extensions that they make and grant Carnegie the + * rights to redistribute these changes. + */ +/* + * HISTORY + * $Log: asm_macro.h,v $ + * Revision 1.3 1997/03/03 20:20:46 rahnds + * Cleanup after import. This also seems to bring up the current version. + * + * Revision 1.1.1.1 1995/10/18 10:54:22 deraadt + * initial 88k import; code by nivas and based on mach luna88k + * + * Revision 2.2 93/01/26 18:07:26 danner + * Created. + * [93/01/24 jfriedl] + * + */ + +#ifndef __M88K_ASM_MACRO_H__ +#define __M88K_ASM_MACRO_H__ + +/* + ** Various compiler macros used for speed and efficiency. + ** Anyone can include. + */ + +/* + * PSR_TYPE is the type of the Process Status Register. + */ +typedef unsigned long m88k_psr_type; + +/* + * disable_interrupts_return_psr() + * + * The INTERRUPT_DISABLE bit is set in the PSR and the *PREVIOUS* + * PSR is returned. Intended to be used with set_psr() [below] as in: + * + * { + * m88k_psr_type psr; + * . + * . + * psr = disable_interrupts_return_psr(); + * . + * SHORT [time-wise] CRITICAL SECTION HERE + * . + * set_psr(psr); + * . + * . + */ +static inline m88k_psr_type disable_interrupts_return_psr(void) +{ + m88k_psr_type temp, oldpsr; + asm volatile ( + "ldcr %0, cr1 \n" + "set %1, %0, 1<1> \n" + "stcr %1, cr1 \n" + "tcnd ne0, r0, 0 " : "=r" (oldpsr), "=r" (temp)); + return oldpsr; +} +#define disable_interrupt() (void)disable_interrupts_return_psr() + +/* + * Sets the PSR. See comments above. + */ +static inline void set_psr(m88k_psr_type psr) +{ + asm volatile ("stcr %0, cr1" :: "r" (psr)); +} + +/* + * Enables interrupts. + */ +static inline m88k_psr_type enable_interrupts_return_psr(void) +{ + m88k_psr_type temp, oldpsr; /* need a temporary register */ + asm volatile ( + "ldcr %0, cr1 \n" + "clr %1, %0, 1<1> \n" + "stcr %1, cr1 " : "=r" (oldpsr), "=r" (temp)); + return oldpsr; +} +#define enable_interrupt() (void)enable_interrupts_return_psr() + +#define db_enable_interrupt enable_interrupt +#define db_disable_interrupt disable_interrupt + +/* + * flushes the data pipeline. + */ +static inline void flush_pipeline() +{ + asm volatile ("tcnd ne0, r0, 0"); +} +#define db_flush_pipeline flush_pipeline + +#endif /* __M88K_ASM_MACRO_H__ */ diff --git a/sys/arch/mvme88k/include/assert.h b/sys/arch/mvme88k/include/assert.h new file mode 100644 index 00000000000..c9e72557e77 --- /dev/null +++ b/sys/arch/mvme88k/include/assert.h @@ -0,0 +1,8 @@ +#define assert(x) \ +({\ + if (!(x)) {\ + printf("assertion failure \"%s\" line %d file %s\n", \ + #x, __LINE__, __FILE__); \ + panic("assertion"); \ + } \ +}) diff --git a/sys/arch/mvme88k/include/assym.s b/sys/arch/mvme88k/include/assym.s new file mode 100644 index 00000000000..e394debb96f --- /dev/null +++ b/sys/arch/mvme88k/include/assym.s @@ -0,0 +1,82 @@ +#ifndef __GENASSYM_INCLUDED +#define __GENASSYM_INCLUDED 1 + +#define P_FORW 0 +#define P_BACK 4 +#define P_VMSPACE 32 +#define P_ADDR 236 +#define P_PRIORITY 208 +#define P_STAT 45 +#define P_WCHAN 104 +#define SRUN 2 +#define VM_PMAP 132 +#define V_INTR 12 +#define UPAGES 3 +#define PGSHIFT 12 +#define USIZE 12288 +#define NBPG 4096 +#define U_PROF 840 +#define U_PROFSCALE 852 +#define PCB_ONFAULT 336 +#define SIZEOF_PCB 344 +#define PCB_USER_STATE 80 +#define SYS_exit 1 +#define SYS_execve 59 +#define SYS_sigreturn 103 +#define EF_R0 0 +#define EF_R31 31 +#define EF_FPSR 32 +#define EF_FPCR 33 +#define EF_EPSR 34 +#define EF_SXIP 35 +#define EF_SFIP 37 +#define EF_SNIP 36 +#define EF_SSBR 38 +#define EF_DMT0 39 +#define EF_DMD0 40 +#define EF_DMA0 41 +#define EF_DMT1 42 +#define EF_DMD1 43 +#define EF_DMA1 44 +#define EF_DMT2 45 +#define EF_DMD2 46 +#define EF_DMA2 47 +#define EF_FPECR 48 +#define EF_FPHS1 49 +#define EF_FPLS1 50 +#define EF_FPHS2 51 +#define EF_FPLS2 52 +#define EF_FPPT 53 +#define EF_FPRH 54 +#define EF_FPRL 55 +#define EF_FPIT 56 +#define EF_VECTOR 57 +#define EF_MASK 58 +#define EF_MODE 59 +#define EF_RET 60 +#define EF_IPFSR 61 +#define EF_DPFSR 62 +#define EF_NREGS 64 +#define SIZEOF_EF 256 +#define PCB_PC 0 +#define PCB_IPL 4 +#define PCB_R14 8 +#define PCB_R15 12 +#define PCB_R16 16 +#define PCB_R17 20 +#define PCB_R18 24 +#define PCB_R19 28 +#define PCB_R20 32 +#define PCB_R21 36 +#define PCB_R22 40 +#define PCB_R23 44 +#define PCB_R24 48 +#define PCB_R25 52 +#define PCB_R26 56 +#define PCB_R27 60 +#define PCB_R28 64 +#define PCB_R29 68 +#define PCB_R30 72 +#define PCB_SP 76 + +#endif /* __GENASSYM_INCLUDED */ diff --git a/sys/arch/mvme88k/include/autoconf.h b/sys/arch/mvme88k/include/autoconf.h new file mode 100644 index 00000000000..c5220fad715 --- /dev/null +++ b/sys/arch/mvme88k/include/autoconf.h @@ -0,0 +1,54 @@ +/* + * Copyright (c) 1996 Nivas Madhur + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by Nivas Madhur. + * 4. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ +/* + * Autoconfiguration information. + */ +struct confargs { + int ca_bustype; + caddr_t ca_parent; + caddr_t ca_vaddr; + caddr_t ca_paddr; + int ca_size; + int ca_ipl; + int ca_vec; +}; + +#define BUS_MAIN 0 +#define BUS_MC 1 +#define BUS_PCC 2 +#define BUS_PCCTWO 3 +#define BUS_VMES 4 +#define BUS_VMEL 5 + +int always_match __P((struct device *, struct cfdata *, void *)); + +#define DEVICE_UNIT(device) (device->dv_unit) +#define CFDATA_LOC(cfdata) (cfdata->cf_loc) diff --git a/sys/arch/mvme88k/include/board.h b/sys/arch/mvme88k/include/board.h new file mode 100644 index 00000000000..22011cbbb99 --- /dev/null +++ b/sys/arch/mvme88k/include/board.h @@ -0,0 +1,126 @@ +/* + * Copyright (c) 1996 Nivas Madhur + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by Nivas Madhur. + * 4. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ +/* + * Mach Operating System + * Copyright (c) 1991 Carnegie Mellon University + * Copyright (c) 1991 OMRON Corporation + * All Rights Reserved. + * + * Permission to use, copy, modify and distribute this software and its + * documentation is hereby granted, provided that both the copyright + * notice and this permission notice appear in all copies of the + * software, derivative works or modified versions, and any portions + * thereof, and that both notices appear in supporting documentation. + * + */ +#ifndef _MACHINE_BOARD_H +#define _MACHINE_BOARD_H +/* + * VME187 CPU board constants - derived from Luna88k + */ + +/* + * Something to put append a 'U' to a long constant if it's C so that + * it'll be unsigned in both ANSI and traditional. + */ +#if defined(ASSEMBLER) +# define U(num) num +#else +# if defined(__STDC__) +# define U(num) num ## U +# else +# define U(num) num/**/U +# endif +#endif + +#define MAX_CPUS 1 /* no. of CPUs */ +#define MAX_CMMUS 2 /* 2 CMMUs - 1 data and 1 code */ + +#define SYSV_BASE U(0x00000000) /* system virtual base */ + +#define MAXU_ADDR U(0x40000000) /* size of user virtual space */ +#define MAXPHYSMEM U(0x10000000) /* max physical memory */ + +#define BUGROM_START U(0xFF800000) /* start of BUG PROM */ +#define BUGROM_SIZE U(0x003FFFFF) /* size of BUG PROM */ +#define SRAM_START U(0xFFE00000) /* start of sram used by bug */ +#define SRAM_SIZE U(0x0001FFFF) /* size of sram */ +#define OBIO_START U(0xFFF00000) /* start of local IO */ +#define OBIO_SIZE U(0x000EFFFF) /* size of obio space */ + +#define INT_PRI_LEVEL U(0xFFF4203E) /* interrupt priority level */ +#define INT_MASK_LEVEL U(0xFFF4203F) /* interrupt mask level */ + +#define LOCAL_IO_DEVS U(0xFFF00000) /* local IO devices */ +#define VMEA16 U(0xFFFF0000) /* VMEbus A16 */ + +#define PCC2_ADDR U(0xFFF42000) /* PCCchip2 Regs */ +#define MEM_CTLR U(0xFFF43000) /* MEMC040 mem controller */ +#define SCC_ADDR U(0xFFF45000) /* Cirrus Chip */ +#define LANCE_ADDR U(0xFFF46000) /* 82596CA */ +#define SCSI_ADDR U(0xFFF47000) /* NCR 710 address */ +#define NCR710_SIZE U(0x00000040) /* NCR 710 size */ +#define MK48T08_ADDR U(0xFFFC0000) /* BBRAM, TOD */ + +#define TOD_CAL_CTL U(0xFFFC1FF8) /* calendar control register */ +#define TOD_CAL_SEC U(0xFFFC1FF9) /* seconds */ +#define TOD_CAL_MIN U(0xFFFC1FFA) /* minutes */ +#define TOD_CAL_HOUR U(0xFFFC1FFB) /* hours */ +#define TOD_CAL_DOW U(0xFFFC1FFC) /* Day Of the Week */ +#define TOD_CAL_DAY U(0xFFFC1FFD) /* days */ +#define TOD_CAL_MON U(0xFFFC1FFE) /* months */ +#define TOD_CAL_YEAR U(0xFFFC1FFF) /* years */ + +#define CMMU_I U(0xFFF77000) /* CMMU instruction */ +#define CMMU_D U(0xFFF7F000) /* CMMU data */ +#define CMMU_SIZE 0x1000 + +#if 0 +/* interrupt vectors */ + +#define PPBSY 0x50 /* printer port busy */ +#define PPPE 0x51 /* printer port PE */ +#define PPSEL 0x52 /* printer port select */ +#define PPFLT 0x53 /* printer port fault */ +#define PPACK 0x54 /* printer port ack */ +#define SCSIIRQ 0x55 /* SCSI IRQ */ +#define LANCERR 0x56 /* LANC ERR */ +#define LANCIRQ 0x57 /* LANC IRQ */ +#define TIMER2IRQ 0x58 /* Tick Timer 2 vec */ +#define TIMER1IRQ 0x59 /* Tick Timer 1 vec */ +#define GPIOIRQ 0x5A /* GPIO IRQ */ +#define SRXEXIRQ 0x5C /* Serial RX Exception IRQ */ +#define SRMIRQ 0x5D /* Serial Modem IRQ */ +#define STXIRQ 0x5E /* Serial TX IRQ */ +#define SRXIRQ 0x5F /* Serial RX IRQ */ +#endif /* 0 */ + +#endif /* _MACHINE_BOARD_H */ diff --git a/sys/arch/mvme88k/include/bug.h b/sys/arch/mvme88k/include/bug.h new file mode 100644 index 00000000000..b1c3686f655 --- /dev/null +++ b/sys/arch/mvme88k/include/bug.h @@ -0,0 +1,12 @@ +#include <machine/bugio.h> + +struct bugenv { + int clun; + int dlun; + int ipl; + int ctlr; + int (*entry)(); + int cfgblk; + char *argstart; + char *argend; +}; diff --git a/sys/arch/mvme88k/include/bugio.h b/sys/arch/mvme88k/include/bugio.h new file mode 100644 index 00000000000..0bb026958dc --- /dev/null +++ b/sys/arch/mvme88k/include/bugio.h @@ -0,0 +1,80 @@ +#include "sys/cdefs.h" + +struct bugdisk_io { + char clun; + char dlun; + short status; + void *addr; + int blkno; +#define fileno blkno + short nblks; + char flag; +#define FILEMARKFLAG 0x80 +#define IGNOREFILENO 0x02 +#define ENDOFFILE 0x01 + char am; +}; + +/* values are in BCD {upper nibble+lower nibble} */ + +struct bugrtc { + unsigned char Y; + unsigned char M; + unsigned char D; + unsigned char d; + unsigned char H; + unsigned char m; + unsigned char s; + unsigned char c; +}; + +/* Board ID - lots of info */ + +struct bugbrdid { + unsigned char eye[4]; + char rev; + char month; + char day; + char year; + short packetsize; + short dummy; + short brdno; + unsigned char brdsuf[2]; + char options[3]; + char family:4; + char cpu:4; + short clun; + short dlun; + short type; + short dev; + int option; +}; + +struct bugniocall { + unsigned char clun; + unsigned char dlun; + unsigned char ci; + unsigned char cd; +#define NETCTRL_INITDEVICE 0 +#define NETCTRL_GETHDW 1 +#define NETCTRL_TX 2 +#define NETCTRL_RX 3 +#define NETCTRL_FLUSH 4 +#define NETCTRL_RESET 5 + unsigned int cid; + unsigned int memaddr; + unsigned int nbytes; + unsigned int csword; +}; + +char buginchr __P((void)); +int buginstat __P((void)); +int bugoutchr __P((unsigned char)); +int bugoutstr __P((char *, char *)); +int bugpcrlf __P((void)); +int bugdskrd __P((struct bugdisk_io *)); +int bugdskwr __P((struct bugdisk_io *)); +int bugrtcrd __P((struct bugrtc *)); +int bugreturn __P((void)); +int bugbrdid __P((struct bugbrdid *)); +int bugnetctrl __P((struct bugniocall *)); diff --git a/sys/arch/mvme88k/include/cdefs.h b/sys/arch/mvme88k/include/cdefs.h new file mode 100644 index 00000000000..36f4990a9cc --- /dev/null +++ b/sys/arch/mvme88k/include/cdefs.h @@ -0,0 +1,35 @@ +/* $NetBSD: cdefs.h,v 1.2 1995/03/23 20:10:48 jtc Exp $ */ + +/* + * Written by J.T. Conklin <jtc@wimsey.com> 01/17/95. + * Public domain. + */ + +#ifndef _MACHINE_CDEFS_H_ +#define _MACHINE_CDEFS_H_ + +#ifdef __STDC__ +#define _C_LABEL(x) _STRING(_ ## x) +#else +#define _C_LABEL(x) _STRING(_/**/x) +#endif + +#ifdef __GNUC__ +#ifdef __STDC__ +#define __indr_reference(sym,alias) \ + __asm__(".stabs \"_" #alias "\",11,0,0,0"); \ + __asm__(".stabs \"_" #sym "\",1,0,0,0") +#define __warn_references(sym,msg) \ + __asm__(".stabs \"" msg "\",30,0,0,0"); \ + __asm__(".stabs \"_" #sym "\",1,0,0,0") +#else +#define __indr_reference(sym,alias) \ + __asm__(".stabs \"_/**/alias\",11,0,0,0"); \ + __asm__(".stabs \"_/**/sym\",1,0,0,0") +#define __warn_references(sym,msg) \ + __asm__(".stabs msg,30,0,0,0"); \ + __asm__(".stabs \"_/**/sym\",1,0,0,0") +#endif +#endif + +#endif /* !_MACHINE_CDEFS_H_ */ diff --git a/sys/arch/mvme88k/include/cpu.h b/sys/arch/mvme88k/include/cpu.h new file mode 100644 index 00000000000..850b29ac35f --- /dev/null +++ b/sys/arch/mvme88k/include/cpu.h @@ -0,0 +1,156 @@ +/* + * Copyright (c) 1996 Nivas Madhur + * Copyright (c) 1992, 1993 + * The Regents of the University of California. All rights reserved. + * + * This software was developed by the Computer Systems Engineering group + * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and + * contributed to Berkeley. + * + * All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Lawrence Berkeley Laboratory. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef _CPU_H_ +#define _CPU_H_ + +/* + * CTL_MACHDEP definitinos. + */ +#define CPU_MAXID 1 /* no valid machdep ids */ + +#define CTL_MACHDEP_NAMES { \ + { 0, 0 }, \ +} + +#ifdef _KERNEL + +#include <machine/psl.h> +#include <machine/pcb.h> + +/* + * definitions of cpu-dependent requirements + * referenced in generic code + */ +#define COPY_SIGCODE /* copy sigcode above user stack in exec */ + +#define cpu_exec(p) /* nothing */ +#define cpu_wait(p) /* nothing */ +#define cpu_swapout(p) /* nothing */ + +/* + * Arguments to hardclock and gatherstats encapsulate the previous + * machine state in an opaque clockframe. CLKF_INTR is only valid + * if the process is in kernel mode. Clockframe is really trapframe, + * so pointer to clockframe can be safely cast into a pointer to + * trapframe. + */ +struct clockframe { + struct trapframe tf; +}; + +extern intstack; + +#define CLKF_USERMODE(framep) ((((struct trapframe *)(framep))->epsr & 80000000) == 0) +#define CLKF_BASEPRI(framep) (((struct trapframe *)(framep))->mask == 0) +#define CLKF_PC(framep) (((struct trapframe *)(framep))->sxip & ~3) +#define CLKF_INTR(framep) (((struct trapframe *)(framep))->r[31] > intstack) + +#define SIR_NET 1 +#define SIR_CLOCK 2 + +#define setsoftnet() (ssir |= SIR_NET) +#define setsoftclock() (ssir |= SIR_CLOCK) + +#define siroff(x) (ssir &= ~x) + +int ssir; +int want_ast; + +/* + * Preempt the current process if in interrupt from user mode, + * or after the current trap/syscall if in system mode. + */ +int want_resched; /* resched() was called */ +#define need_resched() (want_resched = 1, want_ast = 1) + +/* + * Give a profiling tick to the current process when the user profiling + * buffer pages are invalid. On the sparc, request an ast to send us + * through trap(), marking the proc as needing a profiling tick. + */ +#define need_proftick(p) ((p)->p_flag |= P_OWEUPC, want_ast = 1) + +/* + * Notify the current process (p) that it has a signal pending, + * process as soon as possible. + */ +#define signotify(p) (want_ast = 1) + +struct intrhand { + int (*ih_fn)(); + void *ih_arg; + int ih_ipl; + int ih_wantframe; + struct intrhand *ih_next; +}; + +int intr_establish __P((int vec, struct intrhand *)); + +/* + * return values for intr_establish() + */ + +#define INTR_EST_SUCC 0 +#define INTR_EST_BADVEC 1 +#define INTR_EST_BADIPL 2 + + +/* + * There are 256 possible vectors on a MVME1x7 platform (including + * onboard and VME vectors. Use intr_establish() to register a + * handler for the given vector. vector number is used to index + * into the intr_handlers[] table. + */ +extern struct intrhand *intr_handlers[256]; + +/* + * switchframe - should be double word aligned. + */ +struct switchframe { + u_int sf_pc; /* pc */ + void *sf_proc; /* proc pointer */ +}; + +#endif /* _KERNEL */ +#endif /* _CPU_H_ */ diff --git a/sys/arch/mvme88k/include/cpus.h b/sys/arch/mvme88k/include/cpus.h new file mode 100644 index 00000000000..14501d90f26 --- /dev/null +++ b/sys/arch/mvme88k/include/cpus.h @@ -0,0 +1,64 @@ +/* + * Mach Operating System + * Copyright (c) 1993-1992 Carnegie Mellon University + * All Rights Reserved. + * + * Permission to use, copy, modify and distribute this software and its + * documentation is hereby granted, provided that both the copyright + * notice and this permission notice appear in all copies of the + * software, derivative works or modified versions, and any portions + * thereof, and that both notices appear in supporting documentation. + * + * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" + * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR + * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. + * + * Carnegie Mellon requests users of this software to return to + * + * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU + * School of Computer Science + * Carnegie Mellon University + * Pittsburgh PA 15213-3890 + * + * any improvements or extensions that they make and grant Carnegie Mellon + * the rights to redistribute these changes. + */ +/* + * + * HISTORY + */ +/* + Versions Idents for 88k family chips + */ + +#ifndef _M88K_CPUS_ +#define _M88K_CPUS_ + +/* + * cpu Processor Identification Register (PID). + */ +#ifndef ASSEMBLER +union cpupid { + unsigned cpupid; + struct { + unsigned + /*empty*/:16, + arc:8, + version:7, + master:1; + } m88100; + struct { + unsigned + id:8, + type:3, + version:5, + /*empty*/:16; + } m88200; +}; +#endif ASSEMBLER + +#define M88100 0 +#define M88200 5 +#define M88204 6 + +#endif _M88K_CPUS_ diff --git a/sys/arch/mvme88k/include/db_machdep.h b/sys/arch/mvme88k/include/db_machdep.h new file mode 100644 index 00000000000..9bafbf30ddc --- /dev/null +++ b/sys/arch/mvme88k/include/db_machdep.h @@ -0,0 +1,171 @@ +/* + * Mach Operating System + * Copyright (c) 1993-1991 Carnegie Mellon University + * Copyright (c) 1991 OMRON Corporation + * All Rights Reserved. + * + * Permission to use, copy, modify and distribute this software and its + * documentation is hereby granted, provided that both the copyright + * notice and this permission notice appear in all copies of the + * software, derivative works or modified versions, and any portions + * thereof, and that both notices appear in supporting documentation. + * + * CARNEGIE MELLON AND OMRON ALLOW FREE USE OF THIS SOFTWARE IN ITS "AS IS" + * CONDITION. CARNEGIE MELLON AND OMRON DISCLAIM ANY LIABILITY OF ANY KIND + * FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. + * + * Carnegie Mellon requests users of this software to return to + * + * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU + * School of Computer Science + * Carnegie Mellon University + * Pittsburgh PA 15213-3890 + * + * any improvements or extensions that they make and grant Carnegie the + * rights to redistribute these changes. + */ +/* + * HISTORY + */ + +/* + * Machine-dependent defined for the new kernel debugger + */ + +#ifndef _M88K_DB_MACHDEP_H_ +#define _M88K_DB_MACHDEP_H_ 1 + +#include <sys/types.h> +#include <vm/vm_prot.h> +#include <vm/vm_param.h> +#include <vm/vm_inherit.h> +#include <vm/lock.h> +#include <machine/pcb.h> /* m88100_saved_state */ +#include <machine/psl.h> +#include <machine/trap.h> + +#define BKPT_SIZE (4) /* number of bytes in bkpt inst. */ +#define BKPT_INST (0xF000D082U) /* tb0, 0,r0, vector 132 */ +#define BKPT_SET(inst) (BKPT_INST) + +/* Entry trap for the debugger - used for inline assembly breaks*/ +#define ENTRY_ASM "tb0 0, r0, 132" +#define DDB_ENTRY_TRAP_NO 132 + +typedef vm_offset_t db_addr_t; +typedef int db_expr_t; +typedef struct m88100_saved_state db_regs_t; +db_regs_t ddb_regs; /* register state */ +#define DDB_REGS (&ddb_regs) + +/* + * the low two bits of sxip, snip, sfip have valid bits + * in them that need to masked to get the correct addresses + */ + +#define m88k_pc(regs) \ +({ \ + int ret; \ + \ + if (regs->sxip & 2) /* is valid */ \ + ret = regs->sxip & ~3; \ + else if (regs->snip & 2) \ + ret = regs->snip & ~3; \ + else if (regs->sfip & 2) \ + ret = regs->sfip & ~3; \ + /* we are in trouble - none of the program counters is valid */ \ + ret; \ +}) + +/* + * This is an actual function due to the fact that the sxip + * or snip could be nooped out due to a jmp or rte + */ +#define PC_REGS(regs) ((regs->sxip & 2) ? regs->sxip & ~3 : \ + (regs->snip & 2 ? regs->snip & ~3 : regs->sfip & ~3)) +#define l_PC_REGS(regs) ((regs->sxip & 2) ? regs->sxip : \ + (regs->snip & 2 ? regs->snip : regs->sfip )) + +#define pC_REGS(regs) (regs->sxip & 2) ? regs->sxip : (regs->snip & 2 ? \ + regs->snip : regs->sfip) +extern int db_noisy; +#define NOISY(x) if (db_noisy) x +#define NOISY2(x) if (db_noisy >= 2) x +#define NOISY3(x) if (db_noisy >= 3) x + +extern int quiet_db_read_bytes; + +/* These versions are not constantly doing SPL */ +#define cnmaygetc db_getc +#define cngetc db_getc +#define cnputc db_putc + +/* breakpoint/watchpoint foo */ +#define IS_BREAKPOINT_TRAP(type,code) ((type)==T_KDB_BREAK) +#if defined(T_WATCHPOINT) +#define IS_WATCHPOINT_TRAP(type,code) ((type)==T_KDB_WATCH) +#else +#define IS_WATCHPOINT_TRAP(type,code) 0 +#endif /* T_WATCHPOINT */ + +/* we don't want coff support */ +#define DB_NO_COFF 1 + +/* need software single step */ +#define SOFTWARE_SSTEP 1 /* we need this XXX nivas */ + +/* + * Debugger can get to any address space + */ + +#define DB_ACCESS_LEVEL DB_ACCESS_ANY + +#define DB_VALID_KERN_ADDR(addr) (!badaddr((void*)(addr), 1)) +#define DB_VALID_ADDRESS(addr,user) \ + (user ? db_check_user_addr(addr) : DB_VALID_KERN_ADDR(addr)) + +/* instruction type checking - others are implemented in db_sstep.c */ + +#define inst_trap_return(ins) ((ins) == 0xf400fc00U) + +/* don't need to load symbols */ +#define DB_SYMBOLS_PRELOADED 1 + +/* machine specific commands have been added to ddb */ +#define DB_MACHINE_COMMANDS 1 +/* inst_return(ins) - is the instruction a function call return. + * Not mutually exclusive with inst_branch. Should be a jmp r1. */ +#define inst_return(I) (((I)&0xfffffbffU) == 0xf400c001U ? TRUE : FALSE) + +#ifdef __GNUC__ +/* + * inst_call - function call predicate: is the instruction a function call. + * Could be either bsr or jsr + */ +#define inst_call(I) ({ unsigned i = (I); \ + ((((i) & 0xf8000000U) == 0xc8000000U || /*bsr*/ \ + ((i) & 0xfffffbe0U) == 0xf400c800U) /*jsr*/ \ + ? TRUE : FALSE) \ +;}) + +/* + * This routine should return true for instructions that result in unconditonal + * transfers of the flow of control. (Unconditional Jumps, subroutine calls, + * subroutine returns, etc). + * + * Trap and return from trap should not be listed here. + */ +#define inst_unconditional_flow_transfer(I) ({ unsigned i = (I); \ + ((((i) & 0xf0000000U) == 0xc0000000U || /* br, bsr */ \ + ((i) & 0xfffff3e0U) == 0xf400c000U) /* jmp, jsr */ \ + ? TRUE: FALSE) \ +;}) + +/* Return true if the instruction has a delay slot. */ +#define db_branch_is_delayed(I) inst_delayed(I) + +#endif /* __GNUC__ */ + +#define db_printf_enter db_printing + +#endif /* _M88K_DB_MACHDEP_H_ */ diff --git a/sys/arch/mvme88k/include/disklabel.h b/sys/arch/mvme88k/include/disklabel.h new file mode 100644 index 00000000000..493f04530d2 --- /dev/null +++ b/sys/arch/mvme88k/include/disklabel.h @@ -0,0 +1,136 @@ +/* + * Copyright (c) 1996 Nivas Madhur + * Copyright (c) 1995 Dale Rahn. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by Dale Rahn. + * 4. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef _MACHINE_DISKLABEL_H_ +#define _MACHINE_DISKLABEL_H_ + +/* number of boot pieces , ie xxboot bootxx */ +#define NUMBOOT 2 + +#define PARTITIONSHIFT 4 + +#define LABELSECTOR 0 /* sector containing label */ +#define LABELOFFSET 0 /* offset of label in sector */ +#define MAXPARTITIONS (1 << PARTITIONSHIFT) /* number of partitions */ +#define RAW_PART 2 /* raw partition: xx?c */ + +/* + * used to encode disk minor numbers + * this should probably be moved to sys/disklabel.h + */ +#define DISKUNIT(dev) (minor(dev) / MAXPARTITIONS) +#define DISKPART(dev) (minor(dev) % MAXPARTITIONS) +#define MAKEDISKDEV(maj, unit, part) \ + (makedev((maj), ((unit) * MAXPARTITIONS) + (part))) + +/* + * Note: this structure is exactly 512 bytes in size. If you move fields + * around, make sure the various members are properly aligned and the + * compiler won't do any additional padding. + */ + +struct cpu_disklabel { + /* VID */ + u_char vid_id[4]; + u_char vid_0[16]; + u_int vid_oss; + u_short vid_osl; + u_char vid_1[4]; + u_short vid_osa_u; + u_short vid_osa_l; + u_char version; + u_char vid_2[1]; + u_short checksum; /* 2 */ + u_short partitions; + u_char vid_vd[16]; + u_long bbsize; + u_long magic1; /* 4 */ + u_short type; /* 2 */ + u_short subtype; /* 2 */ + u_char packname[16]; /* 16 */ + u_long flags; /* 4 */ + u_long drivedata[5]; /* 4 */ + u_long spare[5]; /* 4 */ + + u_long secpercyl; /* 4 */ + u_long secperunit; /* 4 */ + u_long headswitch; /* 4 */ + + u_char vid_3[4]; + u_int vid_cas; + u_char vid_cal; + u_char vid_4_0[3]; + u_char vid_4[64]; + u_char vid_4_1[28]; + u_long sbsize; + u_char vid_mot[8]; + + /* CFG */ + u_char cfg_0[4]; + u_short cfg_atm; + u_short cfg_prm; + u_short cfg_atw; + u_short cfg_rec; + + u_short sparespertrack; + u_short sparespercyl; + u_long acylinders; + u_short rpm; + u_short cylskew; + + u_char cfg_spt; + u_char cfg_hds; + u_short cfg_trk; + u_char cfg_ilv; + u_char cfg_sof; + u_short cfg_psm; + u_short cfg_shd; + u_char cfg_2[2]; + u_short cfg_pcom; + u_char cfg_3; + u_char cfg_ssr; + u_short cfg_rwcc; + u_short cfg_ecc; + u_short cfg_eatm; + u_short cfg_eprm; + u_short cfg_eatw; + u_char cfg_gpb1; + u_char cfg_gpb2; + u_char cfg_gpb3; + u_char cfg_gpb4; + u_char cfg_ssc; + u_char cfg_runit; + u_short cfg_rsvc1; + u_short cfg_rsvc2; + u_long magic2; + u_char cfg_4[192]; +}; +#endif _MACHINE_DISKLABEL_H_ diff --git a/sys/arch/mvme88k/include/endian.h b/sys/arch/mvme88k/include/endian.h new file mode 100644 index 00000000000..de4a384a294 --- /dev/null +++ b/sys/arch/mvme88k/include/endian.h @@ -0,0 +1,89 @@ +/* + * Copyright (c) 1987, 1991, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * from: @(#)endian.h 8.1 (Berkeley) 6/11/93 + * $Id: endian.h,v 1.4 1997/03/03 20:20:58 rahnds Exp $ + */ + +#ifndef _ENDIAN_H_ +#define _ENDIAN_H_ + +/* + * Define the order of 32-bit words in 64-bit words. + */ +#define _QUAD_HIGHWORD 0 +#define _QUAD_LOWWORD 1 + +#ifndef _POSIX_SOURCE +/* + * Definitions for byte order, according to byte significance from low + * address to high. + */ + +#define LITTLE_ENDIAN 1234 /* LSB first: i386, vax */ +#define BIG_ENDIAN 4321 /* MSB first: 68000, 88000 ibm, net */ +#define PDP_ENDIAN 3412 /* LSB first in word, MSW first in long */ + +#define BYTE_ORDER BIG_ENDIAN + +#include <sys/cdefs.h> + +__BEGIN_DECLS +unsigned long htonl __P((unsigned long)); +unsigned short htons __P((unsigned short)); +unsigned long ntohl __P((unsigned long)); +unsigned short ntohs __P((unsigned short)); +__END_DECLS + +/* + * Macros for network/external number representation conversion. + */ +#if BYTE_ORDER == BIG_ENDIAN && !defined(lint) +#define ntohl(x) (x) +#define ntohs(x) (x) +#define htonl(x) (x) +#define htons(x) (x) + +#define NTOHL(x) (x) +#define NTOHS(x) (x) +#define HTONL(x) (x) +#define HTONS(x) (x) + +#else + +#define NTOHL(x) (x) = ntohl((u_long)x) +#define NTOHS(x) (x) = ntohs((u_short)x) +#define HTONL(x) (x) = htonl((u_long)x) +#define HTONS(x) (x) = htons((u_short)x) +#endif +#endif /* ! _POSIX_SOURCE */ +#endif /* !_ENDIAN_H_ */ diff --git a/sys/arch/mvme88k/include/exception_vectors.h b/sys/arch/mvme88k/include/exception_vectors.h new file mode 100644 index 00000000000..5a9457fccb2 --- /dev/null +++ b/sys/arch/mvme88k/include/exception_vectors.h @@ -0,0 +1,167 @@ +/* + * Mach Operating System + * Copyright (c) 1991, 1992 Carnegie Mellon University + * Copyright (c) 1991 OMRON Corporation + * All Rights Reserved. + * + * Permission to use, copy, modify and distribute this software and its + * documentation is hereby granted, provided that both the copyright + * notice and this permission notice appear in all copies of the + * software, derivative works or modified versions, and any portions + * thereof, and that both notices appear in supporting documentation. + * + * CARNEGIE MELLON AND OMRON ALLOW FREE USE OF THIS SOFTWARE IN ITS "AS IS" + * CONDITION. CARNEGIE MELLON AND OMRON DISCLAIM ANY LIABILITY OF ANY KIND + * FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. + * + * Carnegie Mellon requests users of this software to return to + * + * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU + * School of Computer Science + * Carnegie Mellon University + * Pittsburgh PA 15213-3890 + * + * any improvements or extensions that they make and grant Carnegie the + * rights to redistribute these changes. + */ + +#ifndef UNDEFINED +# define UNDEFINED unknown_handler +#endif +/* vector 0x00 (#0) */ word error_handler +/* vector 0x01 (#1) */ word interrupt_handler +/* vector 0x02 (#2) */ word instruction_access_handler +/* vector 0x03 (#3) */ word data_exception_handler +/* vector 0x04 (#4) */ word misaligned_handler +/* vector 0x05 (#5) */ word unimplemented_handler +/* vector 0x06 (#6) */ word privilege_handler +/* vector 0x07 (#7) */ word bounds_handler +/* vector 0x08 (#8) */ word divide_handler +/* vector 0x09 (#9) */ word overflow_handler +/* vector 0x0a (#10) */ word error_handler +/* vector 0x0b (#11) */ word UNDEFINED +/* vector 0x0c (#12) */ word UNDEFINED +/* vector 0x0d (#13) */ word UNDEFINED +/* vector 0x0e (#14) */ word UNDEFINED +/* vector 0x0f (#15) */ word UNDEFINED +/* vector 0x10 (#16) */ word UNDEFINED +/* vector 0x11 (#17) */ word UNDEFINED +/* vector 0x12 (#18) */ word UNDEFINED +/* vector 0x13 (#19) */ word UNDEFINED +/* vector 0x14 (#20) */ word UNDEFINED +/* vector 0x15 (#21) */ word UNDEFINED +/* vector 0x16 (#22) */ word UNDEFINED +/* vector 0x17 (#23) */ word UNDEFINED +/* vector 0x18 (#24) */ word UNDEFINED +/* vector 0x19 (#25) */ word UNDEFINED +/* vector 0x1a (#26) */ word UNDEFINED +/* vector 0x1b (#27) */ word UNDEFINED +/* vector 0x1c (#28) */ word UNDEFINED +/* vector 0x1d (#29) */ word UNDEFINED +/* vector 0x1e (#30) */ word UNDEFINED +/* vector 0x1f (#31) */ word UNDEFINED +/* vector 0x20 (#32) */ word UNDEFINED +/* vector 0x21 (#33) */ word UNDEFINED +/* vector 0x22 (#34) */ word UNDEFINED +/* vector 0x23 (#35) */ word UNDEFINED +/* vector 0x24 (#36) */ word UNDEFINED +/* vector 0x25 (#37) */ word UNDEFINED +/* vector 0x26 (#38) */ word UNDEFINED +/* vector 0x27 (#39) */ word UNDEFINED +/* vector 0x28 (#40) */ word UNDEFINED +/* vector 0x29 (#41) */ word UNDEFINED +/* vector 0x2a (#42) */ word UNDEFINED +/* vector 0x2b (#43) */ word UNDEFINED +/* vector 0x2c (#44) */ word UNDEFINED +/* vector 0x2d (#45) */ word UNDEFINED +/* vector 0x2e (#46) */ word UNDEFINED +/* vector 0x2f (#47) */ word UNDEFINED +/* vector 0x30 (#48) */ word UNDEFINED +/* vector 0x31 (#49) */ word UNDEFINED +/* vector 0x32 (#50) */ word UNDEFINED +/* vector 0x33 (#51) */ word UNDEFINED +/* vector 0x34 (#52) */ word UNDEFINED +/* vector 0x35 (#53) */ word UNDEFINED +/* vector 0x36 (#54) */ word UNDEFINED +/* vector 0x37 (#55) */ word UNDEFINED +/* vector 0x38 (#56) */ word UNDEFINED +/* vector 0x39 (#57) */ word UNDEFINED +/* vector 0x3a (#58) */ word UNDEFINED +/* vector 0x3b (#59) */ word UNDEFINED +/* vector 0x3c (#60) */ word UNDEFINED +/* vector 0x3d (#61) */ word UNDEFINED +/* vector 0x3e (#62) */ word UNDEFINED +/* vector 0x3f (#63) */ word UNDEFINED +/* vector 0x40 (#64) */ word UNDEFINED +/* vector 0x41 (#65) */ word UNDEFINED +/* vector 0x42 (#66) */ word UNDEFINED +/* vector 0x43 (#67) */ word UNDEFINED +/* vector 0x44 (#68) */ word UNDEFINED +/* vector 0x45 (#69) */ word UNDEFINED +/* vector 0x46 (#70) */ word UNDEFINED +/* vector 0x47 (#71) */ word UNDEFINED +/* vector 0x48 (#72) */ word UNDEFINED +/* vector 0x49 (#73) */ word UNDEFINED +/* vector 0x4a (#74) */ word UNDEFINED +/* vector 0x4b (#75) */ word UNDEFINED +/* vector 0x4c (#76) */ word UNDEFINED +/* vector 0x4d (#77) */ word UNDEFINED +/* vector 0x4e (#78) */ word UNDEFINED +/* vector 0x4f (#79) */ word UNDEFINED +/* vector 0x50 (#80) */ word UNDEFINED +/* vector 0x51 (#81) */ word UNDEFINED +/* vector 0x52 (#82) */ word UNDEFINED +/* vector 0x53 (#83) */ word UNDEFINED +/* vector 0x54 (#84) */ word UNDEFINED +/* vector 0x55 (#85) */ word UNDEFINED +/* vector 0x56 (#86) */ word UNDEFINED +/* vector 0x57 (#87) */ word UNDEFINED +/* vector 0x58 (#88) */ word UNDEFINED +/* vector 0x59 (#89) */ word UNDEFINED +/* vector 0x5a (#90) */ word UNDEFINED +/* vector 0x5b (#91) */ word UNDEFINED +/* vector 0x5c (#92) */ word UNDEFINED +/* vector 0x5d (#93) */ word UNDEFINED +/* vector 0x5e (#94) */ word UNDEFINED +/* vector 0x5f (#95) */ word UNDEFINED +/* vector 0x60 (#96) */ word UNDEFINED +/* vector 0x61 (#97) */ word UNDEFINED +/* vector 0x62 (#98) */ word UNDEFINED +/* vector 0x63 (#99) */ word UNDEFINED +/* vector 0x64 (#100) */ word UNDEFINED +/* vector 0x65 (#101) */ word UNDEFINED +/* vector 0x66 (#102) */ word UNDEFINED +/* vector 0x67 (#103) */ word UNDEFINED +/* vector 0x68 (#104) */ word UNDEFINED +/* vector 0x69 (#105) */ word UNDEFINED +/* vector 0x6a (#106) */ word UNDEFINED +/* vector 0x6b (#107) */ word UNDEFINED +/* vector 0x6c (#108) */ word UNDEFINED +/* vector 0x6d (#109) */ word UNDEFINED +/* vector 0x6e (#110) */ word UNDEFINED +/* vector 0x6f (#111) */ word UNDEFINED +/* vector 0x70 (#112) */ word UNDEFINED +/* vector 0x71 (#113) */ word UNDEFINED +/* vector 0x72 (#114) */ word fp_precise_handler +/* vector 0x73 (#115) */ word fp_imprecise_handler +/* vector 0x74 (#116) */ word unimplemented_handler +/* vector 0x75 (#117) */ word UNDEFINED +/* vector 0x76 (#118) */ word unimplemented_handler +/* vector 0x77 (#119) */ word UNDEFINED +/* vector 0x78 (#120) */ word unimplemented_handler +/* vector 0x79 (#121) */ word UNDEFINED +/* vector 0x7a (#122) */ word unimplemented_handler +/* vector 0x7b (#123) */ word UNDEFINED +/* vector 0x7c (#124) */ word unimplemented_handler +/* vector 0x7d (#125) */ word UNDEFINED +/* vector 0x7e (#126) */ word unimplemented_handler +/* vector 0x7f (#127) */ word UNDEFINED +/* vector 0x80 (#128) */ word _syscall_handler +/* vector 0x81 (#129) */ word _syscall_handler +/* vector 0x82 (#130) */ word break +/* vector 0x83 (#131) */ word trace +/* vector 0x84 (#132) */ word entry +#if defined(RAW_PRINTF) && RAW_PRINTF +/* vector 0x85 (#133) */ word user_raw_putstr /* for USER raw_printf() */ +/* vector 0x85 (#134) */ word user_raw_xpr /* for USER raw_xpr() */ +#endif diff --git a/sys/arch/mvme88k/include/exec.h b/sys/arch/mvme88k/include/exec.h new file mode 100644 index 00000000000..b6b1a457ed9 --- /dev/null +++ b/sys/arch/mvme88k/include/exec.h @@ -0,0 +1,23 @@ +#ifndef _MACHINE_EXEC_H_ +#define _MACHINE_EXEC_H_ + +#define __LDPGSZ 4096 + +struct relocation_info_m88k { + unsigned int r_address; /* offset in text or data segment */ + unsigned int r_symbolnum : 24, /* ordinal number of add symbol */ + r_extern : 1, /* 1 if need to add symbol to value */ + r_baserel : 1, + r_pcrel : 1, + r_jmptable : 1, + r_type : 4; + + int r_addend; +}; +#define relocation_info relocation_info_m88k + +#define _NLIST_DO_AOUT + +#define _KERN_DO_AOUT + +#endif _MACHINE_EXEC_H_ diff --git a/sys/arch/mvme88k/include/limits.h b/sys/arch/mvme88k/include/limits.h new file mode 100644 index 00000000000..7633e58d2ae --- /dev/null +++ b/sys/arch/mvme88k/include/limits.h @@ -0,0 +1,82 @@ +/* + * Copyright (c) 1988, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * from: @(#)limits.h 8.3 (Berkeley) 1/4/94 + * $Id: limits.h,v 1.3 1997/03/03 20:21:01 rahnds Exp $ + */ + +#define CHAR_BIT 8 /* number of bits in a char */ +#define MB_LEN_MAX 6 /* Allow 31 bit UTF2 */ + +/* + * According to ANSI (section 2.2.4.2), the values below must be usable by + * #if preprocessing directives. Additionally, the expression must have the + * same type as would an expression that is an object of the corresponding + * type converted according to the integral promotions. The subtraction for + * INT_MIN and LONG_MIN is so the value is not unsigned; 2147483648 is an + * unsigned int for 32-bit two's complement ANSI compilers (section 3.1.3.2). + * These numbers work for pcc as well. The UINT_MAX and ULONG_MAX values + * are written as hex so that GCC will be quiet about large integer constants. + */ +#define SCHAR_MAX 127 /* min value for a signed char */ +#define SCHAR_MIN (-128) /* max value for a signed char */ + +#define UCHAR_MAX 255 /* max value for an unsigned char */ +#define CHAR_MAX 127 /* max value for a char */ +#define CHAR_MIN (-128) /* min value for a char */ + +#define USHRT_MAX 65535 /* max value for an unsigned short */ +#define SHRT_MAX 32767 /* max value for a short */ +#define SHRT_MIN (-32768) /* min value for a short */ + +#define UINT_MAX 0xffffffff /* max value for an unsigned int */ +#define INT_MAX 2147483647 /* max value for an int */ +#define INT_MIN (-2147483647-1) /* min value for an int */ + +#define ULONG_MAX 0xffffffff /* max value for an unsigned long */ +#define LONG_MAX 2147483647 /* max value for a long */ +#define LONG_MIN (-2147483647-1) /* min value for a long */ + +#if !defined(_ANSI_SOURCE) +#define SSIZE_MAX INT_MAX /* max value for a ssize_t */ + +#if !defined(_POSIX_SOURCE) +#define SIZE_T_MAX UINT_MAX /* max value for a size_t */ + +/* GCC requires that quad constants be written as expressions. */ +#define UQUAD_MAX ((u_quad_t)0-1) /* max value for a uquad_t */ + /* max value for a quad_t */ +#define QUAD_MAX ((quad_t)(UQUAD_MAX >> 1)) +#define QUAD_MIN (-QUAD_MAX-1) /* min value for a quad_t */ + +#endif /* !_POSIX_SOURCE */ +#endif /* !_ANSI_SOURCE */ diff --git a/sys/arch/mvme88k/include/locore.h b/sys/arch/mvme88k/include/locore.h new file mode 100644 index 00000000000..fba0a9457e9 --- /dev/null +++ b/sys/arch/mvme88k/include/locore.h @@ -0,0 +1,288 @@ +/* + * Mach Operating System + * Copyright (c) 1993-1991 Carnegie Mellon University + * Copyright (c) 1991 OMRON Corporation + * All Rights Reserved. + * + * Permission to use, copy, modify and distribute this software and its + * documentation is hereby granted, provided that both the copyright + * notice and this permission notice appear in all copies of the + * software, derivative works or modified versions, and any portions + * thereof, and that both notices appear in supporting documentation. + * + * CARNEGIE MELLON AND OMRON ALLOW FREE USE OF THIS SOFTWARE IN ITS "AS IS" + * CONDITION. CARNEGIE MELLON AND OMRON DISCLAIM ANY LIABILITY OF ANY KIND + * FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. + * + * Carnegie Mellon requests users of this software to return to + * + * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU + * School of Computer Science + * Carnegie Mellon University + * Pittsburgh PA 15213-3890 + * + * any improvements or extensions that they make and grant Carnegie the + * rights to redistribute these changes. + */ +/* "locore.h" Omron Corporation + * This file created by Omron Corporation, 1990. + * NOTE: Any assembly file that includes this one must define ASSEMBLER first + */ + +#ifndef __MACHINE_LOCORE_H__ +#define __MACHINE_LOCORE_H__ + + +/* + ********************************************************************** + SYNTACTICAL AND SEMANTIC DOO-DADS + ********************************************************************** + */ +/* + * NEWLINE is defined in 'assmy.s' in the object area to be a double + * backslash, which 'as' interprets the same as '\n' + */ + +/* + * If this has been included in an assembly file, make sure + * LOCORE is defined. Always make sure KERNEL is defined. + */ +#if defined(ASSEMBLER) && !defined(LOCORE) +# define LOCORE +#endif +#if !defined(KERNEL) +# define KERNEL +#endif + +/* Define EH_DEBUG to be non-zero to compile-in various debugging things */ +#ifndef EH_DEBUG +#define EH_DEBUG 0 +#endif EH_DEBUG + +/* this gives the offsets into various structures of various elements, etc */ +#include "assym.s" + +/* + * LABEL(name) + * Defines the name to be a label visible to the world. + * + * _LABEL(name) + * Defines one visible only to the file, unless debugging + * is enabled, in which case it's visible to the world (and + * hence to debuggers, and such). + */ +#define LABEL(name) name: global name NEWLINE +#if EH_DEBUG +# define _LABEL(name) name: global name NEWLINE +#else +# define _LABEL(name) name: NEWLINE +#endif + + +/* + * Useful in some situations. + * NOTE: If ARG1 or ARG2 are r2 or r3, strange things may happen. Watch out! + */ +#define CALL(NAME, ARG1, ARG2) \ + subu r31, r31, 32 NEWLINE \ + or r2, r0, ARG1 NEWLINE \ + bsr.n NAME NEWLINE \ + or r3, r0, ARG2 NEWLINE \ + addu r31, r31, 32 + +/* + ********************************************************************** + SYMBOLIC CONSTANTS AND VALUES and other important things + ********************************************************************** + */ + +/* + * SR1 - CPU FLAGS REGISTER + * + * SR1 contains flags about the current CPU status. + * + * The lowest FLAG_CPU_FIELD_WIDTH bits hold the cpu number (currently 0-3). + * + * + * The bit FLAG_IGNORE_DATA_EXCEPTION indicates that any data exceptions + * should be ignored (well, at least treated in a special way). + * The bit FLAG_INTERRUPT_EXCEPTION indicates that the current exception + * is the interrupt exception. Such information can be gotten + * in other ways, but having it in the flags makes it easy for the + * exception handler to check quickly. + * The bit FLAG_ENABLING_FPU indicates that the exception handler is + * in the process of enabling the FPU (so that an exception can + * be serviced). This is needed because enabling the FPU can + * cause other exceptions to happen, and the whole system is + * in a rather precarious state and so special cautions must + * be taken. + */ +#define FLAG_CPU_FIELD_WIDTH 4 /* must be <= 12 */ + +#define FLAG_IGNORE_DATA_EXCEPTION 5 /* bit number 5 */ +#define FLAG_INTERRUPT_EXCEPTION 6 /* bit number 6 */ +#define FLAG_ENABLING_FPU 7 /* bit number 7 */ + + +/* REGister OFFset into the E.F. (exception frame) */ +#define REG_OFF(reg_num) ((reg_num) * 4) /* (num * sizeof(register int)) */ +#define GENREG_OFF(num) (REG_OFF(EF_R0 + (num))) /* GENeral REGister OFFset */ + + +#define GENERAL_BREATHING_ROOM /* arbitrarily */ 200 +#define KERNEL_STACK_BREATHING_ROOM \ + (GENERAL_BREATHING_ROOM + SIZEOF_STRUCT_PCB + SIZEOF_STRUCT_UTHREAD) + +/* + * Some registers used during the setting up of the new exception frame. + * Don't choose r1, r30, or r31 for any of them. + * + * Also, if any are 'r2' or 'r3', be careful using with CALL above! + */ +#define FLAGS r2 +#define TMP r3 +#define TMP2 r10 +#define TMP3 r11 +#define SAVE_TMP2 st r10, r31, GENREG_OFF(10) +#define SAVE_TMP3 st r11, r31, GENREG_OFF(11) +#define RESTORE_TMP2 ld r10, r31, GENREG_OFF(10) +#define RESTORE_TMP3 ld r11, r31, GENREG_OFF(11) + + +/* alternate CPU control register names */ +#define PID cr0 +#define PSR cr1 +#define EPSR cr2 +#define SSBR cr3 +#define SXIP cr4 +#define SNIP cr5 +#define SFIP cr6 +#define VBR cr7 +#define DMT0 cr8 +#define DMD0 cr9 +#define DMA0 cr10 +#define DMT1 cr11 +#define DMD1 cr12 +#define DMA1 cr13 +#define DMT2 cr14 +#define DMD2 cr15 +#define DMA2 cr16 +#define SR0 cr17 +#define SR1 cr18 +#define SR2 cr19 +#define SR3 cr20 +#define FPECR fcr0 +#define FPHS1 fcr1 +#define FPLS1 fcr2 +#define FPHS2 fcr3 +#define FPLS2 fcr4 +#define FPPT fcr5 +#define FPRH fcr6 +#define FPRL fcr7 +#define FPIT fcr8 +#define FPSR fcr62 +#define FPCR fcr63 + +/* + * Info about the PSR + */ +#define PSR_SHADOW_FREEZE_BIT 0 +#define PSR_INTERRUPT_DISABLE_BIT 1 +#define PSR_FPU_DISABLE_BIT 3 +#define PSR_BIG_ENDIAN_MODE 30 +#define PSR_SUPERVISOR_MODE_BIT 31 + +/* + * Status bits for an SXIP/SNIP/SFIP address. + */ +#define RTE_VALID_BIT 1 +#define RTE_ERROR_BIT 0 + +/* + * Info about DMT0/DMT1/DMT2 + */ +#define DMT_VALID_BIT 0 +#define DMT_WRITE_BIT 1 +#define DMT_LOCK_BIT 12 +#define DMT_DOUBLE_BIT 13 +#define DMT_DAS_BIT 14 +#define DMT_DREG_OFFSET 7 +#define DMT_DREG_WIDTH 5 + +/* + * Bits for eh_debug. + */ +#define DEBUG_INTERRUPT_BIT 0 +#define DEBUG_DATA_BIT 1 +#define DEBUG_INSTRUCTION_BIT 2 +#define DEBUG_MISALIGN_BIT 3 +#define DEBUG_UNIMP_BIT 4 +#define DEBUG_DIVIDE_BIT 5 +#define DEBUG_OF_BIT 6 +#define DEBUG_FPp_BIT 7 +#define DEBUG_FPi_BIT 8 +#define DEBUG_SYSCALL_BIT 9 +#define DEBUG_MACHSYSCALL_BIT 10 +#define DEBUG_UNIMPLEMENTED_BIT 11 +#define DEBUG_PRIVILEGE_BIT 12 +#define DEBUG_BOUNDS_BIT 13 +#define DEBUG_OVERFLOW_BIT 14 +#define DEBUG_ERROR_BIT 15 +#define DEBUG_SIGSYS_BIT 16 +#define DEBUG_SIGTRAP_BIT 17 +#define DEBUG_BREAK_BIT 18 +#define DEBUG_TRACE_BIT 19 +#define DEBUG_KDB_BIT 20 +#define DEBUG_JKDB_BIT 21 +#define DEBUG_BUGCALL_BIT 22 + +#define DEBUG_UNKNOWN_BIT 31 + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +#define YES 1 +#define NO 0 + +#define SCSI_INTS 0x10 +#define SCSI_SSTS 0x18 +#define SCSI_DREG 0x28 + +/* change software timer for 8mm device support -- 90/08/21 CEC OKUI */ +#define SCSI_WAIT 0x5000000 + +/* + * At various times, there is the need to clear the pipeline (i.e. + * synchronize). A "tcnd ne0, r0, foo" will do that (because a trap + * instruction always synchronizes, and this particular instruction + * will never actually take the trap). + */ +#define FLUSH_PIPELINE tcnd ne0, r0, 0 + +/* + * NOP -- NO-Operation. + * + * A do-nothing one clock doesn't-touch-the-scoreboard type of instruction, + * in case one's needed (sometimes useful for debugging). + */ +#define NOP or r0, r0, r0 + +/* + * These things for vector_init.c and locore.c + */ +#if defined(ASSEMBLER) +# define PREDEFINED_BY_ROM 0xffffffff +# define END_OF_VECTOR_LIST 0xfffffffe +#else +# define PREDEFINED_BY_ROM 0xffffffffU +# define END_OF_VECTOR_LIST 0xfffffffeU +#endif + +/* + * Define ERROR__XXX_USR if the xxx.usr bug (mask C82N) is present. + * This implements the workaround. + */ +#define ERRATA__XXX_USR 1 + +#define USERMODE(x) (!(x & (1 << PSR_SUPERVISOR_MODE_BIT))) + +#endif /* __MACHINE_LOCORE_H__ */ diff --git a/sys/arch/mvme88k/include/m88100.h b/sys/arch/mvme88k/include/m88100.h new file mode 100644 index 00000000000..eb047bb08e0 --- /dev/null +++ b/sys/arch/mvme88k/include/m88100.h @@ -0,0 +1,69 @@ +/* + * Mach Operating System + * Copyright (c) 1993-1992 Carnegie Mellon University + * All Rights Reserved. + * + * Permission to use, copy, modify and distribute this software and its + * documentation is hereby granted, provided that both the copyright + * notice and this permission notice appear in all copies of the + * software, derivative works or modified versions, and any portions + * thereof, and that both notices appear in supporting documentation. + * + * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" + * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR + * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. + * + * Carnegie Mellon requests users of this software to return to + * + * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU + * School of Computer Science + * Carnegie Mellon University + * Pittsburgh PA 15213-3890 + * + * any improvements or extensions that they make and grant Carnegie Mellon + * the rights to redistribute these changes. + */ +/* + * HISTORY + */ +/* + * M88100 flags + */ + +#ifndef _M88100_H_ +#define _M88100_H_ + + +/* + * 88100 RISC definitions + */ + +/* DMT0, DMT1, DMT2 */ +#define DMT_BO 0x00008000 /* Byte-Ordering */ +#define DMT_DAS 0x00004000 /* Data Access Space */ +#define DMT_DOUB1 0x00002000 /* Double Word */ +#define DMT_LOCKBAR 0x00001000 /* Bud Lock */ +#define DMT_DREG 0x00000F80 /* Destination Registers 5bits */ +#define DMT_SIGNED 0x00000040 /* Sign-Extended Bit */ +#define DMT_EN 0x0000003C /* Byte Enable Bit */ +#define DMT_WRITE 0x00000002 /* Read/Write Transaction Bit */ +#define DMT_VALID 0x00000001 /* Valid Transaction Bit */ + +#ifndef ASSEMBLER +#include "sys/types.h" + +struct dmt_reg { + unsigned int :16, + dmt_bo:1, + dmt_das:1, + dmt_doub1:1, + dmt_lockbar:1, + dmt_dreg:5, + dmt_signed:1, + dmt_en:4, + dmt_write:1, + dmt_valid:1; +}; +#endif + +#endif _M88100_H_ diff --git a/sys/arch/mvme88k/include/m882xx.h b/sys/arch/mvme88k/include/m882xx.h new file mode 100644 index 00000000000..4c9759db1bc --- /dev/null +++ b/sys/arch/mvme88k/include/m882xx.h @@ -0,0 +1,259 @@ +/* + * Mach Operating System + * Copyright (c) 1993-1992 Carnegie Mellon University + * All Rights Reserved. + * + * Permission to use, copy, modify and distribute this software and its + * documentation is hereby granted, provided that both the copyright + * notice and this permission notice appear in all copies of the + * software, derivative works or modified versions, and any portions + * thereof, and that both notices appear in supporting documentation. + * + * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" + * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR + * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. + * + * Carnegie Mellon requests users of this software to return to + * + * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU + * School of Computer Science + * Carnegie Mellon University + * Pittsburgh PA 15213-3890 + * + * any improvements or extensions that they make and grant Carnegie Mellon + * the rights to redistribute these changes. + */ +/* + * HISTORY + * + */ + + +#ifndef __MACHINE_M882XX_H__ +#define __MACHINE_M882XX_H__ + +#ifndef ASSEMBLER +# include <machine/mmu.h> /* batc_template_t */ +#endif + +#include <machine/board.h> + +/* + * 88200 CMMU definitions + */ +#define CMMU_IDR 0x000 /* CMMU id register */ +#define CMMU_SCR 0x004 /* system command register */ +#define CMMU_SSR 0x008 /* system status register */ +#define CMMU_SAR 0x00C /* system address register */ +#define CMMU_SCTR 0x104 /* system control register */ +#define CMMU_PFSR 0x108 /* P bus fault status register */ +#define CMMU_PFAR 0x10C /* P bus fault address register */ +#define CMMU_SAPR 0x200 /* supervisor area pointer register */ +#define CMMU_UAPR 0x204 /* user area pointer register */ +#define CMMU_BWP0 0x400 /* block ATC writer port 0 */ +#define CMMU_BWP1 0x404 /* block ATC writer port 1 */ +#define CMMU_BWP2 0x408 /* block ATC writer port 2 */ +#define CMMU_BWP3 0x40C /* block ATC writer port 3 */ +#define CMMU_BWP4 0x410 /* block ATC writer port 4 */ +#define CMMU_BWP5 0x414 /* block ATC writer port 5 */ +#define CMMU_BWP6 0x418 /* block ATC writer port 6 */ +#define CMMU_BWP7 0x41C /* block ATC writer port 7 */ +#define CMMU_CDP0 0x800 /* cache data port 0 */ +#define CMMU_CDP1 0x804 /* cache data port 1 */ +#define CMMU_CDP2 0x808 /* cache data port 2 */ +#define CMMU_CDP3 0x80C /* cache data port 3 */ +#define CMMU_CTP0 0x840 /* cache tag port 0 */ +#define CMMU_CTP1 0x844 /* cache tag port 1 */ +#define CMMU_CTP2 0x848 /* cache tag port 2 */ +#define CMMU_CTP3 0x84C /* cache tag port 3 */ +#define CMMU_CSSP 0x880 /* cache set status register */ + +/* 88204 CMMU definitions */ +#define CMMU_CSSP0 0x880 /* cache set status register */ +#define CMMU_CSSP1 0x890 /* cache set status register */ +#define CMMU_CSSP2 0x8A0 /* cache set status register */ +#define CMMU_CSSP3 0x8B0 /* cache set status register */ + +/* CMMU systerm commands */ +#define CMMU_FLUSH_USER_LINE 0x30 /* flush PATC */ +#define CMMU_FLUSH_USER_PAGE 0x31 +#define CMMU_FLUSH_USER_SEGMENT 0x32 +#define CMMU_FLUSH_USER_ALL 0x33 +#define CMMU_FLUSH_SUPER_LINE 0x34 +#define CMMU_FLUSH_SUPER_PAGE 0x35 +#define CMMU_FLUSH_SUPER_SEGMENT 0x36 +#define CMMU_FLUSH_SUPER_ALL 0x37 +#define CMMU_PROBE_USER 0x20 /* probe user address */ +#define CMMU_PROBE_SUPER 0x24 /* probe supervisor address */ +#define CMMU_FLUSH_CACHE_INV_LINE 0x14 /* data cache invalidate */ +#define CMMU_FLUSH_CACHE_INV_PAGE 0x15 +#define CMMU_FLUSH_CACHE_INV_SEGMENT 0x16 +#define CMMU_FLUSH_CACHE_INV_ALL 0x17 +#define CMMU_FLUSH_CACHE_CB_LINE 0x18 /* data cache copyback */ +#define CMMU_FLUSH_CACHE_CB_PAGE 0x19 +#define CMMU_FLUSH_CACHE_CB_SEGMENT 0x1A +#define CMMU_FLUSH_CACHE_CB_ALL 0x1B +#define CMMU_FLUSH_CACHE_CBI_LINE 0x1C /* copyback and invalidate */ +#define CMMU_FLUSH_CACHE_CBI_PAGE 0x1D +#define CMMU_FLUSH_CACHE_CBI_SEGMENT 0x1E +#define CMMU_FLUSH_CACHE_CBI_ALL 0x1F + +/* CMMU system control command */ +#define CMMU_SCTR_PE 0x00008000 /* parity enable */ +#define CMMU_SCTR_SE 0x00004000 /* snoop enable */ +#define CMMU_SCTR_PR 0x00002000 /* priority arbitration */ + +/* CMMU P bus fault status */ +#define CMMU_PFSR_SUCCESS 0 /* no fault */ +#define CMMU_PFSR_BERROR 3 /* bus error */ +#define CMMU_PFSR_SFAULT 4 /* segment fault */ +#define CMMU_PFSR_PFAULT 5 /* page fault */ +#define CMMU_PFSR_SUPER 6 /* supervisor violation */ +#define CMMU_PFSR_WRITE 7 /* writer violation */ + +/* Area Description */ +#define AREA_D_WT 0x00000200 /* write through */ +#define AREA_D_G 0x00000080 /* global */ +#define AREA_D_CI 0x00000040 /* cache inhibit */ +#define AREA_D_TE 0x00000001 /* translation enable */ + +/* Segment Description */ +#define SEG_D_WT 0x00000200 /* write through */ +#define SEG_D_SP 0x00000100 /* supervisor protection */ +#define SEG_D_G 0x00000080 /* global */ +#define SEG_D_CI 0x00000040 /* cache inhibit */ +#define SEG_D_WP 0x00000004 /* write protect */ +#define SEG_D_V 0x00000001 /* valid */ + +/* + * Flags for cmmu_flush_tlb + */ +#define FLUSH_KERNEL 1 +#define FLUSH_USER 0 +#define FLUSH_ALL ((vm_offset_t)~0) + + +#ifndef ASSEMBLER +/* + * This file defines the data structures for the mmu. + * One major data structure, the page descriptor, is not defined here + * but rather in pte.h as struct pte. + */ + +struct area_d { /* area descriptor */ + unsigned + ad_addr:20, /* segment table base address */ + : 2, + ad_wt : 1, /* write through */ + : 1, + ad_g : 1, /* global */ + ad_ci : 1, /* cache inhibit */ + : 5, + ad_te : 1; /* translation enable */ +}; + +struct segment_d { /* segment descriptor */ + unsigned + sd_addr:20, /* page table base address */ + : 2, + sd_wt : 1, /* write through */ + sd_sp : 1, /* supervisor protection */ + sd_g : 1, /* global */ + sd_ci : 1, /* cache inhibit */ + : 3, + sd_wp : 1, /* write protect */ + : 1, + sd_v : 1; /* valid */ +}; + +typedef struct segment_d segment_d_t; + +struct pfsr { /* P bus fault status register */ + unsigned + :13, + pfsr_fc: 3, /* falut code */ + :16; +}; + +struct batc { /* block address translation register */ + unsigned + batc_lba:13, /* logical block address */ + batc_pba:13, /* physical block address */ + batc_s : 1, /* supervisor */ + batc_wt : 4, /* write through */ + batc_g : 1, /* global */ + batc_ci : 1, /* cache inhibit */ + batc_wp : 1, /* write protect */ + batc_v : 1; /* valid */ +}; + +/* + * Prototypes and stuff for cmmu.c. + */ +extern unsigned cpu_sets[MAX_CPUS]; +extern unsigned ncpus; +extern unsigned cache_policy; + +#ifdef CMMU_DEBUG + void show_apr(unsigned value); + void show_sctr(unsigned value); +#endif + +/* + * Prototypes from "motorola/m88k/m88100/cmmu.c" + */ +unsigned cmmu_cpu_number(void); +#if !DDB +static +#endif /* !DDB */ +unsigned cmmu_remote_get(unsigned cpu, unsigned r, unsigned data); +unsigned cmmu_get_idr(unsigned data); +void cmmu_init(void); +void cmmu_shutdown_now(void); +void cmmu_parity_enable(void); +#if !DDB +static +#endif /* !DDB */ +void cmmu_remote_set(unsigned cpu, unsigned r, unsigned data, unsigned x); +void cmmu_set_sapr(unsigned ap); +void cmmu_remote_set_sapr(unsigned cpu, unsigned ap); +void cmmu_set_uapr(unsigned ap); +void cmmu_flush_tlb(unsigned kernel, vm_offset_t vaddr, int size); +void cmmu_flush_remote_cache(int cpu, vm_offset_t physaddr, int size); +void cmmu_flush_cache(vm_offset_t physaddr, int size); +void cmmu_flush_remote_inst_cache(int cpu, vm_offset_t physaddr, int size); +void cmmu_flush_inst_cache(vm_offset_t physaddr, int size); +void cmmu_flush_remote_data_cache(int cpu, vm_offset_t physaddr, int size); +void cmmu_flush_data_cache(vm_offset_t physaddr, int size); + +void cmmu_pmap_activate( + unsigned cpu, + unsigned uapr, + batc_template_t i_batc[BATC_MAX], + batc_template_t d_batc[BATC_MAX]); + +void cmmu_flush_remote_tlb( + unsigned cpu, + unsigned kernel, + vm_offset_t vaddr, + int size); + +void cmmu_set_batc_entry( + unsigned cpu, + unsigned entry_no, + unsigned data, /* 1 = data, 0 = instruction */ + unsigned value); /* the value to stuff into the batc */ + +void cmmu_set_pair_batc_entry( + unsigned cpu, + unsigned entry_no, + unsigned value); /* the value to stuff into the batc */ + +#endif /* ASSEMBLER */ + +#define INST_CMMU 0 +#define DATA_CMMU 1 + +#define NBSG (4*1024*1024) /* segment size */ + +#endif /* __MACHINE_M882XX_H__ */ diff --git a/sys/arch/mvme88k/include/mmu.h b/sys/arch/mvme88k/include/mmu.h new file mode 100644 index 00000000000..b172c595e6e --- /dev/null +++ b/sys/arch/mvme88k/include/mmu.h @@ -0,0 +1,312 @@ +/* + * Ashura Project + */ +/* + * HISTORY + * + * Original SCCS ID in ISEDL + * @(#)mmu.h 1.22 90/09/20 19:13:34 + */ + +#ifndef _MACHINE_MMU_ +#define _MACHINE_MMU_ + +/* for m88k_pgbytes, m8kk_pgshift */ +#include <machine/vmparam.h> + + +/* + * Parameters which determine the 'geometry' of the M88K page tables in memory. + */ +#define SDT_BITS 10 /* M88K segment table size bits */ +#define PDT_BITS 10 /* M88K page table size bits */ +#define PG_BITS M88K_PGSHIFT /* M88K hardware page size bits */ + +/* + * Shifts and masks for M88K (hardware) page + */ +/* M88K_PGBYTES, PG_SHIFT in vm_param.h */ +#define M88K_PGOFSET (M88K_PGBYTES-1) /* offset into M88K page */ +#define M88K_PGMASK (~M88K_PGOFSET) /* page mask */ + +/* + * Convert byte address to page frame number + */ +#define M88K_BTOP(x) (((unsigned) (x)) >> M88K_PGSHIFT) +#define M88K_PTOB(x) (((unsigned) (x)) << M88K_PGSHIFT) + +/* + * Round off or truncate to the nearest page. These will work for + * either addresses of counts. (i.e. 1 byte round to 1 page bytes). + */ +#define M88K_TRUNC_PAGE(x) (((unsigned) (x) & M88K_PGMASK)) +#define M88K_ROUND_PAGE(x) M88K_TRUNC_PAGE((x) + M88K_PGOFSET) + +/* + * M88K area descriptors + */ +typedef struct cmmu_apr { + unsigned long + st_base:20, /* segment table base address */ + rsvA:2, /* reserved */ + wt:1, /* writethrough (cache control) */ + rsvB:1, /* reserved */ + g:1, /* global (cache control) */ + ci:1, /* cache inhibit */ + rsvC:5, /* reserved */ + te:1; /* transration enable */ +} cmmu_apr_t; + +typedef union apr_template { + cmmu_apr_t field; + unsigned long bits; +} apr_template_t; + +/* + * M88K segment descriptors + */ +typedef struct sdt_entry { + unsigned long + table_addr:20, /* page table base address */ + rsvA:2, /* reserved */ + wt:1, /* writethrough (cache control) */ + sup:1, /* supervisor protection */ + g:1, /* global (cache control) */ + no_cache:1, /* cache inhibit */ + rsvB:3, /* reserved */ + prot:1, /* write protect */ + rsvC:1, /* reserved */ + dtype:1; /* valid */ +} sdt_entry_t; + +typedef union sdt_entry_template { + sdt_entry_t sdt_desc; + unsigned long bits; +} sdt_entry_template_t; + +#define SDT_ENTRY_NULL ((sdt_entry_t *) 0) + +/* + * M88K page descriptors + */ +typedef struct pt_entry { + unsigned long + pfn:20, /* page frame address */ + rsvA:1, /* reserved */ + wired:1, /* wired bit <<software>> */ + wt:1, /* writethrough (cache control) */ + sup:1, /* supervisor protection */ + g:1, /* global (cache control) */ + ci:1, /* cache inhibit */ + rsvB:1, /* reserved */ + modified:1, /* modified */ + pg_used:1, /* used (referenced) */ + prot:1, /* write protect */ + rsvC:1, /* reserved */ + dtype:1; /* valid */ +} pt_entry_t; + +typedef union pte_template { + pt_entry_t pte; + unsigned long bits; +} pte_template_t; + +#define PT_ENTRY_NULL ((pt_entry_t *) 0) + +/* + * 88200 PATC (TLB) + */ + +#define PATC_ENTRIES 56 + +/* + * M88K BATC entries + */ +typedef struct { + unsigned long + lba:13, /* logical block address */ + pba:13, /* physical block address */ + sup:1, /* supervisor mode bit */ + wt:1, /* writethrough (cache control) */ + g:1, /* global (cache control) */ + ci:1, /* cache inhibit */ + wp:1, /* write protect */ + v:1; /* valid */ +} batc_entry_t; + +typedef union batc_template { + batc_entry_t field; + unsigned long bits; +} batc_template_t; + +/* + * Parameters and macros for BATC + */ +#define BATC_BLKBYTES (512*1024) /* 'block' size of a BATC entry mapping */ +#define BATC_BLKSHIFT 19 /* number of bits to BATC shift (log2(BATC_BLKBYTES)) */ +#define BATC_BLKMASK (BATC_BLKBYTES-1) /* BATC block mask */ + +#define BATC_MAX 8 /* number of BATC entries */ + +#define BATC_BLK_ALIGNED(x) ((x & BATC_BLKMASK) == 0) + +#define M88K_BTOBLK(x) (x >> BATC_BLKSHIFT) + +/* + * protection codes (prot field) + */ +#define M88K_RO 1 /* read only */ +#define M88K_RW 0 /* read/write */ + +/* + * protection codes (sup field) + */ +#define M88K_SUPV 1 /* translation can only be done in supervisor mode */ +#define M88K_USER 0 /* translation can be done supv. or user mode */ + +/* + * descriptor types + */ +#define DT_INVALID 0 +#define DT_VALID 1 + +/* + * Number of entries in a page table. + */ +#define SDT_ENTRIES (1<<(SDT_BITS)) +#define PDT_ENTRIES (1<<(PDT_BITS)) + +/* + * Size in bytes of a single page table. + */ +#define SDT_SIZE (sizeof(sdt_entry_t) * SDT_ENTRIES) +#define PDT_SIZE (sizeof(pt_entry_t) * PDT_ENTRIES) + +/* + * Shifts and masks + */ +#define SDT_SHIFT (PDT_BITS + PG_BITS) +#define PDT_SHIFT (PG_BITS) + +#define SDT_MASK (((1<<SDT_BITS)-1) << SDT_SHIFT) +#define PDT_MASK (((1<<PDT_BITS)-1) << PDT_SHIFT) + +#define SDT_NEXT(va) ((va + (1<<SDT_SHIFT)) & SDT_MASK) +#define PDT_NEXT(va) ((va + (1<<PDT_SHIFT)) & (SDT_MASK|PDT_MASK)) + +#define SDTIDX(va) ((va & SDT_MASK) >> SDT_SHIFT) +#define PDTIDX(va) ((va & PDT_MASK) >> PDT_SHIFT) + +#define SDTENT(map, va) ((sdt_entry_t *)(map->sdt_vaddr + SDTIDX(va))) + +/* + * Size of a PDT table group. + */ +#define LOG2_PDT_SIZE (PDT_BITS + 2) +#define LOG2_PDT_TABLE_GROUP_SIZE (PAGE_SHIFT - LOG2_PDT_SIZE) +#define PDT_TABLE_GROUP_SIZE (1 << LOG2_PDT_TABLE_GROUP_SIZE) +#define PT_FREE(tbl) kmem_free(kernel_map, (vm_offset_t)tbl, PAGE_SIZE) + +/* + * Va spaces mapped by tables and PDT table group. + */ +#define PDT_VA_SPACE (PDT_ENTRIES * M88K_PGBYTES) +#define PDT_TABLE_GROUP_VA_SPACE (PDT_VA_SPACE * PDT_TABLE_GROUP_SIZE) + +/* + * Number of sdt entries used to map user and kernel space. + */ +#define USER_SDT_ENTRIES SDTIDX(VM_MIN_KERNEL_ADDRESS) +#define KERNEL_SDT_ENTRIES (SDT_ENTRIES - USER_SDT_ENTRIES) + +/* + * Macros to check if the descriptor is valid. + */ +#define SDT_VALID(sd_ptr) ((sd_ptr)->dtype == DT_VALID) +#define PDT_VALID(pd_ptr) ((pd_ptr)->dtype == DT_VALID) + +/* + * Alignment checks for pages (must lie on page boundaries). + */ +#define PAGE_ALIGNED(ad) (((vm_offset_t)(ad) & ~M88K_PGMASK) == 0) +#define CHECK_PAGE_ALIGN(ad,who) \ + if (!PAGE_ALIGNED(ad)) \ + printf("%s: addr %x not page aligned.\n", who, ad) + +/* + * Validate PTE's for all hardware pages in a VM page. + * "ptes_per_vm_page" should be set in pmap_bootstrap. + * + * PARAMETERS: + * pt_entry_t *start; + * unsigned long template; + */ +#define DO_PTES(start, template) \ +{ \ + int i_; \ + pt_entry_t *p_ = start; \ + \ + for (i_ = ptes_per_vm_page; i_>0; i_--) { \ + *(int *)p_++ = (unsigned long)(template); \ + template += M88K_PGBYTES; \ + /* (unsigned long)(template) for m88k C compiler\ + '90.7.24 Fuzzy */ \ + } \ +} + +/* + * Flags for cmmu_store() <cmmu.s> + */ +#define STORE_CMD 0 +#define STORE_UAPR 4 +#define STORE_SAPR 8 +#define STORE_BATCWP 0x400 + +#define C_CMMU 0 +#define D_CMMU 0x1000 + +/* + * Parameters for ATC(TLB) fulsh + */ + +#define CMMU_SCR 0x004 + +#define FLUSH_SUP_ALL 0x37 +#define FLUSH_USR_ALL 0x33 +#define FLUSH_SUP_SEG 0x36 +#define FLUSH_USR_SEG 0x32 +#define FLUSH_SUP_PG 0x35 +#define FLUSH_USR_PG 0x31 + +/* + * Cache coontrol bits for pte + */ +#define CACHE_DFL 0 +#define CACHE_INH 0x40 +#define CACHE_GLOBAL 0x80 +#define CACHE_WT 0x200 + +#define CACHE_MASK (~(unsigned)(CACHE_INH | CACHE_GLOBAL | CACHE_WT)) + +/* + * Prototype for invalidate_pte found in "motorola/m88k/m88100/misc.s" + */ +unsigned invalidate_pte(pt_entry_t *pointer); + +extern vm_offset_t kmapva; + +#define kvtopte(va) \ +({ \ + sdt_entry_t *sdt; \ + sdt = (sdt_entry_t *)kmapva + SDTIDX(va) + SDT_ENTRIES; \ + (pte_template_t *)(sdt->table_addr << PDT_SHIFT) + PDTIDX(va); \ +}) + + +#define DMA_CACHE_SYNC 0x1 +#define DMA_CACHE_SYNC_INVAL 0x2 +#define DMA_CACHE_INV 0x3 +extern void dma_cachectl(vm_offset_t, int, int); + +#endif +/* endif _MACHINE_MMU_ */ diff --git a/sys/arch/mvme88k/include/param.h b/sys/arch/mvme88k/include/param.h new file mode 100644 index 00000000000..f5ef4835d9b --- /dev/null +++ b/sys/arch/mvme88k/include/param.h @@ -0,0 +1,167 @@ +/* + * Copyright (c) 1988 University of Utah. + * Copyright (c) 1982, 1986, 1990 The Regents of the University of California. + * All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * the Systems Programming Group of the University of Utah Computer + * Science Department. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * from: Utah $Hdr: machparam.h 1.11 89/08/14$ + * + * @(#)param.h 7.8 (Berkeley) 6/28/91 + * $Id: param.h,v 1.5 1997/03/03 20:21:06 rahnds Exp $ + */ +#ifndef _MACHINE_PARAM_H_ +#define _MACHINE_PARAM_H_ + +#define MACHINE "m88k" +#define MACHINE_ARCH "m88k" +#define MID_MACHINE MID_M88K + +/* + * Round p (pointer or byte index) up to a correctly-aligned value + * for all data types (int, long, ...). The result is u_int and + * must be cast to any desired pointer type. ALIGN() is used for + * aligning stack, which needs to be on a double word boundary for + * 88k. + */ +#define ALIGNBYTES (sizeof(int) - 1) +#define ALIGN(p) (((u_int)(p) + (sizeof(double) - 1)) & ~(sizeof(double) - 1)) + +#ifndef NBPG +#define NBPG 4096 /* bytes/page */ +#endif /* NBPG */ +#define PGOFSET (NBPG-1) /* byte offset into page */ +#define PGSHIFT 12 /* LOG2(NBPG) */ +#define NPTEPG (NBPG/(sizeof(u_int))) + +#define NBSEG (1<<22) /* bytes/segment */ +#define SEGOFSET (NBSEG-1) /* byte offset into segment */ +#define SEGSHIFT 22 /* LOG2(NBSEG) */ + +/* + * 187 Bug uses the bottom 64k. We allocate ptes to map this into the + * kernel. But when we link the kernel, we tell it to start linking + * past this 64k. How does this change KERNBASE? XXX + */ + +#define KERNBASE 0x0 /* start of kernel virtual */ +#define BTOPKERNBASE ((u_long)KERNBASE >> PGSHIFT) + +#define DEV_BSIZE 512 +#define DEV_BSHIFT 9 /* log2(DEV_BSIZE) */ +#define BLKDEV_IOSIZE 2048 /* Should this be changed? XXX */ +#define MAXPHYS (64 * 1024) /* max raw I/O transfer size */ + +#define CLSIZE 1 +#define CLSIZELOG2 0 + +/* NOTE: SSIZE, SINCR and UPAGES must be multiples of CLSIZE */ +#define SSIZE 1 /* initial stack size/NBPG */ +#define SINCR 1 /* increment of stack/NBPG */ +#define USPACE ctob(UPAGES) + +#define UPAGES 3 /* pages of u-area */ +#define UADDR 0xEEE00000 /* address of u */ +#define UVPN (UADDR>>PGSHIFT)/* virtual page number of u */ +#define KERNELSTACK (UADDR+UPAGES*NBPG) /* top of kernel stack */ + +#define PHYSIO_MAP_START 0xEEF00000 +#define PHYSIO_MAP_SIZE 0x00100000 +#define IOMAP_MAP_START 0xEF000000 /* VME etc */ +#define IOMAP_SIZE 0x018F0000 +#define NIOPMAP 32 + +/* + * Constants related to network buffer management. + * MCLBYTES must be no larger than CLBYTES (the software page size), and, + * on machines that exchange pages of input or output buffers with mbuf + * clusters (MAPPED_MBUFS), MCLBYTES must also be an integral multiple + * of the hardware page size. + */ +#define MSIZE 128 /* size of an mbuf */ +#define MCLBYTES 1024 +#define MCLSHIFT 10 +#define MCLOFSET (MCLBYTES - 1) +#ifndef NMBCLUSTERS +#ifdef GATEWAY +#define NMBCLUSTERS 512 /* map size, max cluster allocation */ +#else +#define NMBCLUSTERS 256 /* map size, max cluster allocation */ +#endif +#endif + +/* + * Size of kernel malloc arena in CLBYTES-sized logical pages + */ +#ifndef NKMEMCLUSTERS +#define NKMEMCLUSTERS (3072*1024/CLBYTES) +#endif + +/* pages ("clicks") to disk blocks */ +#define ctod(x) ((x)<<(PGSHIFT-DEV_BSHIFT)) +#define dtoc(x) ((x)>>(PGSHIFT-DEV_BSHIFT)) +#define dtob(x) ((x)<<DEV_BSHIFT) + +/* pages to bytes */ +#define ctob(x) ((x)<<PGSHIFT) + +/* bytes to pages */ +#define btoc(x) (((unsigned)(x)+(NBPG-1))>>PGSHIFT) + +#define btodb(bytes) /* calculates (bytes / DEV_BSIZE) */ \ + ((unsigned)(bytes) >> DEV_BSHIFT) +#define dbtob(db) /* calculates (db * DEV_BSIZE) */ \ + ((unsigned)(db) << DEV_BSHIFT) + +/* + * Map a ``block device block'' to a file system block. + * This should be device dependent, and should use the bsize + * field from the disk label. + * For now though just use DEV_BSIZE. + */ +#define bdbtofsb(bn) ((bn) / (BLKDEV_IOSIZE/DEV_BSIZE)) +#include <machine/psl.h> + +#ifdef _KERNEL +#define DELAY(x) delay(x) +#endif + +#ifdef _KERNEL +extern int cputyp; +extern int cpumod; +#endif +/* + * Values for the cputyp variable. + */ +#define CPU_187 0x187 +#endif /* !_MACHINE_PARAM_H_ */ diff --git a/sys/arch/mvme88k/include/pcb.h b/sys/arch/mvme88k/include/pcb.h new file mode 100644 index 00000000000..65437b1718a --- /dev/null +++ b/sys/arch/mvme88k/include/pcb.h @@ -0,0 +1,152 @@ +/* + * Copyright (c) 1996 Nivas Madhur + * Mach Operating System + * Copyright (c) 1993-1992 Carnegie Mellon University + * All Rights Reserved. + * + * Permission to use, copy, modify and distribute this software and its + * documentation is hereby granted, provided that both the copyright + * notice and this permission notice appear in all copies of the + * software, derivative works or modified versions, and any portions + * thereof, and that both notices appear in supporting documentation. + * + * CARNEGIE MELLON AND OMRON ALLOW FREE USE OF THIS SOFTWARE IN ITS "AS IS" + * CONDITION. CARNEGIE MELLON AND OMRON DISCLAIM ANY LIABILITY OF ANY KIND + * FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. + * + * Carnegie Mellon requests users of this software to return to + * + * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU + * School of Computer Science + * Carnegie Mellon University + * Pittsburgh PA 15213-3890 + * + * any improvements or extensions that they make and grant Carnegie Mellon + * the rights to redistribute these changes. + */ +/* + * Motorola 88100 pcb definitions + * + */ +/* + */ +#ifndef _PCB_H_ +#define _PCB_H_ + +/* + * Our PCB is the regular PCB+Save area for kernel frame. + * Upon entering kernel mode from user land, save the user context + * in the saved_state area - this is passed as the exception frame. + * On a context switch, only registers that need to be saved by the + * C calling convention and few other regs (pc, psr etc) are saved + * in the kernel_state part of the PCB. Typically, trap fames are + * save on the stack (by low level handlers or by hardware) but, + * we just decided to do it in the PCB. + */ + +/* + * This must always be an even number of words long so that our stack + * will always be properly aligned (88k need 8 byte alignmet). Also, + * place r14 on double word boundary so that we can use st.d while + * saving the regs. + */ + +struct m88100_pcb { + unsigned pcb_pc; /* address to return */ + unsigned pcb_ipl; + unsigned pcb_r14; + unsigned pcb_r15; + unsigned pcb_r16; + unsigned pcb_r17; + unsigned pcb_r18; + unsigned pcb_r19; + unsigned pcb_r20; + unsigned pcb_r21; + unsigned pcb_r22; + unsigned pcb_r23; + unsigned pcb_r24; + unsigned pcb_r25; + unsigned pcb_r26; + unsigned pcb_r27; + unsigned pcb_r28; + unsigned pcb_r29; + unsigned pcb_r30; + unsigned pcb_sp; /* kernel stack pointer */ +}; + + +/* + * m88100_saved_state this structure corresponds to the state + * of the user registers as saved on the + * stack upon kernel entry. This structure + * is used internally only. Since this + * structure may change from version to + * version, it is hidden from the user. + */ + +/* This must always be an even number of words long */ + +struct m88100_saved_state { + unsigned r[32]; + unsigned fpsr; + unsigned fpcr; + unsigned epsr; + unsigned sxip; + unsigned snip; + unsigned sfip; + unsigned ssbr; + unsigned dmt0; + unsigned dmd0; + unsigned dma0; + unsigned dmt1; + unsigned dmd1; + unsigned dma1; + unsigned dmt2; + unsigned dmd2; + unsigned dma2; + unsigned fpecr; + unsigned fphs1; + unsigned fpls1; + unsigned fphs2; + unsigned fpls2; + unsigned fppt; + unsigned fprh; + unsigned fprl; + unsigned fpit; + unsigned vector; /* exception vector number */ + unsigned mask; /* interrupt mask level */ + unsigned mode; /* interrupt mode */ + unsigned scratch1; /* used by locore trap handling code */ + unsigned ipfsr; /* P BUS status - used in inst fault handling */ + unsigned dpfsr; /* P BUS status - used in data fault handling */ + unsigned pad; /* alignment */ +}; + +#define trapframe m88100_saved_state + +struct pcb +{ + struct m88100_pcb kernel_state; + struct m88100_saved_state user_state; + int pcb_onfault; /* for copyin/copyout faults */ + int pcb_pad; /* pad it XXX */ +}; + +typedef struct pcb *pcb_t; /* exported */ + +/* + * Location of saved user registers for the proc. + */ +#define USER_REGS(p) \ + (((struct m88100_saved_state *) (&((p)->p_addr->u_pcb.user_state)))) +/* + * The pcb is augmented with machine-dependent additional data for + * core dumps. Note that the trapframe here is a copy of the one + * from the top of the kernel stack (included here so that the kernel + * stack itself need not be dumped). + */ +struct md_coredump { + struct trapframe md_tf; +}; + +#endif _PCB_H_ diff --git a/sys/arch/mvme88k/include/pcctworeg.h b/sys/arch/mvme88k/include/pcctworeg.h new file mode 100644 index 00000000000..eecc7d47479 --- /dev/null +++ b/sys/arch/mvme88k/include/pcctworeg.h @@ -0,0 +1,146 @@ +/* $NetBSD$ */ + +/* + * Copyright (c) 1995 Theo de Raadt + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by Theo de Raadt + * 4. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/* + * MVME1x7/16x PCC2 chip: sort of a confused mish-mash of the MC in the 162 + * and the PCC in the 147 + */ +struct pcctworeg { + volatile u_char pcc2_chipid; + volatile u_char pcc2_chiprev; + volatile u_char pcc2_genctl; + volatile u_char pcc2_vecbase; /* irq vector base */ + volatile u_long pcc2_t1cmp; /* timer1 compare */ + volatile u_long pcc2_t1count; /* timer1 count */ + volatile u_long pcc2_t2cmp; /* timer2 compare */ + volatile u_long pcc2_t2count; /* timer2 count */ + volatile u_char pcc2_pscalecnt; /* timer prescaler counter */ + volatile u_char pcc2_pscaleadj; /* timer prescaler adjust */ + volatile u_char pcc2_t2ctl; /* timer2 ctrl reg */ + volatile u_char pcc2_t1ctl; /* timer1 ctrl reg */ + volatile u_char pcc2_gpioirq; /* gpio irq */ + volatile u_char pcc2_gpio; /* gpio i/o */ + volatile u_char pcc2_t2irq; + volatile u_char pcc2_t1irq; + volatile u_char pcc2_sccerr; + volatile u_char pcc2_sccirq; + volatile u_char pcc2_scctx; + volatile u_char pcc2_sccrx; + volatile u_char :8; + volatile u_char :8; + volatile u_char :8; + volatile u_char pcc2_sccmoiack; + volatile u_char :8; + volatile u_char pcc2_scctxiack; + volatile u_char :8; + volatile u_char pcc2_sccrxiack; + volatile u_char pcc2_ieerr; + volatile u_char :8; + volatile u_char pcc2_iectl; + volatile u_char pcc2_ieirq; + volatile u_char pcc2_ncrerr; + volatile u_char :8; + volatile u_char :8; + volatile u_char pcc2_ncrirq; + volatile u_char pcc2_prtairq; + volatile u_char pcc2_prtfirq; + volatile u_char pcc2_prtsirq; + volatile u_char pcc2_prtpirq; + volatile u_char pcc2_prtbirq; + volatile u_char :8; + volatile u_char pcc2_prtstat; + volatile u_char pcc2_prtctl; + volatile u_short pcc2_speed; /* DO NOT USE */ + volatile u_short pcc2_prtdat; + volatile u_short :16; + volatile u_char pcc2_ipl; + volatile u_char pcc2_mask; +}; +#define PCC2_PCC2CHIP_ADDR 0xFFF42000 +#define PCC2_PCC2CHIP_OFF 0x42000 +#define PCC2_CHIPID 0x20 + +/* + * points to system's PCCTWO. This is not active until the pcctwo0 + * device has been attached. After that, it gives the virtual address + * at which the PCCTWO can be accessed. + */ +extern struct pcctworeg *sys_pcc2; + +/* + * We lock off our interrupt vector at 0x50. + */ +#define PCC2_VECBASE 0x50 +#define PCC2_NVEC 12 + +/* + * Vectors we use + */ +#define PCC2V_NCR 0x05 +#define PCC2V_IE_ERR 0x06 +#define PCC2V_IE 0x07 +#define PCC2V_TIMER2 0x08 +#define PCC2V_TIMER1 0x09 +#define PCC2V_GPIO 0x0A + +#define PCC2_TCTL_CEN 0x01 +#define PCC2_TCTL_COC 0x02 +#define PCC2_TCTL_COVF 0x04 +#define PCC2_TCTL_OVF 0xf0 + +#define PCC2_GPIO_PLTY 0x80 +#define PCC2_GPIO_EL 0x40 + +#define PCC2_GPIOCR_OE 0x2 +#define PCC2_GPIOCR_O 0x1 + +#define PCC2_SCC_AVEC 0x08 +#define PCC2_SCCRX_INHIBIT (0 << 6) +#define PCC2_SCCRX_SNOOP (1 << 6) +#define PCC2_SCCRX_INVAL (2 << 6) +#define PCC2_SCCRX_RESV (3 << 6) + +#define pcc2_timer_us2lim(us) (us) /* timer increments in "us" */ + +#define PCC2_IRQ_IPL 0x07 +#define PCC2_IRQ_ICLR 0x08 +#define PCC2_IRQ_IEN 0x10 +#define PCC2_IRQ_INT 0x20 + +#define PCC2_GENCTL_FAST 0x01 +#define PCC2_GENCTL_IEN 0x02 +#define PCC2_GENCTL_C040 0x03 + +#define PCC2_SC_INHIBIT (0 << 6) +#define PCC2_SC_SNOOP (1 << 6) +#define PCC2_SC_INVAL (2 << 6) +#define PCC2_SC_RESV (3 << 6) diff --git a/sys/arch/mvme88k/include/pmap.h b/sys/arch/mvme88k/include/pmap.h new file mode 100644 index 00000000000..ef1fd3b7e33 --- /dev/null +++ b/sys/arch/mvme88k/include/pmap.h @@ -0,0 +1,167 @@ +/* + * Mach Operating System + * Copyright (c) 1991 Carnegie Mellon University + * Copyright (c) 1991 OMRON Corporation + * All Rights Reserved. + * + * Permission to use, copy, modify and distribute this software and its + * documentation is hereby granted, provided that both the copyright + * notice and this permission notice appear in all copies of the + * software, derivative works or modified versions, and any portions + * thereof, and that both notices appear in supporting documentation. + * + */ +#ifndef _MACHINE_PMAP_H_ +#define _MACHINE_PMAP_H_ +#define OMRON_PMAP + +#include <machine/psl.h> /* get standard goodies */ +#include <vm/vm_param.h> +#include <vm/vm_prot.h> /* vm_prot_t */ +#include <machine/mmu.h> /* batc_template_t, BATC_MAX, etc.*/ +#include <machine/pcb.h> /* pcb_t, etc.*/ + +typedef struct sdt_entry *sdt_ptr_t; + +/* + * PMAP structure + */ +typedef struct pmap *pmap_t; + +struct pmap { + sdt_ptr_t sdt_paddr; /* physical pointer to sdt */ + sdt_ptr_t sdt_vaddr; /* virtual pointer to sdt */ + int ref_count; /* reference count */ + + struct pmap_statistics stats; /* pmap statistics */ + +#ifdef DEBUG + pmap_t next; + pmap_t prev; +#endif + + /* for OMRON_PMAP */ + batc_template_t i_batc[BATC_MAX]; /* instruction BATCs */ + batc_template_t d_batc[BATC_MAX]; /* data BATCs */ + /* end OMRON_PMAP */ + +}; + +#include <vm/vm.h> + +#define PMAP_NULL ((pmap_t) 0) + +extern pmap_t kernel_pmap; + +#define PMAP_ACTIVATE(pmap, th, my_cpu) _pmap_activate(pmap, th, my_cpu) +#define PMAP_DEACTIVATE(pmap, th, my_cpu) _pmap_deactivate(pmap, th, my_cpu) + +#define PMAP_CONTEXT(pmap, thread) + +#define pmap_resident_count(pmap) ((pmap)->stats.resident_count) + +/* Used in builtin/device_pager.c */ +#define pmap_phys_address(frame) ((vm_offset_t) (M88K_PTOB(frame))) + +/* Used in kern/mach_timedev.c */ +#define pmap_phys_to_frame(phys) ((int) (M88K_BTOP(phys))) + +/* + * Since Our PCB has no infomation about the mapping, + * we have nothing to do in PMAP_PCB_INITIALIZE. + * XXX + */ +/* Used in machine/pcb.c */ +#define PMAP_PCB_INITIALIZE(x) + +/* + * Modes used when calling pmap_cache_fulsh(). + */ +#define FLUSH_CACHE 0 +#define FLUSH_CODE_CACHE 1 +#define FLUSH_DATA_CACHE 2 +#define FLUSH_LOCAL_CACHE 3 +#define FLUSH_LOCAL_CODE_CACHE 4 +#define FLUSH_LOCAL_DATA_CACHE 5 + +/**************************************************************************/ +/*** Prototypes for public functions defined in pmap.c ********************/ +/**************************************************************************/ + +void _pmap_activate(pmap_t pmap, pcb_t, int my_cpu); +void _pmap_deactivate(pmap_t pmap, pcb_t, int my_cpu); +void pmap_activate(pmap_t my_pmap, pcb_t); +void pmap_deactivate(pmap_t pmap, pcb_t); +int pmap_check_transaction(pmap_t pmap, vm_offset_t va, vm_prot_t type); + +vm_offset_t pmap_map_batc( + vm_offset_t virt, + vm_offset_t start, + vm_offset_t end, + vm_prot_t prot, + unsigned cmode); + +#ifdef JUNK +int pmap_attribute( + pmap_t pmap, + vm_offset_t address, + vm_size_t size, + vm_machine_attribute_t attribute, + vm_machine_attribute_val_t* value); /* IN/OUT */ +#endif /* JUNK */ + +void pmap_bootstrap( + vm_offset_t load_start, /* IN */ + vm_offset_t *phys_start, /* IN/OUT */ + vm_offset_t *phys_end, /* IN */ + vm_offset_t *virt_start, /* OUT */ + vm_offset_t *virt_end); /* OUT */ + +pt_entry_t *pmap_pte(pmap_t map, vm_offset_t virt); +void pmap_cache_ctrl(pmap_t pmap, vm_offset_t s, vm_offset_t e, unsigned mode); +void pmap_zero_page(vm_offset_t phys); +void pmap_remove_all(vm_offset_t phys); +vm_offset_t pmap_extract_unlocked(pmap_t pmap, vm_offset_t va); +pmap_t pmap_kernel(void); +void copy_to_phys(vm_offset_t srcva, vm_offset_t dstpa, int bytecount); +void copy_from_phys(vm_offset_t srcpa, vm_offset_t dstva, int bytecount); +void pmap_redzone(pmap_t pmap, vm_offset_t va); +boolean_t pmap_verify_free(vm_offset_t phys); +boolean_t pmap_valid_page(vm_offset_t p); +void icache_flush(vm_offset_t pa); +void pmap_dcache_flush(pmap_t pmap, vm_offset_t va); +void pmap_cache_flush(pmap_t pmap, vm_offset_t virt, int bytes, int mode); +void pmap_print (pmap_t pmap); +void pmap_print_trace (pmap_t pmap, vm_offset_t va, boolean_t long_format); + +#if 0 +#ifdef OMRON_PMAP + void pmap_set_batc( + pmap_t pmap, + boolean_t data, + int i, + vm_offset_t va, + vm_offset_t pa, + boolean_t super, + boolean_t wt, + boolean_t global, + boolean_t ci, + boolean_t wp, + boolean_t valid); + + void use_batc( + task_t task, + boolean_t data, /* for data-cmmu ? */ + int i, /* batc number */ + vm_offset_t va, /* virtual address */ + vm_offset_t pa, /* physical address */ + boolean_t s, /* for super-mode ? */ + boolean_t wt, /* is writethrough */ + boolean_t g, /* is global ? */ + boolean_t ci, /* is cache inhibited ? */ + boolean_t wp, /* is write-protected ? */ + boolean_t v); /* is valid ? */ +#endif +#endif /* 0 */ + +#endif /* endif _MACHINE_PMAP_H_ */ diff --git a/sys/arch/mvme88k/include/pmap_table.h b/sys/arch/mvme88k/include/pmap_table.h new file mode 100644 index 00000000000..555789144ac --- /dev/null +++ b/sys/arch/mvme88k/include/pmap_table.h @@ -0,0 +1,44 @@ +/* + * Mach Operating System + * Copyright (c) 1992 Carnegie Mellon University + * All Rights Reserved. + * + * Permission to use, copy, modify and distribute this software and its + * documentation is hereby granted, provided that both the copyright + * notice and this permission notice appear in all copies of the + * software, derivative works or modified versions, and any portions + * thereof, and that both notices appear in supporting documentation. + * + * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" + * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR + * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. + * + * Carnegie Mellon requests users of this software to return to + * + * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU + * School of Computer Science + * Carnegie Mellon University + * Pittsburgh PA 15213-3890 + * + * any improvements or extensions that they make and grant Carnegie Mellon + * the rights to redistribute these changes. + */ + +/* + * HISTORY + */ + + +/* an entry is considered invalid if pm_size = 0 */ +/* end of list is indicated by pm_size 0xffffffff */ + +typedef struct { + vm_offset_t phys_start; /* in bytes */ + vm_offset_t virt_start; /* in bytes */ + unsigned int size; /* in bytes */ + unsigned int prot; /* vm_prot_read, vm_prot_write */ + unsigned int cacheability; /* none, writeback, normal */ +} pmap_table_entry; + +typedef pmap_table_entry *pmap_table_t; + diff --git a/sys/arch/mvme88k/include/proc.h b/sys/arch/mvme88k/include/proc.h new file mode 100644 index 00000000000..a58ed3cee42 --- /dev/null +++ b/sys/arch/mvme88k/include/proc.h @@ -0,0 +1,58 @@ +/* + * Copyright (c) 1992, 1993 + * The Regents of the University of California. All rights reserved. + * + * This software was developed by the Computer Systems Engineering group + * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and + * contributed to Berkeley. + * + * All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Lawrence Berkeley Laboratory. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)proc.h 8.1 (Berkeley) 6/11/93 + * + * from: Header: proc.h,v 1.6 92/11/26 02:04:41 torek Exp (LBL) + * $Id: proc.h,v 1.3 1997/03/03 20:21:10 rahnds Exp $ + */ + +#include <machine/pcb.h> +#include <machine/mmu.h> + +/* + * Machine-dependent part of the proc structure for VME1X7. + */ +struct mdproc { + struct trapframe *md_tf; /* trap/syscall registers */ + struct fpstate *md_fpstate; /* fpu state, if any; always resident */ + int md_upte[UPAGES]; /* ptes for mapping u page */ +}; diff --git a/sys/arch/mvme88k/include/profile.h b/sys/arch/mvme88k/include/profile.h new file mode 100644 index 00000000000..84dd1e1d80e --- /dev/null +++ b/sys/arch/mvme88k/include/profile.h @@ -0,0 +1,73 @@ +/* + * Copyright (c) 1996 Nivas Madhur + * Copyright (c) 1992, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * from: @(#)profile.h 8.1 (Berkeley) 6/11/93 + * $Id: profile.h,v 1.5 1997/03/03 20:21:11 rahnds Exp $ + */ + +#define _MCOUNT_DECL static inline void _mcount + +#define MCOUNT \ +extern void mcount() asm("mcount"); \ +void \ +mcount() \ +{ \ + int selfret; \ + register int callerret; \ + /* \ + * find the return address for mcount, \ + * and the return address for mcount's caller. \ + * \ + * selfret = ret pushed by mcount call \ + */ \ + asm volatile("st r1,%0" : "=m" (selfret)); \ + /* \ + * callerret = ret pushed by call into self. \ + */ \ + /* \ + * This may not be right. It all depends on where the \ + * caller stores the return address. XXX \ + */ \ + asm volatile("addu r10,r31,48"); \ + asm volatile("ld %0,r10,36" : "=r" (callerret)); \ + _mcount(callerret, selfret); \ +} + +#ifdef KERNEL +/* + * Note that we assume splhigh() and splx() cannot call mcount() + * recursively. + */ +#define MCOUNT_ENTER s = splhigh() +#define MCOUNT_EXIT splx(s) +#endif /* KERNEL */ diff --git a/sys/arch/mvme88k/include/psl.h b/sys/arch/mvme88k/include/psl.h new file mode 100644 index 00000000000..9205c933d00 --- /dev/null +++ b/sys/arch/mvme88k/include/psl.h @@ -0,0 +1,168 @@ +/* + * Copyright (c) 1996 Nivas Madhur + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by Nivas Madhur. + * 4. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ +/* + * Mach Operating System + * Copyright (c) 1991 Carnegie Mellon University + * Copyright (c) 1991 OMRON Corporation + * All Rights Reserved. + * + * Permission to use, copy, modify and distribute this software and its + * documentation is hereby granted, provided that both the copyright + * notice and this permission notice appear in all copies of the + * software, derivative works or modified versions, and any portions + * thereof, and that both notices appear in supporting documentation. + * + */ +#ifndef __M88K_M88100_PSL_H__ +#define __M88K_M88100_PSL_H__ + +/* needs major cleanup - XXX nivas */ + +#if 0 +spl0 is a function by itself. I really am serious about the clean up +above... +#define spl0() spln(0) +#endif /* 0 */ +#define spl1() setipl(1) +#define spl2() setipl(2) +#define spl3() setipl(3) +#define spl4() setipl(4) +#define spl5() setipl(5) +#define spl6() setipl(6) +#define spl7() setipl(7) + +/* + * IPL levels. + * We use 6 as IPL_HIGH so that abort can be programmed at 7 so that + * it is always possible to break into the system unless interrupts + * are disabled. + */ + +#define IPL_NONE 0 +#define IPL_SOFTCLOCK 1 +#define IPL_SOFTNET 1 +#define IPL_BIO 2 +#define IPL_NET 3 +#define IPL_TTY 3 +#define IPL_CLOCK 5 +#define IPL_STATCLOCK 5 +#define IPL_IMP 6 +#define IPL_VM 6 +#define IPL_HIGH 6 +#define IPL_SCHED 6 +#define IPL_NMI 7 +#define IPL_ABORT 7 + +#define splnone spl0 +#define splsoftclock() setipl(IPL_SOFTCLOCK) +#define splsoftnet() setipl(IPL_SOFTNET) +#define splbio() setipl(IPL_BIO) +#define splnet() setipl(IPL_NET) +#define spltty() setipl(IPL_TTY) +#define splclock() setipl(IPL_CLOCK) +#define splstatclock() setipl(IPL_STATCLOCK) +#define splimp() setipl(IPL_IMP) +#define splvm() setipl(IPL_VM) +#define splhigh() setipl(IPL_HIGH) +#define splsched() setipl(IPL_SCHED) + +#define splx(x) ((x) ? setipl((x)) : spl0()) + +/* + * 88100 control registers + */ + +/* + * processor identification register (PID) + */ +#define PID_ARN 0x0000FF00U /* architectural revision number */ +#define PID_VN 0x000000FEU /* version number */ +#define PID_MC 0x00000001U /* master/checker */ + +/* + * processor status register + */ +#define PSR_MODE 0x80000000U /* supervisor/user mode */ +#define PSR_BO 0x40000000U /* byte-ordering 0:big 1:little */ +#define PSR_SER 0x20000000U /* serial mode */ +#define PSR_C 0x10000000U /* carry */ +#define PSR_SFD 0x000003F0U /* SFU disable */ +#define PSR_SFD1 0x00000008U /* SFU1 (FPU) disable */ +#define PSR_MXM 0x00000004U /* misaligned access enable */ +#define PSR_IND 0x00000002U /* interrupt disable */ +#define PSR_SFRZ 0x00000001U /* shadow freeze */ + +/* + * This is used in ext_int() and hard_clock(). + */ +#define PSR_IPL 0x00001000 /* for basepri */ +#define PSR_IPL_LOG 12 /* = log2(PSR_IPL) */ + +#define PSR_MODE_LOG 31 /* = log2(PSR_MODE) */ +#define PSR_BO_LOG 30 /* = log2(PSR_BO) */ +#define PSR_SER_LOG 29 /* = log2(PSR_SER) */ +#define PSR_SFD1_LOG 3 /* = log2(PSR_SFD1) */ +#define PSR_MXM_LOG 2 /* = log2(PSR_MXM) */ +#define PSR_IND_LOG 1 /* = log2(PSR_IND) */ +#define PSR_SFRZ_LOG 0 /* = log2(PSR_SFRZ) */ + +#define PSR_SUPERVISOR (PSR_MODE | PSR_SFD) +#define PSR_USER (PSR_SFD) +#define PSR_SET_BY_USER (PSR_BO | PSR_SER | PSR_C | PSR_MXM) + +#ifndef ASSEMBLER +struct psr { + unsigned + psr_mode: 1, + psr_bo : 1, + psr_ser : 1, + psr_c : 1, + :18, + psr_sfd : 6, + psr_sfd1: 1, + psr_mxm : 1, + psr_ind : 1, + psr_sfrz: 1; +}; +#endif + +#define FIP_V 0x00000002U /* valid */ +#define FIP_E 0x00000001U /* exception */ +#define FIP_ADDR 0xFFFFFFFCU /* address mask */ +#define NIP_V 0x00000002U /* valid */ +#define NIP_E 0x00000001U /* exception */ +#define NIP_ADDR 0xFFFFFFFCU /* address mask */ +#define XIP_V 0x00000002U /* valid */ +#define XIP_E 0x00000001U /* exception */ +#define XIP_ADDR 0xFFFFFFFCU /* address mask */ + +#endif /* __M88K_M88100_PSL_H__ */ + diff --git a/sys/arch/mvme88k/include/ptrace.h b/sys/arch/mvme88k/include/ptrace.h new file mode 100644 index 00000000000..ff20fff9a60 --- /dev/null +++ b/sys/arch/mvme88k/include/ptrace.h @@ -0,0 +1,54 @@ +/* + * Copyright (c) 1992, 1993 + * The Regents of the University of California. All rights reserved. + * + * This software was developed by the Computer Systems Engineering group + * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and + * contributed to Berkeley. + * + * All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Lawrence Berkeley Laboratory. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)ptrace.h 8.1 (Berkeley) 6/11/93 + * + * from: Header: ptrace.h,v 1.6 92/11/26 02:04:43 torek Exp (LBL) + * $Id: ptrace.h,v 1.3 1997/03/03 20:21:13 rahnds Exp $ + */ + +/* + * m88k-dependent ptrace definitions. + */ +#define PT_GETREGS (PT_FIRSTMACH + 0) +#define PT_SETREGS (PT_FIRSTMACH + 1) +#define PT_GETFPREGS (PT_FIRSTMACH + 2) +#define PT_SETFPREGS (PT_FIRSTMACH + 3) diff --git a/sys/arch/mvme88k/include/reg.h b/sys/arch/mvme88k/include/reg.h new file mode 100644 index 00000000000..3d5034c5fda --- /dev/null +++ b/sys/arch/mvme88k/include/reg.h @@ -0,0 +1,77 @@ +/* + * Copyright (c) 1996 Nivas Madhur + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by Nivas Madhur. + * 4. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ +#include <machine/pcb.h> + +struct reg { + unsigned r_r[32]; + unsigned r_fpsr; + unsigned r_fpcr; + unsigned r_epsr; + unsigned r_sxip; + unsigned r_snip; + unsigned r_sfip; + unsigned r_ssbr; + unsigned r_dmt0; + unsigned r_dmd0; + unsigned r_dma0; + unsigned r_dmt1; + unsigned r_dmd1; + unsigned r_dma1; + unsigned r_dmt2; + unsigned r_dmd2; + unsigned r_dma2; + unsigned r_fpecr; + unsigned r_fphs1; + unsigned r_fpls1; + unsigned r_fphs2; + unsigned r_fpls2; + unsigned r_fppt; + unsigned r_fprh; + unsigned r_fprl; + unsigned r_fpit; + unsigned r_vector; /* exception vector number */ + unsigned r_mask; /* interrupt mask level */ + unsigned r_mode; /* interrupt mode */ + unsigned r_scratch1; /* used by locore trap handling code */ + unsigned r_pad; /* to make an even length */ +} ; + +struct fpreg { + unsigned fp_fpecr; + unsigned fp_fphs1; + unsigned fp_fpls1; + unsigned fp_fphs2; + unsigned fp_fpls2; + unsigned fp_fppt; + unsigned fp_fprh; + unsigned fp_fprl; + unsigned fp_fpit; +}; diff --git a/sys/arch/mvme88k/include/setjmp.h b/sys/arch/mvme88k/include/setjmp.h new file mode 100644 index 00000000000..ac2959d3b3e --- /dev/null +++ b/sys/arch/mvme88k/include/setjmp.h @@ -0,0 +1,7 @@ +/* $NetBSD: setjmp.h,v 1.1 1994/12/20 10:37:10 cgd Exp $ */ + +/* + * machine/setjmp.h: machine dependent setjmp-related information. + */ + +#define _JBLEN 22 /* size, in longs, of a jmp_buf */ diff --git a/sys/arch/mvme88k/include/signal.h b/sys/arch/mvme88k/include/signal.h new file mode 100644 index 00000000000..82152bb26b8 --- /dev/null +++ b/sys/arch/mvme88k/include/signal.h @@ -0,0 +1,74 @@ +/* + * Copyright (c) 1996 Nivas Madhur + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by Nivas Madhur. + * 4. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ +typedef int sig_atomic_t; + +/* + * Information pushed on stack when a signal is delivered. + * This is used by the kernel to restore state following + * execution of the signal handler. It is also made available + * to the handler to allow it to restore state properly if + * a non-standard exit is performed. + * + * All machines must have an sc_onstack and sc_mask. + */ +struct sigcontext { + int sc_onstack; /* sigstack state to restore */ + int sc_mask; /* signal mask to restore */ + /* begin machine dependent portion */ + int sc_regs[32]; +#define sc_sp sc_regs[31] + int sc_xip; + int sc_nip; + int sc_fip; + int sc_ps; + int sc_fpsr; + int sc_fpcr; + int sc_ssbr; + int sc_dmt0; + int sc_dmd0; + int sc_dma0; + int sc_dmt1; + int sc_dmd1; + int sc_dma1; + int sc_dmt2; + int sc_dmd2; + int sc_dma2; + int sc_fpecr; + int sc_fphs1; + int sc_fpls1; + int sc_fphs2; + int sc_fpls2; + int sc_fppt; + int sc_fprh; + int sc_fprl; + int sc_fpit; + int sc_xxxx; /* padd to double word boundary */ +}; diff --git a/sys/arch/mvme88k/include/stdarg.h b/sys/arch/mvme88k/include/stdarg.h new file mode 100644 index 00000000000..7b1ff19b6ec --- /dev/null +++ b/sys/arch/mvme88k/include/stdarg.h @@ -0,0 +1,177 @@ +/* This file has local changes by MOTOROLA +Thu Sep 9 09:06:29 CDT 1993 Dale Rahn (drahn@pacific) + * (gstdarg.h, gvarargs.h) C-Front requires all builtins to + be defined. This is to insert these definitions if + __cplusplus is defined but not using the G++ compiler. + */ +/* stdarg.h for GNU. + Note that the type used in va_arg is supposed to match the + actual type **after default promotions**. + Thus, va_arg (..., short) is not valid. */ + +#ifndef _STDARG_H +#ifndef _ANSI_STDARG_H_ +#ifndef __need___va_list +#define _STDARG_H +#define _ANSI_STDARG_H_ +#endif /* not __need___va_list */ +#undef __need___va_list + +#ifndef __GNUC__ +/* Use the system's macros with the system's compiler. + This is relevant only when building GCC with some other compiler. */ +#include <stdarg.h> +#else +#ifdef __clipper__ +#include <va-clipper.h> +#else +#ifdef __m88k__ +#include <machine/va-m88k.h> +#else +#ifdef __i860__ +#include <va-i860.h> +#else +#ifdef __hppa__ +#include <va-pa.h> +#else +#ifdef __mips__ +#include <va-mips.h> +#else +#ifdef __sparc__ +#include <va-sparc.h> +#else +#ifdef __i960__ +#include <va-i960.h> +#else +#ifdef __alpha__ +#include <va-alpha.h> +#else + +/* Define __gnuc_va_list. */ + +#ifndef __GNUC_VA_LIST +#define __GNUC_VA_LIST +#if defined(__svr4__) || defined(_AIX) || defined(_M_UNIX) +typedef char *__gnuc_va_list; +#else +typedef void *__gnuc_va_list; +#endif +#endif + +/* Define the standard macros for the user, + if this invocation was from the user program. */ +#ifdef _STDARG_H + +/* Amount of space required in an argument list for an arg of type TYPE. + TYPE may alternatively be an expression whose type is used. */ + +#define __va_rounded_size(TYPE) \ + (((sizeof (TYPE) + sizeof (int) - 1) / sizeof (int)) * sizeof (int)) + +#define va_start(AP, LASTARG) \ + (AP = ((__gnuc_va_list) __builtin_next_arg ())) + +#undef va_end +void va_end (__gnuc_va_list); /* Defined in libgcc.a */ +#define va_end(AP) + +/* We cast to void * and then to TYPE * because this avoids + a warning about increasing the alignment requirement. */ + +#if defined (__arm__) || defined (__i386__) || defined (__ns32000__) || defined (__vax__) +/* This is for little-endian machines; small args are padded upward. */ +#define va_arg(AP, TYPE) \ + (AP = (__gnuc_va_list) ((char *) (AP) + __va_rounded_size (TYPE)), \ + *((TYPE *) (void *) ((char *) (AP) - __va_rounded_size (TYPE)))) +#else /* big-endian */ +/* This is for big-endian machines; small args are padded downward. */ +#define va_arg(AP, TYPE) \ + (AP = (__gnuc_va_list) ((char *) (AP) + __va_rounded_size (TYPE)), \ + *((TYPE *) (void *) ((char *) (AP) - ((sizeof (TYPE) < 4 \ + ? sizeof (TYPE) \ + : __va_rounded_size (TYPE)))))) +#endif /* big-endian */ +#endif /* _STDARG_H */ + +#endif /* not alpha */ +#endif /* not i960 */ +#endif /* not sparc */ +#endif /* not mips */ +#endif /* not hppa */ +#endif /* not i860 */ +#endif /* not m88k */ +#endif /* not clipper */ + +#ifdef _STDARG_H +/* Define va_list, if desired, from __gnuc_va_list. */ +/* We deliberately do not define va_list when called from + stdio.h, because ANSI C says that stdio.h is not supposed to define + va_list. stdio.h needs to have access to that data type, + but must not use that name. It should use the name __gnuc_va_list, + which is safe because it is reserved for the implementation. */ + +#ifdef _HIDDEN_VA_LIST /* On OSF1, this means varargs.h is "half-loaded". */ +#undef _VA_LIST +#endif + +#ifdef _BSD_VA_LIST_ +#undef _BSD_VA_LIST_ +#define _BSD_VA_LIST_ __gnuc_va_list +#endif /* _BSD_VA_LIST_ */ + +#ifdef __svr4__ +/* SVR4.2 uses _VA_LIST for an internal alias for va_list, + so we must avoid testing it and setting it here. + SVR4 uses _VA_LIST as a flag in stdarg.h, but we should + have no conflict with that. */ +#ifndef _VA_LIST_ +#define _VA_LIST_ +#ifdef __i860__ +#ifndef _VA_LIST +#define _VA_LIST va_list +#endif +#endif /* __i860__ */ +typedef __gnuc_va_list va_list; +#endif /* _VA_LIST_ */ +#else /* not __svr4__ */ + +/* The macro _VA_LIST_ is the same thing used by this file in Ultrix. + But on BSD NET2 we must not test or define or undef it. + (Note that the comments in NET 2's ansi.h + are incorrect for _VA_LIST_--see stdio.h!) */ +#if !defined (_VA_LIST_) || defined (__BSD_NET2__) || defined (____386BSD____) +/* The macro _VA_LIST is used in SCO Unix 3.2. */ +#ifndef _VA_LIST +/* The macro _VA_LIST_T_H is used in the Bull dpx2 */ +#ifndef _VA_LIST_T_H +#define _VA_LIST_T_H +#if !(defined (__BSD_NET2__) || defined (____386BSD____)) +#define _VA_LIST_ +#endif +#define _VA_LIST +typedef __gnuc_va_list va_list; +#endif /* not _VA_LIST_T_H */ +#endif /* not _VA_LIST */ +#endif /* not _VA_LIST_ */ + +#endif /* not __svr4__ */ + +#if defined(__cplusplus) && !defined(__GNUG__) + +/* This is added to work with AT&T C++. */ +extern "C" { + char *__builtin_next_arg(void); + __gnuc_va_list *__builtin_saveregs(void); + void *__builtin_saveregs2(int); + int *__builtin_argptr(void); + int __builtin_argsize(void); + int __builtin_classify_type(...); + int __alignof__(...); +} +#endif + +#endif /* _STDARG_H */ + +#endif /* __GNUC__ */ +#endif /* not _ANSI_STDARG_H_ */ +#endif /* not _STDARG_H */ diff --git a/sys/arch/mvme88k/include/trap.h b/sys/arch/mvme88k/include/trap.h new file mode 100644 index 00000000000..df565c086ce --- /dev/null +++ b/sys/arch/mvme88k/include/trap.h @@ -0,0 +1,71 @@ +/* + * Mach Operating System + * Copyright (c) 1992 Carnegie Mellon University + * All Rights Reserved. + * + * Permission to use, copy, modify and distribute this software and its + * documentation is hereby granted, provided that both the copyright + * notice and this permission notice appear in all copies of the + * software, derivative works or modified versions, and any portions + * thereof, and that both notices appear in supporting documentation. + * + * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" + * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR + * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. + * + * Carnegie Mellon requests users of this software to return to + * + * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU + * School of Computer Science + * Carnegie Mellon University + * Pittsburgh PA 15213-3890 + * + * any improvements or extensions that they make and grant Carnegie Mellon + * the rights to redistribute these changes. + */ +/* + * Trap codes + */ + +#ifndef _M88K_TRAP_H +#define _M88K_TRAP_H 1 + +/* + * Trap type values + */ + +#define T_RESADFLT 0 /* reserved addressing fault */ +#define T_PRIVINFLT 1 /* privileged instruction fault */ +#define T_RESOPFLT 2 /* reserved operand fault */ + +/* End of known constants */ + +#define T_INSTFLT 3 /* instruction access exception */ +#define T_DATAFLT 4 /* data access exception */ +#define T_MISALGNFLT 5 /* misaligned access exception */ +#define T_ILLFLT 6 /* unimplemented opcode exception */ +#define T_BNDFLT 7 /* bounds check violation exception */ +#define T_ZERODIV 8 /* illegal divide exception */ +#define T_OVFFLT 9 /* integer overflow exception */ +#define T_ERRORFLT 10 /* error exception */ +#define T_FPEPFLT 11 /* floating point precise exception */ +#define T_FPEIFLT 12 /* floating point imprecise exception */ +#define T_ASTFLT 13 /* software trap */ +#if DDB +#define T_KDB_ENTRY 14 /* force entry to kernel debugger */ +#define T_KDB_BREAK 15 /* break point hit */ +#define T_KDB_TRACE 16 /* trace */ +#endif /* DDB */ +#define T_UNKNOWNFLT 17 /* unknown exception */ +#define T_SIGTRAP 18 /* generate SIGTRAP */ +#define T_SIGSYS 19 /* generate SIGSYS */ +#define T_STEPBPT 20 /* special breakpoint for single step */ +#define T_USERBPT 21 /* user set breakpoint (for debugger) */ +#define T_SYSCALL 22 /* Syscall */ +#define T_USER 23 /* user mode fault */ +#if DDB +#define T_KDB_WATCH 24 /* watchpoint hit */ +#endif /* DDB */ + +#endif _M88K_TRAP_H + diff --git a/sys/arch/mvme88k/include/types.h b/sys/arch/mvme88k/include/types.h new file mode 100644 index 00000000000..f8d63e931d3 --- /dev/null +++ b/sys/arch/mvme88k/include/types.h @@ -0,0 +1,83 @@ +/* $NetBSD: types.h,v 1.7 1995/07/05 17:46:11 pk Exp $ */ + +/* + * Copyright (c) 1992, 1993 + * The Regents of the University of California. All rights reserved. + * + * This software was developed by the Computer Systems Engineering group + * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and + * contributed to Berkeley. + * + * All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Lawrence Berkeley Laboratory. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)types.h 8.1 (Berkeley) 6/11/93 + */ + +#ifndef _MACHTYPES_H_ +#define _MACHTYPES_H_ + +#include <sys/cdefs.h> + +#if !defined(_ANSI_SOURCE) && !defined(_POSIX_SOURCE) +typedef struct _physadr { + short r[1]; +} *physadr; + +typedef struct label_t { + int val[22]; +} label_t; +#endif + +typedef unsigned long vm_offset_t; +typedef unsigned long vm_size_t; + +/* + * Basic integral types. Omit the typedef if + * not possible for a machine/compiler combination. + */ +#define __BIT_TYPES_DEFINED__ +typedef __signed char int8_t; +typedef unsigned char u_int8_t; +typedef short int16_t; +typedef unsigned short u_int16_t; +typedef int int32_t; +typedef unsigned int u_int32_t; +typedef long long int64_t; +typedef unsigned long long u_int64_t; + +typedef int32_t register_t; + +#define __BDEVSW_DUMP_OLD_TYPE + +#endif /* _MACHTYPES_H_ */ diff --git a/sys/arch/mvme88k/include/va-m88k.h b/sys/arch/mvme88k/include/va-m88k.h new file mode 100644 index 00000000000..caa77c3c12d --- /dev/null +++ b/sys/arch/mvme88k/include/va-m88k.h @@ -0,0 +1,85 @@ +/* This file has local changes by MOTOROLA +Thu Sep 9 09:06:29 CDT 1993 Dale Rahn (drahn@pacific) + * Due to C-Front's usage of __alignof__ builtin the + usage of it must be changed to have an object of that type + as the argument not just the type. + */ +/* GNU C varargs support for the Motorola 88100 */ + +/* Define __gnuc_va_list. */ + +#ifndef __GNUC_VA_LIST +#define __GNUC_VA_LIST + +typedef struct +{ + int __va_arg; /* argument number */ + int *__va_stk; /* start of args passed on stack */ + int *__va_reg; /* start of args passed in regs */ +} __gnuc_va_list; +#endif /* not __GNUC_VA_LIST */ + +/* If this is for internal libc use, don't define anything but + __gnuc_va_list. */ +#if defined (_STDARG_H) || defined (_VARARGS_H) + +#ifdef _STDARG_H /* stdarg.h support */ + +#if __GNUC__ > 1 /* GCC 2.0 and beyond */ +#define va_start(AP,LASTARG) ((AP) = *(__gnuc_va_list *)__builtin_saveregs()) +#else +#define va_start(AP,LASTARG) \ + ( (AP).__va_reg = (int *) __builtin_saveregs2(0), \ + (AP).__va_stk = (int *) __builtin_argptr(), \ + (AP).__va_arg = (int) (__builtin_argsize() + 3) / 4 ) +#endif + +#else /* varargs.h support */ + +#if __GNUC__ > 1 /* GCC 2.0 and beyond */ +#define va_start(AP) ((AP) = *(__gnuc_va_list *)__builtin_saveregs()) +#else +#define va_start(AP) \ + ( (AP).__va_reg = (int *) __builtin_saveregs2(1), \ + (AP).__va_stk = (int *) __builtin_argptr(), \ + (AP).__va_arg = (int) (__builtin_argsize() - 4 + 3) / 4 ) +#endif +#define va_alist __va_1st_arg +#define va_dcl register int va_alist; + +#endif /* _STDARG_H */ + +/* Avoid trouble between this file and _int_varargs.h under DG/UX. This file + can be included by <stdio.h> and others and provides definitions of + __va_size and __va_reg_p and a va_list typedef. Avoid defining va_list + again with _VA_LIST. */ +#ifdef __INT_VARARGS_H +#undef __va_size +#undef __va_reg_p +#define __gnuc_va_list va_list +#define _VA_LIST +#else +/* Similarly, if this gets included first, do nothing in _int_varargs.h. */ +#define __INT_VARARGS_H +#endif + +#define __va_reg_p(TYPE) \ + (__builtin_classify_type(*(TYPE *)0) < 12 \ + ? sizeof(TYPE) <= 8 : sizeof(TYPE) == 4 && __alignof__(*(TYPE *)0) == 4) + +#define __va_size(TYPE) ((sizeof(TYPE) + 3) >> 2) + +/* We cast to void * and then to TYPE * because this avoids + a warning about increasing the alignment requirement. */ +#define va_arg(AP,TYPE) \ + ( (AP).__va_arg = (((AP).__va_arg + (1 << (__alignof__(*(TYPE *)0) >> 3)) - 1) \ + & ~((1 << (__alignof__(*(TYPE *)0) >> 3)) - 1)) \ + + __va_size(TYPE), \ + *((TYPE *) (void *) ((__va_reg_p(TYPE) \ + && (AP).__va_arg < 8 + __va_size(TYPE) \ + ? (AP).__va_reg : (AP).__va_stk) \ + + ((AP).__va_arg - __va_size(TYPE))))) + +#define va_end(AP) + +#endif /* defined (_STDARG_H) || defined (_VARARGS_H) */ diff --git a/sys/arch/mvme88k/include/varargs.h b/sys/arch/mvme88k/include/varargs.h new file mode 100644 index 00000000000..aeef84f45cf --- /dev/null +++ b/sys/arch/mvme88k/include/varargs.h @@ -0,0 +1,191 @@ +/* This file has local changes by MOTOROLA +Thu Sep 9 09:06:29 CDT 1993 Dale Rahn (drahn@pacific) + * (gstdarg.h, gvarargs.h) C-Front requires all builtins to + be defined. This is to insert these definitions if + __cplusplus is defined but not using the G++ compiler. + */ +#ifndef __GNUC__ +/* Use the system's macros with the system's compiler. */ +#include <varargs.h> +#else +/* Record that this is varargs.h; this turns off stdarg.h. */ + +#ifndef _VARARGS_H +#define _VARARGS_H + +#ifdef __sparc__ +#include <va-sparc.h> +#else +#ifdef __spur__ +#include <va-spur.h> +#else +#ifdef __mips__ +#include <va-mips.h> +#else +#ifdef __i860__ +#include <va-i860.h> +#else +#ifdef __pyr__ +#include <va-pyr.h> +#else +#ifdef __clipper__ +#include <va-clipper.h> +#else +#ifdef __m88k__ +#include <machine/va-m88k.h> +#else +#if defined(__hppa__) || defined(hp800) +#include <va-pa.h> +#else +#ifdef __i960__ +#include <va-i960.h> +#else +#ifdef __alpha__ +#include <va-alpha.h> +#else + +#ifdef __NeXT__ + +/* On Next, erase any vestiges of stdarg.h. */ + +#ifdef _ANSI_STDARG_H_ +#define _VA_LIST_ +#endif +#define _ANSI_STDARG_H_ + +#undef va_alist +#undef va_dcl +#undef va_list +#undef va_start +#undef va_end +#undef __va_rounded_size +#undef va_arg +#endif /* __NeXT__ */ + +/* In GCC version 2, we want an ellipsis at the end of the declaration + of the argument list. GCC version 1 can't parse it. */ + +#if __GNUC__ > 1 +#define __va_ellipsis ... +#else +#define __va_ellipsis +#endif + +/* These macros implement traditional (non-ANSI) varargs + for GNU C. */ + +#define va_alist __builtin_va_alist +/* The ... causes current_function_varargs to be set in cc1. */ +#define va_dcl int __builtin_va_alist; __va_ellipsis + +/* Define __gnuc_va_list, just as in gstdarg.h. */ + +#ifndef __GNUC_VA_LIST +#define __GNUC_VA_LIST +#if defined(__svr4__) || defined(_AIX) || defined(_M_UNIX) +typedef char *__gnuc_va_list; +#else +typedef void *__gnuc_va_list; +#endif +#endif + +#define va_start(AP) AP=(char *) &__builtin_va_alist + +#define va_end(AP) + +#define __va_rounded_size(TYPE) \ + (((sizeof (TYPE) + sizeof (int) - 1) / sizeof (int)) * sizeof (int)) + +#if defined (__arm__) || defined (__i386__) || defined (__ns32000__) || defined (__vax__) +/* This is for little-endian machines; small args are padded upward. */ +#define va_arg(AP, TYPE) \ + (AP = (__gnuc_va_list) ((char *) (AP) + __va_rounded_size (TYPE)), \ + *((TYPE *) (void *) ((char *) (AP) - __va_rounded_size (TYPE)))) +#else /* big-endian */ +/* This is for big-endian machines; small args are padded downward. */ +#define va_arg(AP, TYPE) \ + (AP = (__gnuc_va_list) ((char *) (AP) + __va_rounded_size (TYPE)), \ + *((TYPE *) (void *) ((char *) (AP) - ((sizeof (TYPE) < 4 \ + ? sizeof (TYPE) \ + : __va_rounded_size (TYPE)))))) +#endif /* big-endian */ + +#endif /* not alpha */ +#endif /* not i960 */ +#endif /* not hppa */ +#endif /* not m88k */ +#endif /* not clipper */ +#endif /* not pyr */ +#endif /* not i860 */ +#endif /* not mips */ +#endif /* not spur */ +#endif /* not sparc */ +#endif /* not _VARARGS_H */ + +/* Define va_list from __gnuc_va_list. */ + +#ifdef _HIDDEN_VA_LIST /* On OSF1, this means varargs.h is "half-loaded". */ +#undef _VA_LIST +#endif + +#ifdef __svr4__ +/* SVR4.2 uses _VA_LIST for an internal alias for va_list, + so we must avoid testing it and setting it here. + SVR4 uses _VA_LIST as a flag in stdarg.h, but we should + have no conflict with that. */ +#ifndef _VA_LIST_ +#define _VA_LIST_ +#ifdef __i860__ +#ifndef _VA_LIST +#define _VA_LIST va_list +#endif +#endif /* __i860__ */ +typedef __gnuc_va_list va_list; +#endif /* _VA_LIST_ */ + +#else /* not __svr4__ */ + +/* The macro _VA_LIST_ is the same thing used by this file in Ultrix. + But on BSD NET2 we must not test or define or undef it. + (Note that the comments in NET 2's ansi.h + are incorrect for _VA_LIST_--see stdio.h!) */ +#if !defined (_VA_LIST_) || defined (__BSD_NET2__) || defined (____386BSD____) +/* The macro _VA_LIST is used in SCO Unix 3.2. */ +#ifndef _VA_LIST +/* The macro _VA_LIST_T_H is used in the Bull dpx2 */ +#ifndef _VA_LIST_T_H +#define _VA_LIST_T_H +#if !(defined (__BSD_NET2__) || defined (____386BSD____)) +#define _VA_LIST_ +#endif +#define _VA_LIST +typedef __gnuc_va_list va_list; +#endif /* not _VA_LIST_T_H */ +#endif /* not _VA_LIST */ +#endif /* not _VA_LIST_ */ + +#endif /* not __svr4__ */ + +/* took this one out Nivas */ +/* The next BSD release (if there is one) wants this symbol to be + undefined instead of _VA_LIST_. */ +#ifdef _BSD_VA_LIST_ +#undef _BSD_VA_LIST_ +#define _BSD_VA_LIST_ __gnuc_va_list +#endif /* _BSD_VA_LIST_ */ +#if defined(__cplusplus) && !defined(__GNUG__) + +/* This is added to work with AT&T C++. */ +extern "C" { + char *__builtin_next_arg(void); + __gnuc_va_list *__builtin_saveregs(void); + void *__builtin_saveregs2(int); + int *__builtin_argptr(void); + int __builtin_argsize(void); + int __builtin_classify_type(...); + int __alignof__(...); +} +#endif + + +#endif /* __GNUC__ */ diff --git a/sys/arch/mvme88k/include/vid.h b/sys/arch/mvme88k/include/vid.h new file mode 100644 index 00000000000..acaa280dace --- /dev/null +++ b/sys/arch/mvme88k/include/vid.h @@ -0,0 +1,56 @@ +#define START_BLOCK 1 +#define LOADER_SIZE 2 +#define LOADER_ADDRESS 0x1F0000 + +#ifndef __ASSEMBLER__ +struct vid { + unsigned char vid_id[4]; + unsigned char vid_0[16]; + unsigned int vid_oss; + unsigned short vid_osl; + unsigned char vid_1[4]; + unsigned short vid_osa_u; + unsigned short vid_osa_l; + unsigned char vid_2[4]; + unsigned char vid_vd[20]; + unsigned char vid_3[86]; + unsigned int vid_cas; + unsigned char vid_cal; + unsigned char vid_4[99]; + unsigned char vid_mot[8]; +}; +struct cfg { + + unsigned char cfg_0[4]; + unsigned short cfg_atm; + unsigned short cfg_prm; + unsigned short cfg_atw; + unsigned short cfg_rec; + unsigned char cfg_1[12]; + unsigned char cfg_spt; + unsigned char cfg_hds; + unsigned short cfg_trk; + unsigned char cfg_ilv; + unsigned char cfg_sof; + unsigned short cfg_psm; + unsigned short cfg_shd; + unsigned char cfg_2[2]; + unsigned short cfg_pcom; + unsigned char cfg_3; + unsigned char cfg_ssr; + unsigned short cfg_rwcc; + unsigned short cfg_ecc; + unsigned short cfg_eatm; + unsigned short cfg_eprm; + unsigned short cfg_eatw; + unsigned char cfg_gpb1; + unsigned char cfg_gpb2; + unsigned char cfg_gpb3; + unsigned char cfg_gpb4; + unsigned char cfg_ssc; + unsigned char cfg_runit; + unsigned short cfg_rsvc1; + unsigned short cfg_rsvc2; + unsigned char cfg_4[196]; +}; +#endif diff --git a/sys/arch/mvme88k/include/vmparam.h b/sys/arch/mvme88k/include/vmparam.h new file mode 100644 index 00000000000..586fb83fe38 --- /dev/null +++ b/sys/arch/mvme88k/include/vmparam.h @@ -0,0 +1,219 @@ +/* + * Mach Operating System + * Copyright (c) 1992 Carnegie Mellon University + * All Rights Reserved. + * + * Permission to use, copy, modify and distribute this software and its + * documentation is hereby granted, provided that both the copyright + * notice and this permission notice appear in all copies of the + * software, derivative works or modified versions, and any portions + * thereof, and that both notices appear in supporting documentation. + * + * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" + * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR + * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. + * + * Carnegie Mellon requests users of this software to return to + * + * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU + * School of Computer Science + * Carnegie Mellon University + * Pittsburgh PA 15213-3890 + * + * any improvements or extensions that they make and grant Carnegie Mellon + * the rights to redistribute these changes. + */ + +/* + * HISTORY + */ +/* + * File: vm_param.h + * + * machine dependent virtual memory parameters. + * Most of the declarations are preceeded by M88K_ (or m88k_) + * which is OK because only M88K specific code will be using + * them. + */ + + +#ifndef _MACHINE_VM_PARAM_ +#define _MACHINE_VM_PARAM_ + +/* + * USRTEXT is the start of the user text/data space, while USRSTACK + * is the top (end) of the user stack. + */ +#define USRTEXT 0x1000 /* Start of user text */ +#define USRSTACK 0x80000000 /* Start of user stack */ + +/* + * Virtual memory related constants, all in bytes + */ +#ifndef MAXTSIZ +#define MAXTSIZ (8*1024*1024) /* max text size */ +#endif +#ifndef DFLDSIZ +#define DFLDSIZ (16*1024*1024) /* initial data size limit */ +#endif +#ifndef MAXDSIZ +#define MAXDSIZ (64*1024*1024) /* max data size */ +#endif +#ifndef DFLSSIZ +#define DFLSSIZ (512*1024) /* initial stack size limit */ +#endif +#ifndef MAXSSIZ +#define MAXSSIZ MAXDSIZ /* max stack size */ +#endif + +/* + * Default sizes of swap allocation chunks (see dmap.h). + * The actual values may be changed in vminit() based on MAXDSIZ. + * With MAXDSIZ of 16Mb and NDMAP of 38, dmmax will be 1024. + * DMMIN should be at least ctod(1) so that vtod() works. + * vminit() insures this. + */ +#define DMMIN 32 /* smallest swap allocation */ +#define DMMAX 4096 /* largest potential swap allocation */ +#define DMTEXT 1024 /* swap allocation for text */ + +/* + * Size of shared memory map + */ +#ifndef SHMMAXPGS +#define SHMMAXPGS 1024 +#endif + +/* + * The time for a process to be blocked before being very swappable. + * This is a number of seconds which the system takes as being a non-trivial + * amount of real time. You probably shouldn't change this; + * it is used in subtle ways (fractions and multiples of it are, that is, like + * half of a ``long time'', almost a long time, etc.) + * It is related to human patience and other factors which don't really + * change over time. + */ +#define MAXSLP 20 + +/* + * A swapped in process is given a small amount of core without being bothered + * by the page replacement algorithm. Basically this says that if you are + * swapped in you deserve some resources. We protect the last SAFERSS + * pages against paging and will just swap you out rather than paging you. + * Note that each process has at least UPAGES+CLSIZE pages which are not + * paged anyways (this is currently 8+2=10 pages or 5k bytes), so this + * number just means a swapped in process is given around 25k bytes. + * Just for fun: current memory prices are 4600$ a megabyte on VAX (4/22/81), + * so we loan each swapped in process memory worth 100$, or just admit + * that we don't consider it worthwhile and swap it out to disk which costs + * $30/mb or about $0.75. + */ +#define SAFERSS 4 /* nominal ``small'' resident set size + protected against replacement */ + +#define VM_MINUSER_ADDRESS ((vm_offset_t) 0) +#define VM_MAXUSER_ADDRESS ((vm_offset_t) 0xffc00000U) + +#define VM_MINKERNEL_ADDRESS ((vm_offset_t) 0) +#define VM_MAXKERNEL_ADDRESS ((vm_offset_t) 0x1fffffff) + +/* + * Mach derived constants + */ +#define BYTE_SIZE 8 /* byte size in bits */ + +#define M88K_PGBYTES (1<<12) /* bytes per m88k page */ +#define M88K_PGSHIFT 12 /* number of bits to shift for pages */ + +/* + * Convert bytes to pages and convert pages to bytes. + * No rounding is used. + */ + +#define m88k_btop(x) (((unsigned)(x)) >> M88K_PGSHIFT) +#define m88k_ptob(x) (((unsigned)(x)) << M88K_PGSHIFT) + +/* + * Round off or truncate to the nearest page. These will work + * for either addresses or counts. (i.e. 1 byte rounds to 1 page + * bytes. + */ + +#define m88k_round_page(x) ((((unsigned)(x)) + M88K_PGBYTES - 1) & \ + ~(M88K_PGBYTES-1)) +#define m88k_trunc_page(x) (((unsigned)(x)) & ~(M88K_PGBYTES-1)) + +#define VM_MIN_ADDRESS ((vm_offset_t) 0) +#define VM_MAX_ADDRESS ((vm_offset_t) 0xffc00000U) + +#define VM_MIN_USER_ADDRESS ((vm_offset_t) 0) +#define VM_MAX_USER_ADDRESS ((vm_offset_t) 0xffc00000U) + +/* on vme188, max = 0xf0000000 */ + +#define VM_MIN_KERNEL_ADDRESS ((vm_offset_t) 0) +#define VM_MAX_KERNEL_ADDRESS ((vm_offset_t) 0x1fffffff) + +#define KERNEL_STACK_SIZE (3*4096) /* kernel stack size */ +#define INTSTACK_SIZE (3*4096) /* interrupt stack size */ + +/* virtual sizes (bytes) for various kernel submaps */ +#define VM_MBUF_SIZE (NMBCLUSTERS*MCLBYTES) +#define VM_KMEM_SIZE (NKMEMCLUSTERS*CLBYTES) + +/* + * Conversion between MACHINE pages and VM pages + */ + +#define trunc_m88k_to_vm(p) (atop(trunc_page(m88k_ptob(p)))) +#define round_m88k_to_vm(p) (atop(round_page(m88k_ptob(p)))) +#define vm_to_m88k(p) (m88k_btop(ptoa(p))) + +#if 1 /*Do we really need all this stuff*/ +#if 1 /*Do we really need all this stuff*/ +#if 1 /*Do we really need all this stuff*/ +#define M88K_SGPAGES (1<<10) /* pages per m88k segment */ +#define M88K_SGPGSHIFT 10 /* number of bits to shift for segment-page */ +#define M88K_ALSEGMS (1<<10) /* segments per m88k all space */ +#define M88K_ALSGSHIFT 10 /* number of bits to shift for all-segment */ + +#define M88K_SGBYTES (1<<22) /* bytes per m88k segments */ +#define M88K_SGSHIFT 22 /* number of bits to shift for segment */ +#define M88K_ALPAGES (1<<20) /* pages per m88k all space */ +#define M88K_ALPGSHIFT 20 /* number of bits to shift for all-page */ + +/* + * Convert bytes to pages and convert pages to bytes. + * No rounding is used. + */ + +#define m88k_btopr(x) (((unsigned)(x) + (M88K_PGBYTES - 1)) >> M88K_PGSHIFT) +#define m88k_btosr(x) (((unsigned)(x) + (M88K_SGBYTES - 1)) >> M88K_SGSHIFT) +#define m88k_btos(x) (((unsigned)(x)) >> M88K_SGSHIFT) +#define m88k_stob(x) (((unsigned)(x)) << M88K_SGSHIFT) +#define m88k_ptosr(x) (((unsigned)(x) + (M88K_SGPAGES - 1)) >> M88K_SGPGSHIFT) +#define m88k_ptos(x) (((unsigned)(x)) >> M88K_SGPGSHIFT) +#define m88k_stop(x) (((unsigned)(x)) << M88K_SGPGSHIFT) + +/* + * Round off or truncate to the nearest page. These will work + * for either addresses or counts. (i.e. 1 byte rounds to 1 page + * bytes. + */ + +#define m88k_round_segm(x) ((((unsigned)(x)) + M88K_SGBYTES - 1) & \ + ~(M88K_SGBYTES-1)) +#define m88k_next_segm(x) ((((unsigned)(x)) & ~(M88K_SGBYTES-1)) + \ + M88K_SGBYTES) +#define m88k_trunc_segm(x) (((unsigned)(x)) & ~(M88K_SGBYTES-1)) + +#define m88k_round_seg(x) ((((unsigned)(x)) + M88K_SGBYTES - 1) & \ + ~(M88K_SGBYTES-1)) +#define m88k_trunc_seg(x) (((unsigned)(x)) & ~(M88K_SGBYTES-1)) + +#define VEQR_ADDR 0x20000000 /* kernel virtual eq phy mapping */ +#endif /* Do we really need all this stuff */ +#endif /* Do we really need all this stuf */ +#endif /* Do we really need all this stuff */ + +#endif _MACHINE_VM_PARAM_ diff --git a/sys/arch/mvme88k/mvme88k/TODO b/sys/arch/mvme88k/mvme88k/TODO new file mode 100644 index 00000000000..a6151ebd11e --- /dev/null +++ b/sys/arch/mvme88k/mvme88k/TODO @@ -0,0 +1,4 @@ +1. It appears that trap() assumes instruction access or data access + faults can only be caused by page faults. Could do better by + checking PFSR in the CMMU and handling parity errors, page faults, + segmentation faults and protection faults appropriately. diff --git a/sys/arch/mvme88k/mvme88k/autoconf.c b/sys/arch/mvme88k/mvme88k/autoconf.c new file mode 100644 index 00000000000..596bef1fa20 --- /dev/null +++ b/sys/arch/mvme88k/mvme88k/autoconf.c @@ -0,0 +1,198 @@ +/* + * Copyright (c) 1996 Nivas Madhur + * Copyright (c) 1994 Christian E. Hopps + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by Christian E. Hopps. + * 4. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * $Id: autoconf.c,v 1.3 1997/03/03 20:21:28 rahnds Exp $ + */ +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/reboot.h> +#include <sys/conf.h> +#include <sys/device.h> +#include <sys/disklabel.h> +#include <machine/cpu.h> + +void configure __P((void)); +void setroot __P((void)); +void swapconf __P((void)); + +int cold; /* 1 if still booting */ +#include <sys/kernel.h> + +/* + * called at boot time, configure all devices on the system. + */ +void +configure() +{ + if (config_rootfound("mainbus", "mainbus") == 0) + panic("no mainbus found"); + + /* + * Turn external interrupts on. We have all the drivers in + * place now! + */ + enable_interrupt(); + spl0(); + +#if 0 +#ifdef GENERIC + if ((boothowto & RB_ASKNAME) == 0) + setroot(); + setconf(); +#else + setroot(); +#endif +#endif /* 0 */ + setroot(); + swapconf(); + + /* + * Done with autoconfig! + */ + cold = 0; +} + +/*ARGSUSED*/ +int +simple_devprint(auxp, pnp) + void *auxp; + char *pnp; +{ + return(QUIET); +} + +int +matchname(fp, sp) + char *fp, *sp; +{ + int len; + + len = strlen(fp); + if (strlen(sp) != len) + return(0); + if (bcmp(fp, sp, len) == 0) + return(1); + return(0); +} + +void +swapconf() +{ + struct swdevt *swp; + u_int maj; + int nb; + + for (swp = swdevt; swp->sw_dev > 0; swp++) { + maj = major(swp->sw_dev); + + if (maj > nblkdev) + break; + + if (bdevsw[maj].d_psize) { + nb = bdevsw[maj].d_psize(swp->sw_dev); + if (nb > 0 && + (swp->sw_nblks == 0 || swp->sw_nblks > nb)) + swp->sw_nblks = nb; + else + swp->sw_nblks = 0; + } + swp->sw_nblks = ctod(dtoc(swp->sw_nblks)); + } + if (dumplo == 0 && dumpdev != NODEV && bdevsw[major(dumpdev)].d_psize) + /*dumplo = (*bdevsw[major(dumpdev)].d_psize)(dumpdev) - physmem;*/ + dumplo = (*bdevsw[major(dumpdev)].d_psize)(dumpdev) - + ctob(physmem)/DEV_BSIZE; + if (dumplo < 0) + dumplo = 0; + + dumpconf(); +} + +#define DOSWAP /* change swdevt and dumpdev */ +u_long bootdev = 0; /* should be dev_t, but not until 32 bits */ + +static char devname[][2] = { + 0,0, + 0,0, + 0,0, + 0,0, + 's','d', /* 4 = sd -- new SCSI system */ +}; + +void +setroot() +{ + int majdev, mindev, unit, part, adaptor; + dev_t temp, orootdev; + struct swdevt *swp; + + printf("setroot boothowto %x bootdev %x\n", boothowto, bootdev); + if (boothowto & RB_DFLTROOT || + (bootdev & B_MAGICMASK) != (u_long)B_DEVMAGIC) + return; + majdev = (bootdev >> B_TYPESHIFT) & B_TYPEMASK; + if (majdev > sizeof(devname) / sizeof(devname[0])) + return; + adaptor = (bootdev >> B_ADAPTORSHIFT) & B_ADAPTORMASK; + part = (bootdev >> B_PARTITIONSHIFT) & B_PARTITIONMASK; + unit = (bootdev >> B_UNITSHIFT) & B_UNITMASK; + orootdev = rootdev; + rootdev = MAKEDISKDEV(majdev, unit, part); + /* + * If the original rootdev is the same as the one + * just calculated, don't need to adjust the swap configuration. + */ + if (rootdev == orootdev) + return; + printf("changing root device to %c%c%d%c\n", + devname[majdev][0], devname[majdev][1], + unit, part + 'a'); +#ifdef DOSWAP + mindev = DISKUNIT(rootdev); + for (swp = swdevt; swp->sw_dev; swp++) { + printf("DOSWAP swap %x dev %x\n", swp, swp->sw_dev); + if (majdev == major(swp->sw_dev) && + mindev == DISKUNIT(swp->sw_dev)) { + temp = swdevt[0].sw_dev; + swdevt[0].sw_dev = swp->sw_dev; + swp->sw_dev = temp; + break; + } + } + if (swp->sw_dev == 0) + return; + /* + * If dumpdev was the same as the old primary swap + * device, move it to the new primary swap device. + */ + if (temp == dumpdev) + dumpdev = swdevt[0].sw_dev; +#endif +} diff --git a/sys/arch/mvme88k/mvme88k/cmmu.c b/sys/arch/mvme88k/mvme88k/cmmu.c new file mode 100644 index 00000000000..9499324945a --- /dev/null +++ b/sys/arch/mvme88k/mvme88k/cmmu.c @@ -0,0 +1,1354 @@ +/* + * Copyright (c) 1996 Nivas Madhur + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by Nivas Madhur. + * 4. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * $Id: cmmu.c,v 1.3 1997/03/03 20:21:30 rahnds Exp $ + */ +/* + * Mach Operating System + * Copyright (c) 1993-1991 Carnegie Mellon University + * Copyright (c) 1991 OMRON Corporation + * All Rights Reserved. + * + * Permission to use, copy, modify and distribute this software and its + * documentation is hereby granted, provided that both the copyright + * notice and this permission notice appear in all copies of the + * software, derivative works or modified versions, and any portions + * thereof, and that both notices appear in supporting documentation. + * + * CARNEGIE MELLON AND OMRON ALLOW FREE USE OF THIS SOFTWARE IN ITS "AS IS" + * CONDITION. CARNEGIE MELLON AND OMRON DISCLAIM ANY LIABILITY OF ANY KIND + * FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. + * + * Carnegie Mellon requests users of this software to return to + * + * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU + * School of Computer Science + * Carnegie Mellon University + * Pittsburgh PA 15213-3890 + * + * any improvements or extensions that they make and grant Carnegie the + * rights to redistribute these changes. + */ + +#include <sys/param.h> +#include <sys/types.h> +#include <machine/board.h> +#include <machine/cpus.h> +#include <machine/m882xx.h> + +/* On some versions of 88200, page size flushes don't work. I am using + * sledge hammer approach till I find for sure which ones are bad XXX nivas */ +#define BROKEN_MMU_MASK +#if defined(MVME187) +#undef SNOOP_ENABLE +#else +#define SNOOP_ENABLE +#endif /* defined(MVME187) + +#undef SHADOW_BATC /* don't use BATCs for now XXX nivas */ + +struct cmmu_regs +{ + /* base + $000 */ volatile unsigned idr; + /* base + $004 */ volatile unsigned scr; + /* base + $008 */ volatile unsigned ssr; + /* base + $00C */ volatile unsigned sar; + /* */ unsigned padding1[0x3D]; + /* base + $104 */ volatile unsigned sctr; + /* base + $108 */ volatile unsigned pfSTATUSr; + /* base + $10C */ volatile unsigned pfADDRr; + /* */ unsigned padding2[0x3C]; + /* base + $200 */ volatile unsigned sapr; + /* base + $204 */ volatile unsigned uapr; + /* */ unsigned padding3[0x7E]; + /* base + $400 */ volatile unsigned bwp[8]; + /* */ unsigned padding4[0xF8]; + /* base + $800 */ volatile unsigned cdp[4]; + /* */ unsigned padding5[0x0C]; + /* base + $840 */ volatile unsigned ctp[4]; + /* */ unsigned padding6[0x0C]; + /* base + $880 */ volatile unsigned cssp; + + /* The rest for the 88204 */ + #define cssp0 cssp + /* */ unsigned padding7[0x03]; + /* base + $890 */ volatile unsigned cssp1; + /* */ unsigned padding8[0x03]; + /* base + $8A0 */ volatile unsigned cssp2; + /* */ unsigned padding9[0x03]; + /* base + $8B0 */ volatile unsigned cssp3; +}; + +static struct cmmu { + struct cmmu_regs *cmmu_regs; /* CMMU "base" area */ + unsigned char cmmu_cpu; /* cpu number it is attached to */ + unsigned char which; /* either INST_CMMU || DATA_CMMU */ + unsigned char cmmu_alive; +#define CMMU_DEAD 0 /* This cmmu not there */ +#define CMMU_AVAILABLE 1 /* It's there, but which cpu's? */ +#define CMMU_MARRIED 2 /* Know which cpu it belongs to. */ +#if SHADOW_BATC + unsigned batc[8]; +#endif + unsigned char pad; +} cmmu[MAX_CMMUS] = { + {(void *)CMMU_I, 0, 0, 0, 0}, + {(void *)CMMU_D, 0, 1, 0, 0}, +}; + +/* + * We rely upon and use INST_CMMU == 0 and DATA_CMMU == 1 + */ +#if INST_CMMU != 0 || DATA_CMMU != 1 + error("ack gag barf!"); +#endif +struct cpu_cmmu { + struct cmmu *pair[2]; +} cpu_cmmu[1]; + +/* + * CMMU(cpu,data) Is the cmmu struct for the named cpu's indicated cmmu. + * REGS(cpu,data) is the actual register structure. + */ +#define CMMU(cpu, data) cpu_cmmu[(cpu)].pair[(data)?DATA_CMMU:INST_CMMU] +#define REGS(cpu, data) (*CMMU(cpu, data)->cmmu_regs) + +unsigned cache_policy = /*CACHE_INH*/ 0; + +#ifdef CMMU_DEBUG +void +show_apr(unsigned value) +{ + union apr_template apr_template; + apr_template.bits = value; + + _printf("table @ 0x%x000", apr_template.field.st_base); + if (apr_template.field.wt) printf(", writethrough"); + if (apr_template.field.g) printf(", global"); + if (apr_template.field.ci) printf(", cache inhibit"); + if (apr_template.field.te) printf(", valid"); + else printf(", not valid"); + printf("]\n"); +} + +void +show_sctr(unsigned value) +{ + union { + unsigned bits; + struct { + unsigned :16, + pe: 1, + se: 1, + pr: 1, + :13; + } fields; + } sctr; + sctr.bits = value; + printf("%spe, %sse %spr]\n", + sctr.fields.pe ? "" : "!", + sctr.fields.se ? "" : "!", + sctr.fields.pr ? "" : "!"); +} +#endif + +/* + * CMMU initialization routine + */ +void +cmmu_init(void) +{ + unsigned tmp, cmmu_num; + union cpupid id; + int cpu; + + cpu_cmmu[0].pair[INST_CMMU] = cpu_cmmu[0].pair[DATA_CMMU] = 0; + + for (cmmu_num = 0; cmmu_num < MAX_CMMUS; cmmu_num++) { + if (!badwordaddr((vm_offset_t)cmmu[cmmu_num].cmmu_regs)) { + id.cpupid = cmmu[cmmu_num].cmmu_regs->idr; + if (id.m88200.type != M88200 && id.m88200.type !=M88204) + continue; + cmmu[cmmu_num].cmmu_alive = CMMU_AVAILABLE; + + cpu_cmmu[cmmu[cmmu_num].cmmu_cpu].pair[cmmu[cmmu_num].which] = + &cmmu[cmmu_num]; + + /* + * Reset cache data.... + * as per M88200 Manual (2nd Ed.) section 3.11. + */ + for (tmp = 0; tmp < 255; tmp++) { + cmmu[cmmu_num].cmmu_regs->sar = tmp << 4; + cmmu[cmmu_num].cmmu_regs->cssp = 0x3f0ff000; + } + + /* 88204 has additional cache to clear */ + if(id.m88200.type == M88204) + { + for (tmp = 0; tmp < 255; tmp++) { + cmmu[cmmu_num].cmmu_regs->sar = + tmp<<4; + cmmu[cmmu_num].cmmu_regs->cssp1 = + 0x3f0ff000; + } + for (tmp = 0; tmp < 255; tmp++) { + cmmu[cmmu_num].cmmu_regs->sar = + tmp<<4; + cmmu[cmmu_num].cmmu_regs->cssp2 = + 0x3f0ff000; + } + for (tmp = 0; tmp < 255; tmp++) { + cmmu[cmmu_num].cmmu_regs->sar = + tmp<<4; + cmmu[cmmu_num].cmmu_regs->cssp3 = 0x3f0ff000; + } + } + + /* + * Set the SCTR, SAPR, and UAPR to some known state + * (I don't trust the reset to do it). + */ + tmp = + ! CMMU_SCTR_PE | /* not parity enable */ + ! CMMU_SCTR_SE | /* not snoop enable */ + ! CMMU_SCTR_PR ; /*not priority arbitration */ + cmmu[cmmu_num].cmmu_regs->sctr = tmp; + + tmp = + (0x00000 << 12) |/*segment table base address */ + AREA_D_WT | /* write through */ + AREA_D_G | /* global */ + AREA_D_CI | /* cache inhibit */ + ! AREA_D_TE ; /* not translation enable */ + + cmmu[cmmu_num].cmmu_regs->sapr = + cmmu[cmmu_num].cmmu_regs->uapr = tmp; + +#if SHADOW_BATC + cmmu[cmmu_num].batc[0] = + cmmu[cmmu_num].batc[1] = + cmmu[cmmu_num].batc[2] = + cmmu[cmmu_num].batc[3] = + cmmu[cmmu_num].batc[4] = + cmmu[cmmu_num].batc[5] = + cmmu[cmmu_num].batc[6] = + cmmu[cmmu_num].batc[7] = 0; +#endif + cmmu[cmmu_num].cmmu_regs->bwp[0] = + cmmu[cmmu_num].cmmu_regs->bwp[1] = + cmmu[cmmu_num].cmmu_regs->bwp[2] = + cmmu[cmmu_num].cmmu_regs->bwp[3] = + cmmu[cmmu_num].cmmu_regs->bwp[4] = + cmmu[cmmu_num].cmmu_regs->bwp[5] = + cmmu[cmmu_num].cmmu_regs->bwp[6] = + cmmu[cmmu_num].cmmu_regs->bwp[7] = 0; + + cmmu[cmmu_num].cmmu_regs->scr =CMMU_FLUSH_CACHE_INV_ALL; + cmmu[cmmu_num].cmmu_regs->scr = CMMU_FLUSH_SUPER_ALL; + cmmu[cmmu_num].cmmu_regs->scr = CMMU_FLUSH_USER_ALL; + } + } + + /* + * Now that we know which CMMUs are there, let's report on which + * CPU/CMMU sets seem complete (hopefully all) + */ + for (cpu = 0; cpu < MAX_CPUS; cpu++) + { + if (cpu_cmmu[cpu].pair[INST_CMMU] && cpu_cmmu[cpu].pair[DATA_CMMU]) + { + if(id.m88200.type == M88204) + printf("CPU%d is attached with MC88204 CMMU\n", + cpu); + else + printf("CPU%d is attached with MC88200 CMMU\n", + cpu); + } + else if (cpu_cmmu[cpu].pair[INST_CMMU]) + { + printf("CPU%d data CMMU is not working.\n", cpu); + panic("cmmu-data"); + } + else if (cpu_cmmu[cpu].pair[DATA_CMMU]) + { + printf("CPU%d instruction CMMU is not working.\n", cpu); + panic("cmmu"); + } + } + +#if SNOOP_ENABLE + /* + * Enable snooping... MVME187 doesn't support snooping. The + * processor will, but the processor is not going to see the cache + * accesses going on the 040 local bus. XXX nivas + */ + for (cpu = 0; cpu < MAX_CPUS; cpu++) + { + /* + * Enable snooping. + * We enable it for instruction cmmus as well so that we can + * have breakpoints, etc, and modify code. + */ + tmp = + ! CMMU_SCTR_PE | /* not parity enable */ + CMMU_SCTR_SE | /* snoop enable */ + ! CMMU_SCTR_PR ; /* not priority arbitration */ + + REGS(cpu, DATA_CMMU).sctr = tmp; + REGS(cpu, INST_CMMU).sctr = tmp; + REGS(cpu, DATA_CMMU).scr = CMMU_FLUSH_SUPER_ALL; + REGS(cpu, INST_CMMU).scr = CMMU_FLUSH_SUPER_ALL; + } + +#endif /* SNOOP_ENABLE */ + + /* + * Turn on some cache. + */ + for (cpu = 0; cpu < MAX_CPUS; cpu++) + { + /* + * Enable some caching for the instruction stream. + * Can't cache data yet 'cause device addresses can never + * be cached, and we don't have those no-caching zones + * set up yet.... + */ + tmp = + (0x00000 << 12) | /* segment table base address */ + AREA_D_WT | /* write through */ + AREA_D_G | /* global */ + AREA_D_CI | /* cache inhibit */ + ! AREA_D_TE ; /* not translation enable */ + REGS(cpu, INST_CMMU).sapr = tmp; + REGS(cpu, DATA_CMMU).scr = CMMU_FLUSH_SUPER_ALL; + } +} + +/* + * Just before poweroff or reset.... + */ +void +cmmu_shutdown_now(void) +{ + unsigned tmp; + unsigned cmmu_num; + + /* + * Now set some state as we like... + */ + for (cmmu_num = 0; cmmu_num < MAX_CMMUS; cmmu_num++) + { + tmp = + ! CMMU_SCTR_PE | /* parity enable */ +#if SNOOP_ENABLE + ! CMMU_SCTR_SE | /* snoop enable */ +#endif /* SNOOP_ENABLE */ + ! CMMU_SCTR_PR ; /* priority arbitration */ + + cmmu[cmmu_num].cmmu_regs->sctr = tmp; + + tmp = + (0x00000 << 12) | /* segment table base address */ + ! AREA_D_WT | /* write through */ + ! AREA_D_G | /* global */ + AREA_D_CI | /* cache inhibit */ + ! AREA_D_TE ; /* translation disable */ + + cmmu[cmmu_num].cmmu_regs->sapr = tmp; + cmmu[cmmu_num].cmmu_regs->uapr = tmp; + } +} + +/** + ** Funcitons that actually modify CMMU registers. + **/ + +#if !DDB +static +#endif +void +cmmu_remote_set(unsigned cpu, unsigned r, unsigned data, unsigned x) +{ + *(volatile unsigned *)(r + (char*)®S(cpu,data)) = x; +} + +/* + * cmmu_cpu_lock should be held when called if read + * the CMMU_SCR or CMMU_SAR. +**/ +#if !DDB +static +#endif +unsigned +cmmu_remote_get(unsigned cpu, unsigned r, unsigned data) +{ + return (*(volatile unsigned *)(r + (char*)®S(cpu,data))); +} + +/* Needs no locking - read only registers */ +unsigned +cmmu_get_idr(unsigned data) +{ + return REGS(0,data).idr; +} + +void +cmmu_set_sapr(unsigned ap) +{ + int cpu = 0; + + if (cache_policy & CACHE_INH) + ap |= AREA_D_CI; + + REGS(cpu, INST_CMMU).sapr = ap; + REGS(cpu, DATA_CMMU).sapr = ap; +} + +void +cmmu_remote_set_sapr(unsigned cpu, unsigned ap) +{ + if (cache_policy & CACHE_INH) + ap |= AREA_D_CI; + + REGS(cpu, INST_CMMU).sapr = ap; + REGS(cpu, DATA_CMMU).sapr = ap; +} + +void +cmmu_set_uapr(unsigned ap) +{ + int cpu = 0; + + /* this functionality also mimiced in cmmu_pmap_activate() */ + REGS(cpu, INST_CMMU).uapr = ap; + REGS(cpu, DATA_CMMU).uapr = ap; +} + +/* + * Set batc entry number entry_no to value in + * the data or instruction cache depending on data. + * + * Except for the cmmu_init, this function, cmmu_set_pair_batc_entry, + * and cmmu_pmap_activate are the only functions which may set the + * batc values. + */ +void +cmmu_set_batc_entry( + unsigned cpu, + unsigned entry_no, + unsigned data, /* 1 = data, 0 = instruction */ + unsigned value) /* the value to stuff into the batc */ +{ + + REGS(cpu,data).bwp[entry_no] = value; +#if SHADOW_BATC + CMMU(cpu,data)->batc[entry_no] = value; +#endif +#if 0 /* was for debugging piece (peace?) of mind */ + REGS(cpu,data).scr = CMMU_FLUSH_SUPER_ALL; + REGS(cpu,data).scr = CMMU_FLUSH_USER_ALL; +#endif +} + +/* + * Set batc entry number entry_no to value in + * the data and instruction cache for the named CPU. + */ +void +cmmu_set_pair_batc_entry( + unsigned cpu, + unsigned entry_no, + unsigned value) /* the value to stuff into the batc */ +{ + + REGS(cpu,DATA_CMMU).bwp[entry_no] = value; +#if SHADOW_BATC + CMMU(cpu,DATA_CMMU)->batc[entry_no] = value; +#endif + REGS(cpu,INST_CMMU).bwp[entry_no] = value; +#if SHADOW_BATC + CMMU(cpu,INST_CMMU)->batc[entry_no] = value; +#endif + +#if 0 /* was for debugging piece (peace?) of mind */ + REGS(cpu,INST_CMMU).scr = CMMU_FLUSH_SUPER_ALL; + REGS(cpu,INST_CMMU).scr = CMMU_FLUSH_USER_ALL; + REGS(cpu,DATA_CMMU).scr = CMMU_FLUSH_SUPER_ALL; + REGS(cpu,DATA_CMMU).scr = CMMU_FLUSH_USER_ALL; +#endif +} + +/** + ** Functions that invalidate TLB entries. + **/ + +/* + * flush any tlb + * Some functionality mimiced in cmmu_pmap_activate. + */ +void +cmmu_flush_remote_tlb(unsigned cpu, unsigned kernel, vm_offset_t vaddr, int size) +{ + register s = splhigh(); + + if ((unsigned)size > M88K_PGBYTES) + { + REGS(cpu, INST_CMMU).scr = + REGS(cpu, DATA_CMMU).scr = + kernel ? CMMU_FLUSH_SUPER_ALL : CMMU_FLUSH_USER_ALL; + } + else /* a page or smaller */ + { + REGS(cpu, INST_CMMU).sar = (unsigned)vaddr; + REGS(cpu, DATA_CMMU).sar = (unsigned)vaddr; + REGS(cpu, INST_CMMU).scr = + REGS(cpu, DATA_CMMU).scr = + kernel ? CMMU_FLUSH_SUPER_PAGE : CMMU_FLUSH_USER_PAGE; + } + splx(s); +} + +/* + * flush my personal tlb + */ +void +cmmu_flush_tlb(unsigned kernel, vm_offset_t vaddr, int size) +{ + cmmu_flush_remote_tlb(0, kernel, vaddr, size); +} + +/* + * New fast stuff for pmap_activate. + * Does what a few calls used to do. + * Only called from pmap.c's _pmap_activate(). + */ +void +cmmu_pmap_activate( + unsigned cpu, + unsigned uapr, + batc_template_t i_batc[BATC_MAX], + batc_template_t d_batc[BATC_MAX]) +{ + int entry_no; + + /* the following is from cmmu_set_uapr */ + REGS(cpu, INST_CMMU).uapr = uapr; + REGS(cpu, DATA_CMMU).uapr = uapr; + + for (entry_no = 0; entry_no < BATC_MAX; entry_no++) { + REGS(cpu,INST_CMMU).bwp[entry_no] = i_batc[entry_no].bits; + REGS(cpu,DATA_CMMU).bwp[entry_no] = d_batc[entry_no].bits; +#if SHADOW_BATC + CMMU(cpu,INST_CMMU)->batc[entry_no] = i_batc[entry_no].bits; + CMMU(cpu,DATA_CMMU)->batc[entry_no] = d_batc[entry_no].bits; +#endif + } + + /* + * Flush the user TLB. + * IF THE KERNEL WILL EVER CARE ABOUT THE BATC ENTRIES, + * THE SUPERVISOR TLBs SHOULB EE FLUSHED AS WELL. + */ + REGS(cpu, INST_CMMU).scr = CMMU_FLUSH_USER_ALL; + REGS(cpu, DATA_CMMU).scr = CMMU_FLUSH_USER_ALL; +} + +/** + ** Functions that invalidate caches. + ** + ** Cache invalidates require physical addresses. Care must be exercised when + ** using segment invalidates. This implies that the starting physical address + ** plus the segment length should be invalidated. A typical mistake is to + ** extract the first physical page of a segment from a virtual address, and + ** then expecting to invalidate when the pages are not physically contiguous. + ** + ** We don't push Instruction Caches prior to invalidate because they are not + ** snooped and never modified (I guess it doesn't matter then which form + ** of the command we use then). + **/ +/* + * flush both Instruction and Data caches + */ +void +cmmu_flush_remote_cache(int cpu, vm_offset_t physaddr, int size) +{ + register s = splhigh(); + +#if !defined(BROKEN_MMU_MASK) + + if (size < 0 || size > NBSG ) { + REGS(cpu, INST_CMMU).scr = CMMU_FLUSH_CACHE_CBI_ALL; + REGS(cpu, DATA_CMMU).scr = CMMU_FLUSH_CACHE_CBI_ALL; + } + else if (size <= 16) { + REGS(cpu, INST_CMMU).sar = (unsigned)physaddr; + REGS(cpu, DATA_CMMU).sar = (unsigned)physaddr; + REGS(cpu, INST_CMMU).scr = CMMU_FLUSH_CACHE_CBI_LINE; + REGS(cpu, DATA_CMMU).scr = CMMU_FLUSH_CACHE_CBI_LINE; + } + else if (size <= NBPG) { + REGS(cpu, INST_CMMU).sar = (unsigned)physaddr; + REGS(cpu, DATA_CMMU).sar = (unsigned)physaddr; + REGS(cpu, INST_CMMU).scr = CMMU_FLUSH_CACHE_CBI_PAGE; + REGS(cpu, DATA_CMMU).scr = CMMU_FLUSH_CACHE_CBI_PAGE; + } + else { + REGS(cpu, INST_CMMU).sar = (unsigned)physaddr; + REGS(cpu, DATA_CMMU).sar = (unsigned)physaddr; + REGS(cpu, INST_CMMU).scr = CMMU_FLUSH_CACHE_CBI_SEGMENT; + REGS(cpu, DATA_CMMU).scr = CMMU_FLUSH_CACHE_CBI_SEGMENT; + } + +#else + REGS(cpu, INST_CMMU).scr = CMMU_FLUSH_CACHE_CBI_ALL; + REGS(cpu, DATA_CMMU).scr = CMMU_FLUSH_CACHE_CBI_ALL; +#endif /* !BROKEN_MMU_MASK */ + splx(s); +} + +/* + * flush both Instruction and Data caches + */ +void +cmmu_flush_cache(vm_offset_t physaddr, int size) +{ + cmmu_flush_remote_cache(0, physaddr, size); +} + +/* + * flush Instruction caches + */ +void +cmmu_flush_remote_inst_cache(int cpu, vm_offset_t physaddr, int size) +{ + register s = splhigh(); + +#if !defined(BROKEN_MMU_MASK) + if (size < 0 || size > NBSG ) { + REGS(cpu, INST_CMMU).scr = CMMU_FLUSH_CACHE_CBI_ALL; + } + else if (size <= 16) { + REGS(cpu, INST_CMMU).sar = (unsigned)physaddr; + REGS(cpu, INST_CMMU).scr = CMMU_FLUSH_CACHE_CBI_LINE; + } + else if (size <= NBPG) { + REGS(cpu, INST_CMMU).sar = (unsigned)physaddr; + REGS(cpu, INST_CMMU).scr = CMMU_FLUSH_CACHE_CBI_PAGE; + } + else { + REGS(cpu, INST_CMMU).sar = (unsigned)physaddr; + REGS(cpu, INST_CMMU).scr = CMMU_FLUSH_CACHE_CBI_SEGMENT; + } +#else + REGS(cpu, INST_CMMU).scr = CMMU_FLUSH_CACHE_CBI_ALL; +#endif /* !BROKEN_MMU_MASK */ + + splx(s); +} + +/* + * flush Instruction caches + */ +void +cmmu_flush_inst_cache(vm_offset_t physaddr, int size) +{ + cmmu_flush_remote_inst_cache(0, physaddr, size); +} + +void +cmmu_flush_remote_data_cache(int cpu, vm_offset_t physaddr, int size) +{ + register s = splhigh(); + +#if !defined(BROKEN_MMU_MASK) + if (size < 0 || size > NBSG ) { + REGS(cpu, DATA_CMMU).scr = CMMU_FLUSH_CACHE_CBI_ALL; + } + else if (size <= 16) { + REGS(cpu, DATA_CMMU).sar = (unsigned)physaddr; + REGS(cpu, DATA_CMMU).scr = CMMU_FLUSH_CACHE_CBI_LINE; + } + else if (size <= NBPG) { + REGS(cpu, DATA_CMMU).sar = (unsigned)physaddr; + REGS(cpu, DATA_CMMU).scr = CMMU_FLUSH_CACHE_CBI_PAGE; + } + else { + REGS(cpu, DATA_CMMU).sar = (unsigned)physaddr; + REGS(cpu, DATA_CMMU).scr = CMMU_FLUSH_CACHE_CBI_SEGMENT; + } +#else + REGS(cpu, DATA_CMMU).scr = CMMU_FLUSH_CACHE_CBI_ALL; +#endif /* !BROKEN_MMU_MASK */ + + splx(s); +} + +/* + * flush data cache + */ +void +cmmu_flush_data_cache(vm_offset_t physaddr, int size) +{ + cmmu_flush_remote_data_cache(0, physaddr, size); +} + +/* + * sync dcache (and icache too) + */ +static void +cmmu_sync_cache(vm_offset_t physaddr, int size) +{ + register s = splhigh(); + +#if !defined(BROKEN_MMU_MASK) + if (size < 0 || size > NBSG ) { + REGS(0, INST_CMMU).scr = CMMU_FLUSH_CACHE_CB_ALL; + REGS(0, DATA_CMMU).scr = CMMU_FLUSH_CACHE_CB_ALL; + } + else if (size <= 16) { + REGS(0, INST_CMMU).sar = (unsigned)physaddr; + REGS(0, INST_CMMU).scr = CMMU_FLUSH_CACHE_CB_LINE; + REGS(0, DATA_CMMU).sar = (unsigned)physaddr; + REGS(0, DATA_CMMU).scr = CMMU_FLUSH_CACHE_CB_LINE; + } + else if (size <= NBPG) { + REGS(0, INST_CMMU).sar = (unsigned)physaddr; + REGS(0, INST_CMMU).scr = CMMU_FLUSH_CACHE_CB_PAGE; + REGS(0, DATA_CMMU).sar = (unsigned)physaddr; + REGS(0, DATA_CMMU).scr = CMMU_FLUSH_CACHE_CB_PAGE; + } + else { + REGS(0, INST_CMMU).sar = (unsigned)physaddr; + REGS(0, INST_CMMU).scr = CMMU_FLUSH_CACHE_CB_SEGMENT; + REGS(0, DATA_CMMU).sar = (unsigned)physaddr; + REGS(0, DATA_CMMU).scr = CMMU_FLUSH_CACHE_CB_SEGMENT; + } +#else + REGS(0, DATA_CMMU).scr = CMMU_FLUSH_CACHE_CB_ALL; + REGS(0, DATA_CMMU).scr = CMMU_FLUSH_CACHE_CB_ALL; +#endif /* !BROKEN_MMU_MASK */ + splx(s); +} + +static void +cmmu_sync_inval_cache(vm_offset_t physaddr, int size) +{ + register s = splhigh(); + +#if !defined(BROKEN_MMU_MASK) + if (size < 0 || size > NBSG ) { + REGS(0, DATA_CMMU).scr = CMMU_FLUSH_CACHE_CBI_ALL; + REGS(0, INST_CMMU).scr = CMMU_FLUSH_CACHE_CBI_ALL; + } + else if (size <= 16) { + REGS(0, DATA_CMMU).sar = (unsigned)physaddr; + REGS(0, DATA_CMMU).scr = CMMU_FLUSH_CACHE_CBI_LINE; + REGS(0, INST_CMMU).sar = (unsigned)physaddr; + REGS(0, INST_CMMU).scr = CMMU_FLUSH_CACHE_CBI_LINE; + } + else if (size <= NBPG) { + REGS(0, DATA_CMMU).sar = (unsigned)physaddr; + REGS(0, DATA_CMMU).scr = CMMU_FLUSH_CACHE_CBI_PAGE; + REGS(0, INST_CMMU).sar = (unsigned)physaddr; + REGS(0, INST_CMMU).scr = CMMU_FLUSH_CACHE_CBI_PAGE; + } + else { + REGS(0, DATA_CMMU).sar = (unsigned)physaddr; + REGS(0, DATA_CMMU).scr = CMMU_FLUSH_CACHE_CBI_SEGMENT; + REGS(0, INST_CMMU).sar = (unsigned)physaddr; + REGS(0, INST_CMMU).scr = CMMU_FLUSH_CACHE_CBI_SEGMENT; + } + +#else + REGS(0, DATA_CMMU).scr = CMMU_FLUSH_CACHE_CBI_ALL; + REGS(0, INST_CMMU).scr = CMMU_FLUSH_CACHE_CBI_ALL; +#endif /* !BROKEN_MMU_MASK */ + splx(s); +} + +static void +cmmu_inval_cache(vm_offset_t physaddr, int size) +{ + register s = splhigh(); + +#if !defined(BROKEN_MMU_MASK) + if (size < 0 || size > NBSG ) { + REGS(0, DATA_CMMU).scr = CMMU_FLUSH_CACHE_INV_ALL; + REGS(0, INST_CMMU).scr = CMMU_FLUSH_CACHE_INV_ALL; + } + else if (size <= 16) { + REGS(0, DATA_CMMU).sar = (unsigned)physaddr; + REGS(0, DATA_CMMU).scr = CMMU_FLUSH_CACHE_INV_LINE; + REGS(0, INST_CMMU).sar = (unsigned)physaddr; + REGS(0, INST_CMMU).scr = CMMU_FLUSH_CACHE_INV_LINE; + } + else if (size <= NBPG) { + REGS(0, DATA_CMMU).sar = (unsigned)physaddr; + REGS(0, DATA_CMMU).scr = CMMU_FLUSH_CACHE_INV_PAGE; + REGS(0, INST_CMMU).sar = (unsigned)physaddr; + REGS(0, INST_CMMU).scr = CMMU_FLUSH_CACHE_INV_PAGE; + } + else { + REGS(0, DATA_CMMU).sar = (unsigned)physaddr; + REGS(0, DATA_CMMU).scr = CMMU_FLUSH_CACHE_INV_SEGMENT; + REGS(0, INST_CMMU).sar = (unsigned)physaddr; + REGS(0, INST_CMMU).scr = CMMU_FLUSH_CACHE_INV_SEGMENT; + } +#else + REGS(0, DATA_CMMU).scr = CMMU_FLUSH_CACHE_INV_ALL; + REGS(0, INST_CMMU).scr = CMMU_FLUSH_CACHE_INV_ALL; +#endif /* !BROKEN_MMU_MASK */ + + splx(s); +} + +void +dma_cachectl(vm_offset_t va, int size, int op) +{ + int count; + +#if !defined(BROKEN_MMU_MASK) + while (size) { + + count = NBPG - ((int)va & PGOFSET); + + if (size < count) + count = size; + + if (op == DMA_CACHE_SYNC) + cmmu_sync_cache(kvtop(va), count); + else if (op == DMA_CACHE_SYNC_INVAL) + cmmu_sync_inval_cache(kvtop(va), count); + else + cmmu_inval_cache(kvtop(va), count); + + va = (vm_offset_t)((int)va + count); + size -= count; + } +#else + + if (op == DMA_CACHE_SYNC) + cmmu_sync_cache(kvtop(va), size); + else if (op == DMA_CACHE_SYNC_INVAL) + cmmu_sync_inval_cache(kvtop(va), size); + else + cmmu_inval_cache(kvtop(va), size); +#endif /* !BROKEN_MMU_MASK */ +} + +#if DDB +union ssr { + unsigned bits; + struct { + unsigned :16, + ce:1, + be:1, + :4, + wt:1, + sp:1, + g:1, + ci:1, + :1, + m:1, + u:1, + wp:1, + bh:1, + v:1; + } field; +}; + +union cssp { + unsigned bits; + struct { + unsigned : 2, + l: 6, + d3: 1, + d2: 1, + d1: 1, + d0: 1, + vv3: 2, + vv2: 2, + vv1: 2, + vv0: 2, + :12; + } field; +}; + +union batcu { + unsigned bits; + struct { /* block address translation register */ + unsigned int + lba:13, /* logical block address */ + pba:13, /* physical block address */ + s:1, /* supervisor */ + wt:4, /* write through */ + g:1, /* global */ + ci:1, /* cache inhibit */ + wp:1, /* write protect */ + v:1; /* valid */ + } field; +}; + +#define VV_EX_UNMOD 0 +#define VV_EX_MOD 1 +#define VV_SHARED_UNMOD 2 +#define VV_INVALID 3 + +#define D(UNION, LINE) \ + ((LINE) == 3 ? (UNION).field.d3 : \ + ((LINE) == 2 ? (UNION).field.d2 : \ + ((LINE) == 1 ? (UNION).field.d1 : \ + ((LINE) == 0 ? (UNION).field.d0 : ~0)))) +#define VV(UNION, LINE) \ + ((LINE) == 3 ? (UNION).field.vv3 : \ + ((LINE) == 2 ? (UNION).field.vv2 : \ + ((LINE) == 1 ? (UNION).field.vv1 : \ + ((LINE) == 0 ? (UNION).field.vv0 : ~0)))) + + +#undef VEQR_ADDR +#define VEQR_ADDR 0 + +/* + * Show (for debugging) how the given CMMU translates the given ADDRESS. + * If cmmu == -1, the data cmmu for the current cpu is used. + */ +void +cmmu_show_translation( + unsigned address, + unsigned supervisor_flag, + unsigned verbose_flag, + int cmmu_num) +{ + /* + * A virtual address is split into three fields. Two are used as + * indicies into tables (segment and page), and one is an offset into + * a page of memory. + */ + union { + unsigned bits; + struct { + unsigned segment_table_index:10, + page_table_index:10, + page_offset:12; + } field; + } virtual_address; + unsigned value; + + if (verbose_flag) + db_printf("-------------------------------------------\n"); + + + /****** ACCESS PROPER CMMU or THREAD ***********/ +#if 0 /* no thread */ + if (thread != 0) + { + /* the following tidbit from _pmap_activate in m88k/pmap.c */ + register apr_template_t apr_data; + supervisor_flag = 0; /* thread implies user */ + + if (thread->task == 0) { + db_printf("[thread %x has empty task pointer]\n", thread); + return; + } else if (thread->task->map == 0) { + db_printf("[thread/task %x/%x has empty map pointer]\n", + thread, thread->task); + return; + } else if (thread->task->map->pmap == 0) { + db_printf("[thread/task/map %x/%x/%x has empty pmap pointer]\n", + thread, thread->task, thread->task->map); + return; + } + if (thread->task->map->pmap->lock.lock_data) { + db_printf("[Warning: thread %x's task %x's map %x's " + "pmap %x is locked]\n", thread, thread->task, + thread->task->map, thread->task->map->pmap); + } + apr_data.bits = 0; + apr_data.field.st_base = M88K_BTOP(thread->task->map->pmap->sdt_paddr); + apr_data.field.wt = 0; + apr_data.field.g = 1; + apr_data.field.ci = 0; + apr_data.field.te = 1; + value = apr_data.bits; + if (verbose_flag) { + db_printf("[thread %x task %x map %x pmap %x UAPR is %x]\n", + thread, thread->task, thread->task->map, + thread->task->map->pmap, value); + } + } + else +#endif /* 0 */ + { + if (cmmu_num == -1) + { + if (cpu_cmmu[0].pair[DATA_CMMU] == 0) + { + db_printf("ack! can't figure my own data cmmu number.\n"); + return; + } + cmmu_num = cpu_cmmu[0].pair[DATA_CMMU] - cmmu; + if (verbose_flag) + db_printf("The data cmmu for cpu#%d is cmmu#%d.\n", + 0, cmmu_num); + } + else if (cmmu_num < 0 || cmmu_num >= MAX_CMMUS) + { + db_printf("invalid cpu number [%d]... must be in range [0..%d]\n", + cmmu_num, MAX_CMMUS - 1); + return; + } + + if (cmmu[cmmu_num].cmmu_alive == 0) + { + db_printf("warning: cmmu %d is not alive.\n", cmmu_num); + #if 0 + return; + #endif + } + + if (!verbose_flag) + { + if (!(cmmu[cmmu_num].cmmu_regs->sctr & CMMU_SCTR_SE)) + db_printf("WARNING: snooping not enabled for CMMU#%d.\n", + cmmu_num); + } + else + { + int i; + for (i=0; i<MAX_CMMUS; i++) + if ((i == cmmu_num || cmmu[i].cmmu_alive) && + (verbose_flag>1 || !(cmmu[i].cmmu_regs->sctr&CMMU_SCTR_SE))) + { + db_printf("CMMU#%d (cpu %d %s) snooping %s\n", i, + cmmu[i].cmmu_cpu, cmmu[i].which ? "data" : "inst", + (cmmu[i].cmmu_regs->sctr & CMMU_SCTR_SE) ? "on":"OFF"); + } + } + + if (supervisor_flag) + value = cmmu[cmmu_num].cmmu_regs->sapr; + else + value = cmmu[cmmu_num].cmmu_regs->uapr; + + } + + /******* LOOK AT THE BATC ** (if not a thread) **************/ +#if 0 +#if SHADOW_BATC + if (thread == 0) + { + int i; + union batcu batc; + for (i = 0; i < 8; i++) { + batc.bits = cmmu[cmmu_num].batc[i]; + if (batc.field.v == 0) { + if (verbose_flag>1) + db_printf("cmmu #%d batc[%d] invalid.\n", cmmu_num, i); + } else { + db_printf("cmmu#%d batc[%d] v%08x p%08x", cmmu_num, i, + batc.field.lba << 18, batc.field.pba); + if (batc.field.s) db_printf(", supervisor"); + if (batc.field.wt) db_printf(", wt.th"); + if (batc.field.g) db_printf(", global"); + if (batc.field.ci) db_printf(", cache inhibit"); + if (batc.field.wp) db_printf(", write protect"); + } + } + } +#endif +#endif /* 0 */ + + /******* SEE WHAT A PROBE SAYS (if not a thread) ***********/ +#if 0 + if (thread == 0) +#endif /* 0 */ + { + union ssr ssr; + struct cmmu_regs *cmmu_regs = cmmu[cmmu_num].cmmu_regs; + cmmu_regs->sar = address; + cmmu_regs->scr = supervisor_flag ? CMMU_PROBE_SUPER : CMMU_PROBE_USER; + ssr.bits = cmmu_regs->ssr; + if (verbose_flag > 1) + db_printf("probe of 0x%08x returns ssr=0x%08x\n", + address, ssr.bits); + if (ssr.field.v) + db_printf("PROBE of 0x%08x returns phys=0x%x", + address, cmmu_regs->sar); + else + db_printf("PROBE fault at 0x%x", cmmu_regs->pfADDRr); + if (ssr.field.ce) db_printf(", copyback err"); + if (ssr.field.be) db_printf(", bus err"); + if (ssr.field.wt) db_printf(", writethrough"); + if (ssr.field.sp) db_printf(", sup prot"); + if (ssr.field.g) db_printf(", global"); + if (ssr.field.ci) db_printf(", cache inhibit"); + if (ssr.field.m) db_printf(", modified"); + if (ssr.field.u) db_printf(", used"); + if (ssr.field.wp) db_printf(", write prot"); + if (ssr.field.bh) db_printf(", BATC"); + db_printf(".\n"); + } + + /******* INTERPRET AREA DESCRIPTOR *********/ + { + union apr_template apr_template; + apr_template.bits = value; + if (verbose_flag > 1) { + db_printf("CMMU#%d", cmmu_num); +#if 0 + if (thread == 0) + db_printf("CMMU#%d", cmmu_num); + else + db_printf("THREAD %x", thread); +#endif /* 0 */ + db_printf(" %cAPR is 0x%08x\n", + supervisor_flag ? 'S' : 'U', apr_template.bits); + } + db_printf("CMMU#%d", cmmu_num); +#if 0 + if (thread == 0) + db_printf("CMMU#%d", cmmu_num); + else + db_printf("THREAD %x", thread); +#endif /* 0 / + db_printf(" %cAPR: SegTbl: 0x%x000p", + supervisor_flag ? 'S' : 'U', apr_template.field.st_base); + if (apr_template.field.wt) db_printf(", WTHRU"); + else db_printf(", !wthru"); + if (apr_template.field.g) db_printf(", GLOBAL"); + else db_printf(", !global"); + if (apr_template.field.ci) db_printf(", $INHIBIT"); + else db_printf(", $ok"); + if (apr_template.field.te) db_printf(", VALID"); + else db_printf(", !valid"); + db_printf(".\n"); + + /* if not valid, done now */ + if (apr_template.field.te == 0) { + db_printf("<would report an error, valid bit not set>\n"); + return; + } + + value = apr_template.field.st_base << 12; /* now point to seg page */ + } + + /* translate value from physical to virtual */ + if (verbose_flag) + db_printf("[%x physical is %x virtual]\n", value, value + VEQR_ADDR); + value += VEQR_ADDR; + + virtual_address.bits = address; + + /****** ACCESS SEGMENT TABLE AND INTERPRET SEGMENT DESCRIPTOR *******/ + { + union sdt_entry_template std_template; + if (verbose_flag) + db_printf("will follow to entry %d of page at 0x%x...\n", + virtual_address.field.segment_table_index, value); + value |= virtual_address.field.segment_table_index * + sizeof(struct sdt_entry); + + if (badwordaddr(value)) { + db_printf("ERROR: unable to access page at 0x%08x.\n", value); + return; + } + + std_template.bits = *(unsigned *)value; + if (verbose_flag > 1) + db_printf("SEG DESC @0x%x is 0x%08x\n", value, std_template.bits); + db_printf("SEG DESC @0x%x: PgTbl: 0x%x000", + value, std_template.sdt_desc.table_addr); + if (std_template.sdt_desc.wt) db_printf(", WTHRU"); + else db_printf(", !wthru"); + if (std_template.sdt_desc.sup) db_printf(", S-PROT"); + else db_printf(", UserOk"); + if (std_template.sdt_desc.g) db_printf(", GLOBAL"); + else db_printf(", !global"); + if (std_template.sdt_desc.no_cache) db_printf(", $INHIBIT"); + else db_printf(", $ok"); + if (std_template.sdt_desc.prot) db_printf(", W-PROT"); + else db_printf(", WriteOk"); + if (std_template.sdt_desc.dtype) db_printf(", VALID"); + else db_printf(", !valid"); + db_printf(".\n"); + + /* if not valid, done now */ + if (std_template.sdt_desc.dtype == 0) { + db_printf("<would report an error, STD entry not valid>\n"); + return; + } + + value = std_template.sdt_desc.table_addr << 12; + } + + /* translate value from physical to virtual */ + if (verbose_flag) + db_printf("[%x physical is %x virtual]\n", value, value + VEQR_ADDR); + value += VEQR_ADDR; + + /******* PAGE TABLE *********/ + { + union pte_template pte_template; + if (verbose_flag) + db_printf("will follow to entry %d of page at 0x%x...\n", + virtual_address.field.page_table_index, value); + value |= virtual_address.field.page_table_index * + sizeof(struct pt_entry); + + if (badwordaddr(value)) { + db_printf("error: unable to access page at 0x%08x.\n", value); + return; + } + + pte_template.bits = *(unsigned *)value; + if (verbose_flag > 1) + db_printf("PAGE DESC @0x%x is 0x%08x.\n", value, pte_template.bits); + db_printf("PAGE DESC @0x%x: page @%x000", + value, pte_template.pte.pfn); + if (pte_template.pte.wired) db_printf(", WIRE"); + else db_printf(", !wire"); + if (pte_template.pte.wt) db_printf(", WTHRU"); + else db_printf(", !wthru"); + if (pte_template.pte.sup) db_printf(", S-PROT"); + else db_printf(", UserOk"); + if (pte_template.pte.g) db_printf(", GLOBAL"); + else db_printf(", !global"); + if (pte_template.pte.ci) db_printf(", $INHIBIT"); + else db_printf(", $ok"); + if (pte_template.pte.modified) db_printf(", MOD"); + else db_printf(", !mod"); + if (pte_template.pte.pg_used) db_printf(", USED"); + else db_printf(", !used"); + if (pte_template.pte.prot) db_printf(", W-PROT"); + else db_printf(", WriteOk"); + if (pte_template.pte.dtype) db_printf(", VALID"); + else db_printf(", !valid"); + db_printf(".\n"); + + /* if not valid, done now */ + if (pte_template.pte.dtype == 0) { + db_printf("<would report an error, PTE entry not valid>\n"); + return; + } + + value = pte_template.pte.pfn << 12; + if (verbose_flag) + db_printf("will follow to byte %d of page at 0x%x...\n", + virtual_address.field.page_offset, value); + value |= virtual_address.field.page_offset; + + if (badwordaddr(value)) { + db_printf("error: unable to access page at 0x%08x.\n", value); + return; + } + } + + /* translate value from physical to virtual */ + if (verbose_flag) + db_printf("[%x physical is %x virtual]\n", value, value + VEQR_ADDR); + value += VEQR_ADDR; + + db_printf("WORD at 0x%x is 0x%08x.\n", value, *(unsigned *)value); +} + + +void +cmmu_cache_state(unsigned addr, unsigned supervisor_flag) +{ + static char *vv_name[4] = + {"exclu-unmod", "exclu-mod", "shared-unmod", "invalid"}; + int cmmu_num; + for (cmmu_num = 0; cmmu_num < MAX_CMMUS; cmmu_num++) + { + union ssr ssr; + union cssp cssp; + struct cmmu_regs *R; + unsigned tag, line; + if (!cmmu[cmmu_num].cmmu_alive) + continue; + R = cmmu[cmmu_num].cmmu_regs; + db_printf("cmmu #%d %s cmmu for cpu %d.\n", cmmu_num, + cmmu[cmmu_num].which ? "data" : "inst", + cmmu[cmmu_num].cmmu_cpu); + R->sar = addr; + R->scr = supervisor_flag ? CMMU_PROBE_SUPER : CMMU_PROBE_USER; + + ssr.bits = R->ssr; + if (!ssr.field.v) { + db_printf("PROBE of 0x%08x faults.\n",addr); + continue; + } + db_printf("PROBE of 0x%08x returns phys=0x%x", addr, R->sar); + + tag = R->sar & ~0xfff; + cssp.bits = R->cssp; + + /* check to see if any of the tags for the set match the address */ + for (line = 0; line < 4; line++) + { + if (VV(cssp, line) == VV_INVALID) + { + db_printf("line %d invalid.\n", line); + continue; /* line is invalid */ + } + if (D(cssp, line)) + { + db_printf("line %d disabled.\n", line); + continue; /* line is disabled */ + } + + if ((R->ctp[line] & ~0xfff) != tag) + { + db_printf("line %d address tag is %x.\n", line, + (R->ctp[line] & ~0xfff)); + continue; + } + db_printf("found in line %d as %08x (%s).\n", + line, R->cdp[line], vv_name[VV(cssp, line)]); + } + } +} + +void +show_cmmu_info(unsigned addr) +{ + int cmmu_num; + cmmu_cache_state(addr, 1); + + for (cmmu_num = 0; cmmu_num < MAX_CMMUS; cmmu_num++) + if (cmmu[cmmu_num].cmmu_alive) { + db_printf("cmmu #%d %s cmmu for cpu %d: ", cmmu_num, + cmmu[cmmu_num].which ? "data" : "inst", + cmmu[cmmu_num].cmmu_cpu); + cmmu_show_translation(addr, 1, 0, cmmu_num); + } +} +#endif /* end if DDB */ diff --git a/sys/arch/mvme88k/mvme88k/conf.c b/sys/arch/mvme88k/mvme88k/conf.c new file mode 100644 index 00000000000..2e4f06a6700 --- /dev/null +++ b/sys/arch/mvme88k/mvme88k/conf.c @@ -0,0 +1,378 @@ +/* $NetBSD: conf.c,v 1.28 1995/04/19 22:37:27 mycroft Exp $ */ + +/*- + * Copyright (c) 1991 The Regents of the University of California. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)conf.c 7.9 (Berkeley) 5/28/91 + */ + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/buf.h> +#include <sys/ioctl.h> +#include <sys/tty.h> +#include <sys/conf.h> +#include <sys/vnode.h> + +int ttselect __P((dev_t, int, struct proc *)); + +bdev_decl(sw); +#include "st.h" +bdev_decl(st); +#include "sd.h" +bdev_decl(sd); +#include "cd.h" +bdev_decl(cd); + +#if notyet +#include "ch.h" +bdev_decl(ch); +#include "xd.h" +bdev_decl(xd); +#endif /* notyet */ + +#include "vnd.h" +bdev_decl(vnd); + +#ifdef LKM +int lkmenodev(); +#else +#define lkmenodev enodev +#endif + +struct bdevsw bdevsw[] = +{ + bdev_notdef(), /* 0 */ + bdev_notdef(), /* 1 */ + bdev_notdef(), /* 2 */ + bdev_swap_init(1,sw), /* 3: swap pseudo-device */ + bdev_disk_init(NSD,sd), /* 4: SCSI disk */ + bdev_tape_init(NST,st), /* 5: SCSI tape */ + bdev_disk_init(NCD,cd), /* 6: SCSI CD-ROM */ + bdev_notdef(), /* 7 */ + bdev_disk_init(NVND,vnd), /* 8: vnode disk driver */ + bdev_notdef(), /* 9 */ +#if notyet + bdev_disk_init(NXD,xd), /* 10: XD disk */ +#endif /* notyet */ + bdev_notdef(), /* 11 */ + bdev_notdef(), /* 12 */ + bdev_lkm_dummy(), /* 13 */ + bdev_lkm_dummy(), /* 14 */ + bdev_lkm_dummy(), /* 15 */ + bdev_lkm_dummy(), /* 16 */ + bdev_lkm_dummy(), /* 17 */ + bdev_lkm_dummy(), /* 18 */ +}; +int nblkdev = sizeof(bdevsw) / sizeof(bdevsw[0]); + +cdev_decl(cn); +cdev_decl(ctty); +#define mmread mmrw +#define mmwrite mmrw +cdev_decl(mm); +cdev_decl(sw); + +#if notyet +#include "sram.h" +cdev_decl(sram); + +#include "vmel.h" +cdev_decl(vmel); + +#include "vmes.h" +cdev_decl(vmes); + +#include "nvram.h" +cdev_decl(nvram); + +#include "flash.h" +cdev_decl(flash); +#endif /* notyet */ + +#include "pty.h" +#define ptstty ptytty +#define ptsioctl ptyioctl +cdev_decl(pts); +#define ptctty ptytty +#define ptcioctl ptyioctl +cdev_decl(ptc); +cdev_decl(log); +cdev_decl(fd); + +#if notyet +#include "zs.h" +cdev_decl(zs); +#endif /* notyet */ +#include "cl.h" +cdev_decl(cl); + +#include "bugtty.h" +cdev_decl(bugtty); + +/* open, close, write, ioctl */ +#define cdev_lp_init(c,n) { \ + dev_init(c,n,open), dev_init(c,n,close), (dev_type_read((*))) enodev, \ + dev_init(c,n,write), dev_init(c,n,ioctl), (dev_type_stop((*))) enodev, \ + 0, seltrue, (dev_type_mmap((*))) enodev } + +/* open, close, ioctl, mmap, ioctl */ +#define cdev_mdev_init(c,n) { \ + dev_init(c,n,open), dev_init(c,n,close), dev_init(c,n,read), \ + dev_init(c,n,write), dev_init(c,n,ioctl), \ + (dev_type_stop((*))) enodev, 0, (dev_type_select((*))) enodev, \ + dev_init(c,n,mmap) } + +#if notyet +#include "lp.h" +cdev_decl(lp); +#include "lptwo.h" +cdev_decl(lptwo); +#endif /* notyet */ + +cdev_decl(st); +cdev_decl(sd); +cdev_decl(cd); +cdev_decl(xd); +cdev_decl(vnd); + +dev_decl(filedesc,open); + +#include "bpfilter.h" +cdev_decl(bpf); + +#include "tun.h" +cdev_decl(tun); + +#ifdef LKM +#define NLKM 1 +#else +#define NLKM 0 +#endif + +cdev_decl(lkm); + +struct cdevsw cdevsw[] = +{ + cdev_cn_init(1,cn), /* 0: virtual console */ + cdev_ctty_init(1,ctty), /* 1: controlling terminal */ + cdev_mm_init(1,mm), /* 2: /dev/{null,mem,kmem,...} */ + cdev_swap_init(1,sw), /* 3: /dev/drum (swap pseudo-device) */ + cdev_tty_init(NPTY,pts), /* 4: pseudo-tty slave */ + cdev_ptc_init(NPTY,ptc), /* 5: pseudo-tty master */ + cdev_log_init(1,log), /* 6: /dev/klog */ +#if notyet + cdev_mdev_init(NSRAM,sram), /* 7: /dev/sramX */ +#else /* notyet */ + cdev_notdef(), /* 7: /dev/sramX */ +#endif /* notyet */ + cdev_disk_init(NSD,sd), /* 8: SCSI disk */ + cdev_disk_init(NCD,cd), /* 9: SCSI CD-ROM */ +#if notyet + cdev_mdev_init(NNVRAM,nvram), /* 10: /dev/nvramX */ + cdev_mdev_init(NFLASH,flash), /* 11: /dev/flashX */ + cdev_tty_init(NZS,zs), /* 12: SCC serial (tty[a-d]) */ +#else + cdev_notdef(), /* 10 */ + cdev_notdef(), /* 11 */ + cdev_notdef(), /* 12: SCC serial (tty[a-d]) */ +#endif /* notyet */ + cdev_tty_init(NCL,cl), /* 13: CL-CD1400 serial (tty0[0-3]) */ + cdev_tty_init(NBUGTTY,bugtty), /* 14: BUGtty (ttyB) */ + cdev_notdef(), /* 15 */ + cdev_notdef(), /* 16 */ + cdev_notdef(), /* 17: concatenated disk */ + cdev_notdef(), /* 18 */ + cdev_disk_init(NVND,vnd), /* 19: vnode disk */ + cdev_tape_init(NST,st), /* 20: SCSI tape */ + cdev_fd_init(1,filedesc), /* 21: file descriptor pseudo-dev */ + cdev_bpftun_init(NBPFILTER,bpf),/* 22: berkeley packet filter */ + cdev_bpftun_init(NTUN,tun), /* 23: network tunnel */ + cdev_lkm_init(NLKM,lkm), /* 24: loadable module driver */ + cdev_notdef(), /* 25 */ +#if notyet + cdev_disk_init(NXD,xd), /* 26: XD disk */ +#else + cdev_notdef(), /* 26: XD disk */ +#endif /* notyet */ + cdev_notdef(), /* 27 */ +#if notyet + cdev_lp_init(NLP,lp), /* 28: lp */ + cdev_lp_init(NLPTWO,lptwo), /* 29: lptwo */ +#else + cdev_notdef(), /* 28: lp */ + cdev_notdef(), /* 29: lptwo */ +#endif /* notyet */ + cdev_notdef(), /* 30 */ +#if notyet + cdev_mdev_init(NVMEL,vmel), /* 31: /dev/vmelX */ + cdev_mdev_init(NVMES,vmes), /* 32: /dev/vmesX */ +#else /* notyet */ + cdev_notdef(), /* 31: /dev/vmelX */ + cdev_notdef(), /* 32: /dev/vmesX */ +#endif /* notyet */ + cdev_lkm_dummy(), /* 33 */ + cdev_lkm_dummy(), /* 34 */ + cdev_lkm_dummy(), /* 35 */ + cdev_lkm_dummy(), /* 36 */ + cdev_lkm_dummy(), /* 37 */ + cdev_lkm_dummy(), /* 38 */ +}; +int nchrdev = sizeof(cdevsw) / sizeof(cdevsw[0]); + +int mem_no = 2; /* major device number of memory special file */ + +/* + * Swapdev is a fake device implemented + * in sw.c used only internally to get to swstrategy. + * It cannot be provided to the users, because the + * swstrategy routine munches the b_dev and b_blkno entries + * before calling the appropriate driver. This would horribly + * confuse, e.g. the hashing routines. Instead, /dev/drum is + * provided as a character (raw) device. + */ +dev_t swapdev = makedev(3, 0); + +/* + * Returns true if dev is /dev/mem or /dev/kmem. + */ +iskmemdev(dev) + dev_t dev; +{ + + return (major(dev) == mem_no && minor(dev) < 2); +} + +/* + * Returns true if dev is /dev/zero. + */ +iszerodev(dev) + dev_t dev; +{ + + return (major(dev) == mem_no && minor(dev) == 12); +} + +static int chrtoblktbl[] = { + /* XXXX This needs to be dynamic for LKMs. */ + /*VCHR*/ /*VBLK*/ + /* 0 */ NODEV, + /* 1 */ NODEV, + /* 2 */ NODEV, + /* 3 */ NODEV, + /* 4 */ NODEV, + /* 5 */ NODEV, + /* 6 */ NODEV, + /* 7 */ NODEV, + /* 8 */ 4, /* SCSI disk */ + /* 9 */ 6, /* SCSI CD-ROM */ + /* 10 */ NODEV, + /* 11 */ NODEV, + /* 12 */ NODEV, + /* 13 */ NODEV, + /* 14 */ NODEV, + /* 15 */ NODEV, + /* 16 */ NODEV, + /* 17 */ NODEV, + /* 18 */ NODEV, + /* 19 */ 8, /* vnode disk */ + /* 20 */ NODEV, + /* 21 */ NODEV, + /* 22 */ NODEV, + /* 23 */ NODEV, + /* 24 */ NODEV, + /* 25 */ NODEV, + /* 26 */ 10, /* XD disk */ +}; + +/* + * Convert a character device number to a block device number. + */ +chrtoblk(dev) + dev_t dev; +{ + int blkmaj; + + if (major(dev) >= nchrdev || + major(dev) >= sizeof(chrtoblktbl)/sizeof(chrtoblktbl[0])) + return (NODEV); + blkmaj = chrtoblktbl[major(dev)]; + if (blkmaj == NODEV) + return (NODEV); + return (makedev(blkmaj, minor(dev))); +} + +/* + * Convert a character device number to a block device number. + */ +dev_t +blktochr(dev) + dev_t dev; +{ + int blkmaj = major(dev); + int i; + + if (blkmaj >= nblkdev) + return (NODEV); + for (i = 0; i < sizeof(chrtoblktbl)/sizeof(chrtoblktbl[0]); i++) + if (blkmaj == chrtoblktbl[i]) + return (makedev(i, minor(dev))); + return (NODEV); +} + +/* + * This entire table could be autoconfig()ed but that would mean that + * the kernel's idea of the console would be out of sync with that of + * the standalone boot. I think it best that they both use the same + * known algorithm unless we see a pressing need otherwise. + */ +#include <dev/cons.h> + +#define zscnpollc nullcnpollc +cons_decl(zs); +#define clcnpollc nullcnpollc +cons_decl(cl); +#define bugttycnpollc nullcnpollc +cons_decl(bugtty); + +struct consdev constab[] = { +#if NZS > 0 + cons_init(zs), +#endif +#if NCL > 0 + cons_init(cl), +#endif +#if NBUGTTY > 0 + cons_init(bugtty), +#endif + { 0 }, +}; diff --git a/sys/arch/mvme88k/mvme88k/eh.S b/sys/arch/mvme88k/mvme88k/eh.S new file mode 100644 index 00000000000..c16d5244a9f --- /dev/null +++ b/sys/arch/mvme88k/mvme88k/eh.S @@ -0,0 +1,1798 @@ +/* + * Mach Operating System + * Copyright (c) 1993-1991 Carnegie Mellon University + * Copyright (c) 1991 OMRON Corporation + * Copyright (c) 1996 Nivas Madhur + * All Rights Reserved. + * + * Permission to use, copy, modify and distribute this software and its + * documentation is hereby granted, provided that both the copyright + * notice and this permission notice appear in all copies of the + * software, derivative works or modified versions, and any portions + * thereof, and that both notices appear in supporting documentation. + * + * CARNEGIE MELLON AND OMRON ALLOW FREE USE OF THIS SOFTWARE IN ITS "AS IS" + * CONDITION. CARNEGIE MELLON AND OMRON DISCLAIM ANY LIABILITY OF ANY KIND + * FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. + * + * Carnegie Mellon requests users of this software to return to + * + * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU + * School of Computer Science + * Carnegie Mellon University + * Pittsburgh PA 15213-3890 + * + * any improvements or extensions that they make and grant Carnegie the + * rights to redistribute these changes. + */ +/* + * HISTORY + * 1. Should get rid of SR0 reference for thread stuff. + * 2. Make up my mind what is _kstack. I think it + * should be p->p_addr+UPAGES. (p_addr + * is pointing to user struct and swapin is + * making sure it is updated) + * Whatever is _kstack, its usage in this file should be + * revisited. + */ + + /* + **************************************************************RCS****** + * + * ------------------------------------------------------------------- + * ; In the following discussion, references are made to: ; + * ; MC88100 - RISC MICROPROCESSOR USER'S MANUAL ; + * ; (second edition). Reference in []s refer to section numbers. ; + * ; ; + * ; This discussion assumes that you are at least vaguely familiar ; + * ; with 88100 exception handling (chapter 6), the MACH kernel, and ; + * ; that you have a brain (and use it while reading this). ; + * ; ; + * ; I also assume (and hope) that you're not offended by ; + * ; frequent misspellings. ; + * ; ; + * ; Jeffrey Friedl ; + * ; jfriedl@rna.ncl.omron.co.jp ; + * ; December, 1989 ; + * ------------------------------------------------------------------- + * + * EXCEPTIONS, INTERRUPTS, and TRAPS + * --------------------------------- + * This is the machine exception handler. + * In the MC88100, various "conditions" cause an exception, where + * processing momentarily jumps here to "service" the exception, + * and then continues where it left off. + * + * There are a number of different types of exceptions. + * For example, exception #6 is the privilege violation exception which + * is raised when the user tries to execute a supervisor-only instruction. + * + * Exception #1 is the interrupt exception, and is raised when an + * outside device raises the INT line on the CPU. This happens, + * for example, when the clock signals that it is time for a context + * switch, or perhaps the disk drive signaling that some operation + * is complete. + * + * Traps are also exceptions. Traps are ways for user programs to request + * kernel operations. For example, "tcnd eq0, r0, 128" will raise + * exception 128, the system call exception. + * + * + * SERVICING AN EXCEPTION + * ----------------------- + * When an exception occurs, each control register is saved in its + * respective shadow register and execution continues from the + * appropriate exception handler. The exception handler must + * - save the context from the time of the exception + * - service the exception + * - restore the context (registers, etc) + * - pick up from where the exception occurred. + * + * The context is saved on a stack. Actually, in the user_state area + * in the PCB if the exception happens in user mode. + * + * Servicing the exception is usually straightforward and in fact not dealt + * with very much here. Usually a C routine is called to handle it. + * For example, when a privilege exception is raised, the routine that sends + * an "illegal instruction" signal to the offending process is called. + * + * When the exception has been serviced, the context is restored from the + * stack and execution resumes from where it left off. + * + * In more detail: + * + * Saving the exception-time context. + * --------------------------------- + * In saving the exception-time context, we copy the shadow and general + * purpose registers to memory. Since one exception may occur while + * servicing another, the memory used to save the exception-time context may + * not be static (i.e. the same every time). Thus, memory on a stack is set + * aside for the exception frame (area where the exception-time context is + * saved). The same stack is also used when C routines are called (to + * service the exception). + * + * Each process has a stack in kernel space (called the "kernel stack", + * short for "process's kernel stack) as well as the user space stack. When + * entering the kernel from user space, the kernel stack is unused. On this + * stack we save the exception state and (most likely call a C routine to) + * service the exception. + * + * Before servicing an exception, several issues must be addressed. + * + * 1) When an interrupt is recognized by the hardware, the data pipeline is + * allowed to clear. However, if one of these data accesses faults (bad + * reference, or a reference to a page which needs to be swapped in), that + * reference, as well as any others in the pipeline at the time (at most + * three total) are left there, to be taken care of by the exception + * handler [6.4.1]. This involves swapping in the proper page and + * manually doing the appropriate load or store. + * + * The other (at most, two other) data accesses that might have been in + * the pipeline must also be manually completed (even though they may not + * be at fault [yes, that's a bad pun, thank you]). + * + * 2) If any of the (at most three) uncompleted data access in the pipeline + * are loads (from memory to a register), then the bit for the destination + * register is set in the SSBR. Since the hardware will never complete + * that load (since we do it manually), the hardware will never clear that + * SSBR bit. Thus, we must clear it manually. If this isn't done, the + * system will hang waiting for a bit to clear that will never. + * + * 3) If the exception is the privilege violation exception, the bounds + * violation exception, or the misaligned access exception, the + * destination register bit in the SSBR may need to be cleared. + * + * 4) If the exception is one of the floating exceptions, then the + * destination register for that floating process won't be written, + * and the SSBR must be cleared explicitly. + * + * 5) The FPU must be enabled (as it is disabled by the exception processing + * hardware) and allowed to complete actions in progress. This is so + * so that it may be used in the servicing of any instruction. + * When the FPU is being restarted, operations attempting to complete + * may themselves fault (raising another exception). + * + * More on Restarting the FPU + * -------------------------- + * The manual [section 6.4.3.4] gives only minor mention to this + * rather complex task. Before the FPU is restarted all SSBR bits are + * cleared for actions that the exception handler completes (as mentioned + * above) so that the SSBR is clear unless there are FPU operations that + * have not actually been completed (and hence not written to the registers). + * Also, all control registers (at least all those that we care about) are + * saved to the stack exception frame before the FPU is restarted (this + * is important... the reason comes later). + * + * The FPU is restarted by doing an rte to a trap-not-taken (the rte + * actually enables the fpu because we ensure that the EPSR has the + * FPU-enable bit on; the trap-not-taken ensures anything in the FPU + * completes by waiting until scoreboard register is clear). + * + * At the time the FPU is restarted (the rte to the trap-not-taken) the FPU + * can write to ANY of the general registers. Thus, we must make sure that + * all general registers (r1..r31) are in their pre-exception state so that + * when saved to the exception frame after the FPU is enabled, they properly + * reflect any changes made by the FPU in being restarted. + * + * Because we can't save the pointer to the exception frame in a general + * register during the FPU restart (it could get overwritten by the FPU!), + * we save it in a control register, SR3, during the restart. + * + * + * HOWEVER ..... + * + * Because other uncompleted actions in the FPU may fault when the FPU is + * restarted, a new exception may be raised during the restart. This may + * happen recursively a number of times. Thus, during a restart, ANY register + * whatsoever may be modified, including control registers. Because of this + * we must make sure that the exception handler preserves SR3 throughout + * servicing an exception so that, if the exception had been raised during + * an FPU restart, it is returned unmolested when control returns to the FPU + * restart. + * + * Thus: if an exception is from kernel space, we MUST preserve SR3. + * (if it from user space, no FPU-enable can be in progress and SR3 is + * unimportant). + * + * Now is a good time to recap SR0..SR3 usage: + * SR0 - + * SR1 - CPU flags (exception handler flags) + * SR2 - generally free + * SR3 - free only if the exception is from user mode + * + * Once the FPU has been restarted, the general registers are saved to the + * exception frame. If the exception is not the interrupt exception, + * interrupts are enabled and any faulted data accesses (see above) are + * serviced. In either case, the exception is then serviced (usually by + * calling a C routine). After servicing, any faulted data accesses are + * serviced (if it had been the interrupt exception). The context is then + * restored and control returns to where the exception occurred. + * + */ + +#ifndef ASSEMBLER +#define ASSEMBLER +#endif + +#include <machine/trap.h> /* for T_ defines */ +#include <machine/asm.h> + +/* + * The exception frame as defined in "machine/pcb.h" (among other places) is + * a bit outdated and needs to be changed. Until then, we'll define some + * pseudo-fields there for our needs. + * + * EF_SR3 A place to save the exception-time SR3 from just after the + * time when an exception is raised until just after the FPU + * has been restarted. This does not necessarly conflict with + * the general registers (though it can if you're not careful) + * and so we can use a spot later used to save a general register. + * + * EF_FLAGS This is just the old EF_MODE. "EF_MODE" isn't a very good name. + */ +#define EF_SR3 (EF_R0 + 5) +#define EF_FLAGS EF_MODE + +#define FLAG_FROM_KERNEL 8 /* this should be in locore.h */ + + text + align 8 + +/*************************************************************************** + *************************************************************************** + ** + ** #define PREP(NAME, NUM, BIT, SSBR_STUFF, FLAG_CHECK) + ** + ** This is the "exception processing preparaton" common to all exception + ** processing. It is used in the following manor: + ** + ** LABEL(foo_handler) + ** PREP("foo", 11, DEBUG_FOO_BIT, No_SSBR_Stuff, No_Precheck) + ** CALL(_trap, T_FOO_FAULT, r31) + ** DONE(DEBUG_FOO_BIT) + ** + ** This defines the exception handler for the "foo" exception. + ** The arguments ro PREP(): + ** NAME - String for debugging (more info later) + ** NUM - The exception number [see the manual, Table 6-1] + ** BIT - Bit to check in eh_debug for debugging (more info later) + ** SSBR_STUFF - + ** If the exception might leave some bits in the SSBR set, + ** this should indicate how they are cleared. + ** FLAG_PRECHECK - + ** This is for the data access exception only. See it for + ** more info. + ** + ** + ** What's in between PREP() and DONE() (usually a CALL) is the actual + ** servicing of the interrupt. During this time, any register may + ** be used freely as they've all been saved in the exception frame + ** (which is pointed-to by r31). + **/ +#define PREP(NAME, NUM, BIT, SSBR_STUFF, FLAG_PRECHECK) ; \ + xcr FLAGS, FLAGS, SR1 ; \ + FLAG_PRECHECK ; \ + ; \ + /* the bsr later clobbers r1, so save now */ ; \ + stcr r1, SR2 /* r1 now free */ ; \ + ; \ + /* set or clear the FLAG_FROM_KERNEL bit */ ; \ + ldcr r1, EPSR ; \ + bb0.n PSR_SUPERVISOR_MODE_BIT, r1, 1f ; \ + clr FLAGS, FLAGS, 1<FLAG_FROM_KERNEL> ; \ + set FLAGS, FLAGS, 1<FLAG_FROM_KERNEL> ; \ + ; \ + /* get a stack (exception frame) */ ; \ + 1: bsr setup_phase_one ; \ + ; \ + /* TMP2 now free -- use to set EF_VECTOR */ ; \ + or TMP2, r0, NUM ; \ + st TMP2, r31, REG_OFF(EF_VECTOR) ; \ + ; \ + /* Clear any bits in the SSBR (held in TMP) */ ; \ + /* SSBR_STUFF may be empty, though. */ ; \ + SSBR_STUFF ; \ + ; \ + /* call setup_phase_two to restart the FPU */ ; \ + /* and to save all general registers. */ ; \ + bsr setup_phase_two ; \ + ; \ + /* All general regs free -- do any debugging */ ; \ + PREP_DEBUG(BIT, NAME) + +#undef EH_DEBUG +#define EH_DEBUG 1 + +/* Some defines for use with PREP() */ +#define No_SSBR_Stuff /* empty */ +#define Clear_SSBR_Dest bsr clear_dest_ssbr_bit +#define No_Precheck /* empty */ +#define Data_Precheck \ + bb1.n FLAG_IGNORE_DATA_EXCEPTION, FLAGS, ignore_data_exception + +#if EH_DEBUG + /* + * If we allow debugging, there is a variable "eh_debug" + * in which there is a bit for each exception. If the bit + * is set for an exception, debugging information is printed + * about that exception whenever it occurs. + * + * The bits are defined in "locore.h" + */ + LABEL(_eh_debug) word 0x00000000 + + /* + * additional pre-servicing preparation to be done when + * debugging... check eh_debug and make the call if + * need be. + */ + #define PREP_DEBUG(DebugNumber, Name) \ + or.u r2, r0, hi16(_eh_debug) ; \ + ld r3, r2, lo16(_eh_debug) ; \ + bb0 DebugNumber, r3, 4f ; \ + /* call MY_info(ef,thread,flags,kind)*/ ; \ + or r2, r30, r0 ; \ + ldcr r3, SR0 ; \ + ldcr r4, SR1 ; \ + or.u r5, r0, hi16(2f) ; \ + or r5, r5, lo16(2f) ; \ + bsr.n _MY_info ; \ + subu r31, r31, 40 ; \ + br.n 4f ; \ + addu r31, r31, 40 ; \ + data ; \ + 2: string Name ; \ + byte 0 ; \ + align 4 ; \ + text ; \ + 4: + + + /* + * Post-servicing work to be done. + * When debugging, check "eh_debug" and call the + * debug routined if neeed be. + * + * Then, return from the interrupt handler. + */ + #define DONE(DebugNumber) \ + or.u r2, r0, hi16(_eh_debug) ; \ + ld r3, r2, lo16(_eh_debug) ; \ + bb0 DebugNumber, r3, 2f ; \ + ldcr r4, SR1 ; \ + CALL(_MY_info_done, r31, r4) ; \ + 2: br return_from_exception_handler +#else + /* + * If not debugging, then no debug-prep to do. + * Also, when you're done, you're done! (no debug check). + */ + #define PREP_DEBUG(bit, name) + #define DONE(num) br return_from_exception_handler +#endif + + +/*#########################################################################*/ +/*#### THE ACTUAL EXCEPTION HANDLER ENTRY POINTS ##########################*/ +/*#########################################################################*/ + +/* unknown exception handler */ +LABEL(unknown_handler) + PREP("unknown", 0, DEBUG_UNKNOWN_BIT, No_SSBR_Stuff, No_Precheck) + CALL(_trap, T_UNKNOWNFLT, r30) + DONE(DEBUG_UNKNOWN_BIT) + +/* interrupt exception handler */ +LABEL(interrupt_handler) + PREP("interrupt", 1, DEBUG_INTERRUPT_BIT, No_SSBR_Stuff, No_Precheck) + CALL(_ext_int, 1, r30) + DONE(DEBUG_INTERRUPT_BIT) + +/* instruction access exception handler */ +LABEL(instruction_access_handler) + PREP("inst", 2, DEBUG_INSTRUCTION_BIT, No_SSBR_Stuff, No_Precheck) + CALL(_trap, T_INSTFLT, r30) +#if 0 + /* done in trap now */ + /* + * Now, to retry the instruction. + * Copy the SNIP to the SFIP, clearing the E bit. + * Copy the SXIP to the SNIP, clearing the E bit. + */ + ld r1, r30, REG_OFF(EF_SNIP) + ld r2, r30, REG_OFF(EF_SXIP) + clr r1, r1, 1<RTE_ERROR_BIT> + clr r2, r2, 1<RTE_ERROR_BIT> + st r1, r30, REG_OFF(EF_SFIP) + st r2, r30, REG_OFF(EF_SNIP) +#endif /* 0 */ + DONE(DEBUG_INSTRUCTION_BIT) + +/* + * data access exception handler -- + * See badaddr() below for info about Data_Precheck. + */ +LABEL(data_exception_handler) + PREP("data", 3, DEBUG_DATA_BIT, No_SSBR_Stuff, Data_Precheck) + DONE(DEBUG_DATA_BIT) + +/* misaligned access exception handler */ +LABEL(misaligned_handler) + PREP("misalign", 4, DEBUG_MISALIGN_BIT, Clear_SSBR_Dest, No_Precheck) + CALL(_trap, T_MISALGNFLT, r30) + DONE(DEBUG_MISALIGN_BIT) + +/* unimplemented opcode exception handler */ +LABEL(unimplemented_handler) + PREP("unimp", 5, DEBUG_UNIMPLEMENTED_BIT, No_SSBR_Stuff, No_Precheck) + CALL(_trap, T_ILLFLT, r30) + DONE(DEBUG_UNIMPLEMENTED_BIT) + +/* + * Some versions of the chip have * a bug whereby false privilege + * violation exceptions are raised. If the valid bit in the SXIP is clear, + * it is false. If so, just return. The code before PREP handles this.... + */ +LABEL(privilege_handler) + stcr r1, SR2 /* hold r1 for a moment */ + ldcr r1, SXIP /* look at the sxip... valid bit set? */ + bb1.n RTE_VALID_BIT, r1, 1f /*skip over return if a valid exception*/ + ldcr r1, SR2 /* restore r1 */ + RTE + 1: PREP("privilege", 6, DEBUG_PRIVILEGE_BIT, Clear_SSBR_Dest, No_Precheck) + CALL(_trap, T_PRIVINFLT, r30) + DONE(DEBUG_PRIVILEGE_BIT) + +/* + * I'm not sure what the trap(T_BNDFLT,...) does, but it doesn't send + * a signal to the process... + */ +LABEL(bounds_handler) + PREP("bounds", 7, DEBUG_BOUNDS_BIT, Clear_SSBR_Dest, No_Precheck) + CALL(_trap, T_BNDFLT, r30) + DONE(DEBUG_BOUNDS_BIT) + +/* integer divide-by-zero exception handler */ +LABEL(divide_handler) + PREP("divide", 8, DEBUG_DIVIDE_BIT, Clear_SSBR_Dest, No_Precheck) + CALL(_trap, T_ZERODIV, r30) + DONE(DEBUG_DIVIDE_BIT) + +/* integer overflow exception handelr */ +LABEL(overflow_handler) + PREP("overflow", 9, DEBUG_OVERFLOW_BIT, No_SSBR_Stuff, No_Precheck) + CALL(_trap, T_OVFFLT, r30) + DONE(DEBUG_OVERFLOW_BIT) + +/* Floating-point precise handler */ +#define FPp_SSBR_STUFF bsr clear_FPp_ssbr_bit +LABEL(fp_precise_handler) + PREP("FPU precise", 114, DEBUG_FPp_BIT, FPp_SSBR_STUFF, No_Precheck) + CALL(_Xfp_precise, r0, r30) /* call fp_precise(??, exception_frame)*/ + DONE(DEBUG_FPp_BIT) + +/* Floating-point imprecise handler */ +#define FPi_SSBR_STUFF bsr clear_FPi_ssbr_bit +LABEL(fp_imprecise_handler) + PREP("FPU imprecise", 115, DEBUG_FPi_BIT, FPi_SSBR_STUFF, No_Precheck) + CALL(_Xfp_imprecise, r0, r30) /*call fp_imprecise(??,exception_frame)*/ + DONE(DEBUG_FPi_BIT) + +/* All standard system calls. */ +LABEL(_syscall_handler) + PREP("syscall", 128, DEBUG_SYSCALL_BIT, No_SSBR_Stuff, No_Precheck) + ld r13, r30, GENREG_OFF(13) + CALL(_syscall, r13, r30) /* system call no. is in r13 */ + DONE(DEBUG_SYSCALL_BIT) + +/* trap 496 comes here */ +LABEL(_bugtrap) + PREP("bugsyscall", 496, DEBUG_BUGCALL_BIT, No_SSBR_Stuff, No_Precheck) + ld r9, r30, GENREG_OFF(9) + CALL(_bugsyscall, r9, r30) /* system call no. is in r9 */ + DONE(DEBUG_SYSCALL_BIT) + +LABEL(_sigsys) + PREP("sigsys", 0, DEBUG_SIGSYS_BIT, No_SSBR_Stuff, No_Precheck) + CALL(_trap, T_SIGSYS, r30) + DONE(DEBUG_SIGSYS_BIT) + +LABEL(_sigtrap) + PREP("sigtrap", 0, DEBUG_SIGTRAP_BIT, No_SSBR_Stuff, No_Precheck) + CALL(_trap, T_SIGTRAP, r30) + DONE(DEBUG_SIGTRAP_BIT) + +LABEL(_stepbpt) + PREP("sigtrap", 0, DEBUG_SIGTRAP_BIT, No_SSBR_Stuff, No_Precheck) + CALL(_trap, T_STEPBPT, r30) + DONE(DEBUG_SIGTRAP_BIT) + +LABEL(_userbpt) + PREP("sigtrap", 0, DEBUG_SIGTRAP_BIT, No_SSBR_Stuff, No_Precheck) + CALL(_trap, T_USERBPT, r30) + DONE(DEBUG_SIGTRAP_BIT) + +#if DDB + LABEL(break) + PREP("break", 130, DEBUG_BREAK_BIT, No_SSBR_Stuff, No_Precheck) + CALL(_trap, T_KDB_BREAK, r30) + DONE(DEBUG_BREAK_BIT) + LABEL(trace) + PREP("trace", 131, DEBUG_TRACE_BIT, No_SSBR_Stuff, No_Precheck) + CALL(_trap, T_KDB_TRACE, r30) + DONE(DEBUG_TRACE_BIT) + LABEL(entry) + PREP("kdb", 132, DEBUG_KDB_BIT, No_SSBR_Stuff, No_Precheck) + CALL(_trap, T_KDB_ENTRY, r30) + DONE(DEBUG_KDB_BIT) +#else /* else not DDB */ + LABEL(break) + PREP("break", 130, DEBUG_BREAK_BIT, No_SSBR_Stuff, No_Precheck) + CALL(_trap, T_UNKNOWNFLT, r30) + DONE(DEBUG_BREAK_BIT) + LABEL(trace) + PREP("trace", 131, DEBUG_TRACE_BIT, No_SSBR_Stuff, No_Precheck) + CALL(_trap, T_UNKNOWNFLT, r30) + DONE(DEBUG_TRACE_BIT) + LABEL(entry) + PREP("unknown", 132, DEBUG_UNKNOWN_BIT, No_SSBR_Stuff, No_Precheck) + CALL(_trap, T_UNKNOWNFLT, r30) + DONE(DEBUG_KDB_BIT) +#endif /* DDB */ + + +/*--------------------------------------------------------------------------*/ + +/* + * The error exception handler. + * The error exception is raised when any other non-trap exception is raised + * while shadowing is off. This is Bad News. + * + * The shadow registers are not valid in this case (shadowing was off, ne). + * R1-R31 may be interesting though, so we'll save them. + * + * We'll not worry about trashing r26-29 here, + * since they aren't generally used. + */ +LABEL(error_handler) + /* pick up the slavestack */ + or r26, r0, r31 /* save old stack */ + or.u r31, r0, hi16(_intstack_end) + or r31, r31, lo16(_intstack_end) + + /* zero the stack, so we'll know what we're lookin' at */ + or.u r27, r0, hi16(_intstack) + or r27, r27, lo16(_intstack) + 1: cmp r28, r27, r31 + bb1 ge, r28, 2f /* branch if at the end of the stack */ + st r0, r0, r27 + br.n 1b + addu r27, r27, 4 /* bump up */ + 2: /* stack has been cleared */ + + /* ensure that stack is 8-byte aligned */ + clr r31, r31, 3<0> /* round down to 8-byte boundary */ + + /* create exception frame on stack */ + subu r31, r31, SIZEOF_EF /* r31 now our E.F. */ + + /* save old R31 and other R registers */ + st.d r0 , r31, GENREG_OFF(0) + st.d r2 , r31, GENREG_OFF(2) + st.d r4 , r31, GENREG_OFF(4) + st.d r6 , r31, GENREG_OFF(6) + st.d r8 , r31, GENREG_OFF(8) + st.d r10, r31, GENREG_OFF(10) + st.d r12, r31, GENREG_OFF(12) + st.d r14, r31, GENREG_OFF(14) + st.d r16, r31, GENREG_OFF(16) + st.d r18, r31, GENREG_OFF(18) + st.d r20, r31, GENREG_OFF(20) + st.d r22, r31, GENREG_OFF(22) + st.d r24, r31, GENREG_OFF(24) + st r30, r31, GENREG_OFF(30) + st r26, r31, GENREG_OFF(31) + + /* save shadow registers (are OLD, though) */ + ldcr r10, SXIP + st r10, r31, REG_OFF(EF_SXIP) + ldcr r10, SFIP + st r10, r31, REG_OFF(EF_SFIP) + ldcr r10, SNIP + st r10, r31, REG_OFF(EF_SNIP) + ldcr r10, SSBR + st r10, r31, REG_OFF(EF_SSBR) + ldcr r10, EPSR + st r10, r31, REG_OFF(EF_EPSR) + + ldcr r10, DMT0 + st r10, r31, REG_OFF(EF_DMT0) + ldcr r11, DMD0 + st r11, r31, REG_OFF(EF_DMD0) + ldcr r12, DMA0 + st r12, r31, REG_OFF(EF_DMA0) + + ldcr r10, DMT1 + st r10, r31, REG_OFF(EF_DMT1) + tb1 0, r0, 0 + ldcr r11, DMD1 + st r11, r31, REG_OFF(EF_DMD1) + ldcr r12, DMA1 + st r12, r31, REG_OFF(EF_DMA1) + + ldcr r10, DMT2 + st r10, r31, REG_OFF(EF_DMT2) + ldcr r11, DMD2 + st r11, r31, REG_OFF(EF_DMD2) + ldcr r12, DMA2 + st r12, r31, REG_OFF(EF_DMA2) + + ldcr r10, SR1 + st r10, r31, REG_OFF(EF_MODE) + + /* shove sr2 into EF_FPLS1 */ + ldcr r10, SR2 + st r10, r31, REG_OFF(EF_FPLS1) + + /* shove sr3 into EF_FPHS2 */ + ldcr r10, SR3 + st r10, r31, REG_OFF(EF_FPHS2) + + /* error vector is zippo numero el'zeroooo */ + st r0, r31, REG_OFF(EF_VECTOR) + + stcr r0, SSBR /* won't want shadow bits bothering us later */ + + /* + * Cheap way to enable FPU and start shadowing again. + */ + ldcr r10, PSR + clr r10, r10, 1<PSR_FPU_DISABLE_BIT> /* enable the FPU */ + clr r10, r10, 1<PSR_SHADOW_FREEZE_BIT> /* also enable shadowing */ + + stcr r10, PSR /* bang */ + FLUSH_PIPELINE + + /* put pointer to regs into r30... r31 will become a simple stack */ + or r30, r31, r0 + + subu r31, r31, 0x10 /* make some breathing space */ + st r30, r31, 0x0c /* store frame pointer on the st */ + st r30, r31, 0x08 /* store again for the debugger to recognize */ + or.u r20, r0, hi16(0x87654321) + or r20, r20, lo16(0x87654321) + st r20, r31, 0x04 + st r20, r31, 0x00 + + CALL(_error_fault, r30, r30) + + /* TURN INTERUPTS back on */ + ldcr r1, PSR + clr r1, r1, 1<PSR_INTERRUPT_DISABLE_BIT> + stcr r1, PSR + FLUSH_PIPELINE +LABEL(_error_loop) bsr _error_loop + /* never returns*/ + +/* + *---------------------------------------------------------------------------- + *---------------------------------------------------------------------------- + *---------------------------------------------------------------------------- + */ + + +/* + * This is part of baddadr (below). + */ +_LABEL(ignore_data_exception) + /******************************************************\ + * SR0: pointer to the current thread structure * + * SR1: previous FLAGS reg * + * SR2: free * + * SR3: must presere * + * FLAGS: CPU status flags * + \******************************************************/ + xcr FLAGS, FLAGS, SR1 /* replace SR1, FLAGS */ + + /* + * For more info, see badaddr() below. + * + * We just want to jump to "badaddr__return_nonzero" below. + * + * We don't worry about trashing R2 here because we're + * jumping back to the function badaddr() where we're allowd + * to blast r2..r9 as we see fit. + */ + + /* the "+2" below is to set the VALID bit. */ + or.u r2, r0, hi16(badaddr__return_nonzero + 2) + or r2, r2, lo16(badaddr__return_nonzero + 2) + stcr r2, SNIP /* Make it the next instruction to execute */ + addu r2, r2, 4 + stcr r2, SFIP /* and the next one after that, too. */ + stcr r0, SSBR /* make the scoreboard happy. */ + + /* the following jumps to "badaddr__return_nonzero" in below */ + RTE + +/* + * extern boolean_t badaddr(unsigned addr, unsigned len) + * + * Returns true (non-zero) if the given LEN bytes starting at ADDR are + * not all currently accessable by the kernel. + * + * If all LEN bytes starting at ADDR are accessable, zero is returned. + * + * Len may be be 1, 2, or 4. + * + * This is implementd by setting a special flag in SR1 before trying to access + * the given address. If a data access exception is raised, the address + * is inaccessable. The exception handler will notice the special CPU flag + * and not try to swap the address in. Rather, it will return to + * "badaddr__return_nonzero" in this routine so that we may return non-zero + * to the calling routine. + * + * If no fault is raised, we continue to where we return zero to the calling + * routine (after removing the special CPU flag). + */ + +LABEL(_badaddr) + /* + * Disable interrupts ... don't want a context switch while we're + * doing this! Also, save the old PSR in R8 to restore later. + */ + ldcr r8, PSR + set r4, r8, 1<PSR_INTERRUPT_DISABLE_BIT> + FLUSH_PIPELINE + stcr r4, PSR + + ldcr r5, SR1 + set r5, r5, 1<FLAG_IGNORE_DATA_EXCEPTION> + /* resetting r5 to SR1 done in the delay slot below. */ + + /* + * If it's a word we're doing, do that here. Otherwise, + * see if it's a halfword..... + */ + sub r6, r3, 4 + bcnd.n ne0, r6, badaddr__maybe_halfword + stcr r5, SR1 + FLUSH_PIPELINE + + /* + * It's a bad address if it's misaligned. + */ + bb1 0, r2, badaddr__return_nonzero + bb1 1, r2, badaddr__return_nonzero + /* + * The next line will either fault or not. If it faults, execution + * will go to: data_access_handler (see above) + * and then to: ignore_data_exception (see above) + * and then to: badaddr__return_nonzero (see below) + * which will return to the calling function. + * + * If there is no fault, execution just continues as normal. + */ + ld r5, r2, 0 + FLUSH_PIPELINE + br.n badaddr__return + or r2, r0, r0 /* indicate a zero (address not bad) return.*/ + + badaddr__maybe_halfword: + /* More or less like the code for checking a word above */ + sub r6, r3, 2 + bcnd ne0, r6, badaddr__maybe_byte + + /* it's bad if it's misaligned */ + bb1 0, r2, badaddr__return_nonzero + + FLUSH_PIPELINE + ld.h r5, r2, 0 + FLUSH_PIPELINE + br.n badaddr__return + or r2, r0, r0 + + badaddr__maybe_byte: + /* More or less like the code for checking a word above */ + sub r6, r3, 1 + bcnd ne0, r6, badaddr__unknown_size + FLUSH_PIPELINE + ld.b r5, r2, 0 + FLUSH_PIPELINE + br.n badaddr__return + or r2, r0, r0 + badaddr__unknown_size: +#ifndef NDEBUG + data + 1: string "bad length (%d) to badaddr() from 0x%x\n\000" + text + or.u r2, r0, hi16(1b) + or r2, r2, lo16(1b) + or r4, r0, r1 + bsr _printf + or.u r2, r0, hi16(1b) + or r2, r2, lo16(1b) + bsr _panic + /*NOTREACHED*/ +#endif + +_LABEL(badaddr__return_nonzero) + or r2, r0, 1 + /* fall through to badaddr__return */ + +_LABEL(badaddr__return) + ldcr r4, SR1 + clr r4, r4, 1<FLAG_IGNORE_DATA_EXCEPTION> + stcr r4, SR1 + + /* + * Restore the PSR to what it was before. + * The only difference is that we might be enabling interrupts + * (which we turned off above). If interrupts were already off, + * we do not want to turn them on now, so we just restore from + * where we saved it. + */ + FLUSH_PIPELINE + stcr r8, PSR + jmp r1 + + +/* +****************************************************************************** +****************************************************************************** +****************************************************************************** +*/ + + +LABEL(setup_phase_one) + /***************** REGISTER STATUS BLOCK ***********************\ + * SR0: current thread (if any, null if not) * + * SR1: saved copy of exception-time register now holding FLAGS * + * SR2: saved copy of exception-time r1 * + * SR3: must be preserved .. may be the exception-time stack * + * r1: return address to calling exception handler * + * FLAGS: CPU status flags * + *************************************************** * + * immediate goal: * + * Decide where we're going to put the exception frame. * + * Might be at the end of R31, SR3, or the thread's * + * pcb. * + \***************************************************************/ + + /* Check if we are coming in from a FPU restart exception. + If so, the pcb will be in SR3 */ + bb1.n FLAG_ENABLING_FPU, FLAGS, use_SR3_pcb + xcr r1, r1, SR2 + /* are we coming in from user mode? If so, pick up thread pcb */ + bb0 FLAG_FROM_KERNEL, FLAGS, pickup_stack + + /* Interrupt in kernel mode, not FPU restart */ + _LABEL(already_on_kernel_stack) + /***************** REGISTER STATUS BLOCK ***********************\ + * SR0: current thread (if any, null if not) * + * SR1: saved copy of exception-time register now holding FLAGS * + * SR2: return address to the calling exception handler * + * SR3: must be preserved; may be important for other exceptions * + * FLAGS: CPU status flags * + *************************************************** * + * immediate goal: * + * We're already on the kernel stack, but not having * + * needed to use SR3. We can just make room on the * + * stack (r31) for our exception frame. * + \***************************************************************/ + subu r31, r31, SIZEOF_EF /* r31 now our E.F. */ + st FLAGS, r31, REG_OFF(EF_FLAGS) /* save flags */ + st r1, r31, GENREG_OFF(1) /* save prev. r1 (now r1 free)*/ + + ldcr r1, SR3 /* save previous SR3 */ + st r1, r31, REG_OFF(EF_SR3) + + addu r1, r31, SIZEOF_EF /* save previous r31 */ + br.n have_pcb + st r1, r31, GENREG_OFF(31) + + + _LABEL(use_SR3_pcb) + /***************** REGISTER STATUS BLOCK ***********************\ + * SR0: current thread (if any, null if not) * + * SR1: saved copy of exception-time register now holding FLAGS * + * SR2: return address to the calling exception handler * + * SR3: must be preserved; exception-time stack pointer * + * FLAGS: CPU status flags * + *************************************************** * + * immediate goal: * + * An exception occured while enabling the FPU. Since r31 * + * is the user's r31 while enabling the FPU, we had put * + * our pcb pointer into SR3, so make room from * + * there for our stack pointer. * + * We need to check if SR3 is the old stack pointer or the * + * pointer off to the user pcb. If it pointing to the user * + * pcb, we need to pick up the kernel stack. Otherwise * + * we need to allocate a frame upon it. * + * We look at the EPSR to see if it was from user mode * + * Unfortunately, we have no registers free at the moment * + * But we know register 0 in the pcb frame will always be * + * zero, so we can use it as scratch storage. * + * * + * * + \***************************************************************/ + xcr r30, r30, SR3 /* r30 = old exception frame */ + st r1, r30, GENREG_OFF(0) /* free up r1 */ + ld r1, r30, REG_OFF(EF_EPSR) /* get back the epsr */ + bb0.n PSR_SUPERVISOR_MODE_BIT, r1, 1f /* if user mode */ + ld r1, r30, GENREG_OFF(0) /* restore r1 */ + /* we were in kernel mode - dump frame upon the stack */ + st r0, r30, GENREG_OFF(0) /* repair old frame */ + subu r30, r30, SIZEOF_EF /* r30 now our E.F. */ + st FLAGS, r30, REG_OFF(EF_FLAGS) /* save flags */ + st r1, r30, GENREG_OFF(1) /* save prev. r1 (now r1 free) */ + + st r31, r30, GENREG_OFF(31) /* save previous r31 */ + or r31, r0, r30 /* make r31 our pointer. */ + addu r30, r30, SIZEOF_EF /* r30 now has previous SR3 */ + st r30, r31, REG_OFF(EF_SR3) /* save previous SR3 */ + br.n have_pcb + xcr r30, r30, SR3 /* restore r30 */ + 1: + /* we took an exception while restarting the FPU from user space. + Consequently, we never picked up a stack. Do so now. + R1 is currently free (saved in the exception frame pointed at by + r30) */ + or.u r1, r0, hi16(_kstack) + ld r1, r1, lo16(_kstack) + addu r1, r1, USIZE-SIZEOF_EF + st FLAGS, r1, REG_OFF(EF_FLAGS) /* store flags */ + st r31, r1, GENREG_OFF(31) /* store r31 - now free */ + st r30, r1, REG_OFF(EF_SR3) /* store old SR3 (pcb) */ + or r31, r1, r0 /* make r31 our exception frame pointer */ + ld r1, r30, GENREG_OFF(0) /* restore old r1 */ + st r0, r30, GENREG_OFF(0) /* repair that frame */ + st r1, r31, GENREG_OFF(1) /* store r1 in its proper place */ + br.n have_pcb + xcr r30, r30, SR3 /* restore r30 */ + + _LABEL(pickup_stack) + /***************** REGISTER STATUS BLOCK ***********************\ + * SR0: current thread * + * SR1: saved copy of exception-time register now holding FLAGS * + * SR2: return address to the calling exception handler * + * SR3: free * + * FLAGS: CPU status flags * + *************************************************** * + * immediate goal: * + * Since we're servicing an exception from user mode, we * + * know that SR3 is free. We use it to free up a temp. * + * register to be used in getting the thread's pcb * + \***************************************************************/ + stcr r31, SR3 /* save previous r31 */ + + /* switch to the thread's kernel stack. */ + or.u r31, r0, hi16(_curpcb) + ld r31, r31, lo16(_curpcb) + addu r31, r31, PCB_USER_STATE /* point to user save area */ + st FLAGS, r31, REG_OFF(EF_FLAGS) /* save flags */ + st r1, r31, GENREG_OFF(1) /* save prev. r1 (now r1 free)*/ + ldcr r1, SR3 /* save previous r31 */ + st r1, r31, GENREG_OFF(31) + /*FALLTHROUGH */ + + _LABEL(have_pcb) + /***************** REGISTER STATUS BLOCK ***********************\ + * SR0: current thread * + * SR1: saved copy of exception-time register now holding FLAGS * + * SR2: return address to the calling exception handler * + * SR3: free * + * r1: free * + * FLAGS: CPU status flags * + * r31: our exception frame * + * Valid in the exception frame: * + * Exception-time r1, r31, FLAGS. * + * Exception SR3, if appropriate. * + *************************************************** * + * immediate goal: * + * Save the shadow registers that need to be saved to * + * the exception frame. * + \***************************************************************/ + stcr TMP, SR3 /* free up TMP, TMP2, TMP3 */ + SAVE_TMP2 + SAVE_TMP3 + + /* save some exception-time registers to the exception frame */ + ldcr TMP, EPSR + ldcr TMP2, SFIP + ldcr TMP3, SNIP + st TMP, r31, REG_OFF(EF_EPSR) + st TMP2, r31, REG_OFF(EF_SFIP) + st TMP3, r31, REG_OFF(EF_SNIP) + + /* + * Save Pbus fault status register from data and inst CMMU. + */ + + or.u TMP, r0, hi16(CMMU_I) + ld TMP2, TMP, lo16(CMMU_I) + 0x108 + st TMP2, r31, REG_OFF(EF_IPFSR) + or.u TMP, r0, hi16(CMMU_D) + ld TMP2, TMP, lo16(CMMU_D) + 0x108 + st TMP2, r31, REG_OFF(EF_DPFSR) + + ldcr TMP, SSBR + ldcr TMP2, SXIP + ldcr TMP3, DMT0 + st TMP2, r31, REG_OFF(EF_SXIP) + +#if 0 + /* + * The following is a kludge so that + * a core file will have a copy of + * DMT0 so that 'sim' can display it + * correctly. + * After a data fault has been noticed, + * the real EF_DTM0 is cleared, so I need + * to throw this somewhere. + * There's no special reason I chose this + * register (FPIT)... it's just one of many + * for which it causes no pain to do this. + */ + st TMP3, r31, REG_OFF(EF_FPIT) +#endif + + /* + * The above shadow registers are obligatory for any and all + * exceptions. Now, if the data access pipeline is not clear, + * we must save the DMx shadow registers, as well as clear + * the appropriate SSBR bits for the destination registers of + * loads or xmems. + */ + bb0.n DMT_VALID_BIT, TMP3, DMT_check_finished + st TMP3, r31, REG_OFF(EF_DMT0) + + ldcr TMP2, DMT1 + ldcr TMP3, DMT2 + st TMP2, r31, REG_OFF(EF_DMT1) + st TMP3, r31, REG_OFF(EF_DMT2) + + ldcr TMP2, DMA0 + ldcr TMP3, DMA1 + st TMP2, r31, REG_OFF(EF_DMA0) + st TMP3, r31, REG_OFF(EF_DMA1) + + ldcr TMP2, DMA2 + ldcr TMP3, DMD0 + st TMP2, r31, REG_OFF(EF_DMA2) + st TMP3, r31, REG_OFF(EF_DMD0) + + tb1 0,r0,0 + ldcr TMP2, DMD1 + ldcr TMP3, DMD2 + st TMP2, r31, REG_OFF(EF_DMD1) + st TMP3, r31, REG_OFF(EF_DMD2) + + /* + *--------------------------------------------------------------- + * need to clear "appropriate" bits in the SSBR before + * we restart the FPU + */ + + + _LABEL(check_DMT0) + ldcr TMP2, DMT0 + bb0.n DMT_VALID_BIT, TMP2, DMT_check_finished + stcr r0, DMT0 /* so an exception at fpu_enable doesn't see our DMT0*/ + bb1 DMT_LOCK_BIT, TMP2, do_DMT0 + bb1 DMT_WRITE_BIT, TMP2, check_DMT1 + _LABEL(do_DMT0) + extu TMP2, TMP2, DMT_DREG_WIDTH <DMT_DREG_OFFSET> + set TMP2, TMP2, 1<5> + clr TMP, TMP, TMP2 + + _LABEL(check_DMT1) + ldcr TMP2, DMT1 + bb0 DMT_VALID_BIT, TMP2, check_DMT2 + bb1 DMT_LOCK_BIT, TMP2, do_DMT1 + bb1 DMT_WRITE_BIT, TMP2, check_DMT2 + _LABEL(do_DMT1) + extu TMP2, TMP2, DMT_DREG_WIDTH <DMT_DREG_OFFSET> + set TMP2, TMP2, 1<5> + clr TMP, TMP, TMP2 + + _LABEL(check_DMT2) + ldcr TMP2, DMT2 + bb0 DMT_VALID_BIT, TMP2, DMT_check_finished + bb1 DMT_LOCK_BIT, TMP2, do_DMT2_single + bb1 DMT_WRITE_BIT, TMP2, DMT_check_finished + bb1 DMT_DOUBLE_BIT,TMP2, do_DMT2_double + _LABEL(do_DMT2_single) + extu TMP2, TMP2, DMT_DREG_WIDTH <DMT_DREG_OFFSET> + br.n 1f + set TMP2, TMP2, 1<5> + _LABEL(do_DMT2_double) + extu TMP2, TMP2, DMT_DREG_WIDTH <DMT_DREG_OFFSET> + set TMP2, TMP2, 1<6> +1: clr TMP, TMP, TMP2 + + _LABEL(DMT_check_finished) + /***************** REGISTER STATUS BLOCK ***********************\ + * SR0: current thread * + * SR1: saved copy of exception-time register now holding FLAGS * + * SR2: return address to the calling exception handler * + * SR3: saved TMP * + * r1: free * + * TMP: possibly revised SSBR * + * TMP2: free * + * TMP3: free * + * FLAGS: CPU status flags * + * r31: exception frame * + * Valid in the exception frame: * + * Exception-time r1, r31, FLAGS. * + * Exception-time TMP2, TMP3. * + * Exception-time espr, sfip, snip, sxip. * + * Dmt0. * + * Other data pipeline control registers, if appropriate. * + * Exception SR3, if appropriate. * + \***************************************************************/ + ldcr r1, SR2 + jmp r1 /* return to allow the handler to clear more SSBR bits */ + +/************************************************************************/ +/************************************************************************/ + + _LABEL(clear_FPi_ssbr_bit) + /* + * Clear floatingpont-imprecise ssbr bits. + * Also, save appropriate FPU control registers to the E.F. + * + * r1: return address to calling exception handler + * TMP : (possibly) revised ssbr + * TMP2 : free + * TMP3 : free + */ + fldcr TMP2, FPSR + fldcr TMP3, FPCR + st TMP2, r31, REG_OFF(EF_FPSR) + st TMP3, r31, REG_OFF(EF_FPCR) + + fldcr TMP2, FPECR + fldcr TMP3, FPRH + st TMP2, r31, REG_OFF(EF_FPECR) + st TMP3, r31, REG_OFF(EF_FPRH) + + fldcr TMP2, FPIT + fldcr TMP3, FPRL + st TMP2, r31, REG_OFF(EF_FPIT) + st TMP3, r31, REG_OFF(EF_FPRL) + + /* + * We only need clear the bit in the SSBR for the + * 2nd reg of a double result [see section 6.8.5] + */ + #define FPIT_SIZE_BIT 10 + bb0 FPIT_SIZE_BIT, TMP2, not_double_fpi + extu TMP2, TMP2, 5<0> /* get the reg. */ + set TMP2, TMP2, 1<6> /* set width (width=2 will clear two bits) */ + clr TMP, TMP, TMP2 + + _LABEL(not_double_fpi) + jmp r1 + + +/************************************************************************/ +/************************************************************************/ + + + _LABEL(clear_FPp_ssbr_bit) + /* + * Clear floating pont precise ssbr bits. + * Also, save appropriate FPU control registers to the E.F. + * + * r1: return address to calling exception handler + * TMP : (possibly) revised ssbr + * TMP2 : free + * TMP3 : free + */ + fldcr TMP2, FPSR + fldcr TMP3, FPCR + st TMP2, r31, REG_OFF(EF_FPSR) + st TMP3, r31, REG_OFF(EF_FPCR) + + fldcr TMP2, FPHS1 + fldcr TMP3, FPHS2 + st TMP2, r31, REG_OFF(EF_FPHS1) + st TMP3, r31, REG_OFF(EF_FPHS2) + + fldcr TMP2, FPLS1 + fldcr TMP3, FPLS2 + st TMP2, r31, REG_OFF(EF_FPLS1) + st TMP3, r31, REG_OFF(EF_FPLS2) + + fldcr TMP2, FPPT + fldcr TMP3, FPECR + st TMP2, r31, REG_OFF(EF_FPPT) + st TMP3, r31, REG_OFF(EF_FPECR) + + #define FPPT_SIZE_BIT 5 + bb1.n FPPT_SIZE_BIT, TMP2, 1f + extu TMP3, TMP2, 5<0> /* get FP operation dest reg */ + br.n 2f + set TMP3, TMP3, 1<5> /* set size=1 -- clear one bit for "float" */ + 1: set TMP3, TMP3, 1<6> /* set size=2 -- clear two bit for "double" */ + 2: + clr TMP, TMP, TMP3 /* clear bit(s) in ssbr. */ + jmp r1 + + +/************************************************************************/ +/************************************************************************/ + + + _LABEL(clear_dest_ssbr_bit) + /* + * There are various cases where an exception can leave the + * destination register's bit in the SB set. + * Examples: + * misaligned or privilege exception on a LD or XMEM + * DIV or DIVU by zero. + * + * I think that if the instruction is LD.D, then two bits must + * be cleared. + * + * Even though there are a number of instructions/exception + * combinations that could fire this code up, it's only required + * to be run for the above cases. However, I don't think it'll + * ever be a problem to run this in other cases (ST instructions, + * for example), so I don't bother checking. If we had to check + * for every possible instruction, this code would be much larger. + * + * The only checking, then, is to see if it's a LD.D or not. + * + * At the moment.... + * r1: return address to calling exception handler + * TMP : (possibly) revised ssbr + * TMP2 : free + * TMP3 : free + */ + ldcr TMP3, EPSR /* going to check: user or system memory? */ + ldcr TMP2, SXIP /* get the instruction's address */ + bb1.n PSR_SUPERVISOR_MODE_BIT, TMP3, 2f + clr TMP2, TMP2, 2<0> /* get rid of valid and error bits. */ + + 1: /* user space load here */ +#if ERRATA__XXX_USR + NOP + ld.usr TMP2, TMP2, r0 /* get the instruction itself */ + NOP + NOP + NOP + br 3f +#else + br.n 3f + ld.usr TMP2, TMP2, r0 /* get the instruction itself */ +#endif + + 2: /* system space load here */ + ld TMP2, TMP2, r0 /* get the instruction itself */ + + 3: /* now have the instruction..... */ + /* + * Now see if it's a double load + * There are three forms of double load [IMM16, scaled, unscaled], + * which can be checked by matching against two templates: + * -- 77776666555544443333222211110000 -- + * if (((instruction & 11111100000000000000000000000000) == + * 00010000000000000000000000000000) ;; + * ((instruction & 11111100000000001111110011100000) == + * 11110100000000000001000000000000)) + * { + * It's a load double, so + * clear two SSBR bits. + * } + * else + * { + * It's not a load double. + * Must be a load single, xmem, or st + * Thus, clear one SSBR bit. + * } + */ + /* check the first pattern for ld.d */ + extu TMP3, TMP2, 16<16> /* get the upper 16 bits */ + mask TMP3, TMP3, 0xFC00 /* apply the mask */ + cmp TMP3, TMP3, 0x1000 /* if this is equal, it's a load double */ + bb1 eq, TMP3, misaligned_double + + /* still could be -- check the second pattern for ld.d */ + /* look at the upper 16 bits first */ + extu TMP3, TMP2, 16<16> /* get the upper 16 bits */ + mask TMP3, TMP3, 0xFC00 /* apply the mask */ + cmp TMP3, TMP3, 0xF400 /* if equal, it might be a load double */ + bb1 ne, TMP3, misaligned_single /* not equal, so must be single */ + + /* now look at the lower 16 bits */ + extu TMP3, TMP2, 16<0> /* get the lower 16 bits */ + mask TMP3, TMP3, 0xFCE0 /* apply the mask */ + cmp TMP3, TMP3, 0x1000 /* if this is equal, it's a load double */ + bb1 eq, TMP3, misaligned_double + + _LABEL(misaligned_single) + extu TMP2, TMP2, 5<21> /* get the destination register */ + br.n 1f + set TMP2, TMP2, 1<5> /* set size=1 */ + + _LABEL(misaligned_double) + extu TMP2, TMP2, 5<21> /* get the destination register */ + set TMP2, TMP2, 1<6> /* set size=2 -- clear two bit for "ld.d" */ + + 1: jmp.n r1 + clr TMP, TMP, TMP2 /* clear bit(s) in ssbr. */ + +/************************************************************************/ +/************************************************************************/ + + + + LABEL(setup_phase_two) + /***************** REGISTER STATUS BLOCK ***********************\ + * SR0: current thread * + * SR1: saved copy of exception-time register now holding FLAGS * + * SR2: free * + * SR3: saved TMP * + * r1: return address to calling exception handler * + * TMP: possibly revised SSBR * + * TMP2: free * + * TMP3: free * + * FLAGS: CPU status flags * + * r31: our exception frame * + * Valid in the exception frame: * + * Exception-time r1, r31, FLAGS. * + * Exception-time TMP2, TMP3. * + * Exception-time espr, sfip, snip, sxip. * + * Exception number (EF_VECTOR). * + * Dmt0 * + * Other data pipeline control registers, if appropriate. * + * FPU control registers, if appropriate. * + * Exception SR3, if appropriate. * + *************************************************** * + * immediate goal: * + * restore the system to the exception-time state (except * + * SR3 will be OUR stack pointer) so that we may resart the FPU. * + \***************************************************************/ + stcr TMP, SSBR /* done with SSBR, TMP now free */ + RESTORE_TMP2 /* done with extra temp regs */ + RESTORE_TMP3 /* done with extra temp regs */ + + /* Get the current PSR and modify for the rte to enable the FPU */ + ldcr TMP, PSR + clr TMP, TMP, 1<PSR_FPU_DISABLE_BIT> /* enable the FPU */ + clr TMP, TMP, 1<PSR_SHADOW_FREEZE_BIT> /* also enable shadowing */ + stcr TMP, EPSR + + /* the "+2" below is to set the VALID_BIT */ + or.u TMP, r0, hi16(fpu_enable + 2) + or TMP, TMP, lo16(fpu_enable + 2) + stcr TMP, SNIP /* jump to here fpu_enable */ + addu TMP, TMP, 4 + stcr TMP, SFIP /* and then continue after that */ + + set FLAGS, FLAGS, 1<FLAG_ENABLING_FPU> /* note what we're doing.*/ + xcr FLAGS, FLAGS, SR1 + st r1, r31, REG_OFF(EF_RET) /* save the return address */ + ld r1, r31, GENREG_OFF(1) /* get original r1 */ + + xcr TMP, r31, SR3 /* TMP now restored. R31 now saved in SR3 */ + ld r31, r31, GENREG_OFF(31) /* get original r31 */ + + /***************** REGISTER STATUS BLOCK ***********************\ + * SR0: current thread * + * SR1: CPU flags * + * SR2: free * + * SR3: pointer to our exception frame (our stack pointer) * + * r1 through r31: original exception-time values * + * * + * Valid in the exception frame: * + * Exception-time FLAGS. * + * Exception-time espr, sfip, snip, sxip. * + * Exception number (EF_VECTOR). * + * Dmt0 * + * Other data pipeline control registers, if appropriate. * + * FPU control registers, if appropriate. * + * Exception SR3, if appropriate. * + * Held temporarly in the exception frame: * + * Return address to the calling excption handler. * + *************************************************** * + * immediate goal: * + * Do an RTE to restart the fpu and jump to "fpu_enable" * + * Another exception (or exceptions) may be raised in * + * this, which is why FLAG_ENABLING_FPU is set in SR1. * + \***************************************************************/ + RTE /* jumps to "fpu_enable" on the next line to enable the FPU. */ + + _LABEL(fpu_enable) + FLUSH_PIPELINE + xcr TMP, TMP, SR3 /* get E.F. pointer */ + st.d r30, TMP, GENREG_OFF(30) /* save previous r30, r31 */ + or r31, TMP, r0 /* transfer E.F. pointer to r31 */ + ld TMP, r31, REG_OFF(EF_SR3)/* get previous SR3; maybe important*/ + + /* make sure that the FLAG_ENABLING_FPU bit is off */ + xcr FLAGS, FLAGS, SR1 + clr FLAGS, FLAGS, 1<FLAG_ENABLING_FPU> + xcr FLAGS, FLAGS, SR1 + + xcr TMP, TMP, SR3 /* replace TMP, SR3 */ + + /* now save all regs to the exception frame. */ + st.d r0 , r31, GENREG_OFF(0) + st.d r2 , r31, GENREG_OFF(2) + st.d r4 , r31, GENREG_OFF(4) + st.d r6 , r31, GENREG_OFF(6) + st.d r8 , r31, GENREG_OFF(8) + st.d r10, r31, GENREG_OFF(10) + st.d r12, r31, GENREG_OFF(12) + st.d r14, r31, GENREG_OFF(14) + st.d r16, r31, GENREG_OFF(16) + st.d r18, r31, GENREG_OFF(18) + st.d r20, r31, GENREG_OFF(20) + st.d r22, r31, GENREG_OFF(22) + st.d r24, r31, GENREG_OFF(24) + st.d r26, r31, GENREG_OFF(26) + st.d r28, r31, GENREG_OFF(28) +#ifdef JEFF_DEBUG + /* mark beginning of frame with notable value */ + or.u r20, r0, hi16(0x12345678) + or r20, r20, lo16(0x12345678) + st r20, r31, GENREG_OFF(0) +#endif + + /***************** REGISTER STATUS BLOCK ***********************\ + * SR0: current thread * + * SR1: free * + * SR2: free * + * SR3: previous exception-time SR3 * + * r1: return address to the calling exception handler * + * r2 through r30: free * + * r31: our exception frame * + * * + * Valid in the exception frame: * + * Exception-time r0 through r31. * + * Exception-time FLAGS. * + * Exception-time espr, sfip, snip, sxip. * + * Exception number (EF_VECTOR). * + * Dmt0 * + * Other data pipeline control registers, if appropriate. * + * FPU control registers, if appropriate. * + * Exception SR3, if appropriate. * + *************************************************** * + * immediate goal: * + * Pick up a stack if we came in from user mode. Put * + * A copy of the exception frame pointer into r30 * + * bump the stack a doubleword and write the exception * + * frame pointer. * + * if not an interrupt exception, * + * Turn on interrupts and service any outstanding * + * data access exceptions. * + * Return to calling exception handler to * + * service the exception. * + \***************************************************************/ + + /* + * If it's not the interrupt exception, enable interrupts and + * take care of any data access exceptions...... + * +#if notyet + * If interrupt exception, switch to interrupt stack if not + * already there. Else, switch to kernel stack. +#endif + */ + or r30, r0, r31 /* get a copy of the e.f. pointer */ + ld r2, r31, REG_OFF(EF_EPSR) + bb1 PSR_SUPERVISOR_MODE_BIT, r2, 1f /* If in kernel mode */ + +#if notyet + ld r3, r31, REG_OFF(EF_VECTOR) + cmp r3, r3, 1 /* is interrupt ? */ + bb0 eq, r3, 2f + or.u r31, r0, hi16(_intstack_end) /* swith to int stack */ + or r31, r31, lo16(_intstack_end) + br 3f + 2: +#endif + or.u r31, r0, hi16(_kstack) + ld r31, r31, lo16(_kstack) + addu r31, r31, USIZE /* point at proper end */ + br 3f + 1: +#if notyet + ld r3, r31, REG_OFF(EF_VECTOR) + cmp r3, r3, 1 /* is interrupt ? */ + bb0 eq, r3, 3f /* no, we will stay on kern stack */ + or.u r31, r0, hi16(_intstack_end) /* swith to int stack */ + or r31, r31, lo16(_intstack_end) +#endif /* notyet */ + /* This label is here for debugging */ + exception_handler_has_ksp: global exception_handler_has_ksp + 3: /* + here - r30 holds a pointer to the exception frame. + r31 is a pointer to the kernel stack/interrupt stack. + */ + subu r31, r31, 8 /* make some breathing space */ + st r30, r31, 0 /* store frame pointer on the stack */ +#if DDB + st r30, r31, 4 /* store it again for the debugger to recognize */ +#endif DDB + + ld r2, r30, REG_OFF(EF_VECTOR) + bcnd.n eq0, r2, return_to_calling_exception_handler /* is error */ + ld r14, r30, REG_OFF(EF_RET) + cmp r3, r2, 1 /* interrupt is exception #1 ;Is an interrupt? */ + bb1.n eq, r3, return_to_calling_exception_handler /* skip if so */ + +#if DDB + cmp r3, r2, 130 /* DDB break exception */ + bb1.n eq, r3, return_to_calling_exception_handler + + cmp r3, r2, 132 /* DDB entry exception */ + bb1.n eq, r3, return_to_calling_exception_handler +#endif + + ldcr r2, PSR + clr r2, r2, 1<PSR_INTERRUPT_DISABLE_BIT> /* enable interrupts */ + stcr r2, PSR +#if DDB + FLUSH_PIPELINE +#endif + + /* service any outstanding data pipeline stuff + - check dmt0 anything outstanding?*/ + + ld r3, r30, REG_OFF(EF_DMT0) + bb0 DMT_VALID_BIT, r3, return_to_calling_exception_handler + +/* + r30 can be clobbered by calls. So stuff its value into a + preserved register, say r15. R14 is in use (see return_to_... below). + */ + or r15, r0, r30 + + CALL(_trap, T_DATAFLT, r15) + CALL(_data_access_emulation, r15, r0) + +/* restore it... */ + or r30, r0, r15 + + /* clear the dmt0 word in the E.F */ + st r0, r30, REG_OFF(EF_DMT0) + + _LABEL(return_to_calling_exception_handler) + jmp r14 /* loaded above */ + + +/* + * proc_trampoline. + * When a process setup by cpu_set_kpc() resumes, it will find itself in + * proc_trampoline, with r31 pointing to a ksigframe. proc_trampoline will + * load func and proc values from ksigframe, call the function, and on return + * pop off the ksigframe. Then, it will load pc from the switchframe and + * jump there. + */ + +ENTRY(proc_trampoline) + ld r1,r31,0 /* load func */ + ld r2,r31,4 /* load proc pointer */ + jsr.n r1 + subu r31,r31,40 /* create stack space for function */ + addu r31,r31,48 /* stack space above + ksigframe */ + ld r1, r31,0 /* load pc */ + ld r2, r31,4 /* & proc pointer from switch frame */ + jsr.n r1 + addu r31,r31,8 + bsr _panic + +/* + * proc_do_uret + * this is called as proc_do_uret(proc) from proc_trampoline(). This function + * loads r31 with a pointer to the trap frame for the given proc and calls + * return_from_exception_handler which loads all the registers and does an + * rte. + */ + +ENTRY(proc_do_uret) + ld r3,r2,P_ADDR /* p->p_addr */ + addu r3,r3,PCB_USER_STATE /* p->p_addr.u_pcb.user_state */ + st r3,r31,0 /* put it on the stack */ + br return_from_exception_handler + +LABEL(return_from_exception_handler) +LABEL(_return_from_main) + /* + * Regs r1-r30 are free. R31 is pointing at the word + * on the kernel stack where our pointer to the exception frame + * it stored. Reload it now. + * + * At this point, if EF_DMT0 is not zero, then + * this must have been an interrupt where the fault didn't + * get corrected above. We'll do that now. + * + * We load it into r14 since it is preserved across function + * calls, and we may have to call some routines from within here. + * + * control is transfered here from obvious places in this file + * and thread_bootstrap in luna88k/locore.c. + * + */ +#define FPTR r14 + ld FPTR, r31, 0 /* grab exception frame pointer */ + ld r3, FPTR, REG_OFF(EF_DMT0) + bb0 DMT_VALID_BIT, r3, _check_ast /*[Oh well, nothing to do here] */ + +#if 1 + /* + * This might happen for non-interrupts If the user sets DMT0 + * in an exception handler......... + */ + ld r2, FPTR, REG_OFF(EF_VECTOR) + cmp r2, r2, 1 /* interrupt is exception #1 ; Is an interrupt? */ + bb1 eq, r2, 1f + LABEL(oops) + or.u r4, r0, hi16(2f) + or r4, r4, lo16(2f) +#if DDB + CALL(_db_printf, r4, r0) + tb0 0, r0, 132 +#endif + br 1f + data + 2: string "OOPS: DMT0 not zero and not interrupt.\n\000" + align 8 + text + 1: +#endif + /* + * If it's the interrupt exception, enable interrupt. + * Take care of any data access exception...... 90/8/15 add by yama + */ + + /* + * Is it ever possible to have interrupt exception while EPSR has + * it disabled? I don't think so.. XXX nivas + */ + ld r2, FPTR, REG_OFF(EF_VECTOR) + cmp r2, r2, 1 /* interrupt is exception #1 ; Is an interrupt? */ + bb1 ne, r2, 1f /* If not so, skip */ + + /* if EPSR has interrupts disabled, skip also */ + ld r2, FPTR, REG_OFF(EF_EPSR) + bb1 PSR_INTERRUPT_DISABLE_BIT, r2, 1f /* skip if disabled */ + ldcr r2, PSR + clr r2, r2, 1<PSR_INTERRUPT_DISABLE_BIT> /* enable interrupts */ + FLUSH_PIPELINE + stcr r2, PSR + 1: + ld r2, FPTR, REG_OFF(EF_DMT0) + bb0 DMT_VALID_BIT, r2, 2f + + /* + * if there happens to be a data fault that hasn't been serviced yet, + * go off and service that... + */ + CALL(_trap, T_DATAFLT, r30) + CALL(_data_access_emulation, r30, r0) /* really only 2 args */ + + /* clear the dmt0 word in the E.F. */ + st r0 , FPTR, REG_OFF(EF_DMT0) + 2: + +/* + * If the saved ipl is 0, then call dosoftint() to process soft + * interrupts. + * If returning to user land, look for ASTs + */ + +LABEL(_check_ast) + + ld r2, FPTR, REG_OFF(EF_EPSR) /* get pre-exception PSR */ + bb1 PSR_INTERRUPT_DISABLE_BIT, r2, 1f /* skip if ints off */ + ld r2, FPTR, REG_OFF(EF_MASK) /* get pre-exception ipl */ + bcnd ne0, r2, 1f /* can't do softint's */ + bsr.n _setipl + or r2,r0,1 + bsr _dosoftint + /* is this needed? we are going to restore the ipl below XXX nivas */ + bsr.n _setipl + or r2,r0,0 /* ints are enabled */ + /* at ipl 0 now */ + 1: + ld r2, FPTR, REG_OFF(EF_EPSR) /* get pre-exception PSR */ + bb1 PSR_SUPERVISOR_MODE_BIT, r2, no_ast /*skip if in system mode */ + + /* should assert here - not in user mode with ints off XXX nivas */ + /* get and check want_ast */ + or.u r2, r0, hi16(_want_ast) + ld r3, r2, lo16(_want_ast) + bcnd eq0, r3, no_ast + + /* + * trap(AST,...) will service ast's. + */ + + CALL(_trap, T_ASTFLT, FPTR) + +#if 0 + /* assert that ipl is 0; if going back to user, it should be 0 */ + + bsr _getipl + bcnd eq0, r2, 2f + bsr panic + 2: +#endif + +_LABEL(no_ast) + + /* disable interrupts */ + + ldcr r1, PSR + set r1, r1, 1<PSR_INTERRUPT_DISABLE_BIT> + FLUSH_PIPELINE + stcr r1, PSR + + /* now ready to return....*/ + + /* + * Transfer the frame pointer to r31, since we no longer need a stack. + * No page faults here, and interrupts are disabled. + */ + + ld r2, FPTR, REG_OFF(EF_MASK) /* get pre-exception ipl */ + bsr _setipl + + or r31, r0, FPTR + /* restore r1 later */ + ld.d r2 , r31, GENREG_OFF(2) + ld.d r4 , r31, GENREG_OFF(4) + ld.d r6 , r31, GENREG_OFF(6) + ld.d r8 , r31, GENREG_OFF(8) + ld.d r10, r31, GENREG_OFF(10) + ld.d r12, r31, GENREG_OFF(12) + ld.d r14, r31, GENREG_OFF(14) + ld.d r16, r31, GENREG_OFF(16) + ld.d r18, r31, GENREG_OFF(18) + ld.d r20, r31, GENREG_OFF(20) + ld.d r22, r31, GENREG_OFF(22) + ld.d r24, r31, GENREG_OFF(24) + ld.d r26, r31, GENREG_OFF(26) + ld.d r28, r31, GENREG_OFF(28) + /* restore r1, r30, r31 later */ + + /* disable shadowing */ + ldcr r1, PSR + set r1, r1, 1<PSR_SHADOW_FREEZE_BIT> + FLUSH_PIPELINE + stcr r1, PSR + + /* reload the control regs*/ + st r0,r31, REG_OFF(EF_IPFSR) + st r0,r31, REG_OFF(EF_DPFSR) + + /* + * Note: no need to restore the SXIP. + * When the "rte" causes execution to continue + * first with the instruction pointed to by the NIP + * and then the FIP. + * + * See MC88100 Risc Processor User's Manual, 2nd Edition, + * section 6.4.3.1.2-4 + */ + ld r30, r31, REG_OFF(EF_SNIP) + ld r1, r31, REG_OFF(EF_SFIP) + stcr r0, SSBR + stcr r30, SNIP + stcr r1, SFIP + + ld r30, r31, REG_OFF(EF_EPSR) + ld r1, r31, REG_OFF(EF_MODE) + stcr r30, EPSR + + /* Now restore r1, r30, and r31 */ + ld r1, r31, GENREG_OFF(1) + ld.d r30, r31, GENREG_OFF(30) + + _LABEL(return_from_exception) + RTE diff --git a/sys/arch/mvme88k/mvme88k/genassym.c b/sys/arch/mvme88k/mvme88k/genassym.c new file mode 100644 index 00000000000..297b42b71de --- /dev/null +++ b/sys/arch/mvme88k/mvme88k/genassym.c @@ -0,0 +1,178 @@ +/* + * Copyright (c) 1982, 1990 The Regents of the University of California. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)genassym.c 7.8 (Berkeley) 5/7/91 + * $Id: genassym.c,v 1.3 1997/03/03 20:21:34 rahnds Exp $ + */ + +#ifndef KERNEL +#define KERNEL +#endif /* KERNEL */ + +#include <sys/param.h> +#include <sys/buf.h> +#include <sys/time.h> +#include <sys/proc.h> +#include <sys/mbuf.h> +#include <sys/msgbuf.h> +#include <machine/cpu.h> +#include <machine/trap.h> +#include <machine/psl.h> +#include <machine/vmparam.h> +#include <sys/syscall.h> +#include <vm/vm.h> +#include <sys/user.h> + +#define pair(TOKEN, ELEMENT) \ + printf("#define " TOKEN " %u\n", (unsigned)(ELEMENT)) + +#define int_offset_of_element(ELEMENT) (((unsigned)&(ELEMENT))/sizeof(int)) + +main() +{ + register struct proc *p = (struct proc *)0; + struct m88100_saved_state *ss = (struct m88100_saved_state *) 0; + register struct vmmeter *vm = (struct vmmeter *)0; + register struct user *up = (struct user *)0; + register struct rusage *rup = (struct rusage *)0; + struct vmspace *vms = (struct vmspace *)0; + pmap_t pmap = (pmap_t)0; + struct pcb *pcb = (struct pcb *)0; + struct m88100_pcb *ks = (struct m88100_pcb *)0; + + register unsigned i; + + printf("#ifndef __GENASSYM_INCLUDED\n"); + printf("#define __GENASSYM_INCLUDED 1\n\n"); + + printf("#define\tP_FORW %d\n", &p->p_forw); + printf("#define\tP_BACK %d\n", &p->p_back); + printf("#define\tP_VMSPACE %d\n", &p->p_vmspace); + printf("#define\tP_ADDR %d\n", &p->p_addr); + printf("#define\tP_PRIORITY %d\n", &p->p_priority); + printf("#define\tP_STAT %d\n", &p->p_stat); + printf("#define\tP_WCHAN %d\n", &p->p_wchan); + printf("#define\tSRUN %d\n", SRUN); + + printf("#define\tVM_PMAP %d\n", &vms->vm_pmap); + printf("#define\tV_INTR %d\n", &vm->v_intr); + + printf("#define\tUPAGES %d\n", UPAGES); + printf("#define\tPGSHIFT %d\n", PGSHIFT); + printf("#define\tUSIZE %d\n", USPACE); + printf("#define\tNBPG %d\n", NBPG); + + printf("#define\tU_PROF %d\n", &up->u_stats.p_prof); + printf("#define\tU_PROFSCALE %d\n", &up->u_stats.p_prof.pr_scale); + printf("#define\tPCB_ONFAULT %d\n", &pcb->pcb_onfault); + printf("#define\tSIZEOF_PCB %d\n", sizeof(struct pcb)); + + printf("#define\tPCB_USER_STATE %d\n", &pcb->user_state); + + printf("#define\tSYS_exit %d\n", SYS_exit); + printf("#define\tSYS_execve %d\n", SYS_execve); + printf("#define\tSYS_sigreturn %d\n", SYS_sigreturn); + + pair("EF_R0", int_offset_of_element(ss->r[0])); + pair("EF_R31", int_offset_of_element(ss->r[31])); + pair("EF_FPSR", int_offset_of_element(ss->fpsr)); + pair("EF_FPCR", int_offset_of_element(ss->fpcr)); + pair("EF_EPSR", int_offset_of_element(ss->epsr)); + pair("EF_SXIP", int_offset_of_element(ss->sxip)); + pair("EF_SFIP", int_offset_of_element(ss->sfip)); + pair("EF_SNIP", int_offset_of_element(ss->snip)); + pair("EF_SSBR", int_offset_of_element(ss->ssbr)); + pair("EF_DMT0", int_offset_of_element(ss->dmt0)); + pair("EF_DMD0", int_offset_of_element(ss->dmd0)); + pair("EF_DMA0", int_offset_of_element(ss->dma0)); + pair("EF_DMT1", int_offset_of_element(ss->dmt1)); + pair("EF_DMD1", int_offset_of_element(ss->dmd1)); + pair("EF_DMA1", int_offset_of_element(ss->dma1)); + pair("EF_DMT2", int_offset_of_element(ss->dmt2)); + pair("EF_DMD2", int_offset_of_element(ss->dmd2)); + pair("EF_DMA2", int_offset_of_element(ss->dma2)); + pair("EF_FPECR", int_offset_of_element(ss->fpecr)); + pair("EF_FPHS1", int_offset_of_element(ss->fphs1)); + pair("EF_FPLS1", int_offset_of_element(ss->fpls1)); + pair("EF_FPHS2", int_offset_of_element(ss->fphs2)); + pair("EF_FPLS2", int_offset_of_element(ss->fpls2)); + pair("EF_FPPT", int_offset_of_element(ss->fppt)); + pair("EF_FPRH", int_offset_of_element(ss->fprh)); + pair("EF_FPRL", int_offset_of_element(ss->fprl)); + pair("EF_FPIT", int_offset_of_element(ss->fpit)); + pair("EF_VECTOR", int_offset_of_element(ss->vector)); + pair("EF_MASK", int_offset_of_element(ss->mask)); + pair("EF_MODE", int_offset_of_element(ss->mode)); + + pair("EF_RET", int_offset_of_element(ss->scratch1)); + pair("EF_IPFSR",int_offset_of_element(ss->ipfsr)); + pair("EF_DPFSR",int_offset_of_element(ss->dpfsr)); + pair("EF_NREGS", sizeof(*ss)/sizeof(int)); + + /* make a sanity check */ + if (sizeof(*ss) & 7) + { + /* + * This contortion using write instead of fputs(stderr) + * is necessary because we can't include stdio.h in here. + */ + static char buf[] = + "Exception frame not a multiple of double words\n"; + write(2 /* stderr */,buf,sizeof(buf)); + exit(1); + } + pair("SIZEOF_EF", sizeof(*ss)); + + pair("PCB_PC", int_offset_of_element(ks->pcb_pc) * 4); + pair("PCB_IPL", int_offset_of_element(ks->pcb_ipl) * 4); + pair("PCB_R14", int_offset_of_element(ks->pcb_r14) * 4); + pair("PCB_R15", int_offset_of_element(ks->pcb_r15) * 4); + pair("PCB_R16", int_offset_of_element(ks->pcb_r16) * 4); + pair("PCB_R17", int_offset_of_element(ks->pcb_r17) * 4); + pair("PCB_R18", int_offset_of_element(ks->pcb_r18) * 4); + pair("PCB_R19", int_offset_of_element(ks->pcb_r19) * 4); + pair("PCB_R20", int_offset_of_element(ks->pcb_r20) * 4); + pair("PCB_R21", int_offset_of_element(ks->pcb_r21) * 4); + pair("PCB_R22", int_offset_of_element(ks->pcb_r22) * 4); + pair("PCB_R23", int_offset_of_element(ks->pcb_r23) * 4); + pair("PCB_R24", int_offset_of_element(ks->pcb_r24) * 4); + pair("PCB_R25", int_offset_of_element(ks->pcb_r25) * 4); + pair("PCB_R26", int_offset_of_element(ks->pcb_r26) * 4); + pair("PCB_R27", int_offset_of_element(ks->pcb_r27) * 4); + pair("PCB_R28", int_offset_of_element(ks->pcb_r28) * 4); + pair("PCB_R29", int_offset_of_element(ks->pcb_r29) * 4); + pair("PCB_R30", int_offset_of_element(ks->pcb_r30) * 4); + pair("PCB_SP", int_offset_of_element(ks->pcb_sp) * 4); + + printf("\n#endif /* __GENASSYM_INCLUDED */\n"); + exit(0); +} diff --git a/sys/arch/mvme88k/mvme88k/locore.S b/sys/arch/mvme88k/mvme88k/locore.S new file mode 100644 index 00000000000..d247e39c4c2 --- /dev/null +++ b/sys/arch/mvme88k/mvme88k/locore.S @@ -0,0 +1,378 @@ +/* + * Copyright (c) 1996 Nivas Madhur + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by Nivas Madhur. + * 4. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ +/* + * Mach Operating System + * Copyright (c) 1993-1991 Carnegie Mellon University + * Copyright (c) 1991 OMRON Corporation + * All Rights Reserved. + * + * Permission to use, copy, modify and distribute this software and its + * documentation is hereby granted, provided that both the copyright + * notice and this permission notice appear in all copies of the + * software, derivative works or modified versions, and any portions + * thereof, and that both notices appear in supporting documentation. + * + * CARNEGIE MELLON AND OMRON ALLOW FREE USE OF THIS SOFTWARE IN ITS "AS IS" + * CONDITION. CARNEGIE MELLON AND OMRON DISCLAIM ANY LIABILITY OF ANY KIND + * FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. + * + * Carnegie Mellon requests users of this software to return to + * + * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU + * School of Computer Science + * Carnegie Mellon University + * Pittsburgh PA 15213-3890 + * + * any improvements or extensions that they make and grant Carnegie the + * rights to redistribute these changes. + */ + +#ifndef ASSEMBLER +#define ASSEMBLER +#endif + +#include "machine/asm.h" +#include "machine/m88100.h" +#include "machine/trap.h" +#include "machine/psl.h" +#include "machine/vmparam.h" /* INTSTACK_SIZE */ + +/***********************************************************************/ + +#ifndef UADDR +#define UADDR 0xEEE00000 /* address of u */ +#endif /* UADDR */ + +/* + * The memory looks like: + * 0x00000 - 0x01000 : trap vectors + * 0x01000 - 0x10000 : first 64k used by BUG + * 0x10000 == start : Boot loader jumps here. (for now, this can + * handle only NMAGIC - screwy linker) + * + ***********************************************************************/ + text + +LABEL(_kernelstart) +LABEL(_start) +LABEL(start) + br _start_text +#if 0 + .align 4096 /* VBR points to page aligned list */ + _LABEL(vector_list) /* references memory BELOW this line */ + #include "machine/exception_vectors.h" + word END_OF_VECTOR_LIST + + _LABEL(_msgsw) + word 0 /* Bits here turn on/off debugging somewhere. */ +#endif + +ENTRY(doboot) + /* + * Try hitting the SRST bit in VMEchip2 to reset the system. + */ + or.u r3,r0, 0xfff4 + ld r4,r3, 0x0060 /* read offset (LCSR +0x60) */ + set r4,r4,1<23> /* set SYSRST bit - bit 23 */ + st r4,r3, 0x0060 /* and store it back */ + + /* + * We will be here if the reset above failed. In this case, + * we will try to return to bug. + * + * Switch to interrupt stack and call __doboot to take care + * going to BUG. Need to do this since __doboot turns off the + * the MMU and we need to be on a 1-to-1 mapped stack so that + * further calls don't get data access exceptions. + */ + + /* Should we use idle_u instead? XXX nivas */ + or.u r31, r0, hi16(_intstack_end) + or r31, r31, lo16(_intstack_end) + clr r31, r31, 3<0> /* round down to 8-byte boundary */ + + bsr __doboot + /*NOTREACHED*/ + +/**************************************************************************/ +LABEL(_start_text) /* This is the *real* start upon poweron or reset */ +#ifdef OLD_BOOT_LOADER + /* + * Args passed by boot loader + * r2 howto + * r3 first_addr (first available address) + * r4 ((Clun << 8) ; Dlun & FF) -> bootdev + * r5 esym + * r6 miniroot + */ + or.u r13, r0, hi16(_boothowto) + st r2, r13, lo16(_boothowto) + or.u r13, r0, hi16(_first_addr) + st r3, r13, lo16(_first_addr) +#if 0 + or.u r13, r0, hi16(_bootdev) + st r4, r13, lo16(_bootdev) +#endif + or.u r13, r0, hi16(_esym) + st r5, r13, lo16(_esym) + or.u r13, r0, hi16(_miniroot) + st r6, r13, lo16(_miniroot) +#else /* OLD_BOOT_LOADER */ + /* + * Args passed by boot loader + * r2 howto + * r3 not used + * r4 esym + * r5 start of mini + * r6 end miniroot + */ + or.u r13, r0, hi16(_boothowto) + st r2, r13, lo16(_boothowto) +#if 0 + or.u r13, r0, hi16(_bootdev) + st r3, r13, lo16(_bootdev) +#endif + or.u r13, r0, hi16(_first_addr) + st r4, r13, lo16(_first_addr) + or.u r13, r0, hi16(_esym) + st r4, r13, lo16(_esym) + or.u r13, r0, hi16(_miniroot) + st r5, r13, lo16(_miniroot) +#endif /* OLD_BOOT_LOADER */ + /* + * CPU Initialization + * + * Every CPU starts from here.. + * (well, from 'start' above, which just jumps here). + * + * I use r11 and r22 here 'cause they're easy to not + * get mixed up -- r10, for example, looks too similar + * to r0 when not being careful.... + * + * Ensure that the PSR is as we like: + * supervisor mode + * big-endian byte ordering + * concurrent operation allowed + * carry bit clear (I don't think we really care about this) + * FPU enabled + * misaligned access raises an exception + * interrupts disabled + * shadow registers frozen + * + * The manual says not to disable interrupts and freeze shadowing + * at the same time because interupts are not actually disabled + * until after the next instruction. Well, if an interrupt + * occurs now, we're in deep anyway, so I'm going to do + * the two together. + * + * Upon a reset (or poweron, I guess), the PSR indicates: + * supervisor mode + * interrupts, shadowing, FPU, missaligned exception: all disabled + * + * We'll just construct our own turning on what we want. + * + * jfriedl@omron.co.jp + */ + stcr r0, SSBR /* clear this for later */ + + set r11, r0, 1<PSR_SUPERVISOR_MODE_BIT> + set r11, r11, 1<PSR_INTERRUPT_DISABLE_BIT> + stcr r11, PSR + FLUSH_PIPELINE + /* shadowing, FPU, misalgined access exception: all enabled now.*/ +#if 0 + or.u r11, r0, hi16(_vector_list) + or r11, r11, lo16(_vector_list) + stcr r11, VBR +#endif /* 0 */ + stcr r0, VBR + + /* + * Switch to interrupt stack + * Use idle_u's stack instead? + */ + or.u r31, r0, hi16(_intstack_end) + or r31, r31, lo16(_intstack_end) + clr r31, r31, 3<0> /* round down to 8-byte boundary */ + + /* + * Want to make the call: + * vector_init(VBR, vector_list) + */ + or.u r3, r0, hi16(_vector_list) + or r3, r3, lo16(_vector_list) + bsr.n _vector_init + ldcr r2, VBR + +#if 0 + /* clear BSS. Boot loader might have already done this... */ + or.u r2, r0, hi16(_edata) + or r2, r2, lo16(_edata) + or.u r4, r0, hi16(_end) + or r4, r4, lo16(_end) + bsr.n _bzero /* bzero(edata, end-edata) */ + subu r3, r4, r2 +#endif + + /* still on int stack */ + bsr.n _m187_bootstrap + subu r31, r31, 40 + addu r31, r31, 40 + + /* switch to proc0 uarea */ + + or.u r10, r0, hi16(UADDR) + or r31, r10,lo16(UADDR) + addu r31, r31, USIZE - 8 + + /* + * Block clock interrupts for now. There is a problem with + * clock interrupts when the first clock interrupt is received. + * Hardclock() sees the base priority to be 0 and drops IPL to + * splsofclock() before calling softclock(). This opens up other + * clock interrupts to be received before the first one is ever + * finished. Also, the first entry on calltodo list is stuck for + * ever. As a work around, I will set the IPL to softclock so + * that the CLKF_BASEPRI() check in hardclock() will return false. + * XXX nivas + */ + +#if XXXX + bsr.n _setipl + or r2, r0, IPL_SOFTCLOCK + bsr _enable_interrupt + bsr.n _setipl + or r2, r0, IPL_HIGH +#endif + /* make the call: main() */ + bsr.n _main + subu r31, r31, 40 + addu r31, r31, 40 + bsr _panic + +/*****************************************************************************/ + + data + .align 4096 /* VBR points to page aligned list */ + global _vector_list +_vector_list: /* references memory BELOW this line */ +#include "machine/exception_vectors.h" + word END_OF_VECTOR_LIST + + global _msgsw +_msgsw: + word 0 /* Bits here turn on/off debugging somewhere */ + .align 4096 + global _intstack + global _intstack_end +_intstack: + space 4 * NBPG /* 16K */ +_intstack_end: + +/* + * When a process exits and its u. area goes away, we set curpcb to point + * to this `u.', leaving us with something to use for an interrupt stack, + * and letting all the register save code have a pcb_uw to examine. + * This is also carefully arranged (to come just before u0, so that + * process 0's kernel stack can quietly overrun into it during bootup, if + * we feel like doing that). + * Should be page aligned. + */ + global _idle_u +_idle_u: + space UPAGES * NBPG + +/* + * Process 0's u. + * + * This must be page aligned + */ + global _u0 + align 4096 +_u0: space UPAGES * NBPG +estack0: + +/* + * UPAGES get mapped to kstack + */ + + global _kstack +_kstack: + word UADDR + +#ifdef DDB + global _esym +_esym: + word 0 +#endif /* DDB */ + + global _proc0paddr /* move to C code */ +_proc0paddr: + word _u0 /* KVA of proc0 uarea */ + +/* + * _curpcb points to the current pcb (and hence u. area). + * Initially this is the special one. + */ +/* + * pcb is composed of kernel state + user state + * I may have to change curpcb to u0 + PCB_USER based on what + * other parts expect XXX nivas + */ + global _curpcb /* move to C code */ +_curpcb: word _u0 /* curpcb = &u0 */ + +/* + * Trampoline code. Gets copied to the top of + * user stack in exec. + */ + global _sigcode +_sigcode: + /* r31 points to sigframe */ + ld r2, r31, 0 /* signo */ + ld r3, r31, 4 /* siginfo_t* */ + ld r4, r31, 8 /* sigcontext* */ + ld r5, r31, 12 /* handler */ + jsr.n r5 + subu r31, r31, 40 /* give some stack space */ + addu r31, r31, 40 /* restore old sp value */ + ld r2, r31, 8 /* sigcontext* */ + or r13, r0, SYS_sigreturn + tb0 0, r0, 128 /* syscall trap, calling sigreturn */ + or r0, r0, 0 + or r0, r0, 0 + /* sigreturn will not return unless it fails */ + or r13, r0, SYS_exit + tb0 0, r0, 128 /* syscall trap, exit */ + or r0, r0, 0 + or r0, r0, 0 + global _esigcode +_esigcode: diff --git a/sys/arch/mvme88k/mvme88k/locore_asm_routines.S b/sys/arch/mvme88k/mvme88k/locore_asm_routines.S new file mode 100644 index 00000000000..5735e79a8a1 --- /dev/null +++ b/sys/arch/mvme88k/mvme88k/locore_asm_routines.S @@ -0,0 +1,1736 @@ +/* + * Mach Operating System + * Copyright (c) 1993-1992 Carnegie Mellon University + * Copyright (c) 1991 OMRON Corporation + * Copyright (c) 1996 Nivas Madhur + * All Rights Reserved. + * + * Permission to use, copy, modify and distribute this software and its + * documentation is hereby granted, provided that both the copyright + * notice and this permission notice appear in all copies of the + * software, derivative works or modified versions, and any portions + * thereof, and that both notices appear in supporting documentation. + * + * CARNEGIE MELLON AND OMRON ALLOW FREE USE OF THIS SOFTWARE IN ITS "AS IS" + * CONDITION. CARNEGIE MELLON AND OMRON DISCLAIM ANY LIABILITY OF ANY KIND + * FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. + * + * Carnegie Mellon requests users of this software to return to + * + * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU + * School of Computer Science + * Carnegie Mellon University + * Pittsburgh PA 15213-3890 + * + * any improvements or extensions that they make and grant Carnegie the + * rights to redistribute these changes. + */ +/* locore_asm_routines.c + * + ********************************************************************** + * This file created by Omron Corporation, 1990. + * + * HISTORY + * + **************************************************************RCS*****/ + +#ifndef ASSEMBLER +# define ASSEMBLER +#endif + +#include <machine/trap.h> +#include <machine/board.h> +#include <machine/asm.h> +#include <sys/errno.h> + + +/***************************************************************************** + * DO_LOAD_ADDRESS + * + * unsigned int do_load_word(address, supervisor_mode) + * vm_offset_t address; \\ in r2 + * boolean_t supervisor_mode; \\ in r3 + * + * Return the word at ADDRESS (from user space if SUPERVISOR_MODE is zero, + * supervisor space if non-zero). + * + */ + +ENTRY(do_load_word) /* do_load_word(address, supervisor) */ + bcnd ne0,r3,1f +#if ERRATA__XXX_USR + NOP + ld.usr r2,r2,r0 + NOP + NOP + NOP +#else + ld.usr r2,r2,r0 +#endif + br 2f +1: ld r2,r2,r0 +2: jmp r1 + +ENTRY(do_load_half) /* do_load_half(address, supervisor) */ + bcnd ne0,r3,1f +#if ERRATA__XXX_USR + NOP + ld.h.usr r2,r2,r0 + NOP + NOP + NOP +#else + ld.h.usr r2,r2,r0 +#endif + br 2f +1: ld.h r2,r2,r0 +2: jmp r1 + +ENTRY(do_load_byte) /* do_load_byte(address, supervisor) */ + bcnd ne0,r3,1f +#if ERRATA__XXX_USR + NOP + ld.b.usr r2,r2,r0 + NOP + NOP + NOP +#else + ld.b.usr r2,r2,r0 +#endif + br 2f +1: ld.b r2,r2,r0 +2: jmp r1 + +ENTRY(do_store_word) /* do_store_word(address, data, supervisor) */ + bcnd ne0,r4,1f +#if ERRATA__XXX_USR + NOP + st.usr r3,r2,r0 + NOP + NOP + NOP +#else + st.usr r3,r2,r0 +#endif + br 2f +1: st r3,r2,r0 +2: jmp r1 + +ENTRY(do_store_half) /* do_store_half(address, data, supervisor) */ + bcnd ne0,r4,1f +#if ERRATA__XXX_USR + NOP + st.h.usr r3,r2,r0 + NOP + NOP + NOP +#else + st.h.usr r3,r2,r0 +#endif + br 2f +1: st.h r3,r2,r0 +2: jmp r1 + +ENTRY(do_store_byte) /* do_store_byte(address, data, supervisor) */ + bcnd ne0,r4,1f +#if ERRATA__XXX_USR + NOP + st.b.usr r3,r2,r0 + NOP + NOP + NOP +#else + st.b.usr r3,r2,r0 +#endif + br 2f +1: st.b r3,r2,r0 +2: jmp r1 + +ENTRY(do_xmem_word) /* do_xmem_word(address, data, supervisor) */ + bcnd ne0,r4,1f +#if ERRATA__XXX_USR + NOP + xmem.usr r3,r2,r0 + NOP + NOP + NOP +#else + xmem.usr r3,r2,r0 +#endif + br 2f +1: xmem r3,r2,r0 +2: jmp r1 + +ENTRY(do_xmem_byte) /* do_xmem_byte(address, data, supervisor) */ + bcnd ne0,r4,1f +#if ERRATA__XXX_USR + NOP + xmem.bu.usr r3,r2,r0 + NOP + NOP + NOP +#else + xmem.bu.usr r3,r2,r0 +#endif + br 2f +1: xmem.bu r3,r2,r0 +2: jmp r1 + +/************************************************************************* + ************************************************************************* + ** + ** void enable_interrupt(void) + ** + ** Enables processor interrupts (for the executing cpu). + **/ +#undef enable_interrupt +ENTRY(enable_interrupt) + ldcr r2, PSR + clr r2, r2, 1<PSR_INTERRUPT_DISABLE_BIT> + stcr r2, PSR + FLUSH_PIPELINE + jmp r1 + +#if DDB +/* a version of enable_interrupt for the debugger; should never + have breakpoints set it in. Keep it consistent with enable + interrupt above */ +ENTRY(db_enable_interrupt) + ldcr r2, PSR + clr r2, r2, 1<PSR_INTERRUPT_DISABLE_BIT> + stcr r2, PSR + FLUSH_PIPELINE + jmp r1 +#endif /* DDB */ + +/************************************************************************* + ************************************************************************* + ** + ** unsigned long disable_interrupt(void) + ** + ** Disables processor interrupts (for the executing CPU) and returns + ** the *previous* PSR. + ** + ** if ((oldPSR & 0x02) == 0) + ** interrupts_were_previously_on = 1; + **/ +#undef disable_interrupt +ENTRY(disable_interrupt) + ldcr r2, PSR + set r3, r2, 1<PSR_INTERRUPT_DISABLE_BIT> /* set disable bit*/ + stcr r3, PSR + FLUSH_PIPELINE + jmp r1 + +/* a version of disable_interrupt for the kernel debugger. Should never + have breakpoints set in it. Make sure it stays consistent with + disable_interrupt */ + +#if DDB +ENTRY(db_disable_interrupt) + ldcr r2, PSR + set r3, r2, 1<PSR_INTERRUPT_DISABLE_BIT> /* set disable bit*/ + stcr r3, PSR + FLUSH_PIPELINE + jmp r1 +#endif /* DDB */ + +/* version for the debugger */ + +#if DDB + +ENTRY(db_are_interrupts_disabled) + ldcr r2, PSR /* get the processor status word */ + set r3, r0, 1<PSR_INTERRUPT_DISABLE_BIT> /* set mask */ + jmp.n r1 /* delayed return */ + and r2, r2, r3 /* r2 = r3 & r2 */ +#endif /* DDB */ + +LABEL(_FAULT_ERROR) + or r2,r0,1 /* bad copy */ + jmp r1 + +/* LABEL(_ALLOW_FAULT_START) */ + +/* + * Fetch from user space + * r2 == address in user space + */ + +ENTRY(fuword) +ENTRY(fuiword) + or.u r5, r0, hi16(_curpcb) + ld r6, r5, lo16(_curpcb) + or.u r5, r0, hi16(fusu_fault) + or r5, r5, lo16(fusu_fault) + st r5, r6, PCB_ONFAULT /* pcb_onfault = fusu_fault */ +#if ERRATA__XXX_USR + NOP + ld.usr r5, r0, r2 + NOP + NOP + NOP +#else + ld.usr r5, r0, r2 +#endif + or r2, r0, r5 + br fusu_ret +fusu_fault: + subu r2, r0, 1 +fusu_ret: + or.u r5, r0, hi16(_curpcb) + ld r6, r5, lo16(_curpcb) + st r0, r6, PCB_ONFAULT /* pcb_onfault = 0 */ + + jmp r1 + +ENTRY(fusword) + or.u r5, r0, hi16(_curpcb) + ld r6, r5, lo16(_curpcb) + or.u r5, r0, hi16(fusu_fault) + or r5, r5, lo16(fusu_fault) + st r5, r6, PCB_ONFAULT /* pcb_onfault = fusu_fault */ +#if ERRATA__XXX_USR + NOP + ld.h.usr r5, r0, r2 + NOP + NOP + NOP +#else + ld.h.usr r5, r0, r2 +#endif + or r2, r0, r5 + br fusu_ret + +ENTRY(fubyte) +ENTRY(fuibyte) + or.u r5, r0, hi16(_curpcb) + ld r6, r5, lo16(_curpcb) + or.u r5, r0, hi16(fusu_fault) + or r5, r5, lo16(fusu_fault) + st r5, r6, PCB_ONFAULT /* pcb_onfault = fusu_fault */ +#if ERRATA__XXX_USR + NOP + ld.b.usr r5, r0, r2 + NOP + NOP + NOP +#else + ld.b.usr r5, r0, r2 +#endif + or r2, r0, r5 + br fusu_ret + +ENTRY(fuswintr) + or.u r5, r0, hi16(_curpcb) + ld r6, r5, lo16(_curpcb) + or.u r5, r0, hi16(_fubail) + or r5, r5, lo16(_fubail) + st r5, r6, PCB_ONFAULT /* pcb_onfault = fubail */ +#if ERRATA__XXX_USR + NOP + ld.h.usr r5, r2, r0 + NOP + NOP + NOP +#else + ld.h.usr r5, r2, r0 +#endif + or r2, r0, r5 + br fusu_ret + +ENTRY(fubail) + subu r2, r0, 1 + br fusu_ret + +/* + * store to user space. + * r2 == address in user space + * r3 == byte/short/word + */ + +ENTRY(suword) +ENTRY(suiword) + or.u r5, r0, hi16(_curpcb) + ld r6, r5, lo16(_curpcb) + or.u r5, r0, hi16(fusu_fault) + or r5, r5, lo16(fusu_fault) + st r5, r6, PCB_ONFAULT /* pcb_onfault = fusu_fault */ +#if ERRATA__XXX_USR + NOP + st.usr r3, r2, r0 + NOP + NOP + NOP +#else + st.usr r3, r2, r0 +#endif + or r2, r0, r0 /* return success */ + br fusu_ret + +ENTRY(susword) + or.u r5, r0, hi16(_curpcb) + ld r6, r5, lo16(_curpcb) + or.u r5, r0, hi16(fusu_fault) + or r5, r5, lo16(fusu_fault) + st r5, r6, PCB_ONFAULT /* pcb_onfault = fusu_fault */ +#if ERRATA__XXX_USR + NOP + st.h.usr r3, r2, r0 + NOP + NOP + NOP +#else + st.h.usr r3, r2, r0 +#endif + or r2, r0, r0 /* return success */ + br fusu_ret + +ENTRY(subyte) +ENTRY(suibyte) + or.u r5, r0, hi16(_curpcb) + ld r6, r5, lo16(_curpcb) + or.u r5, r0, hi16(fusu_fault) + or r5, r5, lo16(fusu_fault) + st r5, r6, PCB_ONFAULT /* pcb_onfault = fusu_fault */ +#if ERRATA__XXX_USR + NOP + st.b.usr r3, r2, r0 + NOP + NOP + NOP +#else + st.b.usr r3, r2, r0 +#endif + or r2, r0, r0 /* return success */ + br fusu_ret + +ENTRY(suswintr) + or.u r5, r0, hi16(_curpcb) + ld r6, r5, lo16(_curpcb) + or.u r5, r0, hi16(_subail) + or r5, r5, lo16(_subail) + st r5, r6, PCB_ONFAULT /* pcb_onfault = subail */ +#if ERRATA__XXX_USR + NOP + st.h.usr r3, r2, r0 + NOP + NOP + NOP +#else + st.h.usr r3, r2, r0 +#endif + or r2, r0, r0 /* return success */ + br fusu_ret + +ENTRY(subail) + subu r2, r0, 1 + br fusu_ret + +#if 0 +/* + * copystr(fromaddr, toaddr, maxlength, &lencopied) + * + * Copy a null terminated string from one point to another in + * the kernel address space. + */ +ENTRY(copystr) + or r6,r0,0 + bcnd lt0,r4,Lcsflt1 /* negative count, error */ + bcnd eq0,r4,Lcsdone /* zero count, all done */ +Lcsloop: + ld r8,r2,r6 /* copy a byte */ + st r8,r3,r6 + addu r6,r6,1 /* bump the index */ + bcnd eq0,r8,Lcsdone /* if null, done */ + subu r4,r4,1 /* decrement count to copy */ + bcnd ne0,r4,Lcsloop /* if more to copy, loop */ + br Lcsflt2 /* ran out of room, error */ +Lcsdone: + bcnd eq0, r5, Lcsret /* if return len not desired, return */ + st r6,r5,0 /* stash it */ +Lcsret: + or r2,r0,0 /* good status */ + jmp r1 +Lcsflt1: + or r2,r0,EFAULT /* return fault */ + br Lcsdone +Lcsflt2: + or r2,r0,ENAMETOOLONG /* ran out of space */ + br Lcsdone +Lcsdone: + jmp r1 +#endif /* 0 */ +/* + * Copy specified amount of data from user space into the kernel + * copyin(from, to, len) + * r2 == from (user source address) + * r3 == to (kernel destination address) + * r4 == length + * (r1=return addr) + */ + +#define SRC r2 +#define DEST r3 +#define LEN r4 + +ENTRY(copyin) + /* set up fault handler */ + or.u r5, r0, hi16(_curpcb) + ld r6, r5, lo16(_curpcb) + or.u r5, r0, hi16(.Lciflt) + or r5, r5, lo16(.Lciflt) + st r5, r6, PCB_ONFAULT /* pcb_onfault = .Lciflt */ + + /*bcnd ne0, LEN, 1f ; XXX optimize len = 0 case */ + /*;or r2, r0, 0 */ + /*;br .Lcidone */ + /*;1: ;bcnd lt0, LEN, .Lciflt ; EFAULT if len < 0 */ + + /* If it's a small length (less than 8), then do byte-by-byte */ + cmp r9, LEN, 8 + bb1 lt, r9, copyin_byte_only + + /* If they're not aligned similiarly, use byte only... */ + xor r9, SRC, DEST + mask r8, r9, 0x3 + bcnd ne0, r8, copyin_byte_only + + /* + * At this point, we don't know if they're word aligned or not, + * but we know that what needs to be done to one to align + * it is what's needed for the other. + */ + bb1 0, SRC, copyin_left_align_to_halfword +copyin_left_aligned_to_halfword: + bb1 1, SRC, copyin_left_align_to_word +copyin_left_aligned_to_word: + bb1 0, LEN, copyin_right_align_to_halfword +copyin_right_aligned_to_halfword: + bb1 1, LEN, copyin_right_align_to_word +copyin_right_aligned_to_word: + + /* At this point, both SRC and DEST are aligned to a word */ + /* boundry, and LEN is an even multiple of 4. */ + bb1.n 2, LEN, copyin_right_align_to_doubleword + or r7, r0, 4 + +copyin_right_aligned_to_doubleword: +#if ERRATA__XXX_USR + NOP + ld.usr r5, SRC, r0 + NOP + NOP + NOP + ld.usr r6, SRC, r7 + NOP + NOP + NOP +#else + ld.usr r5, SRC, r0 + ld.usr r6, SRC, r7 +#endif + subu LEN, LEN, 8 + st r5, DEST, r0 + addu SRC, SRC, 8 + st r6, DEST, r7 + bcnd.n ne0, LEN, copyin_right_aligned_to_doubleword + addu DEST, DEST, 8 + or r2, r0, r0 /* successful return */ + br .Lcidone + + /***************************************************/ + +copyin_left_align_to_halfword: +#if ERRATA__XXX_USR + NOP + ld.b.usr r5, SRC, r0 + NOP + NOP + NOP +#else + ld.b.usr r5, SRC, r0 +#endif + subu LEN, LEN, 1 + st.b r5, DEST, r0 + addu SRC, SRC, 1 + br.n copyin_left_aligned_to_halfword + addu DEST, DEST, 1 + +copyin_left_align_to_word: +#if ERRATA__XXX_USR + NOP + ld.h.usr r5, SRC, r0 + NOP + NOP + NOP +#else + ld.h.usr r5, SRC, r0 +#endif + subu LEN, LEN, 2 + st.h r5, DEST, r0 + addu SRC, SRC, 2 + br.n copyin_left_aligned_to_word + addu DEST, DEST, 2 + +copyin_right_align_to_halfword: + subu LEN, LEN, 1 +#if ERRATA__XXX_USR + NOP + ld.b.usr r5, SRC, LEN + NOP + NOP + NOP +#else + ld.b.usr r5, SRC, LEN +#endif + br.n copyin_right_aligned_to_halfword + st.b r5, DEST, LEN + +copyin_right_align_to_word: + subu LEN, LEN, 2 +#if ERRATA__XXX_USR + NOP + ld.h.usr r5, SRC, LEN + NOP + NOP + NOP +#else + ld.h.usr r5, SRC, LEN +#endif + br.n copyin_right_aligned_to_word + st.h r5, DEST, LEN + +copyin_right_align_to_doubleword: + subu LEN, LEN, 4 +#if ERRATA__XXX_USR + NOP + ld.usr r5, SRC, LEN + NOP + NOP + NOP +#else + ld.usr r5, SRC, LEN +#endif + bcnd.n ne0, LEN, copyin_right_aligned_to_doubleword + st r5, DEST, LEN + or r2, r0, r0 /* successful return */ + br .Lcidone + +copyin_byte_only: + bcnd eq0, LEN, 2f + 1: + subu LEN, LEN, 1 +#if ERRATA__XXX_USR + NOP + ld.b.usr r5, SRC, LEN + NOP + NOP + NOP +#else + ld.b.usr r5, SRC, LEN +#endif + bcnd.n ne0, LEN, 1b + st.b r5, DEST, LEN + 2: or r2, r0, r0 /* successful return */ + br .Lcidone +.Lcidone: + or.u r5,r0,hi16(_curpcb) + ld r6,r5,lo16(_curpcb) + st r0,r6,PCB_ONFAULT + jmp r1 +.Lciflt: + or r2, r0, EFAULT /* return fault */ + br .Lcidone + +#undef SRC +#undef DEST +#undef LEN +/*######################################################################*/ +/*######################################################################*/ + +/* + * Copy a null terminated string from the user space to the kernel + * address space. + * + * copyinstr(from, to, maxlen, &lencopied) + * r2 == from + * r3 == to + * r4 == maxlen + * r5 == len actually transferred (includes the terminating NULL!!!) + * r6 & r7 - used as temporaries + */ +#define SRC r2 +#define DEST r3 +#define CNT r4 +#define LEN r5 + +ENTRY(copyinstr) + /* setup fault handler */ + or.u r6, r0, hi16(_curpcb) + ld r7, r6, lo16(_curpcb) + or.u r6, r0, hi16(.Lcisflt) + or r6, r6, lo16(.Lcisflt) + st r6, r7, PCB_ONFAULT + bcnd lt0, CNT, .Lcisflt + bcnd eq0, CNT, .Lcisdone + or r6, r0, 0 + 1: +#if ERRATA__XXX_USR + NOP + ld.bu.usr r7, SRC, r6 + NOP + NOP + NOP +#else + ld.bu.usr r7, SRC, r6 +#endif + st.b r7, DEST, r6 + bcnd.n eq0, r7, 2f /* all done */ + addu r6, r6, 1 + cmp r7, r6, CNT + bb1 lt, r7, 1b + or r2, r0, ENAMETOOLONG /* over flow */ + br .Lcisdone + 2: /* all done */ + or r2, r0, 0 + br .Lcisdone + +.Lcisdone: + bcnd eq0, LEN, 3f + st r6, r0, LEN + 3: or.u r5,r0,hi16(_curpcb) + ld r6,r5,lo16(_curpcb) + st r0,r6,PCB_ONFAULT /* clear the handler */ + jmp r1 +.Lcisflt: + or r2, r0, EFAULT /* return fault */ + br .Lcisdone + +#undef SRC +#undef DEST +#undef CNT +#undef LEN + +/* + * Copy specified amount of data from kernel to the user space + * Copyout(from, to, len) + * r2 == from (kernel source address) + * r3 == to (user destination address) + * r4 == length + */ + +#define SRC r2 +#define DEST r3 +#define LEN r4 + +ENTRY(copyout) + /* setup fault handler */ + or.u r5, r0, hi16(_curpcb) + ld r6, r5, lo16(_curpcb) + or.u r5, r0, hi16(.Lcoflt) + or r5, r5, lo16(.Lcoflt) + st r5, r6, PCB_ONFAULT /* pcb_onfault = .Lcoflt */ +/* ;bcnd ne0, LEN, 1f ; XXX optimize len = 0 case */ +/* ;or r2, r0, 0 */ +/* ;br .Lcodone */ + /*;1: ;bcnd lt0, LEN, .Lcoflt ; EFAULT if len < 0 */ + /* If it's a small length (less than 8), then do byte-by-byte */ + cmp r9, LEN, 8 + bb1 lt, r9, copyout_byte_only + + /* If they're not aligned similiarly, use byte only... */ + xor r9, SRC, DEST + mask r8, r9, 0x3 + bcnd ne0, r8, copyout_byte_only + + /* + * At this point, we don't know if they're word aligned or not, + * but we know that what needs to be done to one to align + * it is what's needed for the other. + */ + bb1 0, SRC, copyout_left_align_to_halfword +copyout_left_aligned_to_halfword: + bb1 1, SRC, copyout_left_align_to_word +copyout_left_aligned_to_word: + bb1 0, LEN, copyout_right_align_to_halfword +copyout_right_aligned_to_halfword: + bb1 1, LEN, copyout_right_align_to_word +copyout_right_aligned_to_word: + + /* + * At this point, both SRC and DEST are aligned to a word + * boundry, and LEN is an even multiple of 4. + */ + bb1.n 2, LEN, copyout_right_align_to_doubleword + or r7, r0, 4 + +copyout_right_aligned_to_doubleword: + ld r5, SRC, r0 + ld r6, SRC, r7 + subu LEN, LEN, 8 +#if ERRATA__XXX_USR + NOP + st.usr r5, DEST, r0 + NOP + NOP + NOP +#else + st.usr r5, DEST, r0 +#endif + addu SRC, SRC, 8 +#if ERRATA__XXX_USR + NOP + st.usr r6, DEST, r7 + NOP + NOP + NOP +#else + st.usr r6, DEST, r7 +#endif + bcnd.n ne0, LEN, copyout_right_aligned_to_doubleword + addu DEST, DEST, 8 + or r2, r0, r0 /* successful return */ + br .Lcodone + + /***************************************************/ +copyout_left_align_to_halfword: + ld.b r5, SRC, r0 + subu LEN, LEN, 1 +#if ERRATA__XXX_USR + NOP + st.b.usr r5, DEST, r0 + NOP + NOP + NOP +#else + st.b.usr r5, DEST, r0 +#endif + addu SRC, SRC, 1 + br.n copyout_left_aligned_to_halfword + addu DEST, DEST, 1 + +copyout_left_align_to_word: + ld.h r5, SRC, r0 + subu LEN, LEN, 2 +#if ERRATA__XXX_USR + NOP + st.h.usr r5, DEST, r0 + NOP + NOP + NOP +#else + st.h.usr r5, DEST, r0 +#endif + addu SRC, SRC, 2 + br.n copyout_left_aligned_to_word + addu DEST, DEST, 2 + +copyout_right_align_to_halfword: + subu LEN, LEN, 1 + ld.b r5, SRC, LEN +#if ERRATA__XXX_USR + NOP + st.b.usr r5, DEST, LEN + NOP + NOP + NOP + br copyout_right_aligned_to_halfword +#else + br.n copyout_right_aligned_to_halfword + st.b.usr r5, DEST, LEN +#endif + +copyout_right_align_to_word: + subu LEN, LEN, 2 + ld.h r5, SRC, LEN +#if ERRATA__XXX_USR + NOP + st.h.usr r5, DEST, LEN + NOP + NOP + NOP + br copyout_right_aligned_to_word +#else + br.n copyout_right_aligned_to_word + st.h.usr r5, DEST, LEN +#endif + +copyout_right_align_to_doubleword: + subu LEN, LEN, 4 + ld r5, SRC, LEN +#if ERRATA__XXX_USR + NOP + st.usr r5, DEST, LEN + NOP + NOP + NOP + bcnd ne0, LEN, copyout_right_aligned_to_doubleword +#else + bcnd.n ne0, LEN, copyout_right_aligned_to_doubleword + st.usr r5, DEST, LEN +#endif + or r2, r0, r0 /* successful return */ + br .Lcodone + +_LABEL(copyout_byte_only) + bcnd eq0, LEN, 2f + 1: + subu LEN, LEN, 1 + ld.b r5, SRC, LEN +#if ERRATA__XXX_USR + NOP + st.b.usr r5, DEST, LEN + NOP + NOP + NOP + bcnd ne0, LEN, 1b +# else + bcnd.n ne0, LEN, 1b + st.b.usr r5, DEST, LEN +# endif + + 2: or r2, r0, r0 /* successful return */ + br .Lcodone + +.Lcodone: + or.u r5,r0,hi16(_curpcb) + ld r6,r5,lo16(_curpcb) + st r0,r6,PCB_ONFAULT /* clear the handler */ + jmp r1 +.Lcoflt: + or r2, r0, EFAULT /* return fault */ + br .Lcodone + +#undef SRC +#undef DEST +#undef LEN + +/* + * Copy a null terminated string from the kernel space to the user + * address space. + * + * copyoutstr(from, to, maxlen, &lencopied) + * r2 == from + * r3 == to + * r4 == maxlen that can be copied + * r5 == len actually copied (including the terminating NULL!!!) + */ + +#define SRC r2 +#define DEST r3 +#define CNT r4 +#define LEN r5 + +ENTRY(copyoutstr) + /* setup fault handler */ + or.u r6, r0, hi16(_curpcb) + ld r7, r6, lo16(_curpcb) + or.u r6, r0, hi16(.Lcosflt) + or r6, r6, lo16(.Lcosflt) + st r6, r7, PCB_ONFAULT + bcnd lt0, CNT, .Lcosflt + bcnd eq0, CNT, .Lcosdone + or r6, r0, 0 + 1: + ld.bu r7, SRC, r6 +#if ERRATA__XXX_USR + NOP + st.b.usr r7, DEST, r6 + NOP + NOP + NOP +#else + st.b.usr r7, DEST, r6 +#endif + bcnd.n eq0, r7, 2f /* all done */ + addu r6, r6, 1 + cmp r7, r6, CNT + bb1 lt, r7, 1b + or r2, r0, ENAMETOOLONG /* over flow */ + br .Lcosdone + 2: /* all done */ + or r2, r0, 0 + br .Lcosdone + +.Lcosflt: + or r2, r0, EFAULT /* return fault */ + br .Lcosdone + +.Lcosdone: + bcnd eq0, LEN, 3f + st r6, r0, LEN + 3: or.u r5,r0,hi16(_curpcb) + ld r6,r5,lo16(_curpcb) + st r0,r6,PCB_ONFAULT /* clear the handler */ + jmp r1 + +#undef SRC +#undef DEST +#undef CNT +#undef LEN + +/*######################################################################*/ +/*LABEL(_ALLOW_FAULT_END)*/ +/*word 0 */ /* to separate from routine below */ +/*######################################################################*/ + +/* + * Gcc 2 generates calls to memcpy for bcopies of unknown size. memcpy + * can simply be implemented as ovbcopy but the src (r2, r3) and dst args need to + * be switched. + */ +/* + * void memcpy(dest, source, count) + * + */ +ENTRY(memcpy) + or r5, r0, r2 /* dst -> tmp */ + or r2, r0, r3 /* src -> 1st arg */ + br.n _ovbcopy /* call ovbcopy */ + or r3, r0, r5 /* dst -> 2nd arg */ + + +/* + * void bcopy(source, destination, count) + * + * copy count bytes of data from source to destination + * Don Harper (don@omron.co.jp), Omron Corporation. + * + */ + +ENTRY(bcopy) +ENTRY(ovbcopy) + bcnd le0,r4,bcopy_out /* nothing to do if count <= 0 */ +/* + * check position of source and destination data + */ + cmp r9,r2,r3 /* compare source address to destination */ + bb1 eq,r9,bcopy_out /* nothing to do if addresses are equal */ + bb1 lo,r9,bcopy_reverse /* copy in reverse if src < destination */ +/* + * source address is greater than destination address, copy forward + */ + cmp r9,r4,16 /* see if we have at least 16 bytes */ + bb1 lt,r9,f_byte_copy /* copy bytes for small data length */ +/* + * determine copy strategy based on alignment of source and destination + */ + mask r6,r2,3 /* get 2 low order bits of source address */ + mask r7,r3,3 /* get 2 low order bits of destintation addr */ + mak r6,r6,0<4> /* convert source bits to table offset */ + mak r7,r7,0<2> /* convert destination bits to table offset */ + or.u r12,r0,hi16(f_strat) /* forward strategy table address (high) */ + or r12,r12,lo16(f_strat) /* forward strategy table address (low) */ + addu r6,r6,r7 /* compute final table offset for strategy */ + ld r12,r12,r6 /* load the strategy routine */ + jmp r12 /* branch to strategy routine */ + + +/* + * Copy three bytes from src to destination then copy words + */ +_LABEL(f_3byte_word_copy) + ld.bu r6,r2,0 /* load byte from source */ + ld.bu r7,r2,1 /* load byte from source */ + ld.bu r8,r2,2 /* load byte from source */ + st.b r6,r3,0 /* store byte to destination */ + st.b r7,r3,1 /* store byte to destination */ + st.b r8,r3,2 /* store byte to destination */ + addu r2,r2,3 /* increment source pointer */ + addu r3,r3,3 /* increment destination pointer */ + br.n f_word_copy /* copy full words */ + subu r4,r4,3 /* decrement length */ + +/* + * Copy 1 halfword from src to destination then copy words + */ +_LABEL(f_1half_word_copy) + ld.hu r6,r2,0 /* load half-word from source */ + st.h r6,r3,0 /* store half-word to destination */ + addu r2,r2,2 /* increment source pointer */ + addu r3,r3,2 /* increment destination pointer */ + br.n f_word_copy /* copy full words */ + subu r4,r4,2 /* decrement remaining length */ + +/* + * Copy 1 byte from src to destination then copy words + */ +_LABEL(f_1byte_word_copy) + ld.bu r6,r2,0 /* load 1 byte from source */ + st.b r6,r3,0 /* store 1 byte to destination */ + addu r2,r2,1 /* increment source pointer */ + addu r3,r3,1 /* increment destination pointer */ + subu r4,r4,1 /* decrement remaining length */ + /* fall through to word copy */ +/* + * Copy as many full words as possible, 4 words per loop + */ +_LABEL(f_word_copy) + cmp r10,r4,16 /* see if we have 16 bytes remaining */ + bb1 lo,r10,f_byte_copy /* not enough left, copy bytes */ + ld r6,r2,0 /* load first word */ + ld r7,r2,4 /* load second word */ + ld r8,r2,8 /* load third word */ + ld r9,r2,12 /* load fourth word */ + st r6,r3,0 /* store first word */ + st r7,r3,4 /* store second word */ + st r8,r3,8 /* store third word */ + st r9,r3,12 /* store fourth word */ + addu r2,r2,16 /* increment source pointer */ + addu r3,r3,16 /* increment destination pointer */ + br.n f_word_copy /* branch to copy another block */ + subu r4,r4,16 /* decrement remaining length */ + +_LABEL(f_1byte_half_copy) + ld.bu r6,r2,0 /* load 1 byte from source */ + st.b r6,r3,0 /* store 1 byte to destination */ + addu r2,r2,1 /* increment source pointer */ + addu r3,r3,1 /* increment destination pointer */ + subu r4,r4,1 /* decrement remaining length */ + /* fall through to half copy */ + +_LABEL(f_half_copy) + cmp r10,r4,16 /* see if we have 16 bytes remaining */ + bb1 lo,r10,f_byte_copy /* not enough left, copy bytes */ + ld.hu r6,r2,0 /* load first half-word */ + ld.hu r7,r2,2 /* load second half-word */ + ld.hu r8,r2,4 /* load third half-word */ + ld.hu r9,r2,6 /* load fourth half-word */ + ld.hu r10,r2,8 /* load fifth half-word */ + ld.hu r11,r2,10 /* load sixth half-word */ + ld.hu r12,r2,12 /* load seventh half-word */ + ld.hu r13,r2,14 /* load eighth half-word */ + st.h r6,r3,0 /* store first half-word */ + st.h r7,r3,2 /* store second half-word */ + st.h r8,r3,4 /* store third half-word */ + st.h r9,r3,6 /* store fourth half-word */ + st.h r10,r3,8 /* store fifth half-word */ + st.h r11,r3,10 /* store sixth half-word */ + st.h r12,r3,12 /* store seventh half-word */ + st.h r13,r3,14 /* store eighth half-word */ + addu r2,r2,16 /* increment source pointer */ + addu r3,r3,16 /* increment destination pointer */ + br.n f_half_copy /* branch to copy another block */ + subu r4,r4,16 /* decrement remaining length */ + +_LABEL(f_byte_copy) + bcnd eq0,r4,bcopy_out /* branch if nothing left to copy */ + ld.bu r6,r2,0 /* load byte from source */ + st.b r6,r3,0 /* store byte in destination */ + addu r2,r2,1 /* increment source pointer */ + addu r3,r3,1 /* increment destination pointer */ + br.n f_byte_copy /* branch for next byte */ + subu r4,r4,1 /* decrement remaining length */ + +/* + * source address is less than destination address, copy in reverse + */ +_LABEL(bcopy_reverse) +/* + * start copy pointers at end of data + */ + addu r2,r2,r4 /* start source at end of data */ + addu r3,r3,r4 /* start destination at end of data */ +/* + * check for short data + */ + cmp r9,r4,16 /* see if we have at least 16 bytes */ + bb1 lt,r9,r_byte_copy /* copy bytes for small data length */ +/* + * determine copy strategy based on alignment of source and destination + */ + mask r6,r2,3 /* get 2 low order bits of source address */ + mask r7,r3,3 /* get 2 low order bits of destintation addr */ + mak r6,r6,0<4> /* convert source bits to table offset */ + mak r7,r7,0<2> /* convert destination bits to table offset */ + or.u r12,r0,hi16(r_strat) /* reverse strategy table address (high) */ + or r12,r12,lo16(r_strat) /* reverse strategy table address (low) */ + addu r6,r6,r7 /* compute final table offset for strategy */ + ld r12,r12,r6 /* load the strategy routine */ + jmp r12 /* branch to strategy routine */ + +/* + * Copy three bytes from src to destination then copy words + */ +_LABEL(r_3byte_word_copy) + subu r2,r2,3 /* decrement source pointer */ + subu r3,r3,3 /* decrement destination pointer */ + ld.bu r6,r2,0 /* load byte from source */ + ld.bu r7,r2,1 /* load byte from source */ + ld.bu r8,r2,2 /* load byte from source */ + st.b r6,r3,0 /* store byte to destination */ + st.b r7,r3,1 /* store byte to destination */ + st.b r8,r3,2 /* store byte to destination */ + br.n r_word_copy /* copy full words */ + subu r4,r4,3 /* decrement length */ + +/* + * Copy 1 halfword from src to destination then copy words + */ +_LABEL(r_1half_word_copy) + subu r2,r2,2 /* decrement source pointer */ + subu r3,r3,2 /* decrement destination pointer */ + ld.hu r6,r2,0 /* load half-word from source */ + st.h r6,r3,0 /* store half-word to destination */ + br.n r_word_copy /* copy full words */ + subu r4,r4,2 /* decrement remaining length */ + +/* + * Copy 1 byte from src to destination then copy words + */ +_LABEL(r_1byte_word_copy) + subu r2,r2,1 /* decrement source pointer */ + subu r3,r3,1 /* decrement destination pointer */ + ld.bu r6,r2,0 /* load 1 byte from source */ + st.b r6,r3,0 /* store 1 byte to destination */ + subu r4,r4,1 /* decrement remaining length */ + /* fall through to word copy */ +/* + * Copy as many full words as possible, 4 words per loop + */ +_LABEL(r_word_copy) + cmp r10,r4,16 /* see if we have 16 bytes remaining */ + bb1 lo,r10,r_byte_copy /* not enough left, copy bytes */ + subu r2,r2,16 /* decrement source pointer */ + subu r3,r3,16 /* decrement destination pointer */ + ld r6,r2,0 /* load first word */ + ld r7,r2,4 /* load second word */ + ld r8,r2,8 /* load third word */ + ld r9,r2,12 /* load fourth word */ + st r6,r3,0 /* store first word */ + st r7,r3,4 /* store second word */ + st r8,r3,8 /* store third word */ + st r9,r3,12 /* store fourth word */ + br.n r_word_copy /* branch to copy another block */ + subu r4,r4,16 /* decrement remaining length */ + +_LABEL(r_1byte_half_copy) + subu r2,r2,1 /* decrement source pointer */ + subu r3,r3,1 /* decrement destination pointer */ + ld.bu r6,r2,0 /* load 1 byte from source */ + st.b r6,r3,0 /* store 1 byte to destination */ + subu r4,r4,1 /* decrement remaining length */ + /* fall through to half copy */ + +_LABEL(r_half_copy) + cmp r10,r4,16 /* see if we have 16 bytes remaining */ + bb1 lo,r10,r_byte_copy /* not enough left, copy bytes */ + subu r2,r2,16 /* decrement source pointer */ + subu r3,r3,16 /* decrement destination pointer */ + ld.hu r6,r2,0 /* load first half-word */ + ld.hu r7,r2,2 /* load second half-word */ + ld.hu r8,r2,4 /* load third half-word */ + ld.hu r9,r2,6 /* load fourth half-word */ + ld.hu r10,r2,8 /* load fifth half-word */ + ld.hu r11,r2,10 /* load sixth half-word */ + ld.hu r12,r2,12 /* load seventh half-word */ + ld.hu r13,r2,14 /* load eighth half-word */ + st.h r6,r3,0 /* store first half-word */ + st.h r7,r3,2 /* store second half-word */ + st.h r8,r3,4 /* store third half-word */ + st.h r9,r3,6 /* store fourth half-word */ + st.h r10,r3,8 /* store fifth half-word */ + st.h r11,r3,10 /* store sixth half-word */ + st.h r12,r3,12 /* store seventh half-word */ + st.h r13,r3,14 /* store eighth half-word */ + br.n r_half_copy /* branch to copy another block */ + subu r4,r4,16 /* decrement remaining length */ + +_LABEL(r_byte_copy) + bcnd eq0,r4,bcopy_out /* branch if nothing left to copy */ + subu r2,r2,1 /* decrement source pointer */ + subu r3,r3,1 /* decrement destination pointer */ + ld.bu r6,r2,0 /* load byte from source */ + st.b r6,r3,0 /* store byte in destination */ + br.n r_byte_copy /* branch for next byte */ + subu r4,r4,1 /* decrement remaining length */ + +_LABEL(bcopy_out) + jmp r1 /* all done, return to caller */ + + data + align 4 +_LABEL(f_strat) + word f_word_copy + word f_byte_copy + word f_half_copy + word f_byte_copy + word f_byte_copy + word f_3byte_word_copy + word f_byte_copy + word f_1byte_half_copy + word f_half_copy + word f_byte_copy + word f_1half_word_copy + word f_byte_copy + word f_byte_copy + word f_1byte_half_copy + word f_byte_copy + word f_1byte_word_copy + +_LABEL(r_strat) + word r_word_copy + word r_byte_copy + word r_half_copy + word r_byte_copy + word r_byte_copy + word r_1byte_word_copy + word r_byte_copy + word r_1byte_half_copy + word r_half_copy + word r_byte_copy + word r_1half_word_copy + word r_byte_copy + word r_byte_copy + word r_1byte_half_copy + word r_byte_copy + word r_3byte_word_copy + + text + +/*######################################################################*/ +/*######################################################################*/ + +/* + * April 1990, Omron Corporation + * jfriedl@nff.ncl.omron.co.jp + * + * void bzero(destination, length) + * + * Clear (set to zero) LENGTH bytes of memory starting at DESTINATION. + * Note that there is no return value. + * + * This is fast. Really fast. Especially for long lengths. + */ +#define R_dest r2 +#define R_len r3 + +#define R_bytes r4 +#define R_mark_address r5 +#define R_addr r6 /* R_addr && R_temp SHARE */ +#define R_temp r6 /* R_addr && R_temp SHARE */ + + +ENTRY(blkclr) +ENTRY(bzero) + /* + * If the destination is not word aligned, we'll word align + * it first to make things easier. + * + * We'll check to see first if bit #0 is set and then bit #1 + * (of the destination address). If either are set, it's + * not word aligned. + */ + bb1 0, R_dest, not_initially_word_aligned + bb1 1, R_dest, not_initially_word_aligned + + now_word_aligned: + /* + * before we get into the main loop, grab the + * address of the label "mark" below. + */ + or.u R_mark_address, r0, hi16(mark) + or R_mark_address, R_mark_address, lo16(mark) + + top_of_main_loop: +# define MAX_AT_ONE_TIME 128 + /* + * Now we find out how many words we can zero-fill in a row. + * We do this by doing something like: + * + * bytes &= 0xfffffffc; + * if (bytes > MAX_AT_ONE_TIME) + * bytes = MAX_AT_ONE_TIME; + */ + + /* + * Clear lower two bits of length to give us the number of bytes + * ALIGNED TO THE WORD LENGTH remaining to move. + */ + clr R_bytes, R_len, 2<0> + + /* if we're done clearing WORDS, jump out */ + bcnd eq0, R_bytes, done_doing_words + + /* if the number of bytes > MAX_AT_ONE_TIME, do only the max */ + cmp R_temp, R_bytes, MAX_AT_ONE_TIME + bb1 lt, R_temp, 1f + + /* + * Since we're doing the max, we know exactly where we're + * jumping (the first one in the list!), so we can jump + * right there. However, we've still got to adjust + * the length, so we'll jump to where we ajust the length + * which just happens to fall through to the first store zero + * in the list. + * + * Note, however, that we're jumping to an instruction that + * would be in the delay slot for the jump in front of it, + * so if you change things here, WATCH OUT. + */ + br.n do_max + or R_bytes, r0, MAX_AT_ONE_TIME + + 1: + + /* + * Now we have the number of bytes to zero during this iteration, + * (which, as it happens, is the last iteration if we're here). + * We'll calculate the proper place to jump and then jump there, + * after adjusting the length. NOTE that there is a label between + * the "jmp.n" and the "subu" below... the "subu" is NOT always + * executed in the delay slot of the "jmp.n". + */ + subu R_addr, R_mark_address, R_bytes + + /* and go there (after adjusting the length via ".n") */ + jmp.n R_addr +do_max: subu R_len, R_len, R_bytes /* NOTE: this is in the delay slot! */ + + st r0, R_dest, 0x7c /* 128 */ + st r0, R_dest, 0x78 /* 124 */ + st r0, R_dest, 0x74 /* 120 */ + st r0, R_dest, 0x70 /* 116 */ + st r0, R_dest, 0x6c /* 112 */ + st r0, R_dest, 0x68 /* 108 */ + st r0, R_dest, 0x64 /* 104 */ + st r0, R_dest, 0x60 /* 100 */ + st r0, R_dest, 0x5c /* 96 */ + st r0, R_dest, 0x58 /* 92 */ + st r0, R_dest, 0x54 /* 88 */ + st r0, R_dest, 0x50 /* 84 */ + st r0, R_dest, 0x4c /* 80 */ + st r0, R_dest, 0x48 /* 76 */ + st r0, R_dest, 0x44 /* 72 */ + st r0, R_dest, 0x40 /* 68 */ + st r0, R_dest, 0x3c /* 64 */ + st r0, R_dest, 0x38 /* 60 */ + st r0, R_dest, 0x34 /* 56 */ + st r0, R_dest, 0x30 /* 52 */ + st r0, R_dest, 0x2c /* 44 */ + st r0, R_dest, 0x28 /* 40 */ + st r0, R_dest, 0x24 /* 36 */ + st r0, R_dest, 0x20 /* 32 */ + st r0, R_dest, 0x1c /* 28 */ + st r0, R_dest, 0x18 /* 24 */ + st r0, R_dest, 0x14 /* 20 */ + st r0, R_dest, 0x10 /* 16 */ + st r0, R_dest, 0x0c /* 12 */ + st r0, R_dest, 0x08 /* 8 */ + st r0, R_dest, 0x04 /* 4 */ + st r0, R_dest, 0x00 /* 0 */ + + mark: + br.n top_of_main_loop + addu R_dest, R_dest, R_bytes /* bump up the dest address */ + + + + done_doing_words: + bcnd ne0, R_len, finish_up_last_bytes + jmp r1 /* RETURN */ + + finish_up_last_bytes: + subu R_len, R_len, 1 + bcnd.n ne0, R_len, finish_up_last_bytes + st.b r0, R_dest, R_len + + leave: + jmp r1 /* RETURN */ + + not_initially_word_aligned: + /* + * Bzero to word-align the address (at least if the length allows it). + */ + bcnd eq0, R_len, leave + st.b r0, R_dest, 0 + addu R_dest, R_dest, 1 + mask R_temp, R_dest, 0x3 + bcnd.n eq0, R_temp, now_word_aligned + subu R_len, R_len, 1 + br not_initially_word_aligned + +#undef R_dest +#undef R_len +#undef R_bytes +#undef R_mark_address +#undef R_addr +#undef R_temp +#undef MAX_AT_ONE_TIME + +/**********************************************************************/ +/**********************************************************************/ +/**********************************************************************/ + +/* + * non-local goto + * int setjmp(label_t *); + * void longjmp(label_t*); + */ + global _setjmp +_setjmp: + st r1,r2,0 + st r14,r2,4 + st r15,r2,2*4 + st r16,r2,3*4 + st r17,r2,4*4 + st r18,r2,5*4 + st r19,r2,6*4 + st r20,r2,7*4 + st r21,r2,8*4 + st r22,r2,9*4 + st r23,r2,10*4 + st r24,r2,11*4 + st r25,r2,12*4 + st r26,r2,13*4 + st r27,r2,14*4 + st r28,r2,15*4 + st r29,r2,16*4 + st r30,r2,17*4 + st r31,r2,18*4 + jmp.n r1 + or r2,r0,r0 + + global _longjmp +_longjmp: + ld r1,r2,0 + ld r14,r2,4 + ld r15,r2,2*4 + ld r16,r2,3*4 + ld r17,r2,4*4 + ld r18,r2,5*4 + ld r19,r2,6*4 + ld r20,r2,7*4 + ld r21,r2,8*4 + ld r22,r2,9*4 + ld r23,r2,10*4 + ld r24,r2,11*4 + ld r25,r2,12*4 + ld r26,r2,13*4 + ld r27,r2,14*4 + ld r28,r2,15*4 + ld r29,r2,16*4 + ld r30,r2,17*4 + ld r31,r2,18*4 + jmp.n r1 + or r2,r0,1 + +ENTRY(longjmp_int_enable) + ld r1,r2,0 + ld r14,r2,4 + ld r15,r2,2*4 + ld r16,r2,3*4 + ld r17,r2,4*4 + ld r18,r2,5*4 + ld r19,r2,6*4 + ld r20,r2,7*4 + ld r21,r2,8*4 + ld r22,r2,9*4 + ld r23,r2,10*4 + ld r24,r2,11*4 + ld r25,r2,12*4 + ld r26,r2,13*4 + ld r27,r2,14*4 + ld r28,r2,15*4 + ld r29,r2,16*4 + ld r30,r2,17*4 + ld r31,r2,18*4 + or r2,r3,r0 + ldcr r10,PSR + clr r10,r10,1<PSR_INTERRUPT_DISABLE_BIT> + stcr r10,PSR + jmp r1 + +ENTRY(getsp) + or r2, r0, r31 + jmp r1 + +/* + * This has to be cleaned - we should not use INT_MASK_LEVEL. Should + * use pcc2_int_lvl instead. XXX nivas + */ +/* + * I don't think we need to explictly enable interrupts. We can always enable + * interrupts and depend on the int level and mask in PCC2 to block the + * appropriate interrupts for us. If we don't depend on the PCC2 to block ints + * for us, we need to explicitly set the IND bit in the PSR for every spln(x) + * when x > 0. But for now... Rewrite the whole mess. XXX nivas + * This is bogus - it is blocking interrupts for all but 0 XXX nivas + */ + +ENTRY(spln) + ldcr r10,PSR + or r11,r0,r10 + or r5,r2,r0 + bb1 PSR_INTERRUPT_DISABLE_BIT,r10,1f + set r10,r10,1<PSR_INTERRUPT_DISABLE_BIT> + stcr r10,PSR + FLUSH_PIPELINE + 1: + or.u r3,r0,hi16(INT_MASK_LEVEL) + or r3,r3,lo16(INT_MASK_LEVEL) + xmem.bu r2,r3,r0 + bcnd ne0, r5, 2f + clr r11, r11, 1<PSR_INTERRUPT_DISABLE_BIT> + stcr r11,PSR + FLUSH_PIPELINE + 2: + jmp r1 + +ENTRY(getipl) +ENTRY(spl) + ldcr r10,PSR + or r11,r0,r10 + bb1 PSR_INTERRUPT_DISABLE_BIT, r10, 1f + set r10,r10,1<PSR_INTERRUPT_DISABLE_BIT> + stcr r10,PSR + FLUSH_PIPELINE + 1: + or.u r3,r0,hi16(INT_MASK_LEVEL) + ld.b r2,r3,lo16(INT_MASK_LEVEL) + stcr r11,PSR + FLUSH_PIPELINE + jmp r1 + +/* + * Set the interrupt mask to the value passed in, returning the + * the current mask level. This routine does not enable/disable + * interrupts explicitly. It is assumed that the callers know what + * to do with interrupts. + */ + +ENTRY(setipl) + ldcr r10,PSR + or r11,r0,r10 + bb1 PSR_INTERRUPT_DISABLE_BIT, r10, 1f + set r10,r10,1<PSR_INTERRUPT_DISABLE_BIT> + stcr r10,PSR /* disable ints, if needed */ + FLUSH_PIPELINE + 1: + /* get the current mask value */ + or.u r3,r0,hi16(INT_MASK_LEVEL) + or r3,r3,lo16(INT_MASK_LEVEL) + xmem.bu r2,r3,r0 /* xchng the new mask value */ + FLUSH_PIPELINE + stcr r11,PSR /* restore psr */ + FLUSH_PIPELINE + jmp r1 /* and return the old value */ + +/* + * invalidate_pte(pte) + * + * This function will invalidate specified pte indivisibly + * to avoid the write-back of used-bit and/or modify-bit into + * that pte. It also returns the pte found in the table. + */ +ENTRY(invalidate_pte) + or r3,r0,r0 + xmem r3,r2,r0 + tb1 0,r0,0 + jmp.n r1 + or r2,r3,r0 + +#if DDB + +ENTRY(db_spln) + ldcr r10,PSR + or r11,r0,r10 + or r5,r2,r0 + bb1 PSR_INTERRUPT_DISABLE_BIT,r10,1f + set r10,r10,1<PSR_INTERRUPT_DISABLE_BIT> + stcr r10,PSR + FLUSH_PIPELINE + 1: + or.u r3,r0,hi16(INT_MASK_LEVEL) + or r3,r3,lo16(INT_MASK_LEVEL) + xmem.bu r2,r3,r0 + bcnd ne0, r5, 2f + clr r11, r11, 1<PSR_INTERRUPT_DISABLE_BIT> + stcr r11,PSR + FLUSH_PIPELINE + 2: + jmp r1 + +ENTRY(db_setipl) + ldcr r10,PSR + or r11,r0,r10 + bb1 PSR_INTERRUPT_DISABLE_BIT, r10, 1f + set r10,r10,1<PSR_INTERRUPT_DISABLE_BIT> + stcr r10,PSR /* disable ints, if needed */ + FLUSH_PIPELINE + 1: + /* get the current mask value */ + or.u r3,r0,hi16(INT_MASK_LEVEL) + or r3,r3,lo16(INT_MASK_LEVEL) + xmem.bu r2,r3,r0 /* xchng the new mask value */ + FLUSH_PIPELINE + stcr r11,PSR /* restore psr */ + FLUSH_PIPELINE + jmp r1 /* and return the old value */ + +ENTRY(db_getipl) +ENTRY(db_spl) + ldcr r10,PSR + or r11,r0,r10 + bb1 PSR_INTERRUPT_DISABLE_BIT, r10, 1f + set r10,r10,1<PSR_INTERRUPT_DISABLE_BIT> + stcr r10,PSR + 1: + or.u r3,r0,hi16(INT_MASK_LEVEL) + ld.b r2,r3,lo16(INT_MASK_LEVEL) + stcr r11,PSR + FLUSH_PIPELINE + jmp r1 + +ENTRY(db_flush_pipeline) + FLUSH_PIPELINE + jmp r1 +#endif /* DDB */ + +ENTRY(read_processor_identification_register) + jmp.n r1 + ldcr r2, PID + +ENTRY(safe_byte_access) + ld.b r9,r0,r2 + tb1 0,r0,0 + br @L1 + or r0,r0,r0 +@L1: + st.b r9,r0,r3 + jmp r1 + +ENTRY(guarded_access) +ENTRY(guarded_access_start) + cmp r9,r3,4 + bb1 eq,r9,@L145 + cmp r9,r3,2 + bb1 eq,r9,@L144 + cmp r9,r3,1 + bb1 eq,r9,@L143 + br _guarded_access_bad +@L143: + ld.b r9,r0,r2 + tb1 0, r0, 0 + st.b r9,r0,r4 + br @L142 +@L144: + ld.h r9,r0,r2 + tb1 0, r0, 0 + st.h r9,r0,r4 + br @L142 +@L145: + ld r9,r0,r2 + tb1 0, r0, 0 + st r9,r0,r4 + br @L142 + +ENTRY(guarded_access_bad) + jmp.n r1 + or r2,r0,14 +@L142: + +ENTRY(guarded_access_end) + jmp.n r1 + or r2,r0,0 diff --git a/sys/arch/mvme88k/mvme88k/locore_c_routines.c b/sys/arch/mvme88k/mvme88k/locore_c_routines.c new file mode 100644 index 00000000000..483dcb17d5e --- /dev/null +++ b/sys/arch/mvme88k/mvme88k/locore_c_routines.c @@ -0,0 +1,312 @@ +/* + * Mach Operating System + * Copyright (c) 1993-1991 Carnegie Mellon University + * Copyright (c) 1991 OMRON Corporation + * All Rights Reserved. + * + * Permission to use, copy, modify and distribute this software and its + * documentation is hereby granted, provided that both the copyright + * notice and this permission notice appear in all copies of the + * software, derivative works or modified versions, and any portions + * thereof, and that both notices appear in supporting documentation. + * + * CARNEGIE MELLON AND OMRON ALLOW FREE USE OF THIS SOFTWARE IN ITS "AS IS" + * CONDITION. CARNEGIE MELLON AND OMRON DISCLAIM ANY LIABILITY OF ANY KIND + * FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. + * + * Carnegie Mellon requests users of this software to return to + * + * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU + * School of Computer Science + * Carnegie Mellon University + * Pittsburgh PA 15213-3890 + * + * any improvements or extensions that they make and grant Carnegie the + * rights to redistribute these changes. + */ +/* + * HISTORY + *****************************************************************RCS**/ +/* This file created by Omron Corporation, 1990. */ + +#include <machine/m88100.h> /* DMT_VALID */ +#include <assym.s> /* EF_NREGS, etc. */ +#include <machine/locore.h> /* END_OF_VECTOR_LIST, etc. */ +#ifdef DDB + #include <ddb/db_output.h> /* db_printf() */ +#endif /* DDB */ + + +#if defined(DDB) && defined(JEFF_DEBUG) +# define DATA_DEBUG 1 +#endif + + +#if DDB +# define DEBUG_MSG db_printf +#else +# define DEBUG_MSG printf +#endif /* DDB */ + +/* + * data access emulation for M88100 exceptions + */ +#define DMT_BYTE 1 +#define DMT_HALF 2 +#define DMT_WORD 4 + +static struct +{ + unsigned char offset; + unsigned char size; +} dmt_en_info[16] = +{ + {0, 0}, {3, DMT_BYTE}, {2, DMT_BYTE}, {2, DMT_HALF}, + {1, DMT_BYTE}, {0, 0}, {0, 0}, {0, 0}, + {0, DMT_BYTE}, {0, 0}, {0, 0}, {0, 0}, + {0, DMT_HALF}, {0, 0}, {0, 0}, {0, DMT_WORD} +}; + +#if DATA_DEBUG + int data_access_emulation_debug = 0; + static char *bytes[] = + { + "____", "___x", "__x_", "__xx", + "_x__", "_x_x", "_xx_", "_xxx", + "x___", "x__x", "x_x_", "x_xx", + "xx__", "xx_x", "xxx_", "xxxx", + }; + #define DAE_DEBUG(stuff) { \ + if ((data_access_emulation_debug != 0) && ( \ + data_access_emulation_debug == 0xffffffff)) { stuff ;} } +#else + #define DAE_DEBUG(stuff) +#endif + +void data_access_emulation(unsigned *eframe) +{ + register int x; + register struct dmt_reg *dmtx; + register unsigned dmax, dmdx; + register unsigned v, reg; + + if (!(eframe[EF_DMT0] & DMT_VALID)) + return; + + for (x = 0; x < 3; x++) + { + dmtx = (struct dmt_reg *)&eframe[EF_DMT0+x*3]; + + if (!dmtx->dmt_valid) + continue; + + dmdx = eframe[EF_DMD0+x*3]; + dmax = eframe[EF_DMA0+x*3]; + + DAE_DEBUG + ( + if (dmtx->dmt_write) + DEBUG_MSG("[DMT%d=%x: st.%c %x to %x as [%s] %s %s]\n", + x, eframe[EF_DMT0+x*3], dmtx->dmt_das ? 's' : 'u', + dmdx, dmax, bytes[dmtx->dmt_en], + dmtx->dmt_doub1 ? "double": "not double", + dmtx->dmt_lockbar ? "xmem": "not xmem"); + else + DEBUG_MSG("[DMT%d=%x: ld.%c r%d<-%x as [%s] %s %s]\n", + x, eframe[EF_DMT0+x*3], dmtx->dmt_das ? 's' : 'u', + dmtx->dmt_dreg, dmax, bytes[dmtx->dmt_en], + dmtx->dmt_doub1 ? "double": "not double", + dmtx->dmt_lockbar ? "xmem": "not xmem"); + ) + + dmax += dmt_en_info[dmtx->dmt_en].offset; + reg = dmtx->dmt_dreg; + + if ( ! dmtx->dmt_lockbar) + { + /* the fault is not during an XMEM */ + + if (x == 2 && dmtx->dmt_doub1) + { + /* pipeline 2 (earliest stage) for a double */ + + if (dmtx->dmt_write) + { + /* STORE DOUBLE WILL BE RE-INITIATED BY rte */ + } + else + { + /* EMULATE ld.d INSTRUCTION */ + v = do_load_word(dmax, dmtx->dmt_das); + if (reg != 0) + eframe[EF_R0 + reg] = v; + v = do_load_word(dmax ^ 4, dmtx->dmt_das); + if (reg != 31) + eframe[EF_R0 + reg + 1] = v; + } + } + else /* not pipeline #2 with a double */ + { + if (dmtx->dmt_write) switch (dmt_en_info[dmtx->dmt_en].size) + { + case DMT_BYTE: + DAE_DEBUG(DEBUG_MSG("[byte %x -> [%x(%c)]\n", + dmdx & 0xff, dmax, dmtx->dmt_das ? 's' : 'u')) + do_store_byte(dmax, dmdx, dmtx->dmt_das); + break; + case DMT_HALF: + DAE_DEBUG(DEBUG_MSG("[half %x -> [%x(%c)]\n", + dmdx & 0xffff, dmax, dmtx->dmt_das ? 's' : 'u')) + do_store_half(dmax, dmdx, dmtx->dmt_das); + break; + case DMT_WORD: + DAE_DEBUG(DEBUG_MSG("[word %x -> [%x(%c)]\n", + dmdx, dmax, dmtx->dmt_das ? 's' : 'u')) + do_store_word(dmax, dmdx, dmtx->dmt_das); + break; + } + else /* else it's a read */ + { + switch (dmt_en_info[dmtx->dmt_en].size) + { + case DMT_BYTE: + v = do_load_byte(dmax, dmtx->dmt_das); + if (!dmtx->dmt_signed) + v &= 0x000000ff; + break; + case DMT_HALF: + v = do_load_half(dmax, dmtx->dmt_das); + if (!dmtx->dmt_signed) + v &= 0x0000ffff; + break; + case DMT_WORD: + default: /* 'default' just to shut up lint */ + v = do_load_word(dmax, dmtx->dmt_das); + break; + } + if (reg == 0) { + DAE_DEBUG(DEBUG_MSG("[no write to r0 done]\n")); + } + else + { + DAE_DEBUG(DEBUG_MSG("[r%d <- %x]\n", + reg, v)); + eframe[EF_R0 + reg] = v; + } + } + } + } + else /* if lockbar is set... it's part of an XMEM */ + { + /* + * According to Motorola's "General Information", + * the dmt_doub1 bit is never set in this case, as it should be. + * They call this "general information" - I call it a f*cking bug! + * + * Anyway, if lockbar is set (as it is if we're here) and if + * the write is not set, then it's the same as if doub1 + * was set... + */ + if ( ! dmtx->dmt_write) + { + if (x != 2) + { + /* RERUN xmem WITH DMD(x+1) */ + x++; + dmdx = eframe[EF_DMD0 + x*3]; + } + else + { + /* RERUN xmem WITH DMD2 */ + } + + if (dmt_en_info[dmtx->dmt_en].size == DMT_WORD) + v = do_xmem_word(dmax, dmdx, dmtx->dmt_das); + else + v = do_xmem_byte(dmax, dmdx, dmtx->dmt_das); + eframe[EF_R0 + reg] = v; + } + else + { + if (x == 0) + { + eframe[EF_R0 + reg] = dmdx; + eframe[EF_SFIP] = eframe[EF_SNIP]; + eframe[EF_SNIP] = eframe[EF_SXIP]; + eframe[EF_SXIP] = 0; + /* xmem RERUN ON rte */ + eframe[EF_DMT0] = 0; + return; + } + } + } + } + eframe[EF_DMT0] = 0; +} + +/* + *********************************************************************** + *********************************************************************** + */ +#define SIGSYS_MAX 501 +#define SIGTRAP_MAX 511 + +#define EMPTY_BR 0xC0000000U /* empty "br" instruction */ +#define NO_OP 0xf4005800U /* "or r0, r0, r0" */ + +typedef struct +{ + unsigned word_one, + word_two; +} m88k_exception_vector_area; + +#define BRANCH(FROM, TO) (EMPTY_BR | ((unsigned)(TO) - (unsigned)(FROM)) >> 2) + +#define SET_VECTOR(NUM, to, VALUE) { \ + unsigned _NUM = (unsigned)(NUM); \ + unsigned _VALUE = (unsigned)(VALUE); \ + vector[_NUM].word_one = NO_OP; \ + vector[_NUM].word_two = BRANCH(&vector[_NUM].word_two, _VALUE); \ +} + +/* + * vector_init(vector, vector_init_list) + * + * This routine sets up the m88k vector table for the running processor. + * It is called with a very little stack, and interrupts disabled, + * so don't call any other functions! + * XXX clean this - nivas + */ +void vector_init( + m88k_exception_vector_area *vector, + unsigned *vector_init_list) +{ + register unsigned num; + register unsigned vec; + extern void sigsys(), sigtrap(), stepbpt(), userbpt(); + extern void syscall_handler(); + + for (num = 0; (vec = vector_init_list[num]) != END_OF_VECTOR_LIST; num++) + { + if (vec != PREDEFINED_BY_ROM) + SET_VECTOR(num, to, vec); + } + + while (num < 496) + SET_VECTOR(num++, to, sigsys); + num++; /* skip 496, BUG ROM vector */ + + SET_VECTOR(450, to, syscall_handler); +#if 0 + while (num <= SIGSYS_MAX) + SET_VECTOR(num++, to, sigsys); + + while (num <= SIGTRAP_MAX) + SET_VECTOR(num++, to, sigtrap); + + SET_VECTOR(504, to, stepbpt); + SET_VECTOR(511, to, userbpt); + vector[496].word_one = 496 * 4; + vector[497].word_two = 497 * 4; +#endif +} diff --git a/sys/arch/mvme88k/mvme88k/m88100_fp.S b/sys/arch/mvme88k/mvme88k/m88100_fp.S new file mode 100644 index 00000000000..8cbddddfa62 --- /dev/null +++ b/sys/arch/mvme88k/mvme88k/m88100_fp.S @@ -0,0 +1,2303 @@ +/* + * Mach Operating System + * Copyright (c) 1991 Carnegie Mellon University + * Copyright (c) 1991 OMRON Corporation + * All Rights Reserved. + * + * Permission to use, copy, modify and distribute this software and its + * documentation is hereby granted, provided that both the copyright + * notice and this permission notice appear in all copies of the + * software, derivative works or modified versions, and any portions + * thereof, and that both notices appear in supporting documentation. + * + * CARNEGIE MELLON AND OMRON ALLOW FREE USE OF THIS SOFTWARE IN ITS "AS IS" + * CONDITION. CARNEGIE MELLON AND OMRON DISCLAIM ANY LIABILITY OF ANY KIND + * FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. + * + * Carnegie Mellon requests users of this software to return to + * + * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU + * School of Computer Science + * Carnegie Mellon University + * Pittsburgh PA 15213-3890 + * + * any improvements or extensions that they make and grant Carnegie the + * rights to redistribute these changes. + */ + +/* Floating point trouble routines */ + +#define LOCORE + +#define ASSEMBLER + +#include <machine/trap.h> +#include <machine/asm.h> + +#define psr cr1 +#define spsr cr2 +#define ssb cr3 +#define scip cr4 +#define snip cr5 +#define sfip cr6 +#define vbr cr7 +#define dmt0 cr8 +#define scratch1 cr18 +#define scratch2 cr20 +#define fpecr fcr0 +#define s1hi fcr1 +#define s1lo fcr2 +#define s2hi fcr3 +#define s2lo fcr4 +#define pcr fcr5 +#define manthi fcr6 +#define mantlo fcr7 +#define impcr fcr8 +#define fpsr fcr62 +#define fpcr fcr63 +#define valid 1 +#define exception 0 +#define exc_disable 0 +#define FP_disable 3 +#define dexc 27 +#define serial 29 +#define destsize 10 +#define inexact 0 +#define overflow 1 +#define underflow 2 +#define divzero 3 +#define oper 4 +#define sign 31 +#define s1size 9 +#define s2size 7 +#define dsize 5 +#define full 1 +#define fault 0 +#define FADDop 0x05 +#define FSUBop 0x06 +#define FCMPop 0x07 +#define FMULop 0x00 +#define FDIVop 0x0e +#define FSQRTop 0x0f +#define FLTop 0x04 +#define INTop 0x09 +#define NINTop 0x0a +#define TRNCop 0x0b +#define mode 31 +#define s1sign 9 +#define s2sign 8 +#define s1nan 7 +#define s2nan 6 +#define s1inf 5 +#define s2inf 4 +#define s1zero 3 +#define s2zero 2 +#define s1denorm 1 +#define s2denorm 0 +#define sigbit 19 +#define sigbits 22 +#define sigbitd 19 +#define nc 0 +#define cp 1 +#define eq 2 +#define ne 3 +#define gt 4 +#define le 5 +#define lt 6 +#define ge 7 +#define ou 8 +#define ib 9 +#define in 10 +#define ob 11 + +#define modehi 30 +#define modelo 29 +#define rndhi 15 +#define rndlo 14 +#define efunf 7 +#define efovf 6 +#define efinx 5 + +#define MARK or r21, r0, __LINE__ + + text + align 8 + global _Xfp_precise +_Xfp_precise: + or r29, r3, r0 /* r29 is now the E.F. */ + subu r31, r31, 40 + st r1, r31, 32 + st r29, r31, 36 + + ld r2, r29, EF_FPSR * 4 + ld r3, r29, EF_FPCR * 4 + ld r4, r29, EF_FPECR * 4 + ld r5, r29, EF_FPHS1 * 4 + ld r6, r29, EF_FPLS1 * 4 + ld r7, r29, EF_FPHS2 * 4 + ld r8, r29, EF_FPLS2 * 4 + ld r9, r29, EF_FPPT * 4 + + + /* Load into r1 the return address for the 0 handlers. Looking */ + /* at FPECR, branch to the appropriate 0 handler. However, */ + /* if none of the 0 bits are enabled, then a floating point */ + /* instruction was issued with the floating point unit disabled. This */ + /* will cause an unimplemented opcode 0. */ + + or.u r1,r0,hi16(wrapup) /* load return address of function */ + or r1,r1,lo16(wrapup) +2: bb0 6,r4, 3f /* branch to FPunimp if bit set */ + br FPuimp +3: bb0 7,r4, 4f /* branch to FPintover if bit set */ + br _FPintover +4: /* bb0 5,r4, 5f ;branch to FPpriviol if bit set */ + /* br _FPpriviol */ +5: bb0 4,r4, 6f /* branch to FPresoper if bit set */ + br _FPresoper +6: bb0 3,r4, 7f /* branch to FPdivzero if bit set */ + br _FPdivzero +7: + or.u r4, r4, 0xffff + +FPuimp: global FPuimp +fp_p_trap: + subu r31,r31,40 /* allocate stack */ + st r1,r31,36 /* save return address */ + st r3,r31,32 /* save exception frame */ + or r2,r0,T_FPEPFLT /* load trap type */ + or r3, r29, r0 + bsr _trap /* trap */ + ld r1,r31,36 /* recover return address */ + addu r31,r31,40 /* deallocate stack */ + br fp_p_return + + /* To write back the results to the user registers, disable exceptions */ + /* and the floating point unit. Write FPSR and FPCR and load the SNIP */ + /* and SFIP. */ + /* r5 will contain the upper word of the result */ + /* r6 will contain the lower word of the result */ + +wrapup: global wrapup + tb1 0,r0,0 /* make sure all floating point operations */ + /* have finished */ + ldcr r10, cr1 /* load the PSR */ + or r10, r10, 0x2 /* disable interrupts */ + stcr r10, cr1 +#if 0 +Why is this done? -jfriedl + or r10, r10, 0x8 /* set SFU 1 disable bit, disable SFU 1 */ + stcr r10, cr1 +#endif + ld r1, r31, 32 + ld r29, r31, 36 + addu r31, r31, 40 + + fstcr r2, fpsr /* write revised value of FPSR */ + fstcr r3, fpcr /* write revised value of FPCR */ + + /* result writeback routine */ + addu r3, r29, EF_R0 * 4 + extu r2, r9, 5<0> /* get 5 bits of destination register */ + bb0 5, r9, writesingle /* branch if destination is single */ + +/* writedouble here */ + st r5, r3 [r2] /* write high word */ + add r2, r2, 1 /* for double, the low word is the */ + /* unspecified register */ + clr r2, r2, 27<5> /* perform equivalent of mod 32 */ +writesingle: + st r6, r3 [r2] /* write low word into memory */ + +fp_p_return: + jmp r1 + + text + align 8 + global _FPdivzero + + +/* Check if the numerator is zero. If the numerator is zero, then handle */ +/* this instruction as you would a 0/0 invalid operation. */ + +_FPdivzero: + st r1,r31,0 /* save return address */ + bb1 s1size,r9,1f /* branch if numerator double */ +/* single number */ + clr r10,r5,1<sign> /* clear sign bit */ + extu r11,r6,3<29> /* grab upper bits of lower word */ + or r10,r10,r11 /* combine ones of mantissa */ + bcnd eq0,r10,resoper /* numerator is zero, handle reserved */ + /* operand */ + br setbit /* set divzero bit */ +1: +/* double number */ + clr r10,r5,1<sign> /* clear sign bit */ + or r10,r10,r6 /* or high and low words */ + bcnd ne0,r10,setbit /* set divzero bit */ + +/* The numerator is zero, so handle the invalid operation by setting the */ +/* invalid operation bit and branching to the user handler if there is one */ +/* or writing a quiet NaN to the destination. */ + +resoper: + set r2,r2,1<oper> /* set bit in FPSR */ +#ifdef HANDLER + bb0 oper,r3,noreshand /* branch to execute default handling for */ + /* reserved operands */ + bsr _handler /* branch to user handler */ + br FP_div_return /* return from function */ +#endif + +noreshand: + set r5,r0,0<0> /* put a NaN in high word */ + set r6,r0,0<0> /* put a NaN in low word */ + br FP_div_return /* return from subroutine */ + /* writing to a word which may be ignored */ + /* is just as quick as checking the precision */ + /* of the destination */ + +/* The operation is divide by zero, so set the divide by zero bit in the */ +/* FPSR. If the user handler is set, then go to the user handler, else */ +/* go to the default mode. */ + +setbit: +#ifdef HANDLER + set r2,r2,1<divzero> /* set bit in FPSR */ + bb0 divzero,r3,default /* go to default routine if no handler */ + bsr _handler /* execute handler routine */ + br FP_div_return /* return from subroutine */ +#endif + + +/* Considering the sign of the numerator and zero, write a correctly */ +/* signed infinity of the proper precision into the destination. */ + +default: + bb1 dsize,r9,FPzero_double /* branch to handle double result */ +FPzero_single: + clr r10,r5,31<0> /* clear all of S1HI except sign bit */ + xor r10,r7,r10 /* xor the sign bits of the operands */ + or.u r6,r0,0x7f80 /* load single precision infinity */ + br.n FP_div_return /* return from subroutine */ + or r6,r6,r10 /* load correctly signed infinity */ + +FPzero_double: + clr r10,r5,31<0> /* clear all of S1HI except sign bit */ + xor r10,r7,r10 /* xor the sign bits of the operands */ + or.u r5,r0,0x7ff0 /* load double precision infinity */ + or r5,r5,r10 /* load correctly signed infinity */ + or r6,r0,r0 /* clear lower word of double */ + +FP_div_return: + ld r1,r31,0 /* load return address */ + jmp r1 /* return from subroutine */ + + + +/* Both NINT and TRNC require a certain rounding mode, so check which */ +/* instruction caused the integer conversion overflow. Use a substitute */ +/* FPCR in r1, and modify the rounding mode if the instruction is NINT or TRNC. */ + text + align 8 +_FPintover: global _FPintover + extu r10,r9,5<11> /* extract opcode */ + cmp r11,r10,INTop /* see if instruction is INT */ + st r1,r31,0 /* save return address */ + bb1.n eq,r11,checksize /* instruction is INT, do not modify */ + /* rounding mode */ + or r1,r0,r3 /* load FPCR into r1 */ + cmp r11,r10,NINTop /* see if instruction is NINT */ + bb1 eq,r11,NINT /* instruction is NINT */ + +TRNC: clr r1,r1,2<rndlo> /* clear rounding mode bits, */ + /* instruction is TRNC */ + br.n checksize /* branch to check size */ + set r1,r1,1<rndlo> /* make rounding mode round towards zero */ + +NINT: clr r1,r1,2<rndlo> /* make rounding mode round to nearest */ + + +/* See whether the source is single or double precision. */ + +checksize: bb1 s2size,r9,checkdoub /* S2 is double, branch to see if there */ +/* is a false alarm */ + + +/* An integer has more bits than the mantissa of a single precision floating */ +/* point number, so to check for false alarms (i.e. valid conversion), simply */ +/* check the exponents. False alarms are detected for 2**30 to (2**30) - 1 and */ +/* -2**30 to -2**31. Only seven bits need to be looked at since an exception */ +/* will not occur for the other half of the numbering system. */ +/* To speed up the processing, first check to see if the exponent is 32 or */ +/* greater. */ + +/* This code was originally written for the exponent in the control */ +/* register to have the most significant bit (8 - single, 11 - double) */ +/* flipped and sign extended. For precise exceptions, however, the most */ +/* significant bit is only sign extended. Therefore, the code was chopped */ +/* up so that it would work for positive values of real exponent which were */ +/* only sign extended. */ + +checksing: extu r10,r7,7<20> /* internal representation for single */ +/* precision is IEEE 8 bits sign extended */ +/* to 11 bits; for real exp. = 30, the */ +/* above instruction gives a result exp. */ +/* that has the MSB flipped and sign */ +/* extended like in the IMPCR */ + cmp r11,r10,31 /* compare to 32,but exp. off by 1 */ +/* these 2 instructions to speed up valid */ +/* execution of valid cases */ + bb1 ge,r11,overflw /* valid case, perform overflow routine */ + bb1 sign,r7,checksingn /* source operand is negative */ + +/* If the number is positve and the exponent is greater than 30, than it is */ + /* overflow. */ + +checksingp: cmp r10,r10,29 /* compare to 30, but exp. off by 1 */ + bb1 gt,r10,overflw /* no false alarm, its overflow */ + br conversionsp /* finish single precision conversion */ + +/* If the number is negative, and the exponent is 30, or 31 with a mantissa */ +/* of 0, then it is a false alarm. */ + +checksingn: cmp r11,r10,30 /* compare to 31,but exp. off by 1 */ + bb1 lt,r11,conversionsn /* exp. less than 31, so convert */ + extu r10,r8,3<29> /* get upper three bits of lower mantissa */ + mak r12,r7,20<3> /* get upper 20 bits of mantissa */ + or r10,r10,r12 /* form complete mantissa */ + bcnd eq0,r10,conversionsn /* complete conversion if mantissa is 0 */ + br overflw /* no false alarm, its overflow */ + + +/* False alarms are detected for 2**30 to (2**30) - 1 and */ +/* -2**30 to -2**31. Only seven bits need to be looked at since an exception */ +/* will not occur for the other half of the numbering system. */ +/* To speed up the processing, first check to see if the exponent is 32 or */ +/* greater. Since there are more mantissa bits than integer bits, rounding */ +/* could cause overflow. (2**31) - 1 needs to be checked so that it does */ +/* not round to 2**31, and -2**31 needs to be checked in case it rounds to */ +/* -((2**31) + 1). */ + +checkdoub: extu r10,r7,10<20> /* internal representation for double */ +/* precision is the same IEEE 11 bits */ +/* for real exp. = 30, the */ +/* above instruction gives a result exp. */ +/* that has the MSB flipped and sign */ +/* extended like in the IMPCR */ + cmp r11,r10,31 /* compare to 32,but exp. off by 1 */ +/* these 2 instructions to speed up valid */ +/* execution of valid cases */ + bb1 ge,r11,overflw /* valid case, perform overflow routine */ + bb1 sign,r7,checkdoubn /* source operand is negative */ + +/* If the exponent is not 31, then the floating point number will be rounded */ +/* before the conversion is done. A branch table is set up with bits 4 and 3 */ +/* being the rounding mode, and bits 2, 1, and 0 are the guard, round, and */ +/* sticky bits. */ + +checkdoubp: cmp r11,r10,30 /* compare to 31, but exponent off by 1 */ + bb1 eq,r11,overflw /* no false alarm, its overflow */ + extu r12,r8,1<22> /* get LSB for integer with exp. = 30 */ + mak r12,r12,1<2> /* start to set up field for branch table */ + extu r11,r8,1<21> /* get guard bit */ + mak r11,r11,1<1> /* set up field for branch table */ + or r12,r11,r12 /* set up field for branch table */ + extu r11,r8,21<0> /* get bits for sticky bit */ + bcnd eq0,r11,nostickyp /* do not set sticky */ + set r12,r12,1<0> /* set sticky bit */ +nostickyp: rot r11,r1,0<rndlo> /* shift rounding mode to 2 LSB''s */ + mak r11,r11,2<3> /* set up field, clear other bits */ + or r12,r11,r12 /* set up field for branch table */ + lda r12,r0[r12] /* scale r12 */ + or.u r12,r12,hi16(ptable) /* load pointer into table */ + addu r12,r12,lo16(ptable) + jmp r12 /* jump into branch table */ + +ptable: br conversiondp +p00001: br conversiondp +p00010: br conversiondp +p00011: br paddone +p00100: br conversiondp +p00101: br conversiondp +p00110: br paddone +p00111: br paddone +p01000: br conversiondp +p01001: br conversiondp +p01010: br conversiondp +p01011: br conversiondp +p01100: br conversiondp +p01101: br conversiondp +p01110: br conversiondp +p01111: br conversiondp +p10000: br conversiondp +p10001: br conversiondp +p10010: br conversiondp +p10011: br conversiondp +p10100: br conversiondp +p10101: br conversiondp +p10110: br conversiondp +p10111: br conversiondp +p11000: br conversiondp +p11001: br paddone +p11010: br paddone +p11011: br paddone +p11100: br conversiondp +p11101: br paddone +p11110: br paddone +p11111: br paddone + +/* Add one to the bit of the mantissa which corresponds to the LSB of an */ +/* integer. If the mantissa overflows, then there is a valid integer */ +/* overflow conversion; otherwise, the mantissa can be converted to the integer. */ + +paddone: or r10,r0,r0 /* clear r10 */ + set r10,r10,1<22> /* set LSB bit to 1 for adding */ + addu.co r8,r8,r10 /* add the 1 obtained from rounding */ + clr r11,r7,12<20> /* clear exponent and sign */ + addu.ci r11,r0,r11 /* add carry */ + bb1 20,r11,overflw /* overflow to 2**31, abort the rest */ + br.n conversiondp /* since the exp. was 30, and the exp. */ + /* did not round up to 31, the largest */ + /* number that S2 could become is 2**31-1 */ + or r7,r0,r11 /* store r11 into r7 for conversion */ + +/* Now check for negative double precision sources. If the exponent is 30, */ +/* then convert the false alarm. If the exponent is 31, then check the mantissa */ +/* bits which correspond to integer bits. If any of them are a one, then there */ +/* is overflow. If they are zero, then check the guard, round, and sticky bits. */ +/* Round toward zero and positive will not cause a roundup, but round toward */ +/* nearest and negative may, so perform those roundings. If there is no overflow, */ + /* then convert and return from subroutine. */ + +checkdoubn: cmp r11,r10,29 /* compare to 30, but exp. off by 1 */ + bb1 eq,r11,conversiondn /* false alarm if exp. = 30 */ + extu r10,r8,11<21> /* check upper bits of lower mantissa */ + bcnd ne0,r10,overflw /* one of the bits is a 1, so overflow */ + extu r10,r7,20<0> /* check upper bits of upper mantissa */ + bcnd ne0,r10,overflw /* one of the bits is a 1, so overflow */ + bb0 rndlo,r1,possround /* rounding mode is either round near or */ + /* round negative, which may cause a */ + /* round */ + br.n FPintov_return /* round positive, which will not cause a */ + /* round */ + set r6,r0,1<sign> /* rounding mode is either round zero or */ +possround: extu r12,r8,1<20> /* get guard bit */ + extu r11,r8,20<0> /* get bits for sticky bit */ + bcnd.n eq0,r11,nostickyn /* do not set sticky */ + mak r12,r12,1<1> /* set up field for branch table */ + set r12,r12,1<0> /* set sticky bit */ +nostickyn: bb1 rndhi,r1,negative /* rounding mode is negative */ +nearest: cmp r12,r12,3 /* are both guard and sticky set */ + bb1 eq,r12,overflw /* both guard and sticky are set, */ + /* so signal overflow */ + or r6,r0,r0 /* clear destination register r6 */ + br.n FPintov_return /* return from subroutine */ + set r6,r6,1<sign> /* set the sign bit and take care of */ + /* this special case */ +negative: bcnd ne0,r12,overflw /* -2**31 will be rounded to -(2**31+1), */ + /* so signal overflow */ + or r6,r0,r0 /* clear destination register r6 */ + br.n FPintov_return /* return from subroutine */ + set r6,r6,1<sign> /* set the sign bit and take care of */ + /* this special case */ + + /* since the exp. was 30, and there was */ + /* no round-up, the largest number that */ + /* S2 could have been was 2**31 - 1 */ + + + /* Convert the single precision positive floating point number. */ + +conversionsp: extu r6,r8,3<29> /* extract lower bits of integer */ + mak r6,r6,3<7> /* shift left to correct place in integer */ + mak r10,r7,20<10> /* shift left upper bits of integer */ + or r6,r6,r10 /* form most of integer */ + br.n FPintov_return /* return from subroutine */ + set r6,r6,1<30> /* set hidden one */ + + + /* Convert the single precision negative floating point number. */ + +conversionsn: bb1 eq,r11,exp31s /* use old r11 to see if exp. is 31 */ + extu r6,r8,3<29> /* extract lower bits of mantissa */ + mak r6,r6,3<7> /* shift left to correct place in integer */ + mak r10,r7,20<10> /* shift left upper bits of integer */ + or r6,r6,r10 /* form most of integer */ + set r6,r6,1<30> /* set hidden one */ + or.c r6,r0,r6 /* negate result */ + br.n FPintov_return /* return from subroutine */ + addu r6,r6,1 /* add 1 to get 2''s complement */ +exp31s: or r6,r0,r0 /* clear r6 */ + br.n FPintov_return /* return from subroutine */ + set r6,r6,1<sign> /* set sign bit */ + + + /* Convert the double precision positive floating point number. */ + +conversiondp: extu r6,r8,10<22> /* extract lower bits of integer */ + mak r10,r7,20<10> /* shift left upper bits of integer */ + or r6,r6,r10 /* form most of integer */ + br.n FPintov_return /* return from subroutine */ + set r6,r6,1<30> /* set hidden one */ + + + /* Convert the double precision negative floating point number. The number, */ + /* whose exponent is 30, must be rounded before converting. Bits 4 and 3 are */ + /* the rounding mode, and bits 2, 1, and 0 are the guard, round, and sticky */ + /* bits for the branch table. */ + +conversiondn: extu r12,r8,1<22> /* get LSB for integer with exp. = 30 */ + mak r12,r12,1<2> /* start to set up field for branch table */ + extu r11,r8,1<21> /* get guard bit */ + mak r11,r11,1<1> /* set up field for branch table */ + or r12,r11,r12 /* set up field for branch table */ + extu r11,r8,21<0> /* get bits for sticky bit */ + bcnd eq0,r11,nostkyn /* do not set sticky */ + set r12,r12,1<0> /* set sticky bit */ +nostkyn: rot r11,r1,0<rndlo> /* shift rounding mode to 2 LSB''s */ + mak r11,r11,2<3> /* set up field, clear other bits */ + or r12,r11,r12 /* set up field for branch table */ + lda r12,r0[r12] /* scale r12 */ + or.u r12,r12,hi16(ntable)/* load pointer into table */ + addu r12,r12,lo16(ntable) + jmp r12 /* jump into branch table */ + +ntable: br nnoaddone +n00001: br nnoaddone +n00010: br nnoaddone +n00011: br naddone +n00100: br nnoaddone +n00101: br nnoaddone +n00110: br naddone +n00111: br naddone +n01000: br nnoaddone +n01001: br nnoaddone +n01010: br nnoaddone +n01011: br nnoaddone +n01100: br nnoaddone +n01101: br nnoaddone +n01110: br nnoaddone +n01111: br nnoaddone +n10000: br nnoaddone +n10001: br naddone +n10010: br naddone +n10011: br naddone +n10100: br nnoaddone +n10101: br naddone +n10110: br naddone +n10111: br naddone +n11000: br nnoaddone +n11001: br nnoaddone +n11010: br nnoaddone +n11011: br nnoaddone +n11100: br nnoaddone +n11101: br nnoaddone +n11110: br nnoaddone +n11111: br nnoaddone + + + /* Add one to the mantissa, and check to see if it overflows to -2**31. */ +/* The conversion is done in nnoaddone:. */ + +naddone: or r10,r0,r0 /* clear r10 */ + set r10,r10,1<22> /* set LSB bit to 1 for adding */ + add.co r8,r8,r10 /* add the 1 obtained from rounding */ + clr r7,r7,12<20> /* clear exponent and sign */ + add.ci r7,r0,r7 /* add carry */ + bb1 20,r7,maxneg /* rounded to -2**31,handle separately */ + /* the exponent was originally 30 */ +nnoaddone: extu r6,r8,11<22> /* extract lower bits of integer */ + mak r10,r7,20<10> /* shift left upper bits of integer */ + or r6,r6,r10 /* form most of integer */ + set r6,r6,1<30> /* set hidden one */ + or.c r6,r0,r6 /* negate integer */ + br.n FPintov_return /* return from subroutine */ + addu r6,r6,1 /* add 1 to get 2''s complement */ + +maxneg: or r6,r0,r0 /* clear integer */ + br.n FPintov_return /* return from subroutine */ + set r6,r6,1<sign> /* set sign bit */ + + + /* For valid overflows, check to see if the integer overflow user handler is */ + /* set. If it is set, then go to user handler, else write the correctly */ + /* signed largest integer. */ + +overflw: +#ifdef HANDLER + bb0.n oper,r3,nohandler /* do not go to user handler routine */ + set r2,r2,1<oper> /* set invalid operand bit */ + bsr _handler /* go to user handler routine */ + br FPintov_return /* return from subroutine */ +nohandler: +#endif + bb0.n sign,r7,FPintov_return /* if positive then return from subroutine */ + set r6,r6,31<0> /* set result to largest positive integer */ + or.c r6,r0,r6 /* negate r6,giving largest negative int. */ + +FPintov_return: ld r1,r31,0 /* load return address from memory */ + jmp r1 /* return from subroutine */ + + data + +/* Some instructions only have the S2 operations, so clear S1HI and S1LO */ +/* for those instructions so that the previous contents of S1HI and S1LO */ +/* do not influence this instruction. */ + + text +LABEL(_FPresoper) + st r1, r31, 0 + extu r10,r9,5<11> /* extract opcode */ +/* cmp r11,r10,FSQRTop ;compare to FSQRT */ +/* bb1 eq,r11,S1clear ;clear S1 if instruction only had S2 operand */ + cmp r11,r10,INTop /* compare to INT */ + bb1 eq,r11,S1clear /* clear S1 if instruction only had S2 operand */ + cmp r11,r10,NINTop /* compare to NINT */ + bb1 eq,r11,S1clear /* clear S1 if instruction only had S2 operand */ + cmp r11,r10,TRNCop /* compare to TRNC */ + bb0 eq,r11,opercheck /* check for reserved operands */ + +_LABEL(S1clear) + or r5,r0,r0 /* clear any NaN''s, denorms, or infinities */ + or r6,r0,r0 /* that may be left in S1HI,S1LO from a */ + /* previous instruction */ + +/* r12 contains the following flags: */ +/* bit 9 -- s1sign */ +/* bit 8 -- s2sign */ +/* bit 7 -- s1nan */ +/* bit 6 -- s2nan */ +/* bit 5 -- s1inf */ +/* bit 4 -- s2inf */ +/* bit 3 -- s1zero */ +/* bit 2 -- s2zero */ +/* bit 1 -- s1denorm */ +/* bit 0 -- s2denorm */ + +/* Using code for both single and double precision, check if S1 is either */ +/* a NaN or infinity and set the appropriate flags in r12. Then check if */ +/* S2 is a NaN or infinity. If it is a NaN, then branch to the NaN routine. */ + + +_LABEL(opercheck) + extu r10,r5,11<20> /* internal representation for double */ + bb1.n s1size,r9,S1NaNdoub /* S1 is double precision */ + or r12,r0,r0 /* clear operand flag register */ +_LABEL(S1NaNsing) + xor r10,r10,0x0080 /* internal representation for single */ + ext r10,r10,8<0> /* precision is IEEE 8 bits sign extended */ + /* to 11 bits; for real exp. > 0, the */ + /* above instructions gives a result exp. */ + /* that has the MSB flipped and sign */ + /* extended like in the IMPCR */ + cmp r11,r10,127 /* Is exponent equal to IEEE 255 (internal 127) */ + bb1 ne,r11,S2NaN /* source 1 is not a NaN or infinity */ + mak r10,r5,20<0> /* load r10 with upper bits of S1 mantissa */ + extu r11,r6,3<29> /* get 3 upper bits of lower word */ + or r11,r10,r11 /* combine any existing 1''s */ + bcnd eq0,r11,noS1NaNs /* since r11 can only hold 0 or a positive */ + /* number, branch to noS1NaN when eq0 */ + br.n S2NaN /* see if S2 has a NaN */ + set r12,r12,1<s1nan> /* indicate that S1 has a NaN */ +_LABEL(noS1NaNs) + br.n S2NaN /* check contents of S2 */ + set r12,r0,1<s1inf> /* indicate that S1 has an infinity */ + +_LABEL(S1NaNdoub) + xor r10,r10,0x0400 /* precision is the same IEEE 11 bits */ + /* The */ + /* above instructions gives a result exp. */ + /* that has the MSB flipped and sign */ + /* extended like in the IMPCR */ + cmp r11,r10,1023 /* Is exp. equal to IEEE 2047 (internal 1023) */ + bb1 ne,r11,S2NaN /* source 1 is not a NaN or infinity */ + mak r10,r5,20<0> /* load r10 with upper bits of S1 mantissa */ + or r11,r6,r10 /* combine existing 1''s of mantissa */ + bcnd eq0,r11,noS1NaNd /* since r11 can only hold 0 or a positive */ + /* number, branch to noS1NaN when eq0 */ + br.n S2NaN /* see if S2 has a NaN */ + set r12,r12,1<s1nan> /* indicate that S1 has a NaN */ +_LABEL(noS1NaNd) + set r12,r0,1<s1inf> /* indicate that S1 has an infinity */ + +_LABEL(S2NaN) + bb1.n s2size,r9,S2NaNdoub /* S1 is double precision */ + extu r10,r7,11<20> /* internal representation for double */ +_LABEL(S2NaNsing) + xor r10,r10,0x0080 /* internal representation for single */ + ext r10,r10,8<0> /* precision is IEEE 8 bits sign extended */ + /* to 11 bits; for real exp. > 0, the */ + /* above instruction gives a result exp. */ + /* that has the MSB flipped and sign */ + /* extended like in the IMPCR */ + cmp r11,r10,127 /* Is exponent equal to IEEE 255 (internal 127) */ + bb1 ne,r11,inf /* source 2 is not a NaN or infinity */ + mak r10,r7,20<0> /* load r10 with upper bits of S1 mantissa */ + extu r11,r8,3<29> /* get 3 upper bits of lower word */ + or r11,r10,r11 /* combine any existing 1''s */ + bcnd eq0,r11,noS2NaNs /* since r11 can only hold 0 or a positive */ + /* number, branch to noS2NaNs when eq0 */ + br.n _NaN /* branch to NaN routine */ + set r12,r12,1<s2nan> /* indicate that s2 has a NaN */ +_LABEL(noS2NaNs) + bb0 s1nan,r12, 1f /* branch to NaN if S1 is a NaN */ + br _NaN +1: br.n _infinity /* If S1 had a NaN we would have already */ + /* branched, and S2 does not have a NaN, but */ + /* it does have an infinity, so branch to */ + /* handle the finity */ + set r12,r12,1<s2inf> /* indicate that S2 has an infinity */ + +_LABEL(S2NaNdoub) + xor r10,r10,0x0400 /* precision is the same IEEE 11 bits */ + /* The */ + /* above instruction gives a result exp. */ + /* that has the MSB flipped and sign */ + /* extended like in the IMPCR */ + cmp r11,r10,1023 /* Is exp. equal to IEEE 2047 (internal 1023) */ + bb1 ne,r11,inf /* source 2 is not a NaN or infinity */ + mak r10,r7,20<0> /* load r10 with upper bits of S2 mantissa */ + or r11,r8,r10 /* combine existing 1''s of mantissa */ + bcnd eq0,r11,noS2NaNd /* since r11 can only hold 0 or a positive */ + /* number, branch to noS2NaNd when eq0 */ + br.n _NaN /* branch to NaN routine */ + set r12,r12,1<s2nan> /* indicate that s2 has a NaN */ +_LABEL(noS2NaNd) + bb0 s1nan,r12,1f /* branch to NaN if S1 is a NaN */ + br _NaN +1: br.n _infinity /* If S1 had a NaN we would have already */ + /* branched, and S2 does not have a NaN, but */ + /* it does have an infinity, so branch to */ + /* handle the finity */ + set r12,r12,1<s2inf> /* indicate that S2 has an infinity */ + + +/* If S2 was a NaN, the routine would have already branched to NaN. If S1 */ +/* is a NaN, then branch to NaN. If S1 is not a NaN and S2 is infinity, then */ +/* we would have already branched to infinity. If S1 is infinity, then branch. */ +/* If the routine still has not branched, then branch to denorm, the only */ +/* reserved operand left. */ + +_LABEL(inf) + bb0 s1nan,r12,1f /* branch if S1 has a NaN and S2 does not */ + br _NaN +1: bb0 s1inf,r12,2f /* Neither S1 or S2 has a NaN, and we would */ + /* have branched already if S2 had an */ + /* infinity, so branch if S1 is infinity */ +/* + * The above "bb0 s1inf, r12,2f" had been a "bb1", but it just didn't make + * sense (and didn't work, either), so I changed it. + * jfriedl Dec 1, 1989. + */ + br _infinity +2: + + br _denorm /* branch to denorm, the only remaining */ + /* alternative */ + +/* function _FPunderflow -- */ +/* The documentation for this release give an overall description of this code. */ + + text + global _FPunderflow + +/* First check for an underflow user handler. If there is not one, then */ +/* branch to the routine to make a denormalized number. Before branching */ +/* to the underflow user handler, add 192 to a single precision exponent */ +/* and 1536 to a double precision exponent. */ + +_FPunderflow: st r1,r31,0 /* save return address */ +#ifdef HANDLER + bb0 efunf,r12,denorm /* jump to default procedure */ + bb1.n destsize,r12,doubleprec /* double precision destination */ + set r2,r2,1<underflow> /* set underflow flag in FPSR */ +singleprec: or.u r6,r0,0x0c00 /* load exponent adjust 192 */ + br.n callundhand /* branch to call handler for user handler */ + add r12,r6,r12 /* adjust single precision exponent */ +doubleprec: or.u r6,r0,0x6000 /* load exponent adjust 1536 */ + add r12,r6,r12 /* adjust double precision exponent */ +callundhand: bsr _handler /* call handler for user handler */ + br Ureturn /* return from subroutine */ +#endif + +/* Now the floating point number, which has an exponent smaller than what */ +/* IEEE allows, must be denormalized. Denormalization is done by calculating */ +/* the difference between a denormalized exponent and an underflow exponent and */ +/* shifting the mantissa by that amount. A one may need to be subtracted from */ +/* the LSB if a one was added during rounding. */ +/* r9 is used to contain the guard, round, sticky, and an inaccuracy bit in */ +/* case some bits were shifted off the mantissa during denormalization. */ +/* r9 will contain: bit 4 -- new addone if one added during rounding */ +/* after denormalization */ +/* bit 3 -- inaccuracy flag caused by denormalization */ +/* or pre-denormalization inexactness */ +/* bit 2 -- guard bit of result */ +/* bit 1 -- round bit of result */ +/* bit 0 -- sticky bit of result */ + +denorm: bb1.n destsize,r12,Udouble /* denorm for double */ + extu r9,r10,3<26> /* load r9 with grs */ +Usingle: mak r5,r10,21<3> /* extract high 21 bits of mantissa */ + extu r6,r11,3<29> /* extract low 3 bits of mantissa */ + or r11,r5,r6 /* form 24 bits of mantissa */ + +/* See if the addone bit is set and unround if it is. */ + bb0.n 25,r10,nounrounds /* do not unround if addone bit clear */ + extu r6,r12,12<20> /* extract signed exponent from IMPCR */ +unrounds: subu r11,r11,1 /* subtract 1 from mantissa */ +/* If the hidden bit is cleared after subtracting the one, then the one added */ +/* during the rounding must have propagated through the mantissa. The exponent */ +/* will need to be decremented. */ + bb1 23,r11,nounrounds /* if hidden bit is set,then exponent does */ + /* not need to be decremented */ +decexps: sub r6,r6,1 /* decrement exponent 1 */ + set r11,r11,1<23> /* set the hidden bit */ + +/* For both single and double precision, there are cases where it is easier */ +/* and quicker to make a special case. Examples of this are if the shift */ +/* amount is only 1 or 2, or all the mantissa is shifted off, or all the */ +/* mantissa is shifted off and it is still shifting, or, in the case of */ +/* doubles, if the shift amount is around the boundary of MANTLO and MANTHI. */ + +nounrounds: or r8,r0,lo16(0x00000f81) /* load r8 with -127 in decimal */ + /* for lowest 12 bits */ + sub r7,r8,r6 /* find difference between two exponents, */ + /* this amount is the shift amount */ + cmp r6,r7,3 /* check to see if r7 contains 3 or more */ + bb1 ge,r6,threesing /* br to code that handles shifts of >=3 */ + cmp r6,r7,2 /* check to see if r7 contains 2 */ + bb1 eq,r6,twosing /* br to code that handles shifts of 2 */ +one: rot r9,r9,0<1> /* rotate roundoff register once, this places */ + /* guard in round and round in sticky */ + bb0 31,r9,nosticky1s/* do not or round and sticky if sticky is */ + /* 0, this lost bit will be cleared later */ + set r9,r9,1<0> /* or round and sticky */ +nosticky1s: bb0 0,r11,guardclr1s /* do not set guard bit if LSB = 0 */ + set r9,r9,1<2> /* set guard bit */ +guardclr1s: extu r11,r11,31<1> /* shift mantissa right 1 */ + br.n round /* round result */ + mak r9,r9,3<0> /* clear bits lost during rotation */ + +twosing: rot r9,r9,0<2> /* rotate roundff register twice, this places */ + /* guard in sticky */ + bb0 30,r9,nosticky2s /* do not or guard and sticky if stick is 0 */ + /* this lost bit will be cleared later */ + br.n noround2s /* skip or old guard and old round if old */ + /* sticky set */ + set r9,r9,1<0> /* or guard and sticky */ +nosticky2s: bb0 31,r9,noround2s /* do not or guard and round if round is 0 */ + /* this lost bit will be cleared later */ + set r9,r9,1<0> /* or guard and round */ +noround2s: bb0 0,r11,roundclr2s /* do not set round bit if LSB = 0 */ + set r9,r9,1<1> /* set round bit */ +roundclr2s: bb0 1,r11,guardclr2s /* do not set guard bit if LSB + 1 = 0 */ + set r9,r9,1<2> /* set guard bit */ +guardclr2s: extu r11,r11,30<2> /* shift mantissa right 2 */ + br.n round /* round result */ + mak r9,r9,3<0> /* clear bits lost during rotation */ + +threesing: bb1 0,r9,noguard3s /* check sticky initially */ + /* sticky is set, forget most of the oring */ +nosticky3s: bb0 1,r9,noround3s /* check round initially, do not set sticky */ + br.n noguard3s /* forget most of the rest of oring */ + set r9,r9,1<0> /* if round is clear,set sticky if round set */ +noround3s: bb0.n 2,r9,noguard3s /* check guard initially, do not set sticky */ + clr r9,r9,2<1> /* clear the original guard and round for when */ + /* you get to round section */ + set r9,r9,1<0> /* if guard is clear,set sticky if guard set */ +noguard3s: cmp r6,r7,23 /* check if # of shifts is <=23 */ + bb1 gt,r6,s24 /* branch to see if shifts = 24 */ + sub r6,r7,2 /* get number of bits to check for sticky */ + mak r6,r6,5<5> /* shift width into width field */ + mak r8,r11,r6 /* mask off shifted bits -2 */ + ff1 r8,r8 /* see if r8 has any ones */ + bb1 5,r8,nostky23 /* do not set sticky if no ones found */ + set r9,r9,1<0> /* set sticky bit */ +nostky23: or r8,r0,34 /* start code to get new mantissa plus two */ + /* extra bits for new round and new guard bits */ + subu r8,r8,r7 + mak r8,r8,5<5> /* shift field width into second five bits */ + extu r6,r6,5<5> /* shift previous shifted -2 into offset field */ + or r6,r6,r8 /* complete field */ + extu r11,r11,r6 /* form new mantissa with two extra bits */ + + bb0 0,r11,nornd3s /* do not set new round bit */ + set r9,r9,1<1> /* set new round bit */ +nornd3s: bb0 1,r11,nogrd3s /* do not set new guard bit */ + set r9,r9,1<2> /* set new guard bit */ +nogrd3s: br.n round /* round mantissa */ + extu r11,r11,30<2> /* shift off remaining two bits */ + +s24: cmp r6,r7,24 /* check to see if # of shifts is 24 */ + bb1 gt,r6,s25 /* branch to see if shifts = 25 */ + bb1 0,r9,nostky24 /* skip checking if old sticky set */ + extu r8,r11,22<0> /* prepare to check bits that will be shifted */ + /* into the sticky */ + ff1 r8,r8 /* see if there are any 1''s */ + bb1 5,r8,nostky24 /* do not set sticky if no ones found */ + set r9,r9,1<0> /* set sticky bit */ +nostky24: bb0 22,r11,nornd24 /* do not set new round bit */ + set r9,r9,1<1> /* set new round bit */ +nornd24: set r9,r9,1<2> /* set new guard bit,this is hidden bit */ + br.n round /* round mantissa */ + or r11,r0,r0 /* clear r11, all of mantissa shifted off */ + +s25: cmp r6,r7,25 /* check to see if # of shifts is 25 */ + bb1 gt,r6,s26 /* branch to execute for shifts => 26 */ + bb1 0,r9,nostky25 /* skip checking if old sticky set */ + extu r8,r11,23<0> /* prepare to check bits that will be shifted */ + /* into the sticky */ + ff1 r8,r8 /* see if there are any 1''s */ + bb1 5,r8,nostky25 /* do not set sticky if no ones found */ + set r9,r9,1<0> /* set sticky bit */ +nostky25: set r9,r9,1<1> /* set new round bit,this is hidden bit */ + clr r9,r9,1<2> /* clear guard bit since nothing shifted in */ + br.n round /* round and assemble result */ + or r11,r0,r0 /* clear r11, all of mantissa shifted off */ + +s26: set r9,r9,1<0> /* set sticky bit,this contains hidden bit */ + clr r9,r9,2<1> /* clear guard and round bits since nothing */ + /* shifted in */ + br.n round /* round and assemble result */ + or r11,r0,r0 /* clear mantissa */ + +Udouble: mak r5,r10,21<0> /* extract upper bits of mantissa */ + bb0.n 25,r10,nounroundd /* do not unround if addone bit clear */ + extu r6,r12,12<20>/* extract signed exponenet from IMPCR */ +unroundd: or r8,r0,1 + subu.co r11,r11,r8 /* subtract 1 from mantissa */ + subu.ci r5,r5,r0 /* subtract borrow from upper word */ + bb1 20,r5,nounroundd /* if hidden bit is set, then exponent does */ + /* not need to be decremented */ +decexpd: sub r6,r6,1 /* decrement exponent 1 */ + set r5,r5,1<20> /* set the hidden bit */ + +nounroundd: or r8,r0,lo16(0x00000c01) /* load r8 with -1023 in decimal */ + /* for lowest 12 bits */ + sub r7,r8,r6 /* find difference between two exponents, */ + /* this amount is the shift amount */ + cmp r6,r7,3 /* check to see if r7 contains 3 or more */ + bb1 ge,r6,threedoub /* br to code that handles shifts of >=3 */ + cmp r6,r7,2 /* check to see if r7 contains 2 */ + bb1 eq,r6,twodoub /* br to code that handles shifts of 2 */ + +onedoub: rot r9,r9,0<1> /* rotate roundoff register once, this places */ + /* guard in round and round in sticky */ + bb0 31,r9,nosticky1d/* do not or round and sticky if sticky is 0 */ + /* this lost bit will be cleared later */ + set r9,r9,1<0> /* or old round and old sticky into new sticky */ +nosticky1d: bb0 0,r11,guardclr1d /* do not set new guard bit if old LSB = 0 */ + set r9,r9,1<2> /* set new guard bit */ +guardclr1d: extu r11,r11,31<1> /* shift lower mantissa over 1 */ + mak r6,r5,1<31> /* shift off low bit of high mantissa */ + or r11,r6,r11 /* load high bit onto lower mantissa */ + extu r5,r5,20<1> /* shift right once upper 20 bits of mantissa */ + br.n round /* round mantissa and assemble result */ + mak r9,r9,3<0> /* clear bits lost during rotation */ + +twodoub: rot r9,r9,0<2> /* rotate roundoff register twice, this places */ + /* old guard into sticky */ + bb0 30,r9,nosticky2d /* do not or old guard and old sticky if */ + /* old sticky is 0 */ + br.n noround2d /* skip or of old guard and old round if old */ + /* sticky set */ + set r9,r9,1<0> /* or old guard and old sticky into new sticky */ +nosticky2d: bb0 31,r9,noround2d /* do not or old guard and old round if */ + /* old round is 0 */ + set r9,r9,1<0> /* or old guard and old round into new sticky */ +noround2d: bb0 0,r11,roundclr2d /* do not set round bit if old LSB = 0 */ + set r9,r9,1<1> /* set new round bit */ +roundclr2d: bb0 1,r11,guardclr2d /* do not set guard bit if old LSB + 1 = 0 */ + set r9,r9,1<2> /* set new guard bit */ +guardclr2d: extu r11,r11,30<2> /* shift lower mantissa over 2 */ + mak r6,r5,2<30> /* shift off low bits of high mantissa */ + or r11,r6,r11 /* load high bit onto lower mantissa */ + extu r5,r5,19<2> /* shift right twice upper 19 bits of mantissa */ + br.n round /* round mantissa and assemble result */ + mak r9,r9,3<0> /* clear bits lost during rotation */ + +threedoub: bb1 0,r9,noguard3d /* checky sticky initially */ + /* sticky is set, forget most of rest of oring */ +nosticky3d: bb0 1,r9,noround3d /* check old round, do not set sticky if */ + /* old round is clear, set otherwise */ + br.n noguard3d /* sticky is set, forget most of rest of oring */ + set r9,r9,1<0> /* set sticky if old round is set */ +noround3d: bb0 2,r9,noguard3d /* check old guard, do not set sticky if 0 */ + clr r9,r9,2<1> /* clear the original guard and round for when */ + /* you get to round section */ + set r9,r9,1<0> /* set sticky if old guard is set */ +noguard3d: cmp r6,r7,32 /* do I need to work with a 1 or 2 word mant. */ + /* when forming sticky, round and guard */ + bb1 gt,r6,d33 /* jump to code that handles 2 word mantissas */ + sub r6,r7,2 /* get number of bits to check for sticky */ + mak r6,r6,5<5> /* shift width into width field */ + mak r8,r11,r6 /* mask off shifted bits -2 */ + ff1 r8,r8 /* see if r8 has any ones */ + bb1 5,r8,nostky32 /* do not set sticky if no ones found */ + set r9,r9,1<0> /* set sticky bit */ +nostky32: or r8,r0,34 /* start code to get new mantissa plus two */ + /* extra bits for new round and new guard bits, */ + /* the upper word bits will be shifted after */ + /* the round and guard bits are handled */ + subu r8,r8,r7 + mak r8,r8,5<5> /* shift field width into second five bits */ + extu r6,r6,5<5> /* shift previous shifted -2 into offset field */ + or r6,r6,r8 /* complete bit field */ + extu r11,r11,r6 /* partially form new low mantissa with 2 more */ + /* bits */ + bb0 0,r11,nornd32d /* do not set new round bit */ + set r9,r9,1<1> /* set new round bit */ +nornd32d: bb0 1,r11,nogrd32d /* do not set new guard bit */ + set r9,r9,1<2> /* set new guard bit */ +nogrd32d: extu r11,r11,30<2> /* shift off remaining two bits */ + mak r6,r7,5<5> /* shift field width into second 5 bits, if the */ + /* width is 32, then these bits will be 0 */ + or r8,r0,32 /* load word length into r8 */ + sub r8,r8,r7 /* form offset for high bits moved to low word */ + or r6,r6,r8 /* form complete bit field */ + mak r6,r5,r6 /* get shifted bits of high word */ + or r11,r6,r11 /* form new low word of mantissa */ + bcnd ne0,r8,regular33 /* do not adjust for special case of r8 */ + br.n round /* containing zeros, which would cause */ + or r5,r0,r0 /* all of the bits to be extracted under */ + /* the regular method */ +regular33: mak r6,r7,5<0> /* place lower 5 bits of shift into r6 */ + mak r8,r8,5<5> /* shift r8 into width field */ + or r6,r6,r8 /* form field for shifting of upper bits */ + br.n round /* round and assemble result */ + extu r5,r5,r6 /* form new high word mantissa */ + +d33: cmp r6,r7,33 /* is the number of bits to be shifted is 33? */ + bb1 gt,r6,d34 /* check to see if # of bits is 34 */ + bb1 0,r9,nostky33 /* skip checking if old sticky set */ + mak r6,r11,31<0> /* check bits that will be shifted into sticky */ + ff1 r8,r8 /* check for ones */ + bb1 5,r8,nostky33 /* do not set sticky if there are no ones */ + set r9,r9,1<0> /* set new sticky bit */ +nostky33: bb0 31,r11,nornd33 /* do not set round if bit is not a 1 */ + set r9,r9,1<1> /* set new round bit */ +nornd33: bb0 0,r5,nogrd33 /* do not set guard bit if bit is not a 1 */ + set r9,r9,1<2> /* set new guard bit */ +nogrd33: extu r11,r5,31<1> /* shift high bits into low word */ + br.n round /* round and assemble result */ + or r5,r0,r0 /* clear high word */ + +d34: cmp r6,r7,34 /* is the number of bits to be shifted 34? */ + bb1 gt,r6,d35 /* check to see if # of bits is >= 35 */ + bb1 0,r9,nostky34 /* skip checking if old sticky set */ + ff1 r8,r11 /* check bits that will be shifted into sticky */ + bb1 5,r8,nostky34 /* do not set sticky if there are no ones */ + set r9,r9,1<0> /* set new sticky bit */ +nostky34: bb0 0,r5,nornd34 /* do not set round if bit is not a 1 */ + set r9,r9,1<1> /* set new round bit */ +nornd34: bb0 1,r5,nogrd34 /* do not set guard bit if bit is not a 1 */ + set r9,r9,1<2> /* set new guard bit */ +nogrd34: extu r11,r5,30<2> /* shift high bits into low word */ + br.n round /* round and assemble result */ + or r5,r0,r0 /* clear high word */ + +d35: cmp r6,r7,52 /* see if # of shifts is 35 <= X <= 52 */ + bb1 gt,r6,d53 /* check to see if # of shifts is 52 */ + bb1.n 0,r9,nostky35 /* skip checking if old sticky set */ + sub r7,r7,34 /* subtract 32 from # of shifts so that opera- */ + /* tions can be done on the upper word, and */ + /* then subtract two more checking guard and */ + /* sticky bits */ + ff1 r8,r11 /* see if lower word has a bit for sticky */ + bb1 5,r8,stkycheck35 /* see if upper word has any sticky bits */ + br.n nostky35 /* quit checking for sticky */ + set r9,r9,1<0> /* set sticky bit */ +stkycheck35: mak r6,r7,5<5> /* place width into width field */ + mak r8,r5,r6 /* mask off shifted bits - 2 */ + ff1 r8,r8 /* see if r8 has any ones */ + bb1 5,r8,nostky35 /* do not set sticky if no ones found */ + set r9,r9,1<0> /* set sticky bit */ +nostky35: or r8,r0,32 /* look at what does not get shifted off plus */ + /* round and sticky, remember that the r7 value */ + /* was adjusted so that it did not include */ + /* new round or new sticky in shifted off bits */ + subu r8,r8,r7 /* complement width */ + mak r8,r8,5<5> /* shift width into width field */ + or r8,r7,r8 /* add offset field */ + extu r11,r5,r8 /* extract upper bits into low word */ + bb0 0,r11,nornd35 /* do not set new round bit */ + set r9,r9,1<1> /* set new round bit */ +nornd35: bb0 1,r11,nogrd35 /* do not set new guard bit */ + set r9,r9,1<2> /* set new guard bit */ +nogrd35: extu r11,r11,30<2> /* shift off remaining guard and round bits */ + br.n round /* round and assemble result */ + or r5,r0,r0 /* clear high word */ + +d53: cmp r6,r7,53 /* check to see if # of shifts is 53 */ + bb1 gt,r6,d54 /* branch to see if shifts = 54 */ + bb1 0,r9,nostky53 /* skip checking if old sticky set */ + ff1 r8,r11 /* see if lower word has a bit for sticky */ + bb1 5,r8,stkycheck53 /* see if upper word has any sticky bits */ + br.n nostky53 /* quit checking for sticky */ + set r9,r9,1<0> /* set sticky bit */ +stkycheck53: mak r6,r5,19<0> /* check bits that are shifted into sticky */ + ff1 r8,r6 /* see if r6 has any ones */ + bb1 5,r8,nostky53 /* do not set sticky if no ones found */ + set r9,r9,1<0> /* set sticky bit */ +nostky53: bb0 19,r5,nornd53 /* do not set new round bit */ + set r9,r9,1<1> /* set new round bit */ +nornd53: set r9,r9,1<2> /* set new guard bit,this is hidden bit */ + or r5,r0,r0 /* clear high word */ + br.n round /* round and assemble result */ + or r11,r0,r0 /* clear low word */ + +d54: cmp r6,r7,54 /* check to see if # of shifts is 54 */ + bb1 gt,r6,d55 /* branch to execute for shifts =>55 */ + bb1 0,r9,nostky54 /* skip checking if old sticky set */ + ff1 r8,r11 /* see if lower word has a bit for sticky */ + bb1 5,r8,stkycheck54 /* see if upper word has any sticky bits */ + br.n nostky54 /* quit checking for sticky */ + set r9,r9,1<0> /* set sticky bit */ +stkycheck54: mak r6,r5,20<0> /* check bits that are shifted into sticky */ + ff1 r8,r6 /* see if r6 has any ones */ + bb1 5,r8,nostky54 /* do not set sticky if no ones found */ + set r9,r9,1<0> /* set sticky bit */ +nostky54: set r9,r9,1<1> /* set new round bit,this is hidden bit */ + clr r9,r9,1<2> /* clear guard bit since nothing shifted in */ + or r5,r0,r0 /* clear high word */ + br.n round /* round and assemble result */ + or r11,r0,r0 /* clear low word */ + +d55: set r9,r9,1<0> /* set new sticky bit,this contains hidden bit */ + clr r9,r9,2<1> /* clear guard and round bits since nothing */ + /* shifted in */ + or r5,r0,r0 /* clear high word */ + or r11,r0,r0 /* clear low word */ + + +/* The first item that the rounding code does is see if either guard, round, */ +/* or sticky is set. If all are clear, then there is no denormalization loss */ +/* and no need to round, then branch to assemble answer. */ +/* For rounding, a branch table is set up. The left two most bits are the */ +/* rounding mode. The third bit is either the LSB of the mantissa or the */ +/* sign bit, depending on the rounding mode. The three LSB''s are the guard, */ +/* round and sticky bits. */ + +round: ff1 r8,r9 /* see if there is denormalization loss */ + bb1 5,r8,assemble /* no denormalization loss or inexactness */ + extu r6,r10,2<modelo> /* extract rounding mode */ + bb1.n modehi,r10,signext /* use sign bit instead of LSB */ + mak r6,r6,2<4> /* shift over rounding mode */ + extu r7,r11,1<0> /* extract LSB */ + br.n grs /* skip sign extraction */ + mak r7,r7,1<3> /* shift over LSB */ +signext: extu r7,r10,1<31> /* extract sign bit */ + mak r7,r7,1<3> /* shift sign bit over */ +grs: or r6,r6,r7 + or r6,r6,r9 /* or in guard, round, and sticky */ + or.u r1,r0,hi16(roundtable) /* form address of branch table */ + or r1,r1,lo16(roundtable) + lda r6,r1[r6] /* scale offset into branch table */ + jmp.n r6 /* jump to branch table */ + set r9,r9,1<3> /* set inexact flag in r9 */ + +roundtable: br noaddone +r000001: br noaddone +r000010: br noaddone +r000011: br noaddone +r000100: br noaddone +r000101: br addone +r000110: br addone +r000111: br addone +r001000: br noaddone +r001001: br noaddone +r001010: br noaddone +r001011: br noaddone +r001100: br addone +r001101: br addone +r001110: br addone +r001111: br addone +r010000: br noaddone +r010001: br noaddone +r010010: br noaddone +r010011: br noaddone +r010100: br noaddone +r010101: br noaddone +r010110: br noaddone +r010111: br noaddone +r011000: br noaddone +r011001: br noaddone +r011010: br noaddone +r011011: br noaddone +r011100: br noaddone +r011101: br noaddone +r011110: br noaddone +r011111: br noaddone +r100000: br noaddone +r100001: br noaddone +r100010: br noaddone +r100011: br noaddone +r100100: br noaddone +r100101: br noaddone +r100110: br noaddone +r100111: br noaddone +r101000: br noaddone +r101001: br addone +r101010: br addone +r101011: br addone +r101100: br addone +r101101: br addone +r101110: br addone +r101111: br addone +r110000: br noaddone +r110001: br addone +r110010: br addone +r110011: br addone +r110100: br addone +r110101: br addone +r110110: br addone +r110111: br addone +r111000: br noaddone +r111001: br noaddone +r111010: br noaddone +r111011: br noaddone +r111100: br noaddone +r111101: br noaddone +r111110: br noaddone +r111111: br noaddone + +/* Round by adding a one to the LSB of the mantissa. */ +addone: or r6,r0,1 /* load a 1 into r6 so that add.co can be used */ + add.co r11,r11,r6 /* add a one to the lower word of result */ + bb0.n destsize,r12,noaddone /* single result,forget carry */ + set r9,r9,1<4> /* indicate that a 1 has been added */ + add.ci r5,r5,r0 /* propagate carry into high word */ + + +/* Branch to inexact user handler if there is one. */ + +noaddone: +#ifdef HANDLER + bb1.n efinx,r12,modformdef /* branch to modify form for user */ + /* handler */ + or r2,r2,5 /* set inexact and underflow flags */ +#endif + + +/* Assemble the result of the denormalization routine for writeback to the */ +/* destination register. The exponent of a denormalized number is zero, */ +/* so simply assemble the sign and the new mantissa. */ + +assemble: bb1 destsize,r12,doubassem /* assemble double result */ + bb0 sign,r10,exassems /* exit assemble if sign is zero */ + set r11,r11,1<sign> /* make result negative */ +exassems: br Ureturn /* return from subroutine */ + +doubassem: bb0.n sign,r10,signclr /* do not set sign in r10 */ + or r10,r5,r0 /* load high word from r5 into r10 */ + set r10,r10,1<sign> /* high word with sign loaded */ +signclr: br Ureturn /* return from subroutine */ + + +/* modfordef modifies the result of denormalization to the input format of */ +/* the inexact user handler. This input format is the same format that */ +/* MANTHI, MANTLO, and IMPCR were initially loaded with. */ + +#ifdef HANDLER +modformdef: clr r12,r12,12<20> /* clear result exponent,IMPCR complete */ + clr r10,r10,4<25> /* clear old guard,round,sticky,and addone */ + mak r5,r9,3<26> /* make grs field */ + bb0.n 4,r9,newaddone /* do not set new addone in MANTHI */ + or r10,r5,r10 /* or in new grs field */ + set r10,r10,1<25> /* set new addone */ +newaddone: bb1.n destsize,r12,moddefd /* branch to handle double precision */ + clr r10,r10,21<0> /* clear upper bits of old mantissa */ +moddefs: extu r5,r11,20<3> /* extract upper bits */ + or r10,r5,r10 /* MANTHI complete */ + bsr.n _handler /* execute user handler for inexact */ + rot r11,r11,0<3> /* MANTLO complete */ + br Ureturn /* return from subroutine */ +moddefd: bsr.n _handler /* execute user handler for inexact */ + or r10,r5,r10 /* MANTHI complete,r5 should be set to OR */ +#endif + + +/* Return to fpui. */ + +Ureturn: ld r1,r31,0 /* load return address */ + jmp r1 /* return from subroutine */ + + data + +/* function _FPoverflow -- */ +/* The documentation for this release gives an overall description of this code. */ +data +align 4 +msg2: string "here at line %d, r1 is %x\n\0" +text + +#line 23 + +/* If the overflow user handler bit is not set, then the inexact bit in the */ +/* FPSR is set, and the inexact user handler bit is checked. If it is set, */ +/* then the inexact user handler is executed, else the default routine for */ +/* overflow is executed. */ + text + align 8 + global _FPoverflow +_FPoverflow: + st r1,r31,0 /* save return address */ +#ifdef HANDLER + set r2,r2,1<overflow> /* set overflow bit in r2 which holds FPSR */ + bb1 efovf,r12,hand /* go to user handler if bit set for overflow */ + set r2,r2,1<inexact> /* set inexact bit in r2 since overflow bit */ + /* in FPCR is not set */ + bb0 efinx,r12,nohandler/* if userhandler for inexact not set,then */ + /* round result */ + br callhandler /* branch to user handler for inexact */ + +/* Before the overflow user handler is executed, the exponent is modified */ +/* by subtracting 192 for single precision and 1536 for double precision. */ + +hand: bb1 10,r12,doubleprec /* double precision result */ +singleprec: or.u r5,r0,0x0c00 /* load exponent adjust */ + br.n callhandler /* prepare to call user handler */ + subu r12,r12,r5 /* adjust single precision exponent */ +doubleprec: or.u r5,r0,0x6000 /* load exponent adjust */ + subu r12,r12,r5 /* adjust double precision exponent */ +callhandler: bsr _handler /* branch to common handler routine */ + br return /* return from overflow subroutine */ +#endif + +/* Determine which rounding mode to use for the default procedure. */ + +nohandler: bb1 modehi,r10,signed /* mode is either round toward pos. or neg. */ + bb0 modelo,r10,OFnearest /* rounding mode is round nearest */ + br OFzero /* rounding mode is round zero */ +signed: bb0 modelo,r10,OFnegative /* rounding mode is round negative */ + br positive /* rounding mode is round positive */ + + +/* In the round toward nearest mode, positive values are rounded to */ +/* postive infinity and negative values are loaded toward negative infinity. */ +/* The value for single or double precision is loaded from a data table. */ + +OFnearest: + bb1.n destsize,r12,neardouble /* branch to neardouble of */ + /* double result */ + mask.u r5,r10,0x8000 /* mask off sign bit from MANTHI */ + or.u r11,r0,hi16(0x7f800000) /* load single infinity constant */ + or r11,r11,lo16(0x7f800000) + br.n return /* return with result */ + or r11,r5,r11 /* adjust sign */ +neardouble: + or r11,r0,r0 /* load lower word of infinity */ + or.u r10,r0,hi16(0x7ff00000) /* load upper word of infinity */ + or r10,r10,lo16(0x7ff00000) + br.n return /* return with result */ + or r10,r5,r10 /* adjust sign */ + + +/* In the round toward zero mode, positive values are rounded to the largest */ +/* postive finite number and negative values are rounded toward the largest */ +/* negative finite number. */ +/* The value for single or double precision is loaded from a data table. */ + +OFzero: + bb1.n destsize,r12,zerodouble /* branch to zerodouble of */ + /* double result */ + mask.u r5,r10,0x8000 /* mask off sign bit from MANTHI */ + or.u r11,r0,hi16(0x7f7fffff) /* load single finite number constant */ + or r11,r11,lo16(0x7f7fffff) + br.n return /* return with result */ + or r11,r5,r11 /* adjust sign */ +zerodouble: + set r11,r0,0<0> /* load lower word of finite number */ + or.u r10,r0,hi16(0x7fefffff) /* load upper word of finite number */ + or r10,r10,lo16(0x7fefffff) + br.n return /* return with result */ + or r10,r5,r10 /* adjust sign */ + + +/* In the round toward positve mode, positive values are rounded to */ +/* postive infinity and negative values are loaded toward the largest */ +/* negative finite number. */ +/* The value for single or double precision is loaded from a data table. */ + +positive: + bb1 destsize,r12,posdouble /* branch to section for double result */ +possingle: + bb1 sign,r10,possingleneg /* branch to section for negatives */ +possinglepos: + or.u r11,r0,hi16(0x7f800000) /* load single infinity constant */ + br.n return /* return with result */ + or r11,r11,lo16(0x7f800000) +possingleneg: + or.u r11,r0,hi16(0x7f7fffff) /* load single finite number constant */ + or r11,r11,lo16(0x7f7fffff) + br.n return /* return with result */ + set r11,r11,1<sign> /* set sign for negative */ +posdouble: + bb1 sign,r10,posdoubleneg /* branch to negative double results */ +posdoublepos: + or r11,r0,r0 /* load lower word of double infinity */ + or.u r10,r0,hi16(0x7ff00000) /* load upper word of infinity */ + br.n return /* return with result */ + or r10,r10,lo16(0x7ff00000) +posdoubleneg: + set r11,r0,0<0> /* load lower word of finite number */ + or.u r10,r0,hi16(0x7fefffff) /* load upper word of finite number */ + or r10,r10,lo16(0x7fefffff) + br.n return /* return with result */ + set r10,r10,1<sign> /* set sign for negative */ + + +/* In the round toward negative mode, positive values are rounded to the largest */ +/* postive finite number and negative values are rounded to negative infinity. */ +/* The value for single or double precision is loaded from a data table. */ + +OFnegative: + bb1 destsize,r12,negdouble /* branch to section for double result */ +negsingle: + bb1 sign,r10,negsingleneg /* branch to section for negatives */ +negsinglepos: + or.u r11,r0,hi16(0x7f7fffff) /* load single finite number constant */ + br.n return /* return with result */ + or r11,r11,lo16(0x7f7fffff) +negsingleneg: + or.u r11,r0,hi16(0x7f800000) /* load single infinity constant */ + or r11,r11,lo16(0x7f800000) + br.n return /* return with result */ + set r11,r11,1<sign> /* set sign for negative */ +negdouble: + bb1 sign,r10,negdoubleneg /* branch to negative double results */ +negdoublepos: + set r11,r0,0<0> /* load lower word of finite number */ + or.u r10,r0,hi16(0x7fefffff) /* load upper word of finite number */ + br.n return /* return with result */ + or r10,r10,lo16(0x7fefffff) +negdoubleneg: + or r11,r0,r0 /* load lower word of double infinity */ + or.u r10,r0,hi16(0x7ff00000) /* load upper word of infinity */ + or r10,r10,lo16(0x7ff00000) + set r10,r10,1<sign> /* set sign for negative */ + +return: + ld r1,r31,0 /* ld return address */ + jmp r1 /* return from subroutine */ + + data + + +/* If either S1 or S2 is a signalling NaN, then set the invalid operation */ +/* bit of the FPSR. If the invalid operation user handler flag is set and */ +/* then NaN is signalling, then branch to the handler routine to go to the */ +/* user handler. */ +/* If S1 is the only NaN or one of two NaN''s, then write */ +/* a quiet S1 to the result. A signalling NaN must be made quiet before */ +/* it can be written, but a signalling S2 is not modified in this routine */ +/* if S1 is a NaN. */ + text +LABEL(_NaN) + bb0.n s1nan,r12,S2sigcheck /* S1 is not a NaN */ + st r1,r31,0 /* save return address */ + bb1 sigbit,r5,S2sigcheck /* S1 is not a signaling NaN */ + set r2,r2,1<oper> /* set invalid operation bit in FPSR */ +#ifdef JEFF_DEBUGxxxxxxx + /* + * Generate a signal to the offending process. + * This uses hardcoded constants from mach/exception.h + * and mach/machine/exception.h. + */ + ldcr r2, cr17 /* first arg: current_thread() */ + or r3, r0, 3 /* second arg: EXC_ARITHMETIC */ + or r4, r0, 3 /* third arg: EXC_M88K_FLOAT_P */ + or r5, r0, r0 + subu r31, r31, 48 + bsr.n _thread_doexception + st r1, r31, 44 + ld r1, r31, 44 + br.n FPnan_return + addu r31, r31, 48 +#endif +#ifdef HANDLER + bb0 oper,r3,S1nohandler /* branch if no user handler */ + bsr _handler /* branch to handler */ + br FPnan_return +_LABEL(S1nohandler) +#endif + br.n S1write /* FPSR bit already set, S1 is made quiet, */ + /* and since we always write S1 if it is a */ + /* NaN, write S1 and skip rest of routine */ + set r5,r5,1<sigbit> /* make S1 a quiet NaN */ + +_LABEL(S2sigcheck) + bb0 s2nan,r12,S1write /* S2 is not a NaN */ + bb1 sigbit,r7,S1write /* S2 is not a signaling NaN */ + set r2,r2,1<oper> /* set invalid operation bit in FPSR */ +#ifdef HANDLER + bb0 oper,r3,S2nohandler /* branch if no user handler */ + bsr _handler /* branch to handler */ + br FPnan_return +#endif + +_LABEL(S2nohandler) + set r7,r7,1<sigbit> /* make S2 a quiet NaN */ + + +/* Write a single or double precision quiet NaN unless the opeation is FCMP. */ +/* If the operation is FCMP, then set the not comparable bit in the result. */ + +_LABEL(S1write) + bb0 s1nan,r12,S2write /* do not write S1 if it is not a NaN */ + extu r10,r9,5<11> /* extract opcode */ + cmp r11,r10,FCMPop /* compare to FCMP */ + bb1 ne,r11,S1noFCMP /* operation is not FCMP */ + set r6,r0,1<nc> /* set the not comparable bit */ + br.n FPnan_return /* return from subroutine */ + set r6,r6,1<ne> /* set the not equal bit */ +_LABEL(S1noFCMP) + bb1.n dsize,r9,wrdoubS1 /* double destination */ + set r5,r5,11<20> /* set all exponent bits to 1 */ +/* The single result will be formed the same way whether S1 is a single or double */ +_LABEL(wrsingS1) + mak r10,r5,28<3> /* wipe out extra exponent bits */ + extu r11,r6,3<29> /* get lower three bits of mantissa */ + or r10,r10,r11 /* combine all of result except sign */ + clr r6,r5,31<0> /* clear all but sign */ + br.n FPnan_return /* return from function */ + or r6,r6,r10 /* form result */ + +_LABEL(wrdoubS1) +/* ;;;;; bb1 s1size,r9,wrdoubS1d ;write double source to double dest. */ +/* took out the above instruction -- don't see why it's there.... jfriedl */ +_LABEL(wrdoubS1s) + set r6,r6,29<0> /* set extra bits of lower word */ +_LABEL(wrdoubS1d) + br FPnan_return /* no modification necessary for writing */ + /* double to double, so return from function */ + +_LABEL(S2write) + extu r10,r9,5<11> /* extract opcode */ + cmp r11,r10,FCMPop /* compare to FCMP */ + bb1.n ne,r11,S2noFCMP /* operation is not FCMP */ + set r7,r7,11<20> /* set all exponent bits to 1 */ + set r6,r0,1<nc> /* set the not comparable bit */ + br.n FPnan_return /* return from subroutine */ + set r6,r6,1<ne> /* set the not equal bit */ +_LABEL(S2noFCMP) + bb1.n dsize,r9,wrdoubS2 /* double destination */ + /* + * In the original, the ".n" above and the "set r5..." below + * were omitted here. Since they're in the S1 stuff above, + * and since this isn't working right now (r5 isn't being set + * to it's part of the nan), I'll try this... + * jfriedl Dec 1, 1989 + */ + set r5,r5,11<20> /* set all exponent bits to 1 */ +/* The single result will be formed the same way whether S1 is a single or double */ +_LABEL(wrsingS2) + mak r10,r7,28<3> /* wipe out extra exponent bits */ + extu r11,r8,3<29> /* get lower three bits of mantissa */ + or r10,r10,r11 /* combine all of result except sign */ + clr r6,r7,31<0> /* clear all but sign */ + br.n FPnan_return /* return from function */ + or r6,r6,r10 /* form result */ + +_LABEL(wrdoubS2) + +/* ;;; bb1 s2size,r9,FPnan_return ;write double source to double dest. */ + /* + * I took out the above branch because I just don't see how it + * makes sense. jfriedl Dec 1, '89 + */ +_LABEL(wrdoubS2s) + set r6,r8,29<0> /* set extra bits of lower word */ + + +/* Return from this subroutine with the result. */ + +_LABEL(FPnan_return) + /* no modification necessary for writing */ + /* double to double, so return from function */ + ld r1,r31, 0 /* retrieve return address */ + jmp r1 /* return from function */ + + data + +/* function _infinity -- */ +/* See the documentation of this release for an overall description of this */ +/* code. */ + + +/* Extract the opcode, compare to a constant, and branch to the code */ +/* for the instruction. */ + + text + align 8 + global _infinity +_infinity: extu r10,r9,5<11> /* extract opcode */ + cmp r11,r10,FADDop /* compare to FADD */ + bb1.n eq,r11,FADD /* operation is FADD */ + st r1,r31,0 /* save return address */ + cmp r11,r10,FSUBop /* compare to FSUB */ + bb1 eq,r11,FSUB /* operation is FSUB */ + cmp r11,r10,FCMPop /* compare to FCMP */ + bb1 eq,r11,FCMP /* operation is FCMP */ + cmp r11,r10,FMULop /* compare to FMUL */ + bb1 eq,r11,FMUL /* operation is FMUL */ + cmp r11,r10,FDIVop /* compare to FDIV */ + bb1 eq,r11,FDIV /* operation is FDIV */ +/* cmp r11,r10,FSQRTop;compare to FSQRT */ +/* bb1 eq,r11,FSQRT ;operation is FSQRT */ + cmp r11,r10,INTop /* compare to INT */ + bb1 eq,r11,FP_inf_overflw /* operation is INT */ + cmp r11,r10,NINTop /* compare to NINT */ + bb1 eq,r11,FP_inf_overflw /* operation is NINT */ + cmp r11,r10,TRNCop /* compare to TRNC */ + bb1 eq,r11,FP_inf_overflw /* operation is TRNC */ + + +/* Adding infinities of opposite signs will cause an exception, */ +/* but all other operands will result in a correctly signed infinity. */ + +FADD: bb0 s1inf,r12,addS2write /* branch if S1 not infinity */ + bb0 s2inf,r12,addS1write /* S2 is not inf., so branch to write S1 */ + bb1 sign,r5,addS1neg /* handle case of S1 negative */ +addS1pos: bb1 sign,r7,excpt /* adding infinities of different signs */ + /* causes an exception */ + br poswrinf /* branch to write positive infinity */ +addS1neg: bb0 sign,r7,excpt /* adding infinities of different signs */ + /* causes an exception */ + br negwrinf /* branch to write negative infinity */ +addS1write: bb0 sign,r5,poswrinf /* branch to write positive infinity */ + br negwrinf /* branch to write negative infinity */ +addS2write: bb0 sign,r7,poswrinf /* branch to write positive infinity */ + br negwrinf /* branch to write negative infinity */ + + +/* Subtracting infinities of the same sign will cause an exception, */ +/* but all other operands will result in a correctly signed infinity. */ + +FSUB: bb0 s1inf,r12,subS2write /* branch if S1 not infinity */ + bb0 s2inf,r12,subS1write /* S2 is not inf., so branch to write S1 */ + bb1 sign,r5,subS1neg /* handle case of S1 negative */ +subS1pos: bb0 sign,r7,excpt /* subtracting infinities of the same sign */ + /* causes an exception */ + br poswrinf /* branch to write positive infinity */ +subS1neg: bb1 sign,r7,excpt /* subtracting infinities of the same sign */ + /* causes an exception */ + br negwrinf /* branch to write negative infinity */ +subS1write: bb0 sign,r5,poswrinf /* branch to write positive infinity */ + br negwrinf /* branch to write negative infinity */ +subS2write: bb1 sign,r7,poswrinf /* branch to write positive infinity */ + br negwrinf /* branch to write negative infinity */ + + +/* Compare the operands, at least one of which is infinity, and set the */ +/* correct bits in the destination register. */ + +FCMP: bb0.n s1inf,r12,FCMPS1f /* branch for finite S1 */ + set r4,r0,1<cp> /* since neither S1 or S2 is a NaN, set cp */ +FCMPS1i: bb1 sign,r5,FCMPS1ni /* branch to negative S1i */ +FCMPS1pi: bb0 s2inf,r12,FCMPS1piS2f /* branch to finite S2 with S1pi */ +FCMPS1piS2i: bb1 sign,r7,FCMPS1piS2ni /* branch to negative S2i with S1pi */ +FCMPS1piS2pi: set r4,r4,1<eq> /* set eq bit */ + set r4,r4,1<le> /* set le bit */ + set r4,r4,1<ge> /* set ge bit */ + set r4,r4,1<ib> /* set ib bit */ + br.n move /* return from subroutine */ + set r4,r4,1<ob> /* set ob bit */ +FCMPS1piS2ni: set r4,r4,1<ne> /* set ne bit */ + set r4,r4,1<gt> /* set gt bit */ + br.n move /* return from subroutine */ + set r4,r4,1<ge> /* set ge bit */ +FCMPS1piS2f: set r4,r4,1<ne> /* set ne bit */ + set r4,r4,1<gt> /* set gt bit */ + bsr.n _zero /* see if any of the operands are zero */ + set r4,r4,1<ge> /* set ge bit */ + bb0 s2zero,r12,FCMPS1piS2nz /* check for negative if s2 not zero */ + set r4,r4,1<ou> /* set ou bit */ + br.n move + set r4,r4,1<ob> /* set ob bit */ +FCMPS1piS2nz: bb1 sign,r7,move /* return from subroutine if s2 is neg. */ +FCMPS1piS2pf: set r4,r4,1<ou> /* set ou bit */ + br.n move /* return from subroutine */ + set r4,r4,1<ob> /* set ob bit */ +FCMPS1ni: bb0 s2inf,r12,FCMPS1niS2f /* branch to finite S2 with S1ni */ +FCMPS1niS2i: bb1 sign,r7,FCMPS1niS2ni /* branch to negative S2i with S1ni */ +FCMPS1niS2pi: set r4,r4,1<ne> /* set eq bit */ + set r4,r4,1<le> /* set le bit */ + set r4,r4,1<lt> /* set lt bit */ + set r4,r4,1<ou> /* set ou bit */ + br.n move /* return from subroutine */ + set r4,r4,1<ob> /* set ob bit */ +FCMPS1niS2ni: set r4,r4,1<eq> /* set eq bit */ + set r4,r4,1<le> /* set le bit */ + br.n move /* return from subroutine */ + set r4,r4,1<ge> /* set ge bit */ +FCMPS1niS2f: set r4,r4,1<ne> /* set eq bit */ + set r4,r4,1<le> /* set le bit */ + bsr.n _zero /* see if any of the operands are zero */ + set r4,r4,1<lt> /* set lt bit */ + bb0 s2zero,r12,FCMPS1niS2nz /* branch if s2 is not zero */ + set r4,r4,1<ou> /* set ou bit */ + br.n move + set r4,r4,1<ob> /* set ob bit */ +FCMPS1niS2nz: bb1 sign,r7,move /* return from subroutine if s2 is neg. */ + set r4,r4,1<ou> /* set ou bit */ + br.n move /* return from subroutine */ + set r4,r4,1<ob> /* set ob bit */ +FCMPS1f: bb1 sign,r5,FCMPS1nf /* branch to negative S1f */ +FCMPS1pf: bb1.n sign,r7,FCMPS1pfS2ni /* branch to negative S2i with S1pf */ + set r4,r4,1<ne> /* set ne bit */ +FCMPS1pfS2pi: set r4,r4,1<le> /* set le bit */ + set r4,r4,1<lt> /* set lt bit */ + bsr.n _zero + set r4,r4,1<ib> /* set ib bit */ + bb0 s1zero,r12,FCMPS1pfS2pinozero +FCMPS1pfS2pizero: br.n move + set r4,r4,1<ob> /* set ob bit */ +FCMPS1pfS2pinozero: br.n move + set r4,r4,1<in> /* set in bit */ +FCMPS1pfS2ni: set r4,r4,1<gt> /* set gt bit */ + br.n move /* return from subroutine */ + set r4,r4,1<ge> /* set ge bit */ +FCMPS1nf: bb1.n sign,r7,FCMPS1nfS2ni /* branch to negative S2i with S1nf */ + set r4,r4,1<ne> /* set ne bit */ + set r4,r4,1<le> /* set gt bit */ + set r4,r4,1<lt> /* set ge bit */ + bsr.n _zero /* see which of the operands are zero */ + set r4,r4,1<ob> /* set ob bit */ + bb0 s1zero,r12,FCMPS1nfS2pinozero /* no ls and lo */ +FCMPS1nfS2pizero: br.n move + set r4,r4,1<ib> /* set ib bit */ +FCMPS1nfS2pinozero: br.n move + set r4,r4,1<ou> /* set ou bit */ +FCMPS1nfS2ni: set r4,r4,1<gt> /* set gt bit */ + set r4,r4,1<ge> /* set ge bit */ + +move: br.n inf_return /* return from subroutine */ + or r6,r0,r4 /* transfer answer to r6 */ + + +/* Multiplying infinity and zero causes an exception, but all other */ +/* operations produce a correctly signed infinity. */ + +FMUL: bsr _zero /* see if any of the operands are zero */ + bb1 s1zero,r12,excpt /* infinity X 0 causes an exception */ + bb1 s2zero,r12,excpt /* infinity X 0 causes an exception */ + bb1 sign,r5,FMULS1neg /* handle negative cases of S1 */ + bb0 sign,r7,poswrinf /* + X + = + */ + br negwrinf /* + X - = - */ +FMULS1neg: bb1 sign,r7,poswrinf /* - X - = + */ + br negwrinf /* - X + = - */ + + +/* Dividing infinity by infinity causes an exception, but dividing */ +/* infinity by a finite yields a correctly signed infinity, and */ +/* dividing a finite by an infinity produces a correctly signed zero. */ + +FDIV: bb1 s1inf,r12,FDIVS1inf /* handle case of S1 being infinity */ + bb1 sign,r5,FDIVS1nf /* handle cases of S1 being neg. non-inf. */ + bb1 sign,r7,FDIVS1pfS2mi /* handle case of negative S2 */ +FDIVS1pfS2pi: br poswrzero /* +f / +inf = +0 */ +FDIVS1pfS2mi: br negwrzero /* +f / -inf = -0 */ +FDIVS1nf: bb1 sign,r7,FDIVS1nfS2mi /* handle case of negative S2 */ +FDIVS1nfS2pi: br negwrzero /* -f / +inf = -0 */ +FDIVS1nfS2mi: br poswrzero /* -f / -inf = +0 */ +FDIVS1inf: bb1 s2inf,r12,excpt /* inf / inf = exception */ + bb1 sign,r5,FDIVS1mi /* handle cases of S1 being neg. inf. */ + bb1 sign,r7,FDIVS1piS2nf /* handle case of negative S2 */ +FDIVS1piS2pf: br poswrinf /* +inf / +f = +inf */ +FDIVS1piS2nf: br negwrinf /* +inf / -f = -inf */ +FDIVS1mi: bb1 sign,r7,FDIVS1miS2nf /* handle case of negative S2 */ +FDIVS1miS2pf: br negwrinf /* -inf / +f = -inf */ +FDIVS1miS2nf: br poswrinf /* -inf / -f = +inf */ + + +/* The square root of positive infinity is positive infinity, */ +/* but the square root of negative infinity is a NaN */ + +/* FSQRT: bb0 sign,r7,poswrinf ;write sqrt(inf) = inf */ +/* br excpt ;write sqrt(-inf) = NaN */ + +excpt: + set r2,r2,1<oper> /* set invalid operation bit of FPSR */ +#ifdef HANDLER + bb0 oper,r3,nohandler /* branch if no user handler */ + bsr _handler /* branch to interface with user handler */ + br inf_return /* return from function */ +nohandler: +#endif + set r5,r0,0<0> /* write NaN into r5 */ + br.n inf_return /* return from subroutine */ + set r6,r0,0<0> /* write NaN into r6, writing NaN''s into */ + /* both of these registers is quicker than */ + /* checking for single or double precision */ + + +/* Write positive infinity of the correct precision */ + +poswrinf: bb1 dsize,r9,poswrinfd /* branch to write double precision inf. */ + br.n inf_return /* return from subroutine */ + or.u r6,r0,0x7f80 /* load r6 with single precision pos inf. */ +poswrinfd: or.u r5,r0,0x7ff0 /* load double precision pos inf. */ + br.n inf_return /* return from subroutine */ + or r6,r0,r0 + + +/* Write negative infinity of the correct precision */ + +negwrinf: bb1 dsize,r9,negwrinfd /* branch to write double precision inf. */ + br.n inf_return /* return from subroutine */ + or.u r6,r0,0xff80 /* load r6 with single precision pos inf. */ +negwrinfd: or.u r5,r0,0xfff0 /* load double precision pos inf. */ + br.n inf_return /* return from subroutine */ + or r6,r0,r0 + + +/* Write a positive zero disregarding precision. */ + +poswrzero: or r5,r0,r0 /* write to both high word and low word now */ + br.n inf_return /* it does not matter that both are written */ + or r6,r0,r0 + + +/* Write a negative zero of the correct precision. */ + +negwrzero: or r6,r0,r0 /* clear low word */ + bb1 dsize,r9,negwrzerod /* branch to write double precision zero */ + br.n inf_return /* return from subroutine */ + set r6,r6,1<31> /* set sign bit */ +negwrzerod: or r5,r0,r0 /* clear high word */ + br.n inf_return /* return from subroutine */ + set r5,r5,1<31> /* set sign bit */ + +FP_inf_overflw: + set r2,r2,1<oper> /* set invalid operand bit */ +#ifdef HANDLER + bb0 oper,r3,nohandlero /* do not go to user handler routine */ + bsr _handler /* go to user handler routine */ + br inf_return /* return from subroutine */ +#endif + +nohandlero: bb0.n sign,r7,inf_return /* if positive then return from subroutine */ + + set r6,r6,31<0> /* set result to largest positive integer */ + or.c r6,r0,r6 /* negate r6,giving largest negative int. */ + +inf_return: ld r1,r31,0 /* load return address */ + jmp r1 /* return from subroutine */ + + data + +#define FADD denorm_FADD +#define FSUB denorm_FSUB +#define FCMP denorm_FCMP +#define FMUL denorm_FMUL +#define FDIV denorm_FDIV +#define NINT denorm_NINT +#define TRNC denorm_TRNC +#define return denorm_return +/* function _denorm -- */ +/* See the documentation for this release for an overall description of this */ +/* code. */ + + +/* Check to see if either S1 or S2 is a denormalized number. First */ +/* extract the exponent to see if it is zero, and then check to see if */ +/* the mantissa is not zero. If the number is denormalized, then set the */ +/* 1 or 0 bit 10 r12. */ + + text + align 8 + global _denorm +_denorm: st r1,r31,0 /* save return address */ +dnmcheckS1: extu r10,r5,11<20> /* extract exponent */ + bcnd ne0,r10,dnmsetS2 /* S1 is not a denorm, so S2 must be */ + bb1.n 9,r9,dnmcheckS1d /* S1 is double precision */ + mak r10,r5,20<3> /* mak field with only mantissa bits */ + /* into final result */ +dnmcheckS1s: extu r11,r6,3<29> /* get three low bits of mantissa */ + or r10,r10,r11 /* assemble all of the mantissa bits */ + bcnd eq0,r10,dnmsetS2 /* S1 is not a denorm, so S2 must be */ + br dnmsetS1 /* S1 is a denorm */ + +dnmcheckS1d: or r10,r6,r10 /* or all of mantissa bits */ + bcnd eq0,r10,dnmsetS2 /* S1 is not a denorm, so S2 must be */ +dnmsetS1: set r12,r12,1<1> /* S1 is a denorm */ + +dnmcheckS2: extu r10,r7,11<20> /* extract exponent */ + bcnd ne0,r10,S1form /* S2 is not a denorm */ + bb1.n 7,r9,dnmcheckS2d /* S2 is double precision */ + mak r10,r7,20<3> /* mak field with only mantissa bits */ +dnmcheckS2s: extu r11,r8,3<29> /* get three low bits of mantissa */ + or r10,r10,r11 /* assemble all of the mantissa bits */ + bcnd eq0,r10,S1form /* S2 is not a denorm */ + br dnmsetS2 /* S1 is a denorm */ +dnmcheckS2d: or r10,r8,r10 /* or all or mantissa bits */ + bcnd eq0,r10,S1form /* S2 is not a denorm */ +dnmsetS2: set r12,r12,1<0> /* S2 is a denorm */ + + +/* Since the operations are going to be reperformed with modified denorms, */ +/* the operands which were initially single precision need to be modified */ +/* back to single precision. */ + +S1form: bb1 9,r9,S2form /* S1 is double precision, so do not */ + /* modify S1 into single format */ + mak r11,r5,28<3> /* over final exponent and mantissa */ + /* eliminating extra 3 bits of exponent */ + extu r6,r6,3<29> /* get low 3 bits of mantissa */ + or r11,r6,r11 /* form complete mantissa and exponent */ + extu r10,r5,1<31> /* get the 31 bit */ + mak r10,r10,1<31> /* place 31 bit 10 correct position */ + or r6,r10,r11 /* or 31, exponent, and all of mantissa */ + +S2form: bb1 7,r9,checkop /* S2 is double precision, so do not */ + /* modify S2 into single format */ + mak r11,r7,28<3> /* over final exponent and mantissa */ + /* eliminating extra 3 bits of exponent */ + extu r8,r8,3<29> /* get low 3 bits of mantissa */ + or r11,r8,r11 /* form complete mantissa and exponent */ + extu r10,r7,1<31> /* get the 31 bit */ + mak r10,r10,1<31> /* place 31 bit 10 correct position */ + or r8,r10,r11 /* or 31, exponent, and all of mantissa */ + + +/* Extract the opcode, compare to a constant, and branch to the code that */ +/* deals with that opcode. */ + +checkop: extu r10,r9,5<11> /* extract opcode */ + cmp r11,r10,0x05 /* compare to FADD */ + bb1 2,r11,FADD /* operation is FADD */ + cmp r11,r10,0x06 /* compare to FSUB */ + bb1 2,r11,FSUB /* operation is FSUB */ + cmp r11,r10,0x07 /* compare to FCMP */ + bb1 2,r11,FCMP /* operation is FCMP */ + cmp r11,r10,0x00 /* compare to FMUL */ + bb1 2,r11,FMUL /* operation is FMUL */ + cmp r11,r10,0x0e /* compare to FDIV */ + bb1 2,r11,FDIV /* operation is FDIV */ +/* cmp r11,r10,0x0f;compare to FSQRT */ +/* bb1 2,r11,FSQRT ;operation is FSQRT */ + cmp r11,r10,0x09 /* compare to INT */ + bb1 2,r11,INT /* operation is INT */ + cmp r11,r10,0x0a /* compare to NINT */ + bb1 2,r11,NINT /* operation is NINT */ + cmp r11,r10,0x0b /* compare to TRNC */ + bb1 2,r11,TRNC /* operation is TRNC */ + + +/* For all the following operations, the denormalized number is set to */ +/* zero and the operation is reperformed the correct destination and source */ +/* sizes. */ + +FADD: bb0 1,r12,FADDS2dnm /* S1 is not denorm, so S2 must be */ + or r5,r0,r0 /* set S1 to zero */ + or r6,r0,r0 +FADDS2chk: bb0 0,r12,FADDcalc /* S2 is not a denorm */ +FADDS2dnm: or r7,r0,r0 /* set S2 to zero */ + or r8,r0,r0 +FADDcalc: bb1 5,r9,FADDdD /* branch for double precision destination */ +FADDsD: bb1 9,r9,FADDsDdS1 /* branch for double precision S1 */ +FADDsDsS1: bb1 7,r9,FADDsDsS1dS2 /* branch for double precision S2 */ +FADDsDsS1sS2: br.n return /* return from subroutine */ + fadd.sss r6,r6,r8 /* add the two sources and place result 10 S1 */ +FADDsDsS1dS2: br.n return /* return from subroutine */ + fadd.ssd r6,r6,r7 /* add the two sources and place result 10 S1 */ +FADDsDdS1: bb1 7,r9,FADDsDdS1dS2 /* branch for double precision S2 */ +FADDsDdS1sS2: br.n return /* return from subroutine */ + fadd.sds r6,r5,r8 /* add the two sources and place result 10 S1 */ +FADDsDdS1dS2: br.n return /* return from subroutine */ + fadd.sdd r6,r5,r7 /* add the two sources and place result 10 S1 */ +FADDdD: bb1 9,r9,FADDdDdS1 /* branch for double precision S1 */ +FADDdDsS1: bb1 7,r9,FADDdDsS1dS2 /* branch for double precision S2 */ +FADDdDsS1sS2: br.n return /* return from subroutine */ + fadd.dss r5,r6,r8 /* add the two sources and place result 10 S1 */ +FADDdDsS1dS2: br.n return /* return from subroutine */ + fadd.dsd r5,r6,r7 /* add the two sources and place result 10 S1 */ +FADDdDdS1: bb1 7,r9,FADDdDdS1dS2 /* branch for double precision S2 */ +FADDdDdS1sS2: br.n return /* return from subroutine */ + fadd.dds r5,r5,r8 /* add the two sources and place result 10 S1 */ +FADDdDdS1dS2: br.n return /* return from subroutine */ + fadd.ddd r5,r5,r7 /* add the two sources and place result 10 S1 */ + +FSUB: bb0 1,r12,FSUBS2dnm /* S1 is not denorm, so S2 must be */ + or r5,r0,r0 /* set S1 to zero */ + or r6,r0,r0 +FSUBS2chk: bb0 0,r12,FSUBcalc /* S2 is not a denorm */ +FSUBS2dnm: or r7,r0,r0 /* set S2 to zero */ + or r8,r0,r0 +FSUBcalc: bb1 5,r9,FSUBdD /* branch for double precision destination */ +FSUBsD: bb1 9,r9,FSUBsDdS1 /* branch for double precision S1 */ +FSUBsDsS1: bb1 7,r9,FSUBsDsS1dS2 /* branch for double precision S2 */ +FSUBsDsS1sS2: br.n return /* return from subroutine */ + fsub.sss r6,r6,r8 /* add the two sources and place result 10 S1 */ +FSUBsDsS1dS2: br.n return /* return from subroutine */ + fsub.ssd r6,r6,r7 /* add the two sources and place result 10 S1 */ +FSUBsDdS1: bb1 7,r9,FSUBsDdS1dS2 /* branch for double precision S2 */ +FSUBsDdS1sS2: br.n return /* return from subroutine */ + fsub.sds r6,r5,r8 /* add the two sources and place result 10 S1 */ +FSUBsDdS1dS2: br.n return /* return from subroutine */ + fsub.sdd r6,r5,r7 /* add the two sources and place result 10 S1 */ +FSUBdD: bb1 9,r9,FSUBdDdS1 /* branch for double precision S1 */ +FSUBdDsS1: bb1 7,r9,FSUBdDsS1dS2 /* branch for double precision S2 */ +FSUBdDsS1sS2: br.n return /* return from subroutine */ + fsub.dss r5,r6,r8 /* add the two sources and place result 10 S1 */ +FSUBdDsS1dS2: br.n return /* return from subroutine */ + fsub.dsd r5,r6,r7 /* add the two sources and place result 10 S1 */ +FSUBdDdS1: bb1 7,r9,FSUBdDdS1dS2 /* branch for double precision S2 */ +FSUBdDdS1sS2: br.n return /* return from subroutine */ + fsub.dds r5,r5,r8 /* add the two sources and place result 10 S1 */ +FSUBdDdS1dS2: br.n return /* return from subroutine */ + fsub.ddd r5,r5,r7 /* add the two sources and place result 10 S1 */ + +FCMP: bb0 1,r12,FCMPS2dnm /* S1 is not denorm, so S2 must be */ + or r5,r0,r0 /* set S1 to zero */ + or r6,r0,r0 +FCMPS2chk: bb0 0,r12,FCMPcalc /* S2 is not a denorm */ +FCMPS2dnm: or r7,r0,r0 /* set S2 to zero */ + or r8,r0,r0 +FCMPcalc: bb1 9,r9,FCMPdS1 /* branch for double precision S1 */ +FCMPsS1: bb1 7,r9,FCMPsS1dS2 /* branch for double precision S2 */ +FCMPsS1sS2: br.n return /* return from subroutine */ + fcmp.sss r6,r6,r8 /* add the two sources and place result 10 S1 */ +FCMPsS1dS2: br.n return /* return from subroutine */ + fcmp.ssd r6,r6,r7 /* add the two sources and place result 10 S1 */ +FCMPdS1: bb1 7,r9,FCMPdS1dS2 /* branch for double precision S2 */ +FCMPdS1sS2: br.n return /* return from subroutine */ + fcmp.sds r6,r5,r8 /* add the two sources and place result 10 S1 */ +FCMPdS1dS2: br.n return /* return from subroutine */ + fcmp.sdd r6,r5,r7 /* add the two sources and place result 10 S1 */ + +FMUL: bb0 1,r12,FMULS2dnm /* S1 is not denorm, so S2 must be */ + or r5,r0,r0 /* set S1 to zero */ + or r6,r0,r0 +FMULS2chk: bb0 0,r12,FMULcalc /* S2 is not a denorm */ +FMULS2dnm: or r7,r0,r0 /* set S2 to zero */ + or r8,r0,r0 +FMULcalc: bb1 5,r9,FMULdD /* branch for double precision destination */ +FMULsD: bb1 9,r9,FMULsDdS1 /* branch for double precision S1 */ +FMULsDsS1: bb1 7,r9,FMULsDsS1dS2 /* branch for double precision S2 */ +FMULsDsS1sS2: br.n return /* return from subroutine */ + fmul.sss r6,r6,r8 /* add the two sources and place result 10 S1 */ +FMULsDsS1dS2: br.n return /* return from subroutine */ + fmul.ssd r6,r6,r7 /* add the two sources and place result 10 S1 */ +FMULsDdS1: bb1 7,r9,FMULsDdS1dS2 /* branch for double precision S2 */ +FMULsDdS1sS2: br.n return /* return from subroutine */ + fmul.sds r6,r5,r8 /* add the two sources and place result 10 S1 */ +FMULsDdS1dS2: br.n return /* return from subroutine */ + fmul.sdd r6,r5,r7 /* add the two sources and place result 10 S1 */ +FMULdD: bb1 9,r9,FMULdDdS1 /* branch for double precision S1 */ +FMULdDsS1: bb1 7,r9,FMULdDsS1dS2 /* branch for double precision S2 */ +FMULdDsS1sS2: br.n return /* return from subroutine */ + fmul.dss r5,r6,r8 /* add the two sources and place result 10 S1 */ +FMULdDsS1dS2: br.n return /* return from subroutine */ + fmul.dsd r5,r6,r7 /* add the two sources and place result 10 S1 */ +FMULdDdS1: bb1 7,r9,FMULdDdS1dS2 /* branch for double precision S2 */ +FMULdDdS1sS2: br.n return /* return from subroutine */ + fmul.dds r5,r5,r8 /* add the two sources and place result 10 S1 */ +FMULdDdS1dS2: br.n return /* return from subroutine */ + fmul.ddd r5,r5,r7 /* add the two sources and place result 10 S1 */ + +FDIV: bb0 1,r12,FDIVS2dnm /* S1 is not denorm, so S2 must be */ + or r5,r0,r0 /* set S1 to zero */ + or r6,r0,r0 +FDIVS2chk: bb0 0,r12,FDIVcalc /* S2 is not a denorm */ +FDIVS2dnm: or r7,r0,r0 /* set S2 to zero */ + or r8,r0,r0 +FDIVcalc: bb1 5,r9,FDIVdD /* branch for double precision destination */ +FDIVsD: bb1 9,r9,FDIVsDdS1 /* branch for double precision S1 */ +FDIVsDsS1: bb1 7,r9,FDIVsDsS1dS2 /* branch for double precision S2 */ +FDIVsDsS1sS2: fdiv.sss r6,r6,r8 /* add the two sources and place result 10 S1 */ + br return /* return from subroutine */ +FDIVsDsS1dS2: fdiv.ssd r6,r6,r7 /* add the two sources and place result 10 S1 */ + br return /* return from subroutine */ +FDIVsDdS1: bb1 7,r9,FDIVsDdS1dS2 /* branch for double precision S2 */ +FDIVsDdS1sS2: fdiv.sds r6,r5,r8 /* add the two sources and place result 10 S1 */ + br return /* return from subroutine */ +FDIVsDdS1dS2: fdiv.sdd r6,r5,r7 /* add the two sources and place result 10 S1 */ + br return /* return from subroutine */ +FDIVdD: bb1 9,r9,FDIVdDdS1 /* branch for double precision S1 */ +FDIVdDsS1: bb1 7,r9,FDIVdDsS1dS2 /* branch for double precision S2 */ +FDIVdDsS1sS2: fdiv.dss r5,r6,r8 /* add the two sources and place result 10 S1 */ + br return /* return from subroutine */ +FDIVdDsS1dS2: fdiv.dsd r5,r6,r7 /* add the two sources and place result 10 S1 */ + br return /* return from subroutine */ +FDIVdDdS1: bb1 7,r9,FDIVdDdS1dS2 /* branch for double precision S2 */ +FDIVdDdS1sS2: fdiv.dds r5,r5,r8 /* add the two sources and place result 10 S1 */ + br return /* return from subroutine */ +FDIVdDdS1dS2: fdiv.ddd r5,r5,r7 /* add the two sources and place result 10 S1 */ + br return /* return from subroutine */ + +/* FSQRT: or r7,r0,r0 ;set S2 to zero */ +/* or r8,r0,r0 */ +/* FSQRTcalc: bb1 5,r9,FSQRTdD ;branch for double precision destination */ +/* FSQRTsD: bb1 7,r9,FSQRTsDdS2 ;branch for double precision S2 */ +/* FSQRTsDsS2: br.n return ;return from subroutine */ + /* fsqrt.ss r6,r8 ;add the two sources and place result 10 S1 */ +/* FSQRTsDdS2: br.n return ;return from subroutine */ + /* fsqrt.sd r6,r7 ;add the two sources and place result 10 S1 */ +/* FSQRTdD: bb1 7,r9,FSQRTdDdS2 ;branch for double precision S2 */ +/* FSQRTdDsS2: br.n return ;return from subroutine */ + /* fsqrt.ds r5,r8 ;add the two sources and place result 10 S1 */ +/* FSQRTdDdS2: br.n return ;return from subroutine */ + /* fsqrt.dd r5,r7 ;add the two sources and place result 10 S1 */ + +INT: or r7,r0,r0 /* set S2 to zero */ + or r8,r0,r0 +INTcalc: bb1 7,r9,INTdS2 /* branch for double precision S2 */ +INTsS2: br.n return /* return from subroutine */ + int.ss r6,r8 /* add the two sources and place result 10 S1 */ +INTdS2: br.n return /* return from subroutine */ + int.sd r6,r7 /* add the two sources and place result 10 S1 */ + +NINT: or r7,r0,r0 /* set S2 to zero */ + or r8,r0,r0 +NINTcalc: bb1 7,r9,NINTdS2 /* branch for double precision S2 */ +NINTsS2: br.n return /* return from subroutine */ + nint.ss r6,r8 /* add the two sources and place result 10 S1 */ +NINTdS2: br.n return /* return from subroutine */ + nint.sd r6,r7 /* add the two sources and place result 10 S1 */ + +TRNC: or r7,r0,r0 /* set S2 to zero */ + or r8,r0,r0 +TRNCcalc: bb1 7,r9,TRNCdS2 /* branch for double precision S2 */ +TRNCsS2: br.n return /* return from subroutine */ + trnc.ss r6,r8 /* add the two sources and place result 10 S1 */ +TRNCdS2: trnc.sd r6,r7 /* add the two sources and place result 10 S1 */ + + +/* Return to the routine that detected the reserved operand. */ + +return: ld r1,r31,0 /* load return address */ + jmp r1 /* return from subroutine */ + + data + + +/* S1 and/or S2 is an infinity, and the other operand may be a zero. */ +/* Knowing which operands are infinity, check the remaining operands for zeros. */ + + text + align 8 + global _zero +_zero: bb0 s1inf,r12,S1noinf /* see if S1 is zero */ + bb0 s2inf,r12,S2noinf /* see if S2 is zero */ + jmp r1 /* return from function */ + +/* See if S1 is zero. Whether or not S1 is a zero, being in this routine */ +/* implies that S2 is infinity, so return to subroutine infinity after */ +/* completing this code. Set the s1zero flag in r12 if S1 is zero. */ + +S1noinf: bb1 s1size,r9,S1noinfd /* work with double precision operand */ +S1noinfs: or r10,r0,r5 /* load high word into r10 */ + clr r10,r10,1<sign> /* clear the sign bit */ + extu r11,r6,3<29> /* extract lower 3 bits of mantissa */ + or r10,r10,r11 /* or these 3 bits with high word */ + bcnd ne0,r10,operation /* do not set zero flag */ + jmp.n r1 /* since this operand was not infinity, */ + /* S2 must have been, so return from */ + /* function */ + set r12,r12,1<s1zero> /* set zeroflag */ +S1noinfd: clr r10,r5,1<sign> /* clear the sign bit */ + or r10,r6,r10 /* or high and low word */ + bcnd ne0,r10,operation /* do not set zero flag */ + jmp.n r1 /* since this operand was not infinity, */ + /* S2 must have been, so return from */ + /* function */ + set r12,r12,1<s1zero> /* set zeroflag */ + + +/* Check S2 for zero. If it is zero, then set the s2zero flag in r12. */ + +S2noinf: bb1 s2size,r9,S2noinfd /* work with double precision operand */ +S2noinfs: or r10,r0,r7 /* load high word into r10 */ + clr r10,r10,1<sign> /* clear the sign bit */ + extu r11,r8,3<29> /* extract lower 3 bits of mantissa */ + or r10,r10,r11 /* or these 3 bits with high word */ + bcnd ne0,r10,operation /* do not set zero flag */ + jmp.n r1 /* since this operand was not infinity, */ + /* S1 must have been, so return from */ + /* function */ + set r12,r12,1<s2zero> /* set zeroflag */ +S2noinfd: clr r10,r7,1<sign> /* clear the sign bit */ + or r10,r8,r10 /* or high and low word */ + bcnd ne0,r10,operation /* do not set zero flag */ + set r12,r12,1<s2zero> /* set zeroflag */ + /* since this operand was not infinity, */ + /* S1 must have been, so return from */ + /* function */ +operation: jmp r1 /* return from function */ + + data + + text + align 8 +/* input: r3 is the excepton frame */ +_Xfp_imprecise: global _Xfp_imprecise + or r29, r3, r0 /* r29 is now the E.F. */ + subu r31, r31, 40 + st r1, r31, 32 + st r29, r31, 36 + + ld r2 , r29, EF_FPSR * 4 + ld r3 , r29, EF_FPCR * 4 + ld r4 , r29, EF_FPECR * 4 + ld r10, r29, EF_FPRH * 4 + ld r11, r29, EF_FPRL * 4 + ld r12, r29, EF_FPIT * 4 + +/* Load into r1 the return address for the exception handlers. Looking */ +/* at FPECR, branch to the appropriate exception handler. */ + + or.u r1,r0,hi16(fpui_wrapup)/* load return address of functions */ + or r1,r1,lo16(fpui_wrapup) + + bb0 2,r4,2f /* branch to FPunderflow if bit set */ + br _FPunderflow + 2: bb0 1,r4,3f /* branch to FPoverflow if bit set */ + br _FPoverflow + 3: +#ifdef HANDLER + br _handler /* branch to handler since bit will be set */ + /* for inexact */ +#endif + /* should never get here!!!! */ + data + align 8 + 1: string "error in inprecise fp exception handler, r4 is 0x%08x\n\0" + align 8 + text + or.u r2, r0, hi16(1b) + or r2, r2, lo16(1b) + or r3, r4, r0 + bsr _printf + or.u r2, r0, hi16(1b) + or r2, r2, lo16(1b) + bsr _panic + +fpui_wrapup: + tb1 0,r0,0 /* make sure all floating point operations */ + ldcr r5, psr /* load the PSR */ + /* have finished */ + or r5, r5, 0x2 /* disable interrupts */ + stcr r5, psr +#if 0 +Why is this done? -- it screws up things later. + or r5, r5, 0x8 /* set SFU 1 disable bit, disable SFU 1 */ + stcr r5, psr +#endif + ld r1, r31, 32 + ld r29,r31, 36 + addu r31, r31, 40 + + /* write back the results */ + extu r2, r12, 5<0> + addu r3, r29, EF_R0*4 + bb0 destsize, r12, Iwritesingle + st r10, r3 [r2] + addu r2, r2, 1 + clr r2, r2, 27<5> +Iwritesingle: + st r11, r3 [r2] +/* Return.. */ + jmp r1 diff --git a/sys/arch/mvme88k/mvme88k/machdep.c b/sys/arch/mvme88k/mvme88k/machdep.c new file mode 100644 index 00000000000..ac680b25615 --- /dev/null +++ b/sys/arch/mvme88k/mvme88k/machdep.c @@ -0,0 +1,1704 @@ +/* + * Copyright (c) 1996 Nivas Madhur + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by Nivas Madhur. + * 4. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ +/* + * Mach Operating System + * Copyright (c) 1993-1991 Carnegie Mellon University + * Copyright (c) 1991 OMRON Corporation + * All Rights Reserved. + * + * Permission to use, copy, modify and distribute this software and its + * documentation is hereby granted, provided that both the copyright + * notice and this permission notice appear in all copies of the + * software, derivative works or modified versions, and any portions + * thereof, and that both notices appear in supporting documentation. + * + */ + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/signalvar.h> +#include <sys/kernel.h> +#include <sys/map.h> +#include <sys/proc.h> +#include <sys/user.h> +#include <sys/buf.h> +#include <sys/reboot.h> +#include <sys/conf.h> +#include <sys/file.h> +#include <sys/callout.h> +#include <sys/malloc.h> +#include <sys/mbuf.h> +#include <sys/mount.h> +#include <sys/msgbuf.h> +#include <sys/syscallargs.h> +#ifdef SYSVMSG +#include <sys/msg.h> +#endif +#ifdef SYSVSEM +#include <sys/sem.h> +#endif +#ifdef SYSVSHM +#include <sys/shm.h> +#endif +#include <sys/ioctl.h> +#include <sys/exec.h> +#include <sys/sysctl.h> +#include <sys/errno.h> +#include <net/netisr.h> + +#include <mvme88k/dev/pcctworeg.h> +#include <machine/cpu.h> +#include <machine/reg.h> +#include <machine/psl.h> +#include <machine/board.h> +#include <machine/trap.h> +#include <machine/bug.h> + +#include <dev/cons.h> + +#include <vm/vm.h> +#include <vm/vm_map.h> +#include <vm/vm_kern.h> +#include <vm/vm_page.h> +#define __IS_MACHDEP_C__ +#include <assym.s> /* EF_EPSR, etc. */ +#include <machine/m88100.h> /* DMT_VALID */ +#include <machine/m882xx.h> /* CMMU stuff */ +#if DDB +# include <machine/db_machdep.h> +#endif /* DDB */ + +#if DDB +#define DEBUG_MSG db_printf +#else +#define DEBUG_MSG printf +#endif /* DDB */ +static int waittime = -1; + +struct intrhand *intr_handlers[256]; + +unsigned char *ivec[] = { + (unsigned char *)0xFFFE0003, /* not used, no such thing as int 0 */ + (unsigned char *)0xFFFE0007, + (unsigned char *)0xFFFE000B, + (unsigned char *)0xFFFE000F, + (unsigned char *)0xFFFE0013, + (unsigned char *)0xFFFE0017, + (unsigned char *)0xFFFE001B, + (unsigned char *)0xFFFE001F, +}; + +u_char *int_mask_level = (u_char *)INT_MASK_LEVEL; +u_char *int_pri_level = (u_char *)INT_PRI_LEVEL; +u_char *iackaddr; +volatile u_char *pcc2intr_mask; +volatile u_char *pcc2intr_ipl; +volatile vm_offset_t bugromva; +volatile vm_offset_t sramva; +volatile vm_offset_t obiova; + + +int physmem; /* available physical memory, in pages */ +int cold; +vm_offset_t avail_end, avail_start, avail_next; +int msgbufmapped = 0; +int foodebug = 0; +int longformat = 0; + +/* + * safepri is a safe priority for sleep to set for a spin-wait + * during autoconfiguration or after a panic. + */ +int safepri = 0; + +#if XXX_FUTURE +/* + * iomap stuff is for managing chunks of virtual address space that + * can be allocated to IO devices. + * XXX none of the drivers use this at this time. IO address is mapped + * so that pa == va. XXX nivas + */ +vm_offset_t iomapbase; +struct map *iomap; +vm_map_t iomap_map; +int niomap; +#endif + +/* + * Declare these as initialized data so we can patch them. + */ +int nswbuf = 0; +#ifdef NBUF +int nbuf = NBUF; +#else +int nbuf = 0; +#endif +#ifdef BUFPAGES +int bufpages = BUFPAGES; +#else +int bufpages = 0; +#endif +int *nofault; + +caddr_t allocsys __P((caddr_t)); + +/* + * Info for CTL_HW + */ +char machine[] = "MVME187"; /* cpu "architecture" */ +char cpu_model[120]; +extern char version[]; + +struct bugenv bugargs; +struct kernel{ + void *entry; + void *symtab; + void *esym; + int bflags; + int bdev; + char *kname; + void *smini; + void *emini; + void *end_load; +}kflags; +char *esym; + +int boothowto; /* read in kern/bootstrap */ +int cputyp; +int cpuspeed = 25; /* 25 MHZ XXX should be read from NVRAM */ + +#ifndef roundup +#define roundup(value, stride) (((unsigned)(value) + (stride) - 1) & ~((stride)-1)) +#endif /* roundup */ + +vm_size_t mem_size; +vm_size_t rawmem_size; +vm_offset_t first_addr = 0; +vm_offset_t last_addr = 0; + +vm_offset_t avail_start, avail_next, avail_end; +vm_offset_t virtual_avail, virtual_end; +vm_offset_t pcc2consvaddr, clconsvaddr; +vm_offset_t miniroot; + +void *end_loaded; +int bootdev; +int no_symbols = 1; + +struct proc *lastproc; +pcb_t curpcb; + + +extern struct user *proc0paddr; + +/* XXX this is to fake out the console routines, while booting. */ +void bugttycnputc __P((dev_t, int)); +int bugttycngetc __P((dev_t)); +extern void nullcnpollc __P((dev_t, int)); +void cmmu_init(void); + +static struct consdev bugcons = + { NULL, NULL, bugttycngetc, bugttycnputc, + nullcnpollc, makedev(14,0), 1 }; + +/* + * Console initialization: called early on from main, + * before vm init or startup. Do enough configuration + * to choose and initialize a console. + */ +void +consinit() +{ + extern struct consdev *cn_tab; + + /* + * Initialize the console before we print anything out. + */ + cn_tab = NULL; + cninit(); + +#if defined (DDB) + kdb_init(); + if (boothowto & RB_KDB) + Debugger(); +#endif +} + +/* + * Figure out how much real memory is available. + * Start looking from the megabyte after the end of the kernel data, + * until we find non-memory. + */ +vm_offset_t +size_memory(void) +{ + volatile unsigned int *look; + unsigned int *max; + extern char *end; + #define PATTERN 0x5a5a5a5a + #define STRIDE (4*1024) /* 4k at a time */ + #define Roundup(value, stride) (((unsigned)(value) + (stride) - 1) & ~((stride)-1)) + + /* + * count it up. + */ + max = (void*)MAXPHYSMEM; + for (look = (void*)Roundup(end, STRIDE); look < max; + look = (int*)((unsigned)look + STRIDE)) { + unsigned save; + + /* if can't access, we've reached the end */ + if (foodebug) + printf("%x\n", look); + if (badwordaddr((vm_offset_t)look)) { +#if defined(DEBUG) + printf("%x\n", look); +#endif + look = (int *)((int)look - STRIDE); + break; + } + + /* + * If we write a value, we expect to read the same value back. + * We'll do this twice, the 2nd time with the opposite bit + * pattern from the first, to make sure we check all bits. + */ + save = *look; + if (*look = PATTERN, *look != PATTERN) + break; + if (*look = ~PATTERN, *look != ~PATTERN) + break; + *look = save; + } + + physmem = btoc(trunc_page((unsigned)look)); /* in pages */ + return(trunc_page((unsigned)look)); +} + +void +identifycpu() +{ + /* XXX -take this one out. It can be done in m187_bootstrap() */ + strcpy(cpu_model, "Motorola M88K"); + printf("Model: %s\n", cpu_model); +} + +/* The following two functions assume UPAGES == 3 */ +#if UPAGES != 3 +#error "UPAGES changed?" +#endif + +#if USPACE != (UPAGES * NBPG) +#error "USPACE changed?" +#endif + +/* + * Setup u area ptes for u area double mapping. + */ + +void +save_u_area(struct proc *p, vm_offset_t va) +{ + p->p_md.md_upte[0] = kvtopte(va)->bits; + p->p_md.md_upte[1] = kvtopte(va + NBPG)->bits; + p->p_md.md_upte[2] = kvtopte(va + NBPG + NBPG)->bits; +} + +void +load_u_area(struct proc *p) +{ + pte_template_t *t; + + t = kvtopte(UADDR); + t->bits = p->p_md.md_upte[0]; + t = kvtopte(UADDR + NBPG); + t->bits = p->p_md.md_upte[1]; + t = kvtopte(UADDR + NBPG + NBPG); + t->bits = p->p_md.md_upte[2]; + cmmu_flush_tlb(1, UADDR, NBPG); + cmmu_flush_tlb(1, UADDR + NBPG, NBPG); + cmmu_flush_tlb(1, UADDR + NBPG + NBPG, NBPG); +} + +void +cpu_startup() +{ + caddr_t v; + int sz, i; + vm_size_t size; + int base, residual; + vm_offset_t minaddr, maxaddr, uarea_pages; + extern vm_offset_t miniroot; + + /* + * Initialize error message buffer (at end of core). + * avail_end was pre-decremented in m1x7_bootstrap(). + */ + + for (i = 0; i < btoc(sizeof(struct msgbuf)); i++) + pmap_enter(kernel_pmap, (vm_offset_t)msgbufp, + avail_end + i * NBPG, VM_PROT_ALL, TRUE); + + msgbufmapped = 1; + + printf(version); + identifycpu(); + printf("real mem = %d\n", ctob(physmem)); + + /* + * Find out how much space we need, allocate it, + * and then give everything true virtual addresses. + */ + sz = (int)allocsys((caddr_t)0); + if ((v = (caddr_t)kmem_alloc(kernel_map, round_page(sz))) == 0) + panic("startup: no room for tables"); + if (allocsys(v) - v != sz) + panic("startup: table size inconsistency"); + + /* + * Grab UADDR virtual address + */ + + uarea_pages = UADDR; + + vm_map_find(kernel_map, vm_object_allocate(USPACE), 0, + (vm_offset_t *)&uarea_pages, USPACE, TRUE); + + if (uarea_pages != UADDR) { + printf("uarea_pages %x: UADDR not free\n", uarea_pages); + panic("bad UADDR"); + } + + /* + * Grab the BUGROM space that we hardwired in pmap_bootstrap + */ + + bugromva = BUGROM_START; + + vm_map_find(kernel_map, vm_object_allocate(BUGROM_SIZE), 0, + (vm_offset_t *)&bugromva, BUGROM_SIZE, TRUE); + + if (bugromva != BUGROM_START) { + printf("bugromva %x: BUGROM not free\n", bugromva); + panic("bad bugromva"); + } + + /* + * Grab the SRAM space that we hardwired in pmap_bootstrap + */ + + sramva = SRAM_START; + + vm_map_find(kernel_map, vm_object_allocate(SRAM_SIZE), 0, + (vm_offset_t *)&sramva, SRAM_SIZE, TRUE); + + if (sramva != SRAM_START) { + printf("sramva %x: SRAM not free\n", sramva); + panic("bad sramva"); + } + + /* + * Grab the OBIO space that we hardwired in pmap_bootstrap + */ + + obiova = OBIO_START; + + vm_map_find(kernel_map, vm_object_allocate(OBIO_SIZE), 0, + (vm_offset_t *)&obiova, OBIO_SIZE, TRUE); + + if (obiova != OBIO_START) { + printf("obiova %x: OBIO not free\n", obiova); + panic("bad OBIO"); + } + + /* + * Now allocate buffers proper. They are different than the above + * in that they usually occupy more virtual memory than physical. + */ + + size = MAXBSIZE * nbuf; + buffer_map = kmem_suballoc(kernel_map, (vm_offset_t *)&buffers, + &maxaddr, size, TRUE); + minaddr = (vm_offset_t)buffers; + if (vm_map_find(buffer_map, vm_object_allocate(size), (vm_offset_t)0, + (vm_offset_t *)&minaddr, size, FALSE) != KERN_SUCCESS) { + panic("startup: cannot allocate buffers"); + } + if ((bufpages / nbuf) >= btoc(MAXBSIZE)) { + /* don't want to alloc more physical mem than needed */ + bufpages = btoc(MAXBSIZE) * nbuf; + } + base = bufpages / nbuf; + residual = bufpages % nbuf; + + for (i = 0; i < nbuf; i++) { + vm_size_t curbufsize; + vm_offset_t curbuf; + + /* + * First <residual> buffers get (base+1) physical pages + * allocated for them. The rest get (base) physical pages. + * + * The rest of each buffer occupies virtual space, + * but has no physical memory allocated for it. + */ + curbuf = (vm_offset_t)buffers + i * MAXBSIZE; + curbufsize = CLBYTES * (i < residual ? base+1 : base); + + /* this faults in the required physical pages */ + vm_map_pageable(buffer_map, curbuf, curbuf+curbufsize, FALSE); + + vm_map_simplify(buffer_map, curbuf); + } + + /* + * Allocate a submap for exec arguments. This map effectively + * limits the number of processes exec'ing at any time. + */ + exec_map = kmem_suballoc(kernel_map, &minaddr, &maxaddr, + 16*NCARGS, TRUE); + + /* + * Allocate map for physio. + */ + + phys_map = vm_map_create(kernel_pmap, PHYSIO_MAP_START, + PHYSIO_MAP_START + PHYSIO_MAP_SIZE, TRUE); + if (phys_map == NULL) { + panic("cpu_startup: unable to create phys_map"); + } + +#if XXX_FUTURE + iomap_map = vm_map_create(kernel_pmap, IOMAP_MAP_START, + IOMAP_MAP_START + IOMAP_SIZE, TRUE); + if (iomap_map == NULL) { + panic("cpu_startup: unable to create iomap_map"); + } + + /* + * Allocate space from iomap for a (privately managed) pool + * of addresses for IO mappings. + */ + + iomapbase = kmem_alloc_wait(iomap_map, IOMAP_SIZE); + rminit(iomap, IOMAP_SIZE, (u_long)iomapbase, "iomap", niomap); +#endif + + /* + * Finally, allocate mbuf pool. Since mclrefcnt is an off-size + * we use the more space efficient malloc in place of kmem_alloc. + */ + mclrefcnt = (char *)malloc(NMBCLUSTERS+CLBYTES/MCLBYTES, + M_MBUF, M_NOWAIT); + bzero(mclrefcnt, NMBCLUSTERS+CLBYTES/MCLBYTES); + mb_map = kmem_suballoc(kernel_map, (vm_offset_t *)&mbutl, &maxaddr, + VM_MBUF_SIZE, FALSE); + + /* + * Initialize callouts + */ + callfree = callout; + for (i = 1; i < ncallout; i++) + callout[i-1].c_next = &callout[i]; + callout[i-1].c_next = NULL; + + printf("avail mem = %d\n", ptoa(cnt.v_free_count)); + printf("using %d buffers containing %d bytes of memory\n", + nbuf, bufpages * CLBYTES); + +#if 0 + mfs_initminiroot(miniroot); +#endif /* 0 */ + /* + * Set up buffers, so they can be used to read disk labels. + */ + bufinit(); + + /* + * Configure the system. + */ + nofault = NULL; + + /* + * zero out intr_handlers + */ + bzero((void *)intr_handlers, 256 * sizeof(struct intrhand *)); + + configure(); +} + +/* + * Allocate space for system data structures. We are given + * a starting virtual address and we return a final virtual + * address; along the way we set each data structure pointer. + * + * We call allocsys() with 0 to find out how much space we want, + * allocate that much and fill it with zeroes, and then call + * allocsys() again with the correct base virtual address. + */ +caddr_t +allocsys(v) + register caddr_t v; +{ + +#define valloc(name, type, num) \ + v = (caddr_t)(((name) = (type *)v) + (num)) + +#ifdef REAL_CLISTS + valloc(cfree, struct cblock, nclist); +#endif + valloc(callout, struct callout, ncallout); + valloc(swapmap, struct map, nswapmap = maxproc * 2); +#ifdef SYSVSHM + valloc(shmsegs, struct shmid_ds, shminfo.shmmni); +#endif +#ifdef SYSVSEM + valloc(sema, struct semid_ds, seminfo.semmni); + valloc(sem, struct sem, seminfo.semmns); + /* This is pretty disgusting! */ + valloc(semu, int, (seminfo.semmnu * seminfo.semusz) / sizeof(int)); +#endif +#ifdef SYSVMSG + valloc(msgpool, char, msginfo.msgmax); + valloc(msgmaps, struct msgmap, msginfo.msgseg); + valloc(msghdrs, struct msg, msginfo.msgtql); + valloc(msqids, struct msqid_ds, msginfo.msgmni); +#endif + + /* + * Determine how many buffers to allocate (enough to + * hold 5% of total physical memory, but at least 16). + * Allocate 1/2 as many swap buffer headers as file i/o buffers. + */ + if (bufpages == 0) + if (physmem < btoc(2 * 1024 * 1024)) + bufpages = (physmem / 10) / CLSIZE; + else + bufpages = (physmem / 20) / CLSIZE; + if (nbuf == 0) { + nbuf = bufpages; + if (nbuf < 16) + nbuf = 16; + } + if (nswbuf == 0) { + nswbuf = (nbuf / 2) &~ 1; /* force even */ + if (nswbuf > 256) + nswbuf = 256; /* sanity */ + } + valloc(swbuf, struct buf, nswbuf); + valloc(buf, struct buf, nbuf); + +#if XXX_FUTURE + /* + * Arbitrarily limit the number of devices mapping + * the IO space at a given time to NIOPMAP (= 32, default). + */ + valloc(iomap, struct map, niomap = NIOPMAP); +#endif + return v; +} + +/* + * Set registers on exec. + * Clear all except sp and pc. + */ +void +setregs(p, pack, stack, retval) + struct proc *p; + struct exec_package *pack; + u_long stack; + int retval[2]; +{ + register struct trapframe *tf = USER_REGS(p); + + /* + * The syscall will ``return'' to snip; set it. + * argc, argv, envp are placed on the stack by copyregs. + * Point r2 to the stack. crt0 should extract envp from + * argc & argv before calling user's main. + */ +#if 0 + /* + * I don't think I need to mess with fpstate on 88k because + * we make sure the floating point pipeline is drained in + * the trap handlers. Should check on this later. XXX Nivas. + */ + + if ((fs = p->p_md.md_fpstate) != NULL) { + /* + * We hold an FPU state. If we own *the* FPU chip state + * we must get rid of it, and the only way to do that is + * to save it. In any case, get rid of our FPU state. + */ + if (p == fpproc) { + savefpstate(fs); + fpproc = NULL; + } + free((void *)fs, M_SUBPROC); + p->p_md.md_fpstate = NULL; + } +#endif /* 0 */ + bzero((caddr_t)tf, sizeof *tf); + tf->epsr = 0x3f0; /* user mode, interrupts enabled, fp enabled */ + + /* + * We want to start executing at pack->ep_entry. The way to + * do this is force the processor to fetch from ep_entry. Set + * NIP to something bogus and invalid so that it will be a NOOP. + * And set sfip to ep_entry with valid bit on so that it will be + * fetched. + */ + + tf->snip = pack->ep_entry & ~3; + tf->sfip = (pack->ep_entry & ~3) | FIP_V; + tf->r[2] = stack; + tf->r[31] = stack; + retval[1] = 0; +} + +struct sigstate { + int ss_flags; /* which of the following are valid */ + struct trapframe ss_frame; /* original exception frame */ +}; + +/* + * WARNING: code in locore.s assumes the layout shown for sf_signo + * thru sf_handler so... don't screw with them! + */ +struct sigframe { + int sf_signo; /* signo for handler */ + siginfo_t *sf_sip; + struct sigcontext *sf_scp; /* context ptr for handler */ + sig_t sf_handler; /* handler addr for u_sigc */ + struct sigcontext sf_sc; /* actual context */ + siginfo_t sf_si; +}; + +#ifdef DEBUG +int sigdebug = 0; +int sigpid = 0; +#define SDB_FOLLOW 0x01 +#define SDB_KSTACK 0x02 +#define SDB_FPSTATE 0x04 +#endif + +/* + * Send an interrupt to process. + */ +void +sendsig(catcher, sig, mask, code, type, val) + sig_t catcher; + int sig, mask; + unsigned long code; + int type; + union sigval val; +{ + register struct proc *p = curproc; + register struct trapframe *tf; + register struct sigacts *psp = p->p_sigacts; + struct sigframe *fp; + int oonstack, fsize; + struct sigframe sf; + int addr; + extern char sigcode[], esigcode[]; + +#define szsigcode (esigcode - sigcode) + + tf = p->p_md.md_tf; + oonstack = psp->ps_sigstk.ss_flags & SA_ONSTACK; + /* + * Allocate and validate space for the signal handler + * context. Note that if the stack is in data space, the + * call to grow() is a nop, and the copyout() + * will fail if the process has not already allocated + * the space with a `brk'. + */ + fsize = sizeof(struct sigframe); + if ((psp->ps_flags & SAS_ALTSTACK) && + (psp->ps_sigstk.ss_flags & SA_ONSTACK) == 0 && + (psp->ps_sigonstack & sigmask(sig))) { + fp = (struct sigframe *)(psp->ps_sigstk.ss_sp + + psp->ps_sigstk.ss_size - fsize); + psp->ps_sigstk.ss_flags |= SA_ONSTACK; + } else + fp = (struct sigframe *)(tf->r[31] - fsize); + if ((unsigned)fp <= USRSTACK - ctob(p->p_vmspace->vm_ssize)) + (void)grow(p, (unsigned)fp); +#ifdef DEBUG + if ((sigdebug & SDB_FOLLOW) || + (sigdebug & SDB_KSTACK) && p->p_pid == sigpid) + printf("sendsig(%d): sig %d ssp %x usp %x scp %x\n", + p->p_pid, sig, &oonstack, fp, &fp->sf_sc); +#endif + /* + * Build the signal context to be used by sigreturn. + */ + sf.sf_signo = sig; + sf.sf_scp = &fp->sf_sc; + sf.sf_handler = catcher; + sf.sf_sc.sc_onstack = oonstack; + sf.sf_sc.sc_mask = mask; + + if (psp->ps_siginfo & sigmask(sig)) { + sf.sf_sip = &fp->sf_si; + initsiginfo(&sf.sf_si, sig, code, type, val); + } + + + /* + * Copy the whole user context into signal context that we + * are building. + */ + bcopy((caddr_t)tf->r, (caddr_t)sf.sf_sc.sc_regs, + sizeof(sf.sf_sc.sc_regs)); + sf.sf_sc.sc_xip = tf->sxip & ~3; + sf.sf_sc.sc_nip = tf->snip & ~3; + sf.sf_sc.sc_fip = tf->sfip & ~3; + sf.sf_sc.sc_ps = tf->epsr; + sf.sf_sc.sc_sp = tf->r[31]; + sf.sf_sc.sc_fpsr = tf->fpsr; + sf.sf_sc.sc_fpcr = tf->fpcr; + sf.sf_sc.sc_ssbr = tf->ssbr; + sf.sf_sc.sc_dmt0 = tf->dmt0; + sf.sf_sc.sc_dmd0 = tf->dmd0; + sf.sf_sc.sc_dma0 = tf->dma0; + sf.sf_sc.sc_dmt1 = tf->dmt1; + sf.sf_sc.sc_dmd1 = tf->dmd1; + sf.sf_sc.sc_dma1 = tf->dma1; + sf.sf_sc.sc_dmt2 = tf->dmt2; + sf.sf_sc.sc_dmd2 = tf->dmd2; + sf.sf_sc.sc_dma2 = tf->dma2; + sf.sf_sc.sc_fpecr = tf->fpecr; + sf.sf_sc.sc_fphs1 = tf->fphs1; + sf.sf_sc.sc_fpls1 = tf->fpls1; + sf.sf_sc.sc_fphs2 = tf->fphs2; + sf.sf_sc.sc_fpls2 = tf->fpls2; + sf.sf_sc.sc_fppt = tf->fppt; + sf.sf_sc.sc_fprh = tf->fprh; + sf.sf_sc.sc_fprl = tf->fprl; + sf.sf_sc.sc_fpit = tf->fpit; + if (copyout((caddr_t)&sf, (caddr_t)fp, sizeof sf)) { + /* + * Process has trashed its stack; give it an illegal + * instruction to halt it in its tracks. + */ + SIGACTION(p, SIGILL) = SIG_DFL; + sig = sigmask(SIGILL); + p->p_sigignore &= ~sig; + p->p_sigcatch &= ~sig; + p->p_sigmask &= ~sig; + psignal(p, SIGILL); + return; + } + /* + * Build the argument list for the signal handler. + * Signal trampoline code is at base of user stack. + */ + addr = (int)PS_STRINGS - szsigcode; + tf->snip = (addr & ~3) | NIP_V; + tf->sfip = (tf->snip + 4) | FIP_V; + tf->r[31] = (unsigned)fp; +#ifdef DEBUG + if ((sigdebug & SDB_FOLLOW) || + (sigdebug & SDB_KSTACK) && p->p_pid == sigpid) + printf("sendsig(%d): sig %d returns\n", + p->p_pid, sig); +#endif +} + +/* + * System call to cleanup state after a signal + * has been taken. Reset signal mask and + * stack state from context left by sendsig (above). + * Return to previous pc and psl as specified by + * context left by sendsig. Check carefully to + * make sure that the user has not modified the + * psl to gain improper priviledges or to cause + * a machine fault. + */ +/* ARGSUSED */ +sys_sigreturn(p, v, retval) + struct proc *p; + void *v; + register_t *retval; +{ + struct sys_sigreturn_args /* { + syscallarg(struct sigcontext *) sigcntxp; + } */ *uap = v; + register struct sigcontext *scp; + register struct trapframe *tf; + struct sigcontext ksc; + int error; + + scp = (struct sigcontext *)SCARG(uap, sigcntxp); +#ifdef DEBUG + if (sigdebug & SDB_FOLLOW) + printf("sigreturn: pid %d, scp %x\n", p->p_pid, scp); +#endif + if ((int)scp & 3 || useracc((caddr_t)scp, sizeof *scp, B_WRITE) == 0 || + copyin((caddr_t)scp, (caddr_t)&ksc, sizeof(struct sigcontext))) + return (EINVAL); + + tf = p->p_md.md_tf; + scp = &ksc; + /* + * xip, nip and fip must be multiples of 4. This is all + * that is required; if it holds, just do it. + */ +#if 0 + if (((scp->sc_xip | scp->sc_nip | scp->sc_fip) & 3) != 0) + return (EINVAL); +#endif /* 0 */ + if (((scp->sc_xip | scp->sc_nip | scp->sc_fip) & 3) != 0) + printf("xip %x nip %x fip %x\n", + scp->sc_xip, scp->sc_nip, scp->sc_fip); + + + /* + * this can be improved by doing + * bcopy(sc_reg to tf, sizeof sigcontext - 2 words) + * XXX nivas + */ + + bcopy((caddr_t)scp->sc_regs, (caddr_t)tf->r, + sizeof(scp->sc_regs)); + tf->sxip = (scp->sc_xip) | XIP_V; + tf->snip = (scp->sc_nip) | NIP_V; + tf->sfip = (scp->sc_fip) | FIP_V; + tf->epsr = scp->sc_ps; + tf->r[31] = scp->sc_sp; + tf->fpsr = scp->sc_fpsr; + tf->fpcr = scp->sc_fpcr; + tf->ssbr = scp->sc_ssbr; + tf->dmt0 = scp->sc_dmt0; + tf->dmd0 = scp->sc_dmd0; + tf->dma0 = scp->sc_dma0; + tf->dmt1 = scp->sc_dmt1; + tf->dmd1 = scp->sc_dmd1; + tf->dma1 = scp->sc_dma1; + tf->dmt2 = scp->sc_dmt2; + tf->dmd2 = scp->sc_dmd2; + tf->dma2 = scp->sc_dma2; + tf->fpecr = scp->sc_fpecr; + tf->fphs1 = scp->sc_fphs1; + tf->fpls1 = scp->sc_fpls1; + tf->fphs2 = scp->sc_fphs2; + tf->fpls2 = scp->sc_fpls2; + tf->fppt = scp->sc_fppt; + tf->fprh = scp->sc_fprh; + tf->fprl = scp->sc_fprl; + tf->fpit = scp->sc_fpit; + + tf->epsr = scp->sc_ps; + /* + * Restore the user supplied information + */ + if (scp->sc_onstack & 01) + p->p_sigacts->ps_sigstk.ss_flags |= SA_ONSTACK; + else + p->p_sigacts->ps_sigstk.ss_flags &= ~SA_ONSTACK; + p->p_sigmask = scp->sc_mask & ~sigcantmask; + return (EJUSTRETURN); +} + +_doboot() +{ + cmmu_shutdown_now(); + bugreturn(); +} + +void +boot(howto) + register int howto; +{ + /* take a snap shot before clobbering any registers */ + if (curproc) + savectx(curproc->p_addr, 0); + + boothowto = howto; + if ((howto & RB_NOSYNC) == 0 && waittime < 0) { + + extern struct proc proc0; + + /* protect against curproc->p_stats.foo refs in sync() XXX */ + if (curproc == NULL) + curproc = &proc0; + + waittime = 0; + vfs_shutdown(); + + /* + * If we've been adjusting the clock, the todr + * will be out of synch; adjust it now. + */ + resettodr(); + } + splhigh(); /* extreme priority */ + if (howto&RB_HALT) { + printf("halted\n\n"); + bugreturn(); + } else { + if (howto & RB_DUMP) + dumpsys(); + doboot(); + /*NOTREACHED*/ + } + /*NOTREACHED*/ +} + +unsigned dumpmag = 0x8fca0101; /* magic number for savecore */ +int dumpsize = 0; /* also for savecore */ +long dumplo = 0; + +dumpconf() +{ + int nblks; + + dumpsize = physmem; + if (dumpdev != NODEV && bdevsw[major(dumpdev)].d_psize) { + nblks = (*bdevsw[major(dumpdev)].d_psize)(dumpdev); + if (dumpsize > btoc(dbtob(nblks - dumplo))) + dumpsize = btoc(dbtob(nblks - dumplo)); + else if (dumplo == 0) + dumplo = nblks - btodb(ctob(physmem)); + } + /* + * Don't dump on the first CLBYTES (why CLBYTES?) + * in case the dump device includes a disk label. + */ + if (dumplo < btodb(CLBYTES)) + dumplo = btodb(CLBYTES); +} + +/* + * Doadump comes here after turning off memory management and + * getting on the dump stack, either when called above, or by + * the auto-restart code. + */ +dumpsys() +{ + + msgbufmapped = 0; + if (dumpdev == NODEV) + return; + /* + * For dumps during autoconfiguration, + * if dump device has already configured... + */ + if (dumpsize == 0) + dumpconf(); + if (dumplo < 0) + return; + printf("\ndumping to dev %x, offset %d\n", dumpdev, dumplo); + printf("dump "); + switch ((*bdevsw[major(dumpdev)].d_dump)(dumpdev)) { + + case ENXIO: + printf("device bad\n"); + break; + + case EFAULT: + printf("device not ready\n"); + break; + + case EINVAL: + printf("area improper\n"); + break; + + case EIO: + printf("i/o error\n"); + break; + + default: + printf("succeeded\n"); + break; + } +} + +/* + * fill up ivec array with interrupt response vector addresses. + */ +void +setupiackvectors() +{ + register u_char *vaddr; +#ifdef XXX_FUTURE + extern vm_offset_t iomap_mapin(vm_offset_t, vm_size_t, boolean_t); +#endif + + /* + * map a page in for phys address 0xfffe0000 and set the + * addresses for various levels. + */ +#ifdef XXX_FUTURE + vaddr = (u_char *)iomap_mapin(0xfffe0000, NBPG, 1); +#else + vaddr = (u_char *)0xfffe0000; +#endif + + ivec[0] = vaddr + 0x03; + ivec[1] = vaddr + 0x07; + ivec[2] = vaddr + 0x0b; + ivec[3] = vaddr + 0x0f; + ivec[4] = vaddr + 0x13; + ivec[5] = vaddr + 0x17; + ivec[6] = vaddr + 0x1b; + ivec[7] = vaddr + 0x1f; +} + +/* + * Insert ihand in the list of handlers at vector vec. + * Return return different error codes for the different + * errors and let the caller decide what to do. + */ + +int +intr_establish(int vec, struct intrhand *ihand) +{ + register struct intrhand *intr; + + if (vec < 0 || vec > 255) { +#if DIAGNOSTIC + panic("intr_establish: vec (%x) not between 0 and 0xff\n", + vec); +#endif /* DIAGNOSTIC */ + return (INTR_EST_BADVEC); + } + + if (intr = intr_handlers[vec]) { + if (intr->ih_ipl != ihand->ih_ipl) { +#if DIAGNOSTIC + panic("intr_establish: there are other handlers with vec (%x) at ipl %x, but you want it at %x\n", + intr->ih_ipl, vec, ihand->ih_ipl); +#endif /* DIAGNOSTIC */ + return (INTR_EST_BADIPL); + } + + /* + * Go to the end of the chain + */ + while (intr->ih_next) + intr = intr->ih_next; + } + + ihand->ih_next = 0; + + if (intr) + intr->ih_next = ihand; + else + intr_handlers[vec] = ihand; + + return (INTR_EST_SUCC); +} + +/* + * Device interrupt handler + * + * when we enter, interrupts are disabled; + * when we leave, they should be disabled, + * but they need not be disabled throughout + * the routine. + */ + +void +ext_int(u_int v, struct m88100_saved_state *eframe) +{ + register u_char mask, level, xxxvec; + register struct intrhand *intr; + int ret; + u_char vec; + + /* get level and mask */ + + asm volatile("ld.b %0,%1" : "=r" (mask) : "" (*pcc2intr_mask)); + asm volatile("ld.b %0,%1" : "=r" (level) : "" (*pcc2intr_ipl)); + + /* + * It is really bizarre for the mask and level to the be the same. + * pcc2 for 187 blocks all interrupts at and below the mask value, + * so we should not be getting an interrupt at the level that is + * already blocked. I can't explain this case XXX nivas + */ + + if ((mask == level) && level) { + printf("mask == level, %d\n", level); + goto beatit; + } + + /* + * Interrupting level cannot be 0--0 doesn't produce an interrupt. + * Weird! XXX nivas + */ + + if (level == 0) { + printf("Bogons... level %x and mask %x\n", level, mask); + goto beatit; + } + + /* and block interrupts at level or lower */ + setipl((u_char)level); + /* and stash it away in the trap frame */ + eframe->mask = mask; +#if 0 + asm volatile("st.b %1,%0" : "=m" (*pcc2intr_mask) : "r" (level)); +#endif + if (level > 7 || (char)level < 0) { + panic("int level (%x) is not between 0 and 7\n", level); + } + + /* generate IACK and get the vector */ + +#if XXX + asm volatile("ld.b %0,%1" : "=r" (vec) : "" (*ivec[level])); + asm volatile("tb1 0, r0, 0"); + asm volatile("tb1 0, r0, 0"); + asm volatile("tb1 0, r0, 0"); + + asm volatile("tb1 0, r0, 0"); + + if (guarded_access(ivec[level], 1, &vec) == EFAULT) { + printf("Unable to get vector for this interrupt (level %x)\n", + level); + goto out; + } +#endif XXX + + asm volatile("tb1 0, r0, 0"); + if (guarded_access(ivec[level], 1, &vec) == EFAULT) { + printf("Unable to get vector for this interrupt (level %x)\n", + level); + goto out; + } + asm volatile("tb1 0, r0, 0"); + asm volatile("tb1 0, r0, 0"); + asm volatile("tb1 0, r0, 0"); + /*vec = xxxvec;*/ + + if (vec > 0xFF) { + panic("interrupt vector %x greater than 255\n", vec); + } + + enable_interrupt(); + + if ((intr = intr_handlers[vec]) == 0) { + printf("Spurious interrupt (level %x and vec %x)\n", + level, vec); + } + if (intr && intr->ih_ipl != level) { + panic("Handler ipl %x not the same as level %x\n", + intr->ih_ipl, level); + } + + /* + * Walk through all interrupt handlers in the chain for the + * given vector, calling each handler in turn, till some handler + * returns a value != 0. + */ + + for (ret = 0; intr; intr = intr->ih_next) { + if (intr->ih_wantframe) + ret = (*intr->ih_fn)(intr->ih_arg, (void *)eframe); + else + ret = (*intr->ih_fn)(intr->ih_arg); + if (ret) + break; + } + + if (ret == 0) { + printf("Unclaimed interrupt (level %x and vec %x)\n", + level, vec); + } + + /* + * process any remaining data access exceptions before + * returning to assembler + */ + disable_interrupt(); + +out: + if (eframe->dmt0 & DMT_VALID) { + trap(T_DATAFLT, eframe); + data_access_emulation(eframe); + eframe->dmt0 &= ~DMT_VALID; + } + mask = eframe->mask; + + /* + * Restore the mask level to what it was when the interrupt + * was taken. + */ + setipl((u_char)mask); +#if 0 + asm volatile("st.b %1,%0" : "=m" (*pcc2intr_mask) : "r" (mask)); +#endif +#if 0 + splx((u_char)mask); +#endif /* 0 */ + +beatit: + return; +} + +cpu_exec_aout_makecmds(p, epp) + struct proc *p; + struct exec_package *epp; +{ + return ENOEXEC; +} + +sys_sysarch(p, v, retval) + struct proc *p; + void *v; + register_t *retval; +{ + struct sys_sysarch_args /* { + syscallarg(int) op; + syscallarg(char *) parm; + } */ *uap = v; + int error = 0; + + switch((int)SCARG(uap, op)) { + default: + error = EINVAL; + break; + } + return(error); +} + +/* + * machine dependent system variables. + */ +cpu_sysctl(name, namelen, oldp, oldlenp, newp, newlen, p) + int *name; + u_int namelen; + void *oldp; + size_t *oldlenp; + void *newp; + size_t newlen; + struct proc *p; +{ + + /* all sysctl names are this level are terminal */ + if (namelen != 1) + return (ENOTDIR); /* overloaded */ + + switch (name[0]) { + default: + return (EOPNOTSUPP); + } + /*NOTREACHED*/ +} + +/* + * insert an element into a queue + */ + +void +_insque(velement, vhead) + void *velement, *vhead; +{ + register struct prochd *element, *head; + element = velement; + head = vhead; + element->ph_link = head->ph_link; + head->ph_link = (struct proc *)element; + element->ph_rlink = (struct proc *)head; + ((struct prochd *)(element->ph_link))->ph_rlink=(struct proc *)element; +} + +/* + * remove an element from a queue + */ + +void +_remque(velement) + void *velement; +{ + register struct prochd *element; + element = velement; + ((struct prochd *)(element->ph_link))->ph_rlink = element->ph_rlink; + ((struct prochd *)(element->ph_rlink))->ph_link = element->ph_link; + element->ph_rlink = (struct proc *)0; +} + +int +copystr(fromaddr, toaddr, maxlength, lencopied) + const void *fromaddr; + void *toaddr; + size_t maxlength; + size_t *lencopied; +{ + u_int tally; + + tally = 0; + + while (maxlength--) { + *(u_char *)toaddr = *(u_char *)fromaddr++; + tally++; + if (*(u_char *)toaddr++ == 0) { + if(lencopied) *lencopied = tally; + return(0); + } + } + + if (lencopied) + *lencopied = tally; + + return(ENAMETOOLONG); +} + +void +setrunqueue(p) + register struct proc *p; +{ + register struct prochd *q; + register struct proc *oldlast; + register int which = p->p_priority >> 2; + + if (p->p_back != NULL) + panic("setrunqueue %x", p); + q = &qs[which]; + whichqs |= 1 << which; + p->p_forw = (struct proc *)q; + p->p_back = oldlast = q->ph_rlink; + q->ph_rlink = p; + oldlast->p_forw = p; +} + +/* + * Remove process p from its run queue, which should be the one + * indicated by its priority. Calls should be made at splstatclock(). + */ +void +remrunqueue(vp) + struct proc *vp; +{ + register struct proc *p = vp; + register int which = p->p_priority >> 2; + register struct prochd *q; + + if ((whichqs & (1 << which)) == 0) + panic("remrq %x", p); + p->p_forw->p_back = p->p_back; + p->p_back->p_forw = p->p_forw; + p->p_back = NULL; + q = &qs[which]; + if (q->ph_link == (struct proc *)q) + whichqs &= ~(1 << which); +} + +/* dummys for now */ + +bugsyscall() +{ +} + +void +myetheraddr(cp) + u_char *cp; +{ + struct bugniocall niocall; + + niocall.clun = 0; + niocall.dlun = 0; + niocall.ci = 0; + niocall.cd = 0; + niocall.cid = NETCTRL_GETHDW; + niocall.memaddr = (unsigned int)cp; + niocall.nbytes = 6; + + bugnetctrl(&niocall); +} + +netintr() +{ +#ifdef INET + if (netisr & (1 << NETISR_ARP)) { + netisr &= ~(1 << NETISR_ARP); + arpintr(); + } + if (netisr & (1 << NETISR_IP)) { + netisr &= ~(1 << NETISR_IP); + ipintr(); + } +#endif +#ifdef NS + if (netisr & (1 << NETISR_NS)) { + netisr &= ~(1 << NETISR_NS); + nsintr(); + } +#endif +#ifdef ISO + if (netisr & (1 << NETISR_ISO)) { + netisr &= ~(1 << NETISR_ISO); + clnlintr(); + } +#endif +#ifdef CCITT + if (netisr & (1 << NETISR_CCITT)) { + netisr &= ~(1 << NETISR_CCITT); + ccittintr(); + } +#endif +#include "ppp.h" +#if NPPP > 0 + if (netisr & (1 << NETISR_PPP)) { + netisr &= ~(1 << NETISR_PPP); + pppintr(); + } +#endif +} + +void +dosoftint() +{ + if (ssir & SIR_NET) { + siroff(SIR_NET); + cnt.v_soft++; + netintr(); + } + + if (ssir & SIR_CLOCK) { + siroff(SIR_CLOCK); + cnt.v_soft++; + softclock(); + } + + return; +} + +int +spl0() +{ + int x; + int level = 0; + + x = splsoftclock(); + + if (ssir) { + dosoftint(); + } + + setipl(0); + + return(x); +} + +badwordaddr(void *addr) +{ + return badaddr((vm_offset_t)addr, 4); +} + +MY_info(f, p, flags, s) + struct trapframe *f; + caddr_t p; + int flags; + char *s; +{ + regdump(f); + printf("proc %x flags %x type %s\n", p, flags, s); +} + +MY_info_done(f, flags) + struct trapframe *f; + int flags; +{ + regdump(f); +} + +void +nmihand(void *framep) +{ + struct m88100_saved_state *frame = framep; + +#if DDB + DEBUG_MSG("Abort Pressed\n"); + Debugger(); +#else + DEBUG_MSG("Spurious NMI?\n"); +#endif /* DDB */ +} + +regdump(struct trapframe *f) +{ +#define R(i) f->r[i] + printf("R00-05: 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x\n", + R(0),R(1),R(2),R(3),R(4),R(5)); + printf("R06-11: 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x\n", + R(6),R(7),R(8),R(9),R(10),R(11)); + printf("R12-17: 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x\n", + R(12),R(13),R(14),R(15),R(16),R(17)); + printf("R18-23: 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x\n", + R(18),R(19),R(20),R(21),R(22),R(23)); + printf("R24-29: 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x\n", + R(24),R(25),R(26),R(27),R(28),R(29)); + printf("R30-31: 0x%08x 0x%08x\n",R(30),R(31)); + printf("sxip %x snip %x sfip %x\n", f->sxip, f->snip, f->sfip); + if (f->vector == 0x3) { /* print dmt stuff for data access fault */ + printf("dmt0 %x dmd0 %x dma0 %x\n", f->dmt0, f->dmd0, f->dma0); + printf("dmt1 %x dmd1 %x dma1 %x\n", f->dmt1, f->dmd1, f->dma1); + printf("dmt2 %x dmd2 %x dma2 %x\n", f->dmt2, f->dmd2, f->dma2); + } + if (longformat) { + printf("fpsr %x", f->fpsr); + printf("fpcr %x", f->fpcr); + printf("epsr %x", f->epsr); + printf("ssbr %x\n", f->ssbr); + printf("dmt0 %x", f->dmt0); + printf("dmd0 %x", f->dmd0); + printf("dma0 %x", f->dma0); + printf("dmt1 %x", f->dmt1); + printf("dmd1 %x", f->dmd1); + printf("dma1 %x", f->dma1); + printf("dmt2 %x", f->dmt2); + printf("dmd2 %x", f->dmd2); + printf("dma2 %x\n", f->dma2); + printf("fpecr %x", f->fpecr); + printf("fphs1 %x", f->fphs1); + printf("fpls1 %x", f->fpls1); + printf("fphs2 %x", f->fphs2); + printf("fpls2 %x", f->fpls2); + printf("fppt %x", f->fppt); + printf("fprh %x", f->fprh); + printf("fprl %x", f->fprl); + printf("fpit %x\n", f->fpit); + printf("vector %x", f->vector); + printf("mask %x", f->mask); + printf("mode %x", f->mode); + printf("scratch1 %x", f->scratch1); + printf("pad %x\n", f->pad); + } +} + +#if DDB +inline int +db_splhigh(void) +{ + return (db_setipl(IPL_HIGH)); +} + +inline int +db_splx(int s) +{ + return (db_setipl(s)); +} +#endif /* DDB */ + +/* + * Called from locore.S during boot, + * this is the first C code that's run. + */ + +void +m187_bootstrap(void) +{ + extern char version[]; + extern char *edata, *end; + extern int cold; + extern int kernelstart; + extern vm_offset_t size_memory(void); + extern struct consdev *cn_tab; + struct bugbrdid brdid; + + cold = 1; /* we are still booting */ + + cn_tab = &bugcons; + + buginit(); + + bugbrdid(&brdid); + cputyp = brdid.brdno; + + vm_set_page_size(); + +#if 0 + esym = kflags.esym; + boothowto = kflags.bflags; + bootdev = kflags.bdev; +#endif /* 0 */ + +#if 0 + end_loaded = kflags.end_load; + if (esym != NULL) { + end = (char *)((int)(kflags.symtab)); + } else { + first_addr = (vm_offset_t)&end; + } +#endif + + first_addr = m88k_round_page(first_addr); + + if (!no_symbols) + boothowto |= RB_KDB; + + last_addr = size_memory(); + + cmmu_init(); + + avail_start = first_addr; + avail_end = last_addr; + printf("%s",version); + printf("M187 boot: memory from 0x%x to 0x%x\n", avail_start, avail_end); + + /* + * Steal one page at the top of physical memory for msgbuf + */ + avail_end -= PAGE_SIZE; + + pmap_bootstrap((vm_offset_t)M88K_TRUNC_PAGE((unsigned)&kernelstart) /* = loadpt */, + &avail_start, &avail_end, &virtual_avail, + &virtual_end); +#if defined(DEBUG) + printf("returned from pmap_bootstrap\n"); +#endif + + /* + * Must initialize p_addr before autoconfig or + * the fault handler will get a NULL reference. + */ + proc0.p_addr = proc0paddr; + curproc = &proc0; + curpcb = &proc0paddr->u_pcb; + + /* Initialize cached PTEs for u-area mapping. */ + save_u_area(&proc0, (vm_offset_t)proc0paddr); + + /* + * Map proc0's u-area at the standard address (UADDR). + */ + load_u_area(&proc0); + + /* Initialize the "u-area" pages. */ + bzero((caddr_t)UADDR, UPAGES*NBPG); +#if defined(DEBUG) + printf("returning from init\n"); +#endif +} diff --git a/sys/arch/mvme88k/mvme88k/pmap.c b/sys/arch/mvme88k/mvme88k/pmap.c new file mode 100644 index 00000000000..11d8fa5995e --- /dev/null +++ b/sys/arch/mvme88k/mvme88k/pmap.c @@ -0,0 +1,5331 @@ +/* + * Copyright (c) 1996 Nivas Madhur + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by Nivas Madhur. + * 4. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ +/* + * Mach Operating System + * Copyright (c) 1991 Carnegie Mellon University + * Copyright (c) 1991 OMRON Corporation + * All Rights Reserved. + * + * Permission to use, copy, modify and distribute this software and its + * documentation is hereby granted, provided that both the copyright + * notice and this permission notice appear in all copies of the + * software, derivative works or modified versions, and any portions + * thereof, and that both notices appear in supporting documentation. + * + */ + +/* don't want to make them general yet. */ +#ifdef luna88k +# define OMRON_PMAP +#endif +# define OMRON_PMAP + +#include <sys/types.h> +#include <machine/board.h> +#include <vm/pmap.h> +#include <machine/m882xx.h> /* CMMU stuff */ +#include <vm/vm_kern.h> /* vm/vm_kern.h */ + +#include <sys/param.h> +#include <sys/proc.h> +#include <sys/malloc.h> +#include <sys/msgbuf.h> +#include <machine/assert.h> + +#include <mvme88k/dev/pcctworeg.h> +#include <mvme88k/dev/clreg.h> + + /* + * VM externals + */ +extern vm_offset_t avail_start, avail_next, avail_end; +extern vm_offset_t virtual_avail, virtual_end; + +extern vm_offset_t pcc2consvaddr; +extern vm_offset_t clconsvaddr; + +/* + * Static variables, functions and variables for debugging + */ +#ifdef DEBUG +#define STATIC + +/* + * conditional debugging + */ + +#define CD_NORM 0x01 +#define CD_FULL 0x02 + +#define CD_ACTIVATE 0x0000004 /* _pmap_activate */ +#define CD_KMAP 0x0000008 /* pmap_expand_kmap */ +#define CD_MAP 0x0000010 /* pmap_map */ +#define CD_MAPB 0x0000020 /* pmap_map_batc */ +#define CD_CACHE 0x0000040 /* pmap_cache_ctrl */ +#define CD_BOOT 0x0000080 /* pmap_bootstrap */ +#define CD_INIT 0x0000100 /* pmap_init */ +#define CD_CREAT 0x0000200 /* pmap_create */ +#define CD_FREE 0x0000400 /* pmap_free_tables */ +#define CD_DESTR 0x0000800 /* pmap_destroy */ +#define CD_RM 0x0001000 /* pmap_remove */ +#define CD_RMAL 0x0002000 /* pmap_remove_all */ +#define CD_COW 0x0004000 /* pmap_copy_on_write */ +#define CD_PROT 0x0008000 /* pmap_protect */ +#define CD_EXP 0x0010000 /* pmap_expand */ +#define CD_ENT 0x0020000 /* pmap_enter */ +#define CD_UPD 0x0040000 /* pmap_update */ +#define CD_COL 0x0080000 /* pmap_collect */ +#define CD_CMOD 0x0100000 /* pmap_clear_modify */ +#define CD_IMOD 0x0200000 /* pmap_is_modified */ +#define CD_CREF 0x0400000 /* pmap_clear_reference */ +#define CD_PGMV 0x0800000 /* pagemove */ +#define CD_CHKPV 0x1000000 /* check_pv_list */ +#define CD_CHKPM 0x2000000 /* check_pmap_consistency */ +#define CD_CHKM 0x4000000 /* check_map */ +#define CD_ALL 0x0FFFFFC + +int pmap_con_dbg = CD_FULL|CD_NORM; +#else + +#define STATIC static + +#endif /* DEBUG */ + +caddr_t vmmap; +pt_entry_t *vmpte, *msgbufmap; + +STATIC struct pmap kernel_pmap_store; +pmap_t kernel_pmap = &kernel_pmap_store; + +typedef struct kpdt_entry *kpdt_entry_t; +struct kpdt_entry { + kpdt_entry_t next; + vm_offset_t phys; +}; +#define KPDT_ENTRY_NULL ((kpdt_entry_t)0) + +STATIC kpdt_entry_t kpdt_free; + +/* + * MAX_KERNEL_VA_SIZE must fit into the virtual address space between + * VM_MIN_KERNEL_ADDRESS and VM_MAX_KERNEL_ADDRESS. + */ + +#define MAX_KERNEL_VA_SIZE (256*1024*1024) /* 256 Mb */ + +/* + * Size of kernel page tables, which is enough to map MAX_KERNEL_VA_SIZE + */ +#define KERNEL_PDT_SIZE (M88K_BTOP(MAX_KERNEL_VA_SIZE) * sizeof(pt_entry_t)) + +/* + * Size of kernel page tables for mapping onboard IO space. + */ +#define OBIO_PDT_SIZE (M88K_BTOP(OBIO_SIZE) * sizeof(pt_entry_t)) + +#define MAX_KERNEL_PDT_SIZE (KERNEL_PDT_SIZE + OBIO_PDT_SIZE) + +/* + * Two pages of scratch space. + * Used in copy_to_phys(), pmap_copy_page() and pmap_zero_page(). + */ +vm_offset_t phys_map_vaddr1, phys_map_vaddr2; + +int ptes_per_vm_page; /* no. of ptes required to map one VM page */ + +#define PMAP_MAX 512 + +/* + * The Modify List + * + * This is an array, one byte per physical page, which keeps track + * of modified flags for pages which are no longer containd in any + * pmap. (for mapped pages, the modified flags are in the PTE.) + */ +char *pmap_modify_list; + + +/* The PV (Physical to virtual) List. + * + * For each vm_page_t, pmap keeps a list of all currently valid virtual + * mappings of that page. An entry is a pv_entry_t; the list is the + * pv_head_table. This is used by things like pmap_remove, when we must + * find and remove all mappings for a particular physical page. + */ +typedef struct pv_entry { + struct pv_entry *next; /* next pv_entry */ + pmap_t pmap; /* pmap where mapping lies */ + vm_offset_t va; /* virtual address for mapping */ +} *pv_entry_t; + +#define PV_ENTRY_NULL ((pv_entry_t) 0) + +static pv_entry_t pv_head_table; /* array of entries, one per page */ + +/* + * Index into pv_head table, its lock bits, and the modify bits + * starting at pmap_phys_start. + */ +#define PFIDX(pa) (atop(pa - pmap_phys_start)) +#define PFIDX_TO_PVH(pfidx) (&pv_head_table[pfidx]) + + +/* + * Locking and TLB invalidation primitives + */ + +/* + * Locking Protocols: + * + * There are two structures in the pmap module that need locking: + * the pmaps themselves, and the per-page pv_lists (which are locked + * by locking the pv_lock_table entry that corresponds to the pv_head + * for the list in question.) Most routines want to lock a pmap and + * then do operations in it that require pv_list locking -- however + * pmap_remove_all and pmap_copy_on_write operate on a physical page + * basis and want to do the locking in the reverse order, i.e. lock + * a pv_list and then go through all the pmaps referenced by that list. + * To protect against deadlock between these two cases, the pmap_lock + * is used. There are three different locking protocols as a result: + * + * 1. pmap operations only (pmap_extract, pmap_access, ...) Lock only + * the pmap. + * + * 2. pmap-based operations (pmap_enter, pmap_remove, ...) Get a read + * lock on the pmap_lock (shared read), then lock the pmap + * and finally the pv_lists as needed [i.e. pmap lock before + * pv_list lock.] + * + * 3. pv_list-based operations (pmap_remove_all, pmap_copy_on_write, ...) + * Get a write lock on the pmap_lock (exclusive write); this + * also guaranteees exclusive access to the pv_lists. Lock the + * pmaps as needed. + * + * At no time may any routine hold more than one pmap lock or more than + * one pv_list lock. Because interrupt level routines can allocate + * mbufs and cause pmap_enter's, the pmap_lock and the lock on the + * kernel_pmap can only be held at splvm. + */ +/* DCR: 12/18/91 - The above explanation is no longer true. The pmap + * system lock has been removed in favor of a backoff strategy to + * avoid deadlock. Now, pv_list-based operations first get the + * pv_list lock, then try to get the pmap lock, but if they can't, + * they release the pv_list lock and retry the whole operation. + */ + +#define SPLVM(spl) { spl = splvm(); } +#define SPLX(spl) { splx(spl); } + +#define PMAP_LOCK(pmap, spl) SPLVM(spl) +#define PMAP_UNLOCK(pmap, spl) SPLX(spl) + +#define PV_LOCK_TABLE_SIZE(n) 0 +#define LOCK_PVH(index) +#define UNLOCK_PVH(index) + +#define ETHERPAGES 16 +void *etherbuf; +int etherlen; + +/* + * First and last physical address that we maintain any information + * for. Initalized to zero so that pmap operations done before + * pmap_init won't touch any non-existent structures. + */ + +static vm_offset_t pmap_phys_start = (vm_offset_t) 0; +static vm_offset_t pmap_phys_end = (vm_offset_t) 0; + +#define PMAP_MANAGED(pa) (pmap_initialized && ((pa) >= pmap_phys_start && (pa) < pmap_phys_end)) + +/* + * This variable extract vax's pmap.c. + * pmap_verify_free refer to this. + * pmap_init initialize this. + * '90.7.17 Fuzzy + */ +boolean_t pmap_initialized = FALSE;/* Has pmap_init completed? */ + +/* + * Consistency checks. + * These checks are disabled by default; enabled by setting CD_FULL + * in pmap_con_dbg. + */ +#ifdef DEBUG + +static void check_pv_list __P((vm_offset_t, pv_entry_t, char *)); +static void check_pmap_consistency __P((char *)); + +#define CHECK_PV_LIST(phys,pv_h,who) \ + if (pmap_con_dbg & CD_CHKPV) check_pv_list(phys,pv_h,who) +#define CHECK_PMAP_CONSISTENCY(who) \ + if (pmap_con_dbg & CD_CHKPM) check_pmap_consistency(who) +#else +#define CHECK_PV_LIST(phys,pv_h,who) +#define CHECK_PMAP_CONSISTENCY(who) +#endif /* DEBUG */ + +/* + * number of BATC entries used + */ +int batc_used; + +/* + * keep track BATC mapping + */ +batc_entry_t batc_entry[BATC_MAX]; + +int maxcmmu_pb = 4; /* max number of CMMUs per processors pbus */ +int n_cmmus_pb = 1; /* number of CMMUs per processors pbus */ + +#define cpu_number() 0 /* just being lazy, should be taken out -nivas*/ + +vm_offset_t kmapva = 0; +extern vm_offset_t bugromva; +extern vm_offset_t sramva; +extern vm_offset_t obiova; + +STATIC void +flush_atc_entry(unsigned users, vm_offset_t va, int kernel) +{ + cmmu_flush_remote_tlb(cpu_number(), kernel, va, M88K_PGBYTES); +} + +/* + * Routine: _PMAP_ACTIVATE + * + * Author: N. Sugai + * + * Function: + * Binds the given physical map to the given processor. + * + * Parameters: + * pmap pointer to pmap structure + * p pointer to proc structure + * cpu CPU number + * + * If the specified pmap is not kernel_pmap, this routine makes arp + * template and stores it into UAPR (user area pointer register) in the + * CMMUs connected to the specified CPU. + * + * If kernel_pmap is specified, only flushes the TLBs mapping kernel + * virtual space, in the CMMUs connected to the specified CPU. + * + * NOTE: + * All of the code of this function extracted from macro PMAP_ACTIVATE + * to make debugging easy. Accordingly, PMAP_ACTIVATE simlpy call + * _pmap_activate. + * + */ +void +_pmap_activate(pmap_t pmap, pcb_t pcb, int my_cpu) +{ + apr_template_t apr_data; + int n; + +#ifdef DEBUG + if ((pmap_con_dbg & (CD_ACTIVATE | CD_FULL)) == (CD_ACTIVATE | CD_NORM)) + printf("(_pmap_activate :%x) pmap 0x%x\n", curproc, (unsigned)pmap); +#endif + + if (pmap != kernel_pmap) { + /* + * Lock the pmap to put this cpu in its active set. + */ + simple_lock(&pmap->lock); + + apr_data.bits = 0; + apr_data.field.st_base = M88K_BTOP(pmap->sdt_paddr); + apr_data.field.wt = 0; + apr_data.field.g = 1; + apr_data.field.ci = 0; + apr_data.field.te = 1; +#ifdef notyet +#ifdef OMRON_PMAP + /* + * cmmu_pmap_activate will set the uapr and the batc entries, then + * flush the *USER* TLB. IF THE KERNEL WILL EVER CARE ABOUT THE + * BATC ENTRIES, THE SUPERVISOR TLBs SHOULB BE FLUSHED AS WELL. + */ + cmmu_pmap_activate(my_cpu, apr_data.bits, pmap->i_batc, pmap->d_batc); + for (n = 0; n < BATC_MAX; n++) + *(unsigned*)&batc_entry[n] = pmap->i_batc[n].bits; +#else + cmmu_set_uapr(apr_data.bits); + cmmu_flush_tlb(0, 0, -1); +#endif +#endif /* notyet */ + /* + * I am forcing it to not program the BATC at all. pmap.c module + * needs major, major cleanup. XXX nivas + */ + cmmu_set_uapr(apr_data.bits); + cmmu_flush_tlb(0, 0, -1); + + /* + * Mark that this cpu is using the pmap. + */ + simple_unlock(&pmap->lock); + + } else { + + /* + * kernel_pmap must be always active. + */ + +#ifdef DEBUG + if ((pmap_con_dbg & (CD_ACTIVATE | CD_NORM)) == (CD_ACTIVATE | CD_NORM)) + printf("(_pmap_activate :%x) called for kernel_pmap\n", curproc); +#endif + + } +} /* _pmap_activate */ + +/* + * Routine: _PMAP_DEACTIVATE + * + * Author: N. Sugai + * + * Function: + * Unbinds the given physical map to the given processor. + * + * Parameters: + * pmap pointer to pmap structure + * th pointer to thread structure + * cpu CPU number + * + * _pmap_deactive simply clears the cpus_using field in given pmap structure. + * + * NOTE: + * All of the code of this function extracted from macro PMAP_DEACTIVATE + * to make debugging easy. Accordingly, PMAP_DEACTIVATE simlpy call + * _pmap_deactivate. + * + */ +void +_pmap_deactivate(pmap_t pmap, pcb_t pcb, int my_cpu) +{ + if (pmap != kernel_pmap) { + /* Nothing to do */ + } +} + +/* + * Author: Joe Uemura + * Convert machine-independent protection code to M88K protection bits. + * + * History: + * '90.8.3 Fuzzy + * if defined TEST, 'static' undeclared. + * '90.8.30 Fuzzy + * delete "if defined TEST, 'static' undeclared." + * + */ + +STATIC unsigned int +m88k_protection(pmap_t map, vm_prot_t prot) +{ + pte_template_t p; + + p.bits = 0; + p.pte.prot = (prot & VM_PROT_WRITE) ? 0 : 1; + + return(p.bits); + +} /* m88k_protection */ + + +/* + * Routine: PMAP_PTE + * + * Function: + * Given a map and a virtual address, compute a (virtual) pointer + * to the page table entry (PTE) which maps the address . + * If the page table associated with the address does not + * exist, PT_ENTRY_NULL is returned (and the map may need to grow). + * + * Parameters: + * pmap pointer to pmap structure + * virt virtual address for which page table entry is desired + * + * Otherwise the page table address is extracted from the segment table, + * the page table index is added, and the result is returned. + * + * Calls: + * SDTENT + * SDT_VALID + * PDT_IDX + */ + +pt_entry_t * +pmap_pte(pmap_t map, vm_offset_t virt) +{ + sdt_entry_t *sdt; + + /*XXX will this change if physical memory is not contiguous? */ + /* take a look at PDTIDX XXXnivas */ + if (map == PMAP_NULL) + panic("pmap_pte: pmap is NULL"); + + sdt = SDTENT(map,virt); + + /* + * Check whether page table is exist or not. + */ + if (!SDT_VALID(sdt)) + return(PT_ENTRY_NULL); + else + return((pt_entry_t *)(((sdt + SDT_ENTRIES)->table_addr)<<PDT_SHIFT) + + PDTIDX(virt)); + +} /* pmap_pte */ + + +/* + * Routine: PMAP_EXPAND_KMAP (internal) + * + * Function: + * Allocate a page descriptor table (pte_table) and validate associated + * segment table entry, returning pointer to page table entry. This is + * much like 'pmap_expand', except that table space is acquired + * from an area set up by pmap_bootstrap, instead of through + * kmem_alloc. (Obviously, because kmem_alloc uses the kernel map + * for allocation - which we can't do when trying to expand the + * kernel map!) Note that segment tables for the kernel map were + * all allocated at pmap_bootstrap time, so we only need to worry + * about the page table here. + * + * Parameters: + * virt VA for which translation tables are needed + * prot protection attributes for segment entries + * + * Extern/Global: + * kpdt_free kernel page table free queue + * + * Calls: + * m88k_protection + * SDTENT + * SDT_VALID + * PDT_IDX + * + * This routine simply dequeues a table from the kpdt_free list, + * initalizes all its entries (invalidates them), and sets the + * corresponding segment table entry to point to it. If the kpdt_free + * list is empty - we panic (no other places to get memory, sorry). (Such + * a panic indicates that pmap_bootstrap is not allocating enough table + * space for the kernel virtual address space). + * + */ + +STATIC pt_entry_t * +pmap_expand_kmap(vm_offset_t virt, vm_prot_t prot) +{ + int aprot; + sdt_entry_t *sdt; + kpdt_entry_t kpdt_ent; + pmap_t map = kernel_pmap; + +#if DEBUG + if ((pmap_con_dbg & (CD_KMAP | CD_FULL)) == (CD_KMAP | CD_FULL)) + printf("(pmap_expand_kmap :%x) v %x\n", curproc,virt); +#endif + + aprot = m88k_protection (map, prot); + + /* segment table entry derivate from map and virt. */ + sdt = SDTENT(map, virt); + if (SDT_VALID(sdt)) + panic("pmap_expand_kmap: segment table entry VALID"); + + kpdt_ent = kpdt_free; + if (kpdt_ent == KPDT_ENTRY_NULL) { + printf("pmap_expand_kmap: Ran out of kernel pte tables\n"); + return(PT_ENTRY_NULL); + } + kpdt_free = kpdt_free->next; + + ((sdt_entry_template_t *)sdt)->bits = kpdt_ent->phys | aprot | DT_VALID; + ((sdt_entry_template_t *)(sdt + SDT_ENTRIES))->bits = (vm_offset_t)kpdt_ent | aprot | DT_VALID; + (unsigned)(kpdt_ent->phys) = 0; + (unsigned)(kpdt_ent->next) = 0; + + return((pt_entry_t *)(kpdt_ent) + PDTIDX(virt)); +}/* pmap_expand_kmap() */ + +/* + * Routine: PMAP_MAP + * + * Function: + * Map memory at initalization. The physical addresses being + * mapped are not managed and are never unmapped. + * + * Parameters: + * virt virtual address of range to map (IN) + * start physical address of range to map (IN) + * end physical address of end of range (IN) + * prot protection attributes (IN) + * + * Calls: + * pmap_pte + * pmap_expand_kmap + * + * Special Assumptions + * For now, VM is already on, only need to map the specified + * memory. Used only by pmap_bootstrap() and vm_page_startup(). + * + * For each page that needs mapping: + * pmap_pte is called to obtain the address of the page table + * table entry (PTE). If the page table does not exist, + * pmap_expand_kmap is called to allocate it. Finally, the page table + * entry is set to point to the physical page. + * + * + * initialize template with paddr, prot, dt + * look for number of phys pages in range + * { + * pmap_pte(virt) - expand if necessary + * stuff pte from template + * increment virt one page + * increment template paddr one page + * } + * + */ +vm_offset_t +pmap_map(vm_offset_t virt, vm_offset_t start, vm_offset_t end, vm_prot_t prot) +{ + int aprot; + unsigned npages; + unsigned num_phys_pages; + unsigned cmode; + pt_entry_t *pte; + pte_template_t template; + + /* + * cache mode is passed in the top 16 bits. + * extract it from there. And clear the top + * 16 bits from prot. + */ + cmode = (prot & 0xffff0000) >> 16; + prot &= 0x0000ffff; + +#if DEBUG + if ((pmap_con_dbg & (CD_MAP | CD_FULL)) == (CD_MAP | CD_FULL)) + printf ("(pmap_map :%x) phys address from %x to %x mapped at virtual %x, prot %x cmode %x\n", + curproc, start, end, virt, prot, cmode); +#endif + + if (start > end) + panic("pmap_map: start greater than end address"); + + aprot = m88k_protection (kernel_pmap, prot); + + template.bits = M88K_TRUNC_PAGE(start) | aprot | DT_VALID | cmode; + + npages = M88K_BTOP(M88K_ROUND_PAGE(end) - M88K_TRUNC_PAGE(start)); + + for (num_phys_pages = npages; num_phys_pages > 0; num_phys_pages--) { + + if ((pte = pmap_pte(kernel_pmap, virt)) == PT_ENTRY_NULL) + if ((pte = pmap_expand_kmap(virt, VM_PROT_READ|VM_PROT_WRITE)) == PT_ENTRY_NULL) + panic ("pmap_map: Cannot allocate pte table"); + +#ifdef DEBUG + if (pmap_con_dbg & CD_MAP) + if (pte->dtype) + printf("(pmap_map :%x) pte @ 0x%x already valid\n", curproc, (unsigned)pte); +#endif + + *pte = template.pte; + virt += M88K_PGBYTES; + template.bits += M88K_PGBYTES; + } + + return(virt); + +} /* pmap_map() */ + +/* + * Routine: PMAP_MAP_BATC + * + * Function: + * Map memory using BATC at initalization. The physical addresses being + * mapped are not managed and are never unmapped. + * + * Parameters: + * virt virtual address of range to map (IN) + * start physical address of range to map (IN) + * end physical address of end of range (IN) + * prot protection attributes (IN) + * cmode cache control attributes (IN) + * + * External & Global: + * batc_used number of BATC used (IN/OUT) + * + * Calls: + * m88k_protection + * BATC_BLK_ALIGNED + * cmmu_store + * pmap_pte + * pmap_expand_kmap + * + * + * For each page that needs mapping: + * If both virt and phys are on the BATC block boundary, map using BATC. + * Else make mapping in the same manner as pmap_map. + * + * initialize BATC and pte template + * look for number of phys pages in range + * { + * if virt and phys are on BATC block boundary + * { + * map using BATC + * increment virt and phys one BATC block + * continue outer loop + * } + * pmap_pte(virt) - expand if necessary + * stuff pte from template + * increment virt one page + * increment template paddr one page + * } + * + */ +vm_offset_t +pmap_map_batc(vm_offset_t virt, vm_offset_t start, vm_offset_t end, + vm_prot_t prot, unsigned cmode) +{ + int aprot; + unsigned num_phys_pages; + vm_offset_t phys; + pt_entry_t *pte; + pte_template_t template; + batc_template_t batctmp; + register int i; + +#if DEBUG + if ((pmap_con_dbg & (CD_MAPB | CD_FULL)) == (CD_MAPB | CD_FULL)) + printf ("(pmap_map_batc :%x) phys address from %x to %x mapped at virtual %x, prot %x\n", curproc, + start, end, virt, prot); +#endif + + if (start > end) + panic("pmap_map_batc: start greater than end address"); + + aprot = m88k_protection (kernel_pmap, prot); + template.bits = M88K_TRUNC_PAGE(start) | aprot | DT_VALID | cmode; + phys = start; + batctmp.bits = 0; + batctmp.field.sup = 1; /* supervisor */ + batctmp.field.wt = template.pte.wt; /* write through */ + batctmp.field.g = template.pte.g; /* global */ + batctmp.field.ci = template.pte.ci; /* cache inhibit */ + batctmp.field.wp = template.pte.prot; /* protection */ + batctmp.field.v = 1; /* valid */ + + num_phys_pages = M88K_BTOP(M88K_ROUND_PAGE(end) - M88K_TRUNC_PAGE(start)); + + while (num_phys_pages > 0) { + +#ifdef DEBUG + if ((pmap_con_dbg & (CD_MAPB | CD_FULL)) == (CD_MAPB | CD_FULL)) + printf("(pmap_map_batc :%x) num_phys_pg=%x, virt=%x, aligne V=%d, phys=%x, aligne P=%d\n", curproc, + num_phys_pages, virt, BATC_BLK_ALIGNED(virt), phys, BATC_BLK_ALIGNED(phys)); +#endif + + if ( BATC_BLK_ALIGNED(virt) && BATC_BLK_ALIGNED(phys) && + num_phys_pages >= BATC_BLKBYTES/M88K_PGBYTES && + batc_used < BATC_MAX ) { + + /* + * map by BATC + */ + batctmp.field.lba = M88K_BTOBLK(virt); + batctmp.field.pba = M88K_BTOBLK(phys); + + cmmu_set_pair_batc_entry(0, batc_used, batctmp.bits); + + batc_entry[batc_used] = batctmp.field; + +#ifdef DEBUG + if ((pmap_con_dbg & (CD_MAPB | CD_NORM)) == (CD_MAPB | CD_NORM)) { + printf("(pmap_map_batc :%x) BATC used=%d, data=%x\n", curproc, batc_used, batctmp.bits); + } + if (pmap_con_dbg & CD_MAPB) { + + for (i = 0; i < BATC_BLKBYTES; i += M88K_PGBYTES ) { + pte = pmap_pte(kernel_pmap, virt+i); + if (pte->dtype) + printf("(pmap_map_batc :%x) va %x is already mapped : pte %x\n", curproc, virt+i, ((pte_template_t *)pte)->bits); + } + } +#endif + batc_used++; + virt += BATC_BLKBYTES; + phys += BATC_BLKBYTES; + template.pte.pfn = M88K_BTOP(phys); + num_phys_pages -= BATC_BLKBYTES/M88K_PGBYTES; + continue; + } + if ((pte = pmap_pte(kernel_pmap, virt)) == PT_ENTRY_NULL) + if ((pte = pmap_expand_kmap(virt, VM_PROT_READ|VM_PROT_WRITE)) == PT_ENTRY_NULL) + panic ("pmap_map_batc: Cannot allocate pte table"); + +#ifdef DEBUG + if (pmap_con_dbg & CD_MAPB) + if (pte->dtype) + printf("(pmap_map_batc :%x) pte @ 0x%x already valid\n", curproc, (unsigned)pte); +#endif + + *pte = template.pte; + virt += M88K_PGBYTES; + phys += M88K_PGBYTES; + template.bits += M88K_PGBYTES; + num_phys_pages--; + } + + return(M88K_ROUND_PAGE(virt)); + +} /* pmap_map_batc() */ + +/* + * Routine: PMAP_CACHE_CONTROL + * + * Function: + * Set the cache-control bits in the page table entries(PTE) which maps + * the specifid virutal address range. + * + * mode + * writethrough 0x200 + * global 0x80 + * cache inhibit 0x40 + * + * Parameters: + * pmap_t map + * vm_offset_t s + * vm_offset_t e + * unsigned mode + * + * Calls: + * PMAP_LOCK + * PMAP_UNLOCK + * pmap_pte + * invalidate_pte + * flush_atc_entry + * dcachefall + * + * This routine sequences through the pages of the specified range. + * For each, it calls pmap_pte to acquire a pointer to the page table + * entry (PTE). If the PTE is invalid, or non-existant, nothing is done. + * Otherwise, the cache-control bits in the PTE's are adjusted as specified. + * + */ +void +pmap_cache_ctrl(pmap_t pmap, vm_offset_t s, vm_offset_t e, unsigned mode) +{ + int spl, spl_sav; + pt_entry_t *pte; + vm_offset_t va; + int kflush; + int cpu; + register pte_template_t opte; + +#ifdef DEBUG + if ( mode & CACHE_MASK ) { + printf("(cache_ctrl) illegal mode %x\n",mode); + return; + } + if ((pmap_con_dbg & (CD_CACHE | CD_NORM)) == (CD_CACHE | CD_NORM)) { + printf("(pmap_cache_ctrl :%x) pmap %x, va %x, mode %x\n", curproc, pmap, s, mode); + } +#endif /* DEBUG */ + + if ( pmap == PMAP_NULL ) { + panic("pmap_cache_ctrl: pmap is NULL"); + } + + PMAP_LOCK(pmap, spl); + + if (pmap == kernel_pmap) { + kflush = 1; + } else { + kflush = 0; + } + + for (va = s; va < e; va += M88K_PGBYTES) { + if ((pte = pmap_pte(pmap, va)) == PT_ENTRY_NULL) + continue; +#ifdef DEBUG + if ((pmap_con_dbg & (CD_CACHE | CD_NORM)) == (CD_CACHE | CD_NORM)) { + printf("(cache_ctrl) pte@0x%08x\n",(unsigned)pte); + } +#endif /* DEBUG */ + + /* + * Invalidate pte temporarily to avoid being written back + * the modified bit and/or the reference bit by other cpu. + * XXX + */ + spl_sav = splimp(); + opte.bits = invalidate_pte(pte); + ((pte_template_t *)pte)->bits = (opte.bits & CACHE_MASK) | mode; + flush_atc_entry(0, va, kflush); + splx(spl_sav); + + /* + * Data cache should be copied back and invalidated. + */ + cmmu_flush_remote_cache(0, M88K_PTOB(pte->pfn), M88K_PGBYTES); + } + + PMAP_UNLOCK(pmap, spl); + +} /* pmap_cache_ctrl */ + + +/* + * Routine: PMAP_BOOTSTRAP + * + * Function: + * Bootstarp the system enough to run with virtual memory. + * Map the kernel's code and data, allocate the kernel + * translation table space, and map control registers + * and other IO addresses. + * + * Parameters: + * load_start PA where kernel was loaded (IN) + * &phys_start PA of first available physical page (IN/OUT) + * &phys_end PA of last available physical page (IN) + * &virtual_avail VA of first available page (after kernel bss) + * &virtual_end VA of last available page (end of kernel address space) + * + * Extern/Global: + * + * PAGE_SIZE VM (software) page size (IN) + * kernelstart start symbol of kernel text (IN) + * etext end of kernel text (IN) + * phys_map_vaddr1 VA of page mapped arbitrarily for debug/IO (OUT) + * phys_map_vaddr2 VA of page mapped arbitrarily for debug/IO (OUT) + * + * Calls: + * simple_lock_init + * pmap_map + * pmap_map_batc + * + * The physical address 'load_start' is mapped at + * VM_MIN_KERNEL_ADDRESS, which maps the kernel code and data at the + * virtual address for which it was (presumably) linked. Immediately + * following the end of the kernel code/data, sufficent page of + * physical memory are reserved to hold translation tables for the kernel + * address space. The 'phys_start' parameter is adjusted upward to + * reflect this allocation. This space is mapped in virtual memory + * immediately following the kernel code/data map. + * + * A pair of virtual pages are reserved for debugging and IO + * purposes. They are arbitrarily mapped when needed. They are used, + * for example, by pmap_copy_page and pmap_zero_page. + * + * For m88k, we have to map BUG memory also. This is a read only + * mapping for 0x10000 bytes. We will end up having load_start as + * 0 and VM_MIN_KERNEL_ADDRESS as 0 - yes sir, we have one-to-one + * mapping!!! + */ + +void +pmap_bootstrap(vm_offset_t load_start, /* IN */ + vm_offset_t *phys_start, /* IN/OUT */ + vm_offset_t *phys_end, /* IN */ + vm_offset_t *virt_start, /* OUT */ + vm_offset_t *virt_end) /* OUT */ +{ + kpdt_entry_t kpdt_virt; + sdt_entry_t *kmap; + vm_offset_t vaddr, + virt, + kpdt_phys, + s_text, + e_text, + kernel_pmap_size, + etherpa; + apr_template_t apr_data; + pt_entry_t *pte; + int i; + u_long foo; + extern char *kernelstart, *etext; + extern void cmmu_go_virt(void); + +#ifdef DEBUG + if ((pmap_con_dbg & (CD_BOOT | CD_NORM)) == (CD_BOOT | CD_NORM)) { + printf("pmap_bootstrap : \"load_start\" 0x%x\n", load_start); + } +#endif + ptes_per_vm_page = PAGE_SIZE >> M88K_PGSHIFT; + if (ptes_per_vm_page == 0) + panic("pmap_bootstrap: VM page size < MACHINE page size"); + + if (!PAGE_ALIGNED(load_start)) { + panic("pmap_bootstrap : \"load_start\" not on the m88k page boundary : 0x%x\n", load_start); + } + + /* + * Allocate the kernel page table from the front of available + * physical memory, + * i.e. just after where the kernel image was loaded. + */ + /* + * The calling sequence is + * ... + * pmap_bootstrap(&kernelstart,...) + * kernelstart is the first symbol in the load image. + * We link the kernel such that &kernelstart == 0x10000 (size of + * BUG ROM) + * The expression (&kernelstart - load_start) will end up as + * 0, making *virt_start == *phys_start, giving a 1-to-1 map) + */ + + *phys_start = M88K_ROUND_PAGE(*phys_start); + *virt_start = *phys_start + + (M88K_TRUNC_PAGE((unsigned)&kernelstart) - load_start); + + /* + * Initialilze kernel_pmap structure + */ + kernel_pmap->ref_count = 1; + kernel_pmap->sdt_paddr = kmap = (sdt_entry_t *)(*phys_start); + kernel_pmap->sdt_vaddr = (sdt_entry_t *)(*virt_start); + kmapva = *virt_start; + +#ifdef DEBUG + if ((pmap_con_dbg & (CD_BOOT | CD_FULL)) == (CD_BOOT | CD_FULL)) { + printf("kernel_pmap->sdt_paddr = %x\n",kernel_pmap->sdt_paddr); + printf("kernel_pmap->sdt_vaddr = %x\n",kernel_pmap->sdt_vaddr); + } + /* init double-linked list of pmap structure */ + kernel_pmap->next = kernel_pmap; + kernel_pmap->prev = kernel_pmap; +#endif + + /* + * Reserve space for segment table entries. + * One for the regular segment table and one for the shadow table + * The shadow table keeps track of the virtual address of page + * tables. This is used in virtual-to-physical address translation + * functions. Remember, MMU cares only for physical addresses of + * segment and page table addresses. For kernel page tables, we + * really don't need this virtual stuff (since the kernel will + * be mapped 1-to-1) but for user page tables, this is required. + * Just to be consistent, we will maintain the shadow table for + * kernel pmap also. + */ + + kernel_pmap_size = 2*SDT_SIZE; + + /* save pointers to where page table entries start in physical memory */ + kpdt_phys = (*phys_start + kernel_pmap_size); + kpdt_virt = (kpdt_entry_t)(*virt_start + kernel_pmap_size); + kernel_pmap_size += MAX_KERNEL_PDT_SIZE; + *phys_start += kernel_pmap_size; + *virt_start += kernel_pmap_size; + + /* init all segment and page descriptor to zero */ + bzero(kernel_pmap->sdt_vaddr, kernel_pmap_size); + +#ifdef DEBUG + if ((pmap_con_dbg & (CD_BOOT | CD_FULL)) == (CD_BOOT | CD_FULL)) { + printf("kpdt_phys = %x\n",kpdt_phys); + printf("kpdt_virt = %x\n",kpdt_virt); + printf("end of kpdt at (virt)0x%08x ; (phys)0x%08x\n", + *virt_start,*phys_start); + } +#endif + /* + * init the kpdt queue + */ + kpdt_free = kpdt_virt; + for (i = MAX_KERNEL_PDT_SIZE/PDT_SIZE; i>0; i--) { + kpdt_virt->next = (kpdt_entry_t)((vm_offset_t)kpdt_virt + PDT_SIZE); + kpdt_virt->phys = kpdt_phys; + kpdt_virt = kpdt_virt->next; + kpdt_phys += PDT_SIZE; + } + kpdt_virt->next = KPDT_ENTRY_NULL; /* terminate the list */ + + /* + * Map the kernel image into virtual space + */ + + s_text = load_start; /* paddr of text */ + e_text = load_start + ((unsigned)&etext - + M88K_TRUNC_PAGE((unsigned)&kernelstart)); + /* paddr of end of text section*/ + e_text = M88K_ROUND_PAGE(e_text); + +#ifdef OMRON_PMAP +#define PMAPER pmap_map +#else +#define PMAPER pmap_map_batc +#endif + + /* map the first 64k (BUG ROM) read only, cache inhibited (? XXX) */ + vaddr = PMAPER( + 0, + 0, + 0x10000, + (VM_PROT_READ|VM_PROT_WRITE)|(CACHE_INH <<16)); + + assert(vaddr == M88K_TRUNC_PAGE((unsigned)&kernelstart)); + + vaddr = PMAPER( + (vm_offset_t)M88K_TRUNC_PAGE(((unsigned)&kernelstart)), + s_text, + e_text, + VM_PROT_WRITE | VM_PROT_READ|(CACHE_GLOBAL<<16)); /* shouldn't it be RO? XXX*/ + + vaddr = PMAPER( + vaddr, + e_text, + (vm_offset_t)kmap, + (VM_PROT_WRITE|VM_PROT_READ)|(CACHE_GLOBAL << 16)); + + /* + * Map system segment & page tables - should be cache inhibited? + * 88200 manual says that CI bit is driven on the Mbus while accessing + * the translation tree. I don't think we need to map it CACHE_INH + * here... + */ + if (kmapva != vaddr) { +#ifdef DEBUG + if ((pmap_con_dbg & (CD_BOOT | CD_FULL)) == (CD_BOOT | CD_FULL)) { + printf("(pmap_bootstrap) correcting vaddr\n"); + } +#endif + while (vaddr < (*virt_start - kernel_pmap_size)) + vaddr = M88K_ROUND_PAGE(vaddr + 1); + } + + vaddr = PMAPER( + vaddr, + (vm_offset_t)kmap, + *phys_start, + (VM_PROT_WRITE|VM_PROT_READ)|(CACHE_GLOBAL << 16)); + + etherlen = ETHERPAGES * NBPG; + + /* + * Get ethernet buffer - need etherlen bytes physically contiguous. + * 1 to 1 mapped as well???. There is actually a bug in the macros + * used by the 1x7 ethernet driver. Remove this when that is fixed. + * XXX -nivas + */ + + if (vaddr != *virt_start) { +#ifdef DEBUG + if ((pmap_con_dbg & (CD_BOOT | CD_FULL)) == (CD_BOOT | CD_FULL)) { + printf("1:vaddr %x *virt_start %x *phys_start %x\n", vaddr, + *virt_start, *phys_start); + } +#endif + *virt_start = vaddr; + *phys_start = round_page(*phys_start); + } + + *phys_start = vaddr; + + etherbuf = (void *)vaddr; + + vaddr = PMAPER( + vaddr, + *phys_start, + *phys_start + etherlen, + (VM_PROT_WRITE|VM_PROT_READ)|(CACHE_INH << 16)); + + *virt_start += etherlen; + *phys_start += etherlen; + + if (vaddr != *virt_start) { +#ifdef DEBUG + if ((pmap_con_dbg & (CD_BOOT | CD_FULL)) == (CD_BOOT | CD_FULL)) { + printf("2:vaddr %x *virt_start %x *phys_start %x\n", vaddr, + *virt_start, *phys_start); + } +#endif + *virt_start = vaddr; + *phys_start = round_page(*phys_start); + } + + *virt_start = round_page(*virt_start); + *virt_end = VM_MAX_KERNEL_ADDRESS; + + /* + * Map a few more pages for phys routines and debugger. + */ + + phys_map_vaddr1 = round_page(*virt_start); + phys_map_vaddr2 = phys_map_vaddr1 + PAGE_SIZE; + + /* + * To make 1:1 mapping of virt:phys, throw away a few phys pages. + * XXX what is this? nivas + */ + + + *phys_start += 2 * PAGE_SIZE; + *virt_start += 2 * PAGE_SIZE; + + /* + * Map all IO space 1-to-1. Ideally, I would like to not do this + * but have va for the given IO address dynamically allocated. But + * on the 88200, 2 of the BATCs are hardwired to do map the IO space + * 1-to-1; I decided to map the rest of the IO space 1-to-1. + * And bug ROM & the SRAM need to be mapped 1-to-1 if we ever want to + * execute bug system calls after the MMU has been turned on. + * OBIO should be mapped cache inhibited. + */ + + PMAPER( + BUGROM_START, + BUGROM_START, + BUGROM_START + BUGROM_SIZE, + VM_PROT_WRITE|VM_PROT_READ|(CACHE_INH << 16)); + + PMAPER( + SRAM_START, + SRAM_START, + SRAM_START + SRAM_SIZE, + VM_PROT_WRITE|VM_PROT_READ|(CACHE_GLOBAL << 16)); + + PMAPER( + OBIO_START, + OBIO_START, + OBIO_START + OBIO_SIZE, + VM_PROT_WRITE|VM_PROT_READ|(CACHE_INH << 16)); + + /* + * Allocate all the submaps we need. Note that SYSMAP just allocates + * kernel virtual address with no physical backing memory. The idea + * is physical memory will be mapped at this va before using that va. + * This means that if different physcal pages are going to be mapped + * at different times, we better do a tlb flush before using it - * else we will be referencing the wrong page. + */ + +#define SYSMAP(c, p, v, n) \ +({ \ + v = (c)virt; \ + if ((p = pmap_pte(kernel_pmap, virt)) == PT_ENTRY_NULL) \ + pmap_expand_kmap(virt, VM_PROT_READ|VM_PROT_WRITE|(CACHE_GLOBAL << 16)); \ + virt += ((n)*NBPG); \ +}) + + virt = *virt_start; + + SYSMAP(caddr_t, vmpte , vmmap, 1); + SYSMAP(struct msgbuf *, msgbufmap ,msgbufp, 1); + + vmpte->pfn = -1; + vmpte->dtype = DT_INVALID; + + *virt_start = virt; + + /* + * Set translation for UPAGES at UADDR. The idea is we want to + * have translations set up for UADDR. Later on, the ptes for + * for this address will be set so that kstack will refer + * to the u area. Make sure pmap knows about this virtual + * address by doing vm_findspace on kernel_map. + */ + + for (i = 0, virt = UADDR; i < UPAGES; i++, virt += PAGE_SIZE) { +#ifdef DEBUG + if ((pmap_con_dbg & (CD_BOOT | CD_FULL)) == (CD_BOOT | CD_FULL)) { + printf("setting up mapping for Upage %d @ %x\n", i, virt); + } +#endif + if ((pte = pmap_pte(kernel_pmap, virt)) == PT_ENTRY_NULL) + pmap_expand_kmap(virt, VM_PROT_READ|VM_PROT_WRITE|(CACHE_GLOBAL << 16)); + } + + /* + * Switch to using new page tables + */ + + apr_data.bits = 0; + apr_data.field.st_base = M88K_BTOP(kernel_pmap->sdt_paddr); + apr_data.field.wt = 1; + apr_data.field.g = 1; + apr_data.field.ci = 0; + apr_data.field.te = 1; /* Translation enable */ + + /* Invalidate entire kernel TLB. */ +#ifdef DEBUG + if ((pmap_con_dbg & (CD_BOOT | CD_FULL)) == (CD_BOOT | CD_FULL)) { + printf("invalidating tlb %x\n", apr_data.bits); + } +#endif + cmmu_flush_remote_tlb(0, 1, 0, -1); +#ifdef DEBUG + if ((pmap_con_dbg & (CD_BOOT | CD_FULL)) == (CD_BOOT | CD_FULL)) { + printf("done invalidating tlb %x\n", apr_data.bits); + } +#endif + + /* + * Set valid bit to DT_INVALID so that the very first pmap_enter() + * on these won't barf in pmap_remove_range(). + */ + pte = pmap_pte(kernel_pmap, phys_map_vaddr1); + pte->pfn = -1; + pte->dtype = DT_INVALID; + pte = pmap_pte(kernel_pmap, phys_map_vaddr2); + pte->dtype = DT_INVALID; + pte->pfn = -1; + + /* still physical */ + /* Load supervisor pointer to segment table. */ + cmmu_remote_set_sapr(0, apr_data.bits); + /* virtual now on */ +#ifdef DEBUG + if ((pmap_con_dbg & (CD_BOOT | CD_FULL)) == (CD_BOOT | CD_FULL)) { + printf("running virtual - avail_next 0x%x\n", *phys_start); + } +#endif + avail_next = *phys_start; + + return; + +} /* pmap_bootstrap() */ + +/* + * Bootstrap memory allocator. This function allows for early dynamic + * memory allocation until the virtual memory system has been bootstrapped. + * After that point, either kmem_alloc or malloc should be used. This + * function works by stealing pages from the (to be) managed page pool, + * stealing virtual address space, then mapping the pages and zeroing them. + * + * It should be used from pmap_bootstrap till vm_page_startup, afterwards + * it cannot be used, and will generate a panic if tried. Note that this + * memory will never be freed, and in essence it is wired down. + */ + +void * +pmap_bootstrap_alloc(int size) +{ + register void *mem; + + size = round_page(size); + mem = (void *)virtual_avail; + virtual_avail = pmap_map(virtual_avail, avail_start, + avail_start + size, + VM_PROT_READ|VM_PROT_WRITE|(CACHE_GLOBAL << 16)); + avail_start += size; +#ifdef DEBUG + if ((pmap_con_dbg & (CD_BOOT | CD_FULL)) == (CD_BOOT | CD_FULL)) { + printf("pmap_bootstrap_alloc: size %x virtual_avail %x avail_start %x\n", + size, virtual_avail, avail_start); + } +#endif + bzero((void *)mem, size); + return (mem); +} + +/* + * Routine: PMAP_INIT + * + * Function: + * Initialize the pmap module. It is called by vm_init, to initialize + * any structures that the pmap system needs to map virtual memory. + * + * Parameters: + * phys_start physical address of first available page + * (was last set by pmap_bootstrap) + * phys_end physical address of last available page + * + * Extern/Globals + * pv_head_table (OUT) + * pv_lock_table (OUT) + * pmap_modify_list (OUT) + * pmap_phys_start (OUT) + * pmap_phys_end (OUT) + * pmap_initialized(OUT) + * + * Calls: + * kmem_alloc + * zinit + * + * This routine does not really have much to do. It allocates space + * for the pv_head_table, pv_lock_table, pmap_modify_list; and sets these + * pointers. It also initializes zones for pmap structures, pv_entry + * structures, and segment tables. + * + * Last, it sets the pmap_phys_start and pmap_phys_end global + * variables. These define the range of pages 'managed' be pmap. These + * are pages for which pmap must maintain the PV list and the modify + * list. (All other pages are kernel-specific and are permanently + * wired.) + * + * + * kmem_alloc() memory for pv_table + * kmem_alloc() memory for modify_bits + * zinit(pmap_zone) + * zinit(segment zone) + * + */ +void +pmap_init(vm_offset_t phys_start, vm_offset_t phys_end) +{ + register long npages; + register vm_offset_t addr; + register vm_size_t s; + register int i; + vm_size_t pvl_table_size; + +#ifdef DEBUG + if ((pmap_con_dbg & (CD_INIT | CD_NORM)) == (CD_INIT | CD_NORM)) + printf("(pmap_init) phys_start %x phys_end %x\n", phys_start, phys_end); +#endif + + /* + * Allocate memory for the pv_head_table, + * the modify bit array, and the pte_page table. + */ + npages = atop(phys_end - phys_start); + pvl_table_size = PV_LOCK_TABLE_SIZE(npages); + s = (vm_size_t)(npages * sizeof(struct pv_entry) /* pv_list */ + + npages); /* pmap_modify_list */ + +#ifdef DEBUG + if ((pmap_con_dbg & (CD_INIT | CD_FULL)) == (CD_INIT | CD_FULL)) { + printf("(pmap_init) nbr of managed pages = %x\n", npages); + printf("(pmap_init) size of pv_list = %x\n", + npages * sizeof(struct pv_entry)); + } +#endif + + s = round_page(s); + addr = (vm_offset_t)kmem_alloc(kernel_map, s); + + pv_head_table = (pv_entry_t)addr; + addr = (vm_offset_t)(pv_head_table + npages); + + pmap_modify_list = (char *)addr; + + /* + * Only now, when all of the data structures are allocated, + * can we set pmap_phys_start and pmap_phys_end. If we set them + * too soon, the kmem_alloc above will blow up when it causes + * a call to pmap_enter, and pmap_enter tries to manipulate the + * (not yet existing) pv_list. + */ + pmap_phys_start = phys_start; + pmap_phys_end = phys_end; + + pmap_initialized = TRUE; + +} /* pmap_init() */ + + +/* + * Routine: PMAP_ZERO_PAGE + * + * History: + * '90.7.13 Fuzzy + * '90.9.05 Fuzzy + * Bug: template page invalid --> template page valid + * + * template = M88K_TRUNC_PAGE(phys) + * | m88k_protection (kernel_pmap, VM_PROT_READ | VM_PROT_WRITE) + * | DT_VALID; + * ^^^^^^^^ add + * + * Function: + * Zeros the specified (machine independent) page. + * + * Parameters: + * phys PA of page to zero + * + * Extern/Global: + * phys_map_vaddr1 + * + * Calls: + * M88K_TRUNC_PAGE + * m88k_protection + * cmmu_sflush_page + * DO_PTES + * bzero + * + * Special Assumptions: + * no locking required + * + * This routine maps the physical pages ath the 'phys_map' virtual + * address set up in pmap_bootstrap. It flushes the TLB to make the new + * mappings effective, and zeros all the bits. + */ +void +pmap_zero_page(vm_offset_t phys) +{ + vm_offset_t srcva; + pte_template_t template; + unsigned int i; + unsigned int spl_sav; + + register int my_cpu = cpu_number(); + pt_entry_t *srcpte; + + srcva = (vm_offset_t)(phys_map_vaddr1 + (my_cpu * PAGE_SIZE)); + srcpte = pmap_pte(kernel_pmap, srcva); + + for (i = 0; i < ptes_per_vm_page; i++, phys += M88K_PGBYTES) + { + template.bits = M88K_TRUNC_PAGE(phys) + | m88k_protection (kernel_pmap, VM_PROT_READ | VM_PROT_WRITE) + | DT_VALID | CACHE_GLOBAL; + + + spl_sav = splimp(); + cmmu_flush_tlb(1, srcva, M88K_PGBYTES); + *srcpte = template.pte; + splx(spl_sav); + bzero (srcva, M88K_PGBYTES); + /* force the data out */ + cmmu_flush_remote_data_cache(my_cpu,phys, M88K_PGBYTES); + } + +} /* pmap_zero_page() */ + + +/* + * Routine: PMAP_CREATE + * + * Author: Fuzzy + * + * History: + * '90.7.13 Fuzzy level 1 --> segment exchange + * '90.7.16 Fuzzy PT_ALIGNED --> PAGE_ALIGNED exchange + * l1_utemplate delete + * '90.7.20 Fuzzy kernel segment entries in segment table + * entries for user space address delete. + * copying kernel segment entries + * to user pmap segment entries delete. + * all user segment table entries initialize + * to zero (invalid). + * + * Function: + * Create and return a physical map. If the size specified for the + * map is zero, the map is an actual physical map, and may be referenced + * by the hardware. If the size specified is non-zero, the map will be + * used in software only, and is bounded by that size. + * + * Paramerters: + * size size of the map + * + * This routines allocates a pmap structure. + */ +pmap_t +pmap_create(vm_size_t size) +{ + pmap_t p; + + /* + * A software use-only map doesn't even need a map. + */ + if (size != 0) + return(PMAP_NULL); + + CHECK_PMAP_CONSISTENCY("pmap_create"); + + p = (pmap_t)malloc(sizeof(*p), M_VMPMAP, M_WAITOK); + if (p == PMAP_NULL) { + panic("pmap_create: cannot allocate a pmap"); + } + + bzero(p, sizeof(*p)); + pmap_pinit(p); + return(p); + +} /* pmap_create() */ + +void +pmap_pinit(pmap_t p) +{ + pmap_statistics_t stats; + sdt_entry_t *segdt; + int i; + + /* + * Allocate memory for *actual* segment table and *shadow* table. + */ + segdt = (sdt_entry_t *)kmem_alloc(kernel_map, 2 * SDT_SIZE); + if (segdt == NULL) + panic("pmap_create: kmem_alloc failure"); + +#if 0 + /* maybe, we can use bzero to zero out the segdt. XXX nivas */ + bzero(segdt, 2 * SDT_SIZE); */ +#endif /* 0 */ + /* use pmap zero page to zero it out */ + pmap_zero_page(pmap_extract(kernel_pmap,(vm_offset_t)segdt)); + if (PAGE_SIZE == SDT_SIZE) /* only got half */ + pmap_zero_page(pmap_extract(kernel_pmap,(vm_offset_t)segdt+PAGE_SIZE)); + if (PAGE_SIZE < 2*SDT_SIZE) /* get remainder */ + bzero((vm_offset_t)segdt+PAGE_SIZE, (2*SDT_SIZE)-PAGE_SIZE); + + /* + * Initialize pointer to segment table both virtual and physical. + */ + p->sdt_vaddr = segdt; + p->sdt_paddr = (sdt_entry_t *)pmap_extract(kernel_pmap,(vm_offset_t)segdt); + + if (!PAGE_ALIGNED(p->sdt_paddr)) { + printf("pmap_create: std table = %x\n",(int)p->sdt_paddr); + panic("pmap_create: sdt_table not aligned on page boundary"); + } + +#ifdef DEBUG + if ((pmap_con_dbg & (CD_CREAT | CD_NORM)) == (CD_CREAT | CD_NORM)) { + printf("(pmap_create :%x) pmap=0x%x, sdt_vaddr=0x%x, sdt_paddr=0x%x\n", + curproc, (unsigned)p, p->sdt_vaddr, p->sdt_paddr); + } +#endif + +#if notneeded + /* + * memory for page tables should be CACHE DISABLED? + */ + pmap_cache_ctrl(kernel_pmap, + (vm_offset_t)segdt, + (vm_offset_t)segdt+SDT_SIZE, + CACHE_INH); +#endif + /* + * Initalize SDT_ENTRIES. + */ + /* + * There is no need to clear segment table, since kmem_alloc would + * provides us clean pages. + */ + + /* + * Initialize pmap structure. + */ + p->ref_count = 1; + +#ifdef OMRON_PMAP + /* initialize block address translation cache */ + for (i = 0; i < BATC_MAX; i++) { + p->i_batc[i].bits = 0; + p->d_batc[i].bits = 0; + } +#endif + + /* + * Initialize statistics. + */ + stats = &p->stats; + stats->resident_count = 0; + stats->wired_count = 0; + +#ifdef DEBUG + /* link into list of pmaps, just after kernel pmap */ + p->next = kernel_pmap->next; + p->prev = kernel_pmap; + kernel_pmap->next = p; + p->next->prev = p; +#endif + +} /* pmap_pinit() */ + +/* + * Routine: PMAP_FREE_TABLES (internal) + * + * Internal procedure used by pmap_destroy() to actualy deallocate + * the tables. + * + * Parameters: + * pmap pointer to pmap structure + * + * Calls: + * pmap_pte + * kmem_free + * PT_FREE + * + * Special Assumptions: + * No locking is needed, since this is only called which the + * ref_count field of the pmap structure goes to zero. + * + * This routine sequences of through the user address space, releasing + * all translation table space back to the system using PT_FREE. + * The loops are indexed by the virtual address space + * ranges represented by the table group sizes(PDT_TABLE_GROUP_VA_SPACE). + * + */ + +STATIC void +pmap_free_tables(pmap_t pmap) +{ + unsigned long sdt_va; /* outer loop index */ + sdt_entry_t *sdttbl; /* ptr to first entry in the segment table */ + pt_entry_t *gdttbl; /* ptr to first entry in a page table */ + unsigned int i,j; + +#if DEBUG + if ((pmap_con_dbg & (CD_FREE | CD_NORM)) == (CD_FREE | CD_NORM)) + printf("(pmap_free_tables :%x) pmap %x\n", curproc, pmap); +#endif + + sdttbl = pmap->sdt_vaddr; /* addr of segment table */ + + /* + This contortion is here instead of the natural loop + because of integer overflow/wraparound if VM_MAX_USER_ADDRESS is near 0xffffffff + */ + + i = VM_MIN_USER_ADDRESS / PDT_TABLE_GROUP_VA_SPACE; + j = VM_MAX_USER_ADDRESS / PDT_TABLE_GROUP_VA_SPACE; + if ( j < 1024 ) j++; + + /* Segment table Loop */ + for ( ; i < j; i++) + { + sdt_va = PDT_TABLE_GROUP_VA_SPACE*i; + if ((gdttbl = pmap_pte(pmap, (vm_offset_t)sdt_va)) != PT_ENTRY_NULL) { +#ifdef DEBUG + if ((pmap_con_dbg & (CD_FREE | CD_FULL)) == (CD_FREE | CD_FULL)) + printf("(pmap_free_tables :%x) free page table = 0x%x\n", curproc, gdttbl); +#endif + PT_FREE(gdttbl); + } + + } /* Segment Loop */ + +#ifdef DEBUG + if ((pmap_con_dbg & (CD_FREE | CD_FULL)) == (CD_FREE | CD_FULL)) + printf("(pmap_free_tables :%x) free segment table = 0x%x\n", curproc, sdttbl); +#endif + /* + * Freeing both *actual* and *shadow* segment tables + */ + kmem_free(kernel_map, (vm_offset_t)sdttbl, 2*SDT_SIZE); + +} /* pmap_free_tables() */ + + +void +pmap_release(register pmap_t p) +{ + pmap_free_tables(p); +#ifdef DBG + DEBUG ((pmap_con_dbg & (CD_DESTR | CD_NORM)) == (CD_DESTR | CD_NORM)) + printf("(pmap_destroy :%x) ref_count = 0\n", curproc); + /* unlink from list of pmap structs */ + p->prev->next = p->next; + p->next->prev = p->prev; +#endif + +} + +/* + * Routine: PMAP_DESTROY + * + * Function: + * Retire the given physical map from service. Should only be called + * if the map contains no valid mappings. + * + * Parameters: + * pmap pointer to pmap structure + * + * Calls: + * CHECK_PMAP_CONSISTENCY + * PMAP_LOCK, PMAP_UNLOCK + * pmap_free_tables + * zfree + * + * Special Assumptions: + * Map contains no valid mappings. + * + * This routine decrements the reference count in the pmap + * structure. If it goes to zero, pmap_free_tables is called to release + * the memory space to the system. Then, call kmem_free to free the + * pmap structure. + */ +void +pmap_destroy(pmap_t p) +{ + register int c, s; + + if (p == PMAP_NULL) { +#ifdef DEBUG + if ((pmap_con_dbg & (CD_DESTR | CD_NORM)) == (CD_DESTR | CD_NORM)) + printf("(pmap_destroy :%x) pmap is NULL\n", curproc); +#endif + return; + } + + if (p == kernel_pmap) { + panic("pmap_destroy: Attempt to destroy kernel pmap"); + } + + CHECK_PMAP_CONSISTENCY("pmap_destroy"); + + PMAP_LOCK(p, s); + c = --p->ref_count; + PMAP_UNLOCK(p, s); + + if (c == 0) { + pmap_release(p); + free((caddr_t)p,M_VMPMAP); + } + +} /* pmap_destroy() */ + + +/* + * Routine: PMAP_REFERENCE + * + * Function: + * Add a reference to the specified pmap. + * + * Parameters: + * pmap pointer to pmap structure + * + * Calls: + * PMAP_LOCK, PMAP_UNLOCK + * + * Under a pmap read lock, the ref_count field of the pmap structure + * is incremented. The function then returns. + */ +void +pmap_reference(pmap_t p) +{ + int s; + + if (p != PMAP_NULL) { + PMAP_LOCK(p, s); + p->ref_count++; + PMAP_UNLOCK(p, s); + } + +} /* pmap_reference */ + + +/* + * Routine: PMAP_REMOVE_RANGE (internal) + * + * Function: + * Invalidate page table entries associated with the + * given virtual address range. The entries given are the first + * (inclusive) and last (exclusive) entries for the VM pages. + * + * Parameters: + * pmap pointer to pmap structure + * s virtual address of start of range to remove + * e virtual address of start of range to remove + * + * External/Global: + * pv lists + * pmap_modify_list + * + * Calls: + * CHECK_PAGE_ALIGN + * SDTENT + * SDT_VALID + * SDT_NEXT + * pmap_pte + * PDT_VALID + * M88K_PTOB + * PMAP_MANAGED + * PFIDX + * LOCK_PVH + * UNLOCK_PVH + * PFIDX_TO_PVH + * CHECK_PV_LIST + * zfree + * invalidate_pte + * flush_atc_entry + * vm_page_set_modified + * PHYS_TO_VM_PAGE + * + * Special Assumptions: + * The pmap must be locked. + * + * This routine sequences through the pages defined by the given + * range. For each page, pmap_pte is called to obtain a (virtual) + * pointer to the page table entry (PTE) associated with the page's + * virtual address. If the page table entry does not exist, or is invalid, + * nothing need be done. + * + * If the PTE is valid, the routine must invalidated the entry. The + * 'modified' bit, if on, is referenced to the VM through the + * 'vm_page_set_modified' macro, and into the appropriate entry in the + * pmap_modify_list. Next, the function must find the PV list entry + * associated with this pmap/va (if it doesn't exist - the function + * panics). The PV list entry is unlinked from the list, and returned to + * its zone. + */ + +STATIC void +pmap_remove_range(pmap_t pmap, vm_offset_t s, vm_offset_t e) +{ + int pfi; + int pfn; + int num_removed = 0, + num_unwired = 0; + register int i; + pt_entry_t *pte; + pv_entry_t prev, cur; + pv_entry_t pvl; + vm_offset_t pa, va, tva; + register unsigned users; + register pte_template_t opte; + int kflush; + + if (e < s) + panic("pmap_remove_range: end < start"); + + /* + * Pmap has been locked by pmap_remove. + */ + if (pmap == kernel_pmap) { + kflush = 1; + } else { + kflush = 0; + } + + /* + * Loop through the range in vm_page_size increments. + * Do not assume that either start or end fail on any + * kind of page boundary (though this may be true!?). + */ + + CHECK_PAGE_ALIGN(s, "pmap_remove_range - start addr"); + + for (va = s; va < e; va += PAGE_SIZE) { + + sdt_entry_t *sdt; + + sdt = SDTENT(pmap,va); + + if (!SDT_VALID(sdt)) { + va &= SDT_MASK; /* align to segment */ + if (va <= e - (1<<SDT_SHIFT)) + va += (1<<SDT_SHIFT) - PAGE_SIZE; /* no page table, skip to next seg entry */ + else /* wrap around */ + break; + continue; + } + + pte = pmap_pte(pmap,va); + + if (!PDT_VALID(pte)) { + continue; /* no page mapping */ + } + + num_removed++; + + if (pte->wired) + num_unwired++; + + pfn = pte->pfn; + pa = M88K_PTOB(pfn); + + if (PMAP_MANAGED(pa)) { + pfi = PFIDX(pa); + /* + * Remove the mapping from the pvlist for + * this physical page. + */ + pvl = PFIDX_TO_PVH(pfi); + CHECK_PV_LIST(pa, pvl, "pmap_remove_range before"); + + if (pvl->pmap == PMAP_NULL) + panic("pmap_remove: null pv_list"); + + if (pvl->va == va && pvl->pmap == pmap) { + + /* + * Hander is the pv_entry. Copy the next one + * to hander and free the next one (we can't + * free the hander) + */ + cur = pvl->next; + if (cur != PV_ENTRY_NULL) { + *pvl = *cur; + free((caddr_t)cur, M_VMPVENT); + } else { + pvl->pmap = PMAP_NULL; + } + + } else { + + for (prev = pvl; (cur = prev->next) != PV_ENTRY_NULL; prev = cur) { + if (cur->va == va && cur->pmap == pmap) { + break; + } + } + if (cur == PV_ENTRY_NULL) { + printf("pmap_remove_range: looking for VA " + "0x%x (pa 0x%x) PV list at 0x%x\n", va, pa, (unsigned)pvl); + panic("pmap_remove_range: mapping not in pv_list"); + } + + prev->next = cur->next; + free((caddr_t)cur, M_VMPVENT); + } + + CHECK_PV_LIST(pa, pvl, "pmap_remove_range after"); + + } /* if PAGE_MANAGED */ + + /* + * For each pte in vm_page (NOTE: vm_page, not + * M88K (machine dependent) page !! ), reflect + * modify bits to pager and zero (invalidate, + * remove) the pte entry. + */ + tva = va; + for (i = ptes_per_vm_page; i > 0; i--) { + + /* + * Invalidate pte temporarily to avoid being written back + * the modified bit and/or the reference bit by other cpu. + */ + opte.bits = invalidate_pte(pte); + flush_atc_entry(0, tva, kflush); + + if (opte.pte.modified) { + if (IS_VM_PHYSADDR(pa)) { + vm_page_set_modified(PHYS_TO_VM_PAGE(opte.bits & M88K_PGMASK)); + } + /* keep track ourselves too */ + if (PMAP_MANAGED(pa)) + pmap_modify_list[pfi] = 1; + } + pte++; + tva += M88K_PGBYTES; + } + + } /* end for ( va = s; ...) */ + + /* + * Update the counts + */ + pmap->stats.resident_count -= num_removed; + pmap->stats.wired_count -= num_unwired; + +} /* pmap_remove_range */ + +/* + * Routine: PMAP_REMOVE + * + * Function: + * Remove the given range of addresses from the specified map. + * It is assumed that start is properly rounded to the VM page size. + * + * Parameters: + * pmap pointer to pmap structure + * + * Special Assumptions: + * Assumes not all entries must be valid in specified range. + * + * Calls: + * CHECK_PAGE_ALIGN + * PMAP_LOCK, PMAP_UNLOCK + * pmap_remove_range + * panic + * + * After taking pmap read lock, pmap_remove_range is called to do the + * real work. + */ +void +pmap_remove(pmap_t map, vm_offset_t s, vm_offset_t e) +{ + int spl; + + if (map == PMAP_NULL) { + return; + } + +#if DEBUG + if ((pmap_con_dbg & (CD_RM | CD_NORM)) == (CD_RM | CD_NORM)) + printf("(pmap_remove :%x) map %x s %x e %x\n", curproc, map, s, e); +#endif + + CHECK_PAGE_ALIGN(s, "pmap_remove start addr"); + + if (s>e) + panic("pmap_remove: start greater than end address"); + + pmap_remove_range(map, s, e); +} /* pmap_remove() */ + + +/* + * Routine: PMAP_REMOVE_ALL + * + * Function: + * Removes this physical page from all physical maps in which it + * resides. Reflects back modify bits to the pager. + * + * Parameters: + * phys physical address of pages which is to + * be removed from all maps + * + * Extern/Global: + * pv_head_array, pv lists + * pmap_modify_list + * + * Calls: + * PMAP_MANAGED + * SPLVM, SPLX + * PFIDX + * PFIDX_TO_PVH + * CHECK_PV_LIST + * simple_lock + * M88K_PTOB + * PDT_VALID + * pmap_pte + * vm_page_set_modified + * PHYS_TO_VM_PAGE + * zfree + * + * If the page specified by the given address is not a managed page, + * this routine simply returns. Otherwise, the PV list associated with + * that page is traversed. For each pmap/va pair pmap_pte is called to + * obtain a pointer to the page table entry (PTE) associated with the + * va (the PTE must exist and be valid, otherwise the routine panics). + * The hardware 'modified' bit in the PTE is examined. If it is on, the + * pmap_modify_list entry corresponding to the physical page is set to 1. + * Then, the PTE is invalidated, and the PV list entry is unlinked and + * freed. + * + * At the end of this function, the PV list for the specified page + * will be null. + */ +void +pmap_remove_all(vm_offset_t phys) +{ + pv_entry_t pvl, cur; + register pt_entry_t *pte; + int pfi; + register int i; + register vm_offset_t va; + register pmap_t pmap; + int spl; + int dbgcnt = 0; + register unsigned users; + register pte_template_t opte; + int kflush; + + if (!PMAP_MANAGED(phys)) { + /* not a managed page. */ +#ifdef DEBUG + if (pmap_con_dbg & CD_RMAL) + printf("(pmap_remove_all :%x) phys addr 0x%x not a managed page\n", curproc, phys); +#endif + return; + } + + SPLVM(spl); + + /* + * Walk down PV list, removing all mappings. + * We have to do the same work as in pmap_remove_pte_page + * since that routine locks the pv_head. We don't have + * to lock the pv_head, since we have the entire pmap system. + */ +remove_all_Retry: + + pfi = PFIDX(phys); + pvl = PFIDX_TO_PVH(pfi); + CHECK_PV_LIST(phys, pvl, "pmap_remove_all before"); + + /* + * Loop for each entry on the pv list + */ + while ((pmap = pvl->pmap) != PMAP_NULL) { + va = pvl->va; + users = 0; + if (pmap == kernel_pmap) { + kflush = 1; + } else { + kflush = 0; + } + + pte = pmap_pte(pmap, va); + + /* + * Do a few consistency checks to make sure + * the PV list and the pmap are in synch. + */ + if (pte == PT_ENTRY_NULL) { + printf("(pmap_remove_all :%x) phys %x pmap %x va %x dbgcnt %x\n", + (unsigned)curproc, phys, (unsigned)pmap, va, dbgcnt); + panic("pmap_remove_all: pte NULL"); + } + if (!PDT_VALID(pte)) + panic("pmap_remove_all: pte invalid"); + if (M88K_PTOB(pte->pfn) != phys) + panic("pmap_remove_all: pte doesn't point to page"); + if (pte->wired) + panic("pmap_remove_all: removing a wired page"); + + pmap->stats.resident_count--; + + if ((cur = pvl->next) != PV_ENTRY_NULL) { + *pvl = *cur; + free((caddr_t)cur, M_VMPVENT); + } + else + pvl->pmap = PMAP_NULL; + + /* + * Reflect modified pages to pager. + */ + for (i = ptes_per_vm_page; i>0; i--) { + + /* + * Invalidate pte temporarily to avoid being written back + * the modified bit and/or the reference bit by other cpu. + */ + opte.bits = invalidate_pte(pte); + flush_atc_entry(users, va, kflush); + + if (opte.pte.modified) { + vm_page_set_modified((vm_page_t)PHYS_TO_VM_PAGE(phys)); + /* keep track ourselves too */ + pmap_modify_list[pfi] = 1; + } + pte++; + va += M88K_PGBYTES; + } + + /* + * Do not free any page tables, + * leaves that for when VM calls pmap_collect(). + */ + dbgcnt++; + } + CHECK_PV_LIST(phys, pvl, "pmap_remove_all after"); + + SPLX(spl); + +} /* pmap_remove_all() */ + +/* + * Routine: PMAP_COPY_ON_WRITE + * + * Function: + * Remove write privileges from all physical maps for this physical page. + * + * Parameters: + * phys physical address of page to be read-protected. + * + * Calls: + * SPLVM, SPLX + * PFIDX_TO_PVH + * CHECK_PV_LIST + * simple_lock, simple_unlock + * panic + * PDT_VALID + * M88K_PTOB + * pmap_pte + * + * Special Assumptions: + * All mapings of the page are user-space mappings. + * + * This routine walks the PV list. For each pmap/va pair it locates + * the page table entry (the PTE), and sets the hardware enforced + * read-only bit. The TLB is appropriately flushed. + */ +STATIC void +pmap_copy_on_write(vm_offset_t phys) +{ + register pv_entry_t pv_e; + register pt_entry_t *pte; + register int i; + int spl, spl_sav; + register unsigned users; + register pte_template_t opte; + int kflush; + + if (!PMAP_MANAGED(phys)) { +#ifdef DEBUG + if (pmap_con_dbg & CD_CMOD) + printf("(pmap_copy_on_write :%x) phys addr 0x%x not managed \n", curproc, phys); +#endif + return; + } + + SPLVM(spl); + + pv_e = PFIDX_TO_PVH(PFIDX(phys)); + CHECK_PV_LIST(phys, pv_e, "pmap_copy_on_write before"); + if (pv_e->pmap == PMAP_NULL) { + +#ifdef DEBUG + if ((pmap_con_dbg & (CD_COW | CD_NORM)) == (CD_COW | CD_NORM)) + printf("(pmap_copy_on_write :%x) phys addr 0x%x not mapped\n", curproc, phys); +#endif + + SPLX(spl); + + return; /* no mappings */ + } + + /* + * Run down the list of mappings to this physical page, + * disabling write privileges on each one. + */ + + while (pv_e != PV_ENTRY_NULL) { + pmap_t pmap; + vm_offset_t va; + + pmap = pv_e->pmap; + va = pv_e->va; + + users = 0; + if (pmap == kernel_pmap) { + kflush = 1; + } else { + kflush = 0; + } + + /* + * Check for existing and valid pte + */ + pte = pmap_pte(pmap, va); + if (pte == PT_ENTRY_NULL) + panic("pmap_copy_on_write: pte from pv_list not in map"); + if (!PDT_VALID(pte)) + panic("pmap_copy_on_write: invalid pte"); + if (M88K_PTOB(pte->pfn) != phys) + panic("pmap_copy_on_write: pte doesn't point to page"); + + /* + * Flush TLBs of which cpus using pmap. + */ + + for (i = ptes_per_vm_page; i > 0; i--) { + + /* + * Invalidate pte temporarily to avoid being written back + * the modified bit and/or the reference bit by other cpu. + */ + spl_sav = splimp(); + opte.bits = invalidate_pte(pte); + opte.pte.prot = M88K_RO; + ((pte_template_t *)pte)->bits = opte.bits; + flush_atc_entry(users, va, kflush); + splx(spl_sav); + pte++; + va += M88K_PGBYTES; + } + + pv_e = pv_e->next; + } + CHECK_PV_LIST(phys, PFIDX_TO_PVH(PFIDX(phys)), "pmap_copy_on_write"); + + SPLX(spl); + +} /* pmap_copy_on_write */ + +/* + * Routine: PMAP_PROTECT + * + * Function: + * Sets the physical protection on the specified range of this map + * as requested. + * + * Parameters: + * pmap pointer to pmap structure + * s start address of start of range + * e end address of end of range + * prot desired protection attributes + * + * Calls: + * m88k_protection + * PMAP_LOCK, PMAP_UNLOCK + * CHECK_PAGE_ALIGN + * panic + * pmap_pte + * SDT_NEXT + * PDT_VALID + * + * This routine sequences through the pages of the specified range. + * For each, it calls pmap_pte to acquire a pointer to the page table + * entry (PTE). If the PTE is invalid, or non-existant, nothing is done. + * Otherwise, the PTE's protection attributes are adjusted as specified. + */ +void +pmap_protect(pmap_t pmap, vm_offset_t s, vm_offset_t e, vm_prot_t prot) +{ + pte_template_t maprot; + unsigned ap; + int spl, spl_sav; + register int i; + pt_entry_t *pte; + vm_offset_t va, tva; + register unsigned users; + register pte_template_t opte; + int kflush; + + if (pmap == PMAP_NULL || prot & VM_PROT_WRITE) + return; + if ((prot & VM_PROT_READ) == 0) { + pmap_remove(pmap, s, e); + return; + } + if (s > e) + panic("pmap_protect: start grater than end address"); + + maprot.bits = m88k_protection(pmap, prot); + ap = maprot.pte.prot; + + PMAP_LOCK(pmap, spl); + + if (pmap == kernel_pmap) { + kflush = 1; + } else { + kflush = 0; + } + + CHECK_PAGE_ALIGN(s, "pmap_protect"); + + /* + * Loop through the range in vm_page_size increment. + * Do not assume that either start or end fall on any + * kind of page boundary (though this may be true ?!). + */ + for (va = s; va <= e; va += PAGE_SIZE) { + + pte = pmap_pte(pmap, va); + + if (pte == PT_ENTRY_NULL) { + + va &= SDT_MASK; /* align to segment */ + if (va <= e - (1<<SDT_SHIFT)) + va += (1<<SDT_SHIFT) - PAGE_SIZE; /* no page table, skip to next seg entry */ + else /* wrap around */ + break; + +#ifdef DEBUG + if ((pmap_con_dbg & (CD_PROT | CD_FULL)) == (CD_PROT | CD_FULL)) + printf("(pmap_protect :%x) no page table :: skip to 0x%x\n", curproc, va + PAGE_SIZE); +#endif + continue; + } + + if (!PDT_VALID(pte)) { +#ifdef DEBUG + if ((pmap_con_dbg & (CD_PROT | CD_FULL)) == (CD_PROT | CD_FULL)) + printf("(pmap_protect :%x) pte invalid pte @ 0x%x\n", curproc, pte); +#endif + continue; /* no page mapping */ + } + + tva = va; + for (i = ptes_per_vm_page; i>0; i--) { + + /* + * Invalidate pte temporarily to avoid being written back + * the modified bit and/or the reference bit by other cpu. + */ + spl_sav = splimp(); + opte.bits = invalidate_pte(pte); + opte.pte.prot = ap; + ((pte_template_t *)pte)->bits = opte.bits; + flush_atc_entry(0, tva, kflush); + splx(spl_sav); + pte++; + tva += M88K_PGBYTES; + } + } + + PMAP_UNLOCK(pmap, spl); + +} /* pmap_protect() */ + + + +/* + * Routine: PMAP_EXPAND + * + * Function: + * Expands a pmap to be able to map the specified virtual address. + * New kernel virtual memory is allocated for a page table + * + * Must be called with the pmap system and the pmap unlocked, since + * these must be unlocked to use vm_allocate or vm_deallocate (via + * kmem_alloc, zalloc). Thus it must be called in a unlock/lock loop + * that checks whether the map has been expanded enough. ( We won't loop + * forever, since page table aren't shrunk.) + * + * Parameters: + * map point to map structure + * v VA indicating which tables are needed + * + * Extern/Global: + * user_pt_map + * kernel_pmap + * + * Calls: + * pmap_pte + * kmem_alloc + * kmem_free + * zalloc + * zfree + * pmap_extract + * + * Special Assumptions + * no pmap locks held + * + * 1: This routine immediately allocates space for a page table. + * + * 2: The page table entries (PTEs) are initialized (set invalid), and + * the corresponding segment table entry is set to point to the new + * page table. + * + * + * if (kernel_pmap) + * pmap_expand_kmap() + * ptva = kmem_alloc(user_pt_map) + * + */ +STATIC void +pmap_expand(pmap_t map, vm_offset_t v) +{ + int i, + spl; + vm_offset_t pdt_vaddr, + pdt_paddr; + + sdt_entry_t *sdt; + pt_entry_t *pte; + vm_offset_t pmap_extract(); + + if (map == PMAP_NULL) { + panic("pmap_expand: pmap is NULL"); + } + +#ifdef DEBUG + if ((pmap_con_dbg & (CD_EXP | CD_NORM)) == (CD_EXP | CD_NORM)) + printf ("(pmap_expand :%x) map %x v %x\n", curproc, map, v); +#endif + + CHECK_PAGE_ALIGN (v, "pmap_expand"); + + /* + * Handle kernel pmap in pmap_expand_kmap(). + */ + if (map == kernel_pmap) { + PMAP_LOCK(map, spl); + if (pmap_expand_kmap(v, VM_PROT_READ|VM_PROT_WRITE) == PT_ENTRY_NULL) + panic ("pmap_expand: Cannot allocate kernel pte table"); + PMAP_UNLOCK(map, spl); +#ifdef DEBUG + if ((pmap_con_dbg & (CD_EXP | CD_FULL)) == (CD_EXP | CD_FULL)) + printf("(pmap_expand :%x) kernel_pmap\n", curproc); +#endif + return; + } + + /* XXX */ +#ifdef MACH_KERNEL + if (kmem_alloc_wired(kernel_map, &pdt_vaddr, PAGE_SIZE) != KERN_SUCCESS) + panic("pmap_enter: kmem_alloc failure"); + pmap_zero_page(pmap_extract(kernel_pmap, pdt_vaddr)); +#else + pdt_vaddr = kmem_alloc (kernel_map, PAGE_SIZE); +#endif + + pdt_paddr = pmap_extract(kernel_pmap, pdt_vaddr); + +#if notneeded + /* + * the page for page tables should be CACHE DISABLED + */ + pmap_cache_ctrl(kernel_pmap, pdt_vaddr, pdt_vaddr+PAGE_SIZE, CACHE_INH); +#endif + + PMAP_LOCK(map, spl); + + if ((pte = pmap_pte(map, v)) != PT_ENTRY_NULL) { + /* + * Someone else caused us to expand + * during our vm_allocate. + */ + PMAP_UNLOCK(map, spl); + /* XXX */ + kmem_free (kernel_map, pdt_vaddr, PAGE_SIZE); +#ifdef DEBUG + if (pmap_con_dbg & CD_EXP) + printf("(pmap_expand :%x) table has already allocated\n", curproc); +#endif + return; + } + + /* + * Apply a mask to V to obtain the vaddr of the beginning of + * its containing page 'table group',i.e. the group of + * page tables that fit eithin a single VM page. + * Using that, obtain the segment table pointer that references the + * first page table in the group, and initilize all the + * segment table descriptions for the page 'table group'. + */ + v &= ~((1<<(LOG2_PDT_TABLE_GROUP_SIZE+PDT_BITS+PG_BITS))-1); + + sdt = SDTENT(map,v); + + /* + * Init each of the segment entries to point the freshly allocated + * page tables. + */ + + for (i = PDT_TABLE_GROUP_SIZE; i>0; i--) { + ((sdt_entry_template_t *)sdt)->bits = pdt_paddr | M88K_RW | DT_VALID; + ((sdt_entry_template_t *)(sdt + SDT_ENTRIES))->bits = pdt_vaddr | M88K_RW | DT_VALID; + sdt++; + pdt_paddr += PDT_SIZE; + pdt_vaddr += PDT_SIZE; + } + + PMAP_UNLOCK(map, spl); + +} /* pmap_expand() */ + + + +/* + * Routine: PMAP_ENTER + * + * + * Update: + * July 13,90 - JUemura + * initial porting + * *****TO CHECK***** + * locks removed since we don't have to allocate + * level 2 tables anymore. locks needed? + * '90.7.26 Fuzzy VM_MIN_KERNEL_ADDRESS -> VM_MAX_USER_ADDRESS + * '90.8.17 Fuzzy Debug message added(PV no mapped at VA) + * '90.8.31 Sugai Remove redundant message output + * + * Function: + * Insert the given physical page (p) at the specified virtual + * address (v) in the target phisical map with the protecton requested. + * If specified, the page will be wired down, meaning that the + * related pte can not be reclaimed. + * + * N.B.: This is only routine which MAY NOT lazy-evaluation or lose + * information. That is, this routine must actually insert this page + * into the given map NOW. + * + * Parameters: + * pmap pointer to pmap structure + * va VA of page to be mapped + * pa PA of page to be mapped + * prot protection attributes for page + * wired wired attribute for page + * + * Extern/Global: + * pv_head_array, pv lists + * pmap_modify_list + * + * Calls: + * m88k_protection + * pmap_pte + * pmap_expand + * pmap_remove_range + * zfree + * + * This routine starts off by calling pmap_pte to obtain a (virtual) + * pointer to the page table entry corresponding to given virtual + * address. If the page table itself does not exist, pmap_expand is + * called to allocate it. + * + * If the page table entry (PTE) already maps the given physical page, + * all that is needed is to set the protection and wired attributes as + * given. TLB entries are flushed and pmap_enter returns. + * + * If the page table entry (PTE) maps a different physical page than + * that given, the old mapping is removed by a call to map_remove_range. + * And execution of pmap_enter continues. + * + * To map the new physical page, the routine first inserts a new + * entry in the PV list exhibiting the given pmap and virtual address. + * It then inserts the physical page address, protection attributes, and + * wired attributes into the page table entry (PTE). + * + * + * get machine-dependent prot code + * get the pte for this page + * if necessary pmap expand(pmap,v) + * if (changing wired attribute or protection) { + * flush entry from TLB + * update template + * for (ptes per vm page) + * stuff pte + * } else if (mapped at wrong addr) + * flush entry from TLB + * pmap_remove_range + * } else { + * enter mapping in pv_list + * setup template and stuff ptes + * } + * + */ +void +pmap_enter(pmap_t pmap, vm_offset_t va, vm_offset_t pa, + vm_prot_t prot, boolean_t wired) +{ + int ap; + int spl, spl_sav; + pv_entry_t pv_e; + pt_entry_t *pte; + vm_offset_t old_pa; + pte_template_t template; + register int i; + int pfi; + pv_entry_t pvl; + register unsigned users; + register pte_template_t opte; + int kflush; + + if (pmap == PMAP_NULL) { + panic("pmap_enter: pmap is NULL"); + } + + CHECK_PAGE_ALIGN (va, "pmap_entry - VA"); + CHECK_PAGE_ALIGN (pa, "pmap_entry - PA"); + + /* + * Range check no longer use, since we use whole address space + */ + +#ifdef DEBUG + if ((pmap_con_dbg & (CD_ENT | CD_NORM)) == (CD_ENT | CD_NORM)) { + if (pmap == kernel_pmap) + printf ("(pmap_enter :%x) pmap kernel va %x pa %x\n", curproc, va, pa); + else + printf ("(pmap_enter :%x) pmap %x va %x pa %x\n", curproc, pmap, va, pa); + } +#endif + + ap = m88k_protection (pmap, prot); + + /* + * Must allocate a new pvlist entry while we're unlocked; + * zalloc may cause pageout (which will lock the pmap system). + * If we determine we need a pvlist entry, we will unlock + * and allocate one. Then will retry, throwing away + * the allocated entry later (if we no longer need it). + */ + pv_e = PV_ENTRY_NULL; + Retry: + + PMAP_LOCK(pmap, spl); + + /* + * Expand pmap to include this pte. Assume that + * pmap is always expanded to include enough M88K + * pages to map one VM page. + */ + while ((pte = pmap_pte(pmap, va)) == PT_ENTRY_NULL) { + /* + * Must unlock to expand the pmap. + */ + PMAP_UNLOCK(pmap, spl); + pmap_expand(pmap, va); + PMAP_LOCK(pmap, spl); + } + + /* + * Special case if the physical page is already mapped + * at this address. + */ + old_pa = M88K_PTOB(pte->pfn); + if (old_pa == pa) { + + users = 0; + if (pmap == kernel_pmap) { + kflush = 1; + } else { + kflush = 0; + } + + /* + * May be changing its wired attributes or protection + */ + + if (wired && !pte->wired) + pmap->stats.wired_count++; + else if (!wired && pte->wired) + pmap->stats.wired_count--; + + if ((unsigned long)pa >= MAXPHYSMEM) + template.bits = DT_VALID | ap | M88K_TRUNC_PAGE(pa) | CACHE_INH; + else + template.bits = DT_VALID | ap | M88K_TRUNC_PAGE(pa) | CACHE_GLOBAL; + if (wired) + template.pte.wired = 1; + + /* + * If there is a same mapping, we have nothing to do. + */ + if ( !PDT_VALID(pte) || (pte->wired != template.pte.wired) + || (pte->prot != template.pte.prot)) { + + for (i = ptes_per_vm_page; i>0; i--) { + + /* + * Invalidate pte temporarily to avoid being written back + * the modified bit and/or the reference bit by other cpu. + */ + spl_sav = splimp(); + opte.bits = invalidate_pte(pte); + template.pte.modified = opte.pte.modified; + *pte++ = template.pte; + flush_atc_entry(users, va, kflush); + splx(spl_sav); + template.bits += M88K_PGBYTES; + va += M88K_PGBYTES; + } + } + + } else { /* if ( pa == old_pa) */ + + /* + * Remove old mapping from the PV list if necessary. + */ + if (old_pa != (vm_offset_t)-1) { + /* + * Invalidate the translation buffer, + * then remove the mapping. + */ +#ifdef DEBUG + if ((pmap_con_dbg & (CD_ENT | CD_NORM)) == (CD_ENT | CD_NORM)) { + if (va == phys_map_vaddr1 || va == phys_map_vaddr2) { + printf("vaddr1 0x%x vaddr2 0x%x va 0x%x pa 0x%x managed %x\n", + phys_map_vaddr1, phys_map_vaddr2, va, old_pa, + PMAP_MANAGED(pa) ? 1 : 0); + printf("pte %x pfn %x valid %x\n", + pte, pte->pfn, pte->dtype); + } + } +#endif + if (va == phys_map_vaddr1 || va == phys_map_vaddr2) { + flush_atc_entry(0, va, 1); + } else { + pmap_remove_range(pmap, va, va + PAGE_SIZE); + } + } + + if (PMAP_MANAGED(pa)) { +#ifdef DEBUG + if ((pmap_con_dbg & (CD_ENT | CD_NORM)) == (CD_ENT | CD_NORM)) { + if (va == phys_map_vaddr1 || va == phys_map_vaddr2) { + printf("va 0x%x and managed pa 0x%x\n", va, pa); + } + } +#endif + /* + * Enter the mappimg in the PV list for this + * physical page. + */ + pfi = PFIDX(pa); + pvl = PFIDX_TO_PVH(pfi); + CHECK_PV_LIST (pa, pvl, "pmap_enter before"); + + if (pvl->pmap == PMAP_NULL) { + + /* + * No mappings yet + */ + pvl->va = va; + pvl->pmap = pmap; + pvl->next = PV_ENTRY_NULL; + + } else { +#ifdef DEBUG + /* + * check that this mapping is not already there + */ + { + pv_entry_t e = pvl; + while (e != PV_ENTRY_NULL) { + if (e->pmap == pmap && e->va == va) + panic ("pmap_enter: already in pv_list"); + e = e->next; + } + } +#endif + /* + * Add new pv_entry after header. + */ + if (pv_e == PV_ENTRY_NULL) { + PMAP_UNLOCK(pmap, spl); + pv_e = (pv_entry_t) malloc(sizeof *pv_e, M_VMPVENT, + M_NOWAIT); + goto Retry; + } + pv_e->va = va; + pv_e->pmap = pmap; + pv_e->next = pvl->next; + pvl->next = pv_e; + /* + * Remeber that we used the pvlist entry. + */ + pv_e = PV_ENTRY_NULL; + } + } + + /* + * And count the mapping. + */ + pmap->stats.resident_count++; + if (wired) + pmap->stats.wired_count++; + + if ((unsigned long)pa >= MAXPHYSMEM) + template.bits = DT_VALID | ap | M88K_TRUNC_PAGE(pa) | CACHE_INH; + else + template.bits = DT_VALID | ap | M88K_TRUNC_PAGE(pa) | CACHE_GLOBAL; + + if (wired) + template.pte.wired = 1; + + DO_PTES (pte, template.bits); + + } /* if ( pa == old_pa ) ... else */ + + PMAP_UNLOCK(pmap, spl); + + if (pv_e != PV_ENTRY_NULL) + free((caddr_t) pv_e, M_VMPVENT); + +} /* pmap_enter */ + + + +/* + * Routine: pmap_change_wiring + * + * Author: Fuzzy + * + * Function: Change the wiring attributes for a map/virtual-address + * Pair. + * Prameterts: + * pmap pointer to pmap structure + * v virtual address of page to be wired/unwired + * wired flag indicating new wired state + * + * Extern/Global: + * pte_per_vm_page + * + * Calls: + * PMAP_LOCK, PMAP_UNLOCK + * pmap_pte + * panic + * + * Special Assumptions: + * The mapping must already exist in the pmap. + */ +void +pmap_change_wiring(pmap_t map, vm_offset_t v, boolean_t wired) +{ + pt_entry_t *pte; + int i; + int spl; + + PMAP_LOCK(map, spl); + + if ((pte = pmap_pte(map, v)) == PT_ENTRY_NULL) + panic ("pmap_change_wiring: pte missing"); + + if (wired && !pte->wired) + /* + * wiring mapping + */ + map->stats.wired_count++; + + else if (!wired && pte->wired) + /* + * unwired mapping + */ + map->stats.wired_count--; + + for (i = ptes_per_vm_page; i>0; i--) + (pte++)->wired = wired; + + PMAP_UNLOCK(map, spl); + +} /* pmap_change_wiring() */ + + + +/* + * Routine: PMAP_EXTRACT + * + * Author: Fuzzy + * + * Function: + * Extract the physical page address associoated + * with the given map/virtual_address pair. + * + * Parameters: + * pmap pointer to pmap structure + * va virtual address + * + * Calls: + * PMAP_LOCK, PMAP_UNLOCK + * pmap_pte + * + * + * This routine checks BATC mapping first. BATC has been used and + * the specified pmap is kernel_pmap, batc_entry is scanned to find out + * the mapping. + * Then the routine calls pmap_pte to get a (virtual) pointer to + * the page table entry (PTE) associated with the given virtual + * address. If the page table does not exist, or if the PTE is not valid, + * then 0 address is returned. Otherwise, the physical page address from + * the PTE is returned. + */ +vm_offset_t +pmap_extract(pmap_t pmap, vm_offset_t va) +{ + register pt_entry_t *pte; + register vm_offset_t pa; + register int i; + int spl; + + if (pmap == PMAP_NULL) + panic("pmap_extract: pmap is NULL"); + + /* + * check BATC first + */ + if (pmap == kernel_pmap && batc_used > 0) + for (i = batc_used-1; i > 0; i--) + if (batc_entry[i].lba == M88K_BTOBLK(va)) { + pa = (batc_entry[i].pba << BATC_BLKSHIFT) | (va & BATC_BLKMASK ); + return(pa); + } + + PMAP_LOCK(pmap, spl); + + if ((pte = pmap_pte(pmap, va)) == PT_ENTRY_NULL) + pa = (vm_offset_t) 0; + else { + if (PDT_VALID(pte)) + pa = M88K_PTOB(pte->pfn); + else + pa = (vm_offset_t) 0; + } + + if (pa) + pa |= (va & M88K_PGOFSET); /* offset within page */ + + PMAP_UNLOCK(pmap, spl); + +#if 0 + printf("pmap_extract ret %x\n", pa); +#endif /* 0 */ + return(pa); + +} /* pamp_extract() */ + +/* + a version for the kernel debugger +*/ + +vm_offset_t +pmap_extract_unlocked(pmap_t pmap, vm_offset_t va) +{ + pt_entry_t *pte; + vm_offset_t pa; + int i; + + if (pmap == PMAP_NULL) + panic("pmap_extract: pmap is NULL"); + + /* + * check BATC first + */ + if (pmap == kernel_pmap && batc_used > 0) + for (i = batc_used-1; i > 0; i--) + if (batc_entry[i].lba == M88K_BTOBLK(va)) { + pa = (batc_entry[i].pba << BATC_BLKSHIFT) | (va & BATC_BLKMASK ); + return(pa); + } + + if ((pte = pmap_pte(pmap, va)) == PT_ENTRY_NULL) + pa = (vm_offset_t) 0; + else { + if (PDT_VALID(pte)) + pa = M88K_PTOB(pte->pfn); + else + pa = (vm_offset_t) 0; + } + + if (pa) + pa |= (va & M88K_PGOFSET); /* offset within page */ + + return(pa); + +} /* pamp_extract_unlocked() */ + + +/* + * Routine: PMAP_COPY + * + * Function: + * Copy the range specigfied by src_adr/len from the source map + * to the range dst_addr/len in the destination map. This routine + * is only advisory and need not do anything. + * + * Parameters: + * dst_pmap pointer to destination pmap structure + * src_pmap pointer to source pmap structure + * dst_addr VA in destionation map + * len length of address space being copied + * src_addr VA in source map + * + * At this time, the 88200 pmap implementation does nothing in this + * function. Translation tables in the destination map will be allocated + * at VM fault time. + */ +void +pmap_copy(pmap_t dst_pmap, pmap_t src_pmap, vm_offset_t dst_addr, + vm_size_t len, vm_offset_t src_addr) +{ +#ifdef lint + dst_pmap++; src_pmap++; dst_addr++; len++; src_addr++; +#endif + + +}/* pmap_copy() */ + + +/* + * Routine: PMAP_UPDATE + * + * Function: + * Require that all active physical maps contain no incorrect entries + * NOW. [This update includes forcing updates of any address map + * cashing] + * Generally used to ensure that thread about to run will see a + * semantically correct world. + * + * Parameters: + * none + * + * Call: + * cmmuflush + * + * The 88200 pmap implementation does not defer any operations. + * Therefore, the translation table trees are always consistent while the + * pmap lock is not held. Therefore, there is really no work to do in + * this function other than to flush the TLB. + */ +void +pmap_update(void) +{ +#ifdef DBG + if ((pmap_con_dbg & (CD_UPD | CD_FULL)) == (CD_UPD | CD_FULL)) + printf("(pmap_update :%x) Called \n", curproc); +#endif + +}/* pmap_update() */ + + + +/* + * Routine: PMAP_COLLECT + * + * Runction: + * Garbage collects the physical map system for pages which are + * no longer used. there may well be pages which are not + * referenced, but others may be collected as well. + * Called by the pageout daemon when pages are scarce. + * + * Parameters: + * pmap pointer to pmap structure + * + * Calls: + * CHECK_PMAP_CONSISTENCY + * panic + * PMAP_LOCK, PMAP_UNLOCK + * PT_FREE + * pmap_pte + * pmap_remove_range + * + * The intent of this routine is to release memory pages being used + * by translation tables. They can be release only if they contain no + * valid mappings, and their parent table entry has been invalidated. + * + * The routine sequences through the entries user address space, + * inspecting page-sized groups of page tables for wired entries. If + * a full page of tables has no wired enties, any otherwise valid + * entries are invalidated (via pmap_remove_range). Then, the segment + * table entries corresponding to this group of page tables are + * invalidated. Finally, PT_FREE is called to return the page to the + * system. + * + * If all entries in a segment table are invalidated, it too can + * be returned to the system. + * + * [Note: depending upon compilation options, tables may be in zones + * or allocated through kmem_alloc. In the former case, the + * module deals with a single table at a time.] + */ +void +pmap_collect(pmap_t pmap) +{ + + vm_offset_t sdt_va; /* outer loop index */ + vm_offset_t sdt_vt; /* end of segment */ + sdt_entry_t *sdttbl; /* ptr to first entry in the segment table */ + sdt_entry_t *sdtp; /* ptr to index into segment table */ + sdt_entry_t *sdt; /* ptr to index into segment table */ + pt_entry_t *gdttbl; /* ptr to first entry in a page table */ + pt_entry_t *gdttblend; /* ptr to byte after last entry in table group */ + pt_entry_t *gdtp; /* ptr to index into a page table */ + boolean_t found_gdt_wired; /* flag indicating a wired page exists in */ + /* a page table's address range */ + int spl; + unsigned int i,j; + + + + if (pmap == PMAP_NULL) { + panic("pmap_collect: pmap is NULL"); + } + if (pmap == kernel_pmap) { +#ifdef MACH_KERNEL + return; +#else + panic("pmap_collect attempted on kernel pmap"); +#endif + } + + CHECK_PMAP_CONSISTENCY ("pmap_collect"); + +#if DBG + if ((pmap_con_dbg & (CD_COL | CD_NORM)) == (CD_COL | CD_NORM)) + printf ("(pmap_collect :%x) pmap %x\n", curproc, pmap); +#endif + + PMAP_LOCK(pmap, spl); + + sdttbl = pmap->sdt_vaddr; /* addr of segment table */ + sdtp = sdttbl; + + /* + This contortion is here instead of the natural loop + because of integer overflow/wraparound if VM_MAX_USER_ADDRESS is near 0xffffffff + */ + + i = VM_MIN_USER_ADDRESS / PDT_TABLE_GROUP_VA_SPACE; + j = VM_MAX_USER_ADDRESS / PDT_TABLE_GROUP_VA_SPACE; + if ( j < 1024 ) j++; + + /* Segment table loop */ + for ( ; i < j; i++, sdtp += PDT_TABLE_GROUP_SIZE) + { + sdt_va = VM_MIN_USER_ADDRESS + PDT_TABLE_GROUP_VA_SPACE*i; + + gdttbl = pmap_pte(pmap, (vm_offset_t)sdt_va); + + if (gdttbl == PT_ENTRY_NULL) + continue; /* no maps in this range */ + + gdttblend = gdttbl + (PDT_ENTRIES * PDT_TABLE_GROUP_SIZE); + + /* scan page maps for wired pages */ + found_gdt_wired = FALSE; + for (gdtp=gdttbl; gdtp <gdttblend; gdtp++) { + if (gdtp->wired) { + found_gdt_wired = TRUE; + break; + } + } + + if (found_gdt_wired) + continue; /* can't free this range */ + + /* figure out end of range. Watch for wraparound */ + + sdt_vt = sdt_va <= VM_MAX_USER_ADDRESS-PDT_TABLE_GROUP_VA_SPACE ? + sdt_va+PDT_TABLE_GROUP_VA_SPACE : + VM_MAX_USER_ADDRESS; + + /* invalidate all maps in this range */ + pmap_remove_range (pmap, (vm_offset_t)sdt_va, (vm_offset_t)sdt_vt); + + /* + * we can safely deallocated the page map(s) + */ + for (sdt = sdtp; sdt < (sdtp+PDT_TABLE_GROUP_SIZE); sdt++) { + ((sdt_entry_template_t *) sdt) -> bits = 0; + ((sdt_entry_template_t *) sdt+SDT_ENTRIES) -> bits = 0; + } + + /* + * we have to unlock before freeing the table, since PT_FREE + * calls kmem_free or zfree, which will invoke another pmap routine + */ + PMAP_UNLOCK(pmap, spl); + PT_FREE(gdttbl); + PMAP_LOCK(pmap, spl); + + } /* Segment table Loop */ + + PMAP_UNLOCK(pmap, spl); + +#if DBG + if ((pmap_con_dbg & (CD_COL | CD_NORM)) == (CD_COL | CD_NORM)) + printf ("(pmap_collect :%x) done \n", curproc); +#endif + + CHECK_PMAP_CONSISTENCY("pmap_collect"); +} /* pmap collect() */ + + + +/* + * Routine: PMAP_ACTIVATE + * + * Function: + * Binds the given physical map to the given + * processor, and returns a hardware map description. + * In a mono-processor implementation the my_cpu + * argument is ignored, and the PMAP_ACTIVATE macro + * simply sets the MMU root pointer element of the PCB + * to the physical address of the segment descriptor table. + * + * Parameters: + * pmap pointer to pmap structure + * pcbp pointer to current pcb + * cpu CPU number + */ +void +pmap_activate(pmap_t pmap, pcb_t pcb) +{ +#ifdef lint + my_cpu++; +#endif + PMAP_ACTIVATE(pmap, pcb, 0); +} /* pmap_activate() */ + + + +/* + * Routine: PMAP_DEACTIVATE + * + * Function: + * Unbinds the given physical map from the given processor, + * i.e. the pmap i no longer is use on the processor. + * In a mono-processor the PMAP_DEACTIVATE macro is null. + * + * Parameters: + * pmap pointer to pmap structure + * pcb pointer to pcb + */ +void +pmap_deactivate(pmap_t pmap, pcb_t pcb) +{ +#ifdef lint + pmap++; th++; which_cpu++; +#endif + PMAP_DEACTIVATE(pmap, pcb, 0); +} /* pmap_deactivate() */ + + + +/* + * Routine: PMAP_KERNEL + * + * Function: + * Retruns a pointer to the kernel pmap. + */ +pmap_t +pmap_kernel(void) +{ + return (kernel_pmap); +}/* pmap_kernel() */ + + +/* + * Routine: PMAP_COPY_PAGE + * + * Function: + * Copies the specified (machine independent) pages. + * + * Parameters: + * src PA of source page + * dst PA of destination page + * + * Extern/Global: + * phys_map_vaddr1 + * phys_map_vaddr2 + * + * Calls: + * m88kprotection + * M88K_TRUNC_PAGE + * cmmu_sflush_page + * DO_PTES + * bcopy + * + * Special Assumptions: + * no locking reauired + * + * This routine maps the phsical pages at the 'phys_map' virtual + * addresses set up in pmap_bootstrap. It flushes the TLB to make the + * new mappings effective, and performs the copy. + */ +void +pmap_copy_page(vm_offset_t src, vm_offset_t dst) +{ + vm_offset_t dstva, srcva; + unsigned int spl_sav; + int i; + int aprot; + pte_template_t template; + pt_entry_t *dstpte, *srcpte; + int my_cpu = cpu_number(); + + /* + * Map source physical address. + */ + aprot = m88k_protection (kernel_pmap, VM_PROT_READ | VM_PROT_WRITE); + + srcva = (vm_offset_t)(phys_map_vaddr1 + (cpu_number() * PAGE_SIZE)); + dstva = (vm_offset_t)(phys_map_vaddr2 + (cpu_number() * PAGE_SIZE)); + + srcpte = pmap_pte(kernel_pmap, srcva); + dstpte = pmap_pte(kernel_pmap, dstva); + + for (i=0; i < ptes_per_vm_page; i++, src += M88K_PGBYTES, dst += M88K_PGBYTES) + { + template.bits = M88K_TRUNC_PAGE(src) | aprot | DT_VALID | CACHE_GLOBAL; + + /* do we need to write back dirty bits */ + spl_sav = splimp(); + cmmu_flush_tlb(1, srcva, M88K_PGBYTES); + *srcpte = template.pte; + + /* + * Map destination physical address. + */ + template.bits = M88K_TRUNC_PAGE(dst) | aprot | CACHE_GLOBAL | DT_VALID; + cmmu_flush_tlb(1, dstva, M88K_PGBYTES); + *dstpte = template.pte; + splx(spl_sav); + + bcopy((void*)srcva, (void*)dstva, M88K_PGBYTES); + /* flush source, dest out of cache? */ + cmmu_flush_remote_data_cache(my_cpu, src, M88K_PGBYTES); + cmmu_flush_remote_data_cache(my_cpu, dst, M88K_PGBYTES); + } + +} /* pmap_copy_page() */ + + +/* + * copy_to_phys + * + * Copy virtual memory to physical memory by mapping the physical + * memory into virtual memory and then doing a virtual to virtual + * copy with bcopy. + * + * Parameters: + * srcva VA of source page + * dstpa PA of destination page + * bytecount copy byte size + * + * Extern/Global: + * phys_map_vaddr2 + * + * Calls: + * m88kprotection + * M88K_TRUNC_PAGE + * cmmu_sflush_page + * DO_PTES + * bcopy + * + */ +void +copy_to_phys(vm_offset_t srcva, vm_offset_t dstpa, int bytecount) +{ + vm_offset_t dstva; + pt_entry_t *dstpte; + int copy_size, + offset, + aprot; + unsigned int i; + pte_template_t template; + + dstva = (vm_offset_t)(phys_map_vaddr2 + (cpu_number() * PAGE_SIZE)); + dstpte = pmap_pte(kernel_pmap, dstva); + copy_size = M88K_PGBYTES; + offset = dstpa - M88K_TRUNC_PAGE(dstpa); + dstpa -= offset; + + aprot = m88k_protection(kernel_pmap, VM_PROT_READ | VM_PROT_WRITE); + while (bytecount > 0){ + copy_size = M88K_PGBYTES - offset; + if (copy_size > bytecount) + copy_size = bytecount; + + /* + * Map distation physical address. + */ + + for (i = 0; i < ptes_per_vm_page; i++) + { + template.bits = M88K_TRUNC_PAGE(dstpa) | aprot | CACHE_WT | DT_VALID; + cmmu_flush_tlb(1, dstva, M88K_PGBYTES); + *dstpte = template.pte; + + dstva += offset; + bcopy((void*)srcva, (void*)dstva, copy_size); + srcva += copy_size; + dstva += copy_size; + dstpa += M88K_PGBYTES; + bytecount -= copy_size; + offset = 0; + } + } +} + +/* + * copy_from_phys + * + * Copy physical memory to virtual memory by mapping the physical + * memory into virtual memory and then doing a virtual to virtual + * copy with bcopy. + * + * Parameters: + * srcpa PA of source page + * dstva VA of destination page + * bytecount copy byte size + * + * Extern/Global: + * phys_map_vaddr2 + * + * Calls: + * m88kprotection + * M88K_TRUNC_PAGE + * cmmu_sflush_page + * DO_PTES + * bcopy + * + */ +void +copy_from_phys(vm_offset_t srcpa, vm_offset_t dstva, int bytecount) +{ + register vm_offset_t srcva; + register pt_entry_t *srcpte; + register int copy_size, offset; + int aprot; + unsigned int i; + pte_template_t template; + + srcva = (vm_offset_t)(phys_map_vaddr2 + (cpu_number() * PAGE_SIZE)); + srcpte = pmap_pte(kernel_pmap, srcva); + copy_size = M88K_PGBYTES; + offset = srcpa - M88K_TRUNC_PAGE(srcpa); + srcpa -= offset; + + aprot = m88k_protection(kernel_pmap, VM_PROT_READ | VM_PROT_WRITE); + while (bytecount > 0){ + copy_size = M88K_PGBYTES - offset; + if (copy_size > bytecount) + copy_size = bytecount; + + /* + * Map destnation physical address. + */ + + for (i=0; i < ptes_per_vm_page; i++) + { + template.bits = M88K_TRUNC_PAGE(srcpa) | aprot | CACHE_WT | DT_VALID; + cmmu_flush_tlb(1, srcva, M88K_PGBYTES); + *srcpte = template.pte; + + srcva += offset; + bcopy((void*)srcva, (void*)dstva, copy_size); + srcpa += M88K_PGBYTES; + dstva += copy_size; + srcva += copy_size; + bytecount -= copy_size; + offset = 0; + /* cache flush source? */ + } + } +} + +/* + * Routine: PMAP_PAGEABLE + * + * History: + * '90.7.16 Fuzzy + * + * Function: + * Make the specified pages (by pmap, offset) pageable (or not) as + * requested. A page which is not pageable may not take a fault; + * therefore, its page table entry must remain valid for the duration. + * this routine is merely advisory; pmap_enter will specify that + * these pages are to be wired down (or not) as appropriate. + * + * Parameters: + * pmap pointer to pmap structure + * start virtual address of start of range + * end virtual address of end of range + * pageable flag indicating whether range is to be pageable. + * + * This routine currently does nothing in the 88100 implemetation. + */ +void +pmap_pageable(pmap_t pmap, vm_offset_t start, vm_offset_t end, + boolean_t pageable) +{ +#ifdef lint + pmap++; start++; end++; pageable++; +#endif +} /* pmap_pagealbe() */ + + + +/* + * Routine: PMAP_REDZONE + * + * Function: + * Give the kernel read-only access to the specified address. This + * is used to detect stack overflows. It is assumed that the address + * specified is the last possible kernel stack address. Therefore, we + * round up to the nearest machine dependent page. + * + * Parameters: + * pmap pointer to pmap structure + * addr virtual address of page to which access should + * be restricted to read-only + * + * Calls: + * M88K_ROUND_PAGE + * PMAP_LOCK + * pmap_pte + * PDT_VALID + * + * This function calls pmap_pte to obtain a pointer to the page + * table entry associated with the given virtual address. If there is a + * page entry, and it is valid, its write protect bit will be set. + */ +void +pmap_redzone(pmap_t pmap, vm_offset_t va) +{ + pt_entry_t *pte; + int spl, spl_sav; + int i; + unsigned users; + pte_template_t opte; + int kflush; + + va = M88K_ROUND_PAGE(va); + PMAP_LOCK(pmap, spl); + + users = 0; + if (pmap == kernel_pmap) { + kflush = 1; + } else { + kflush = 0; + } + + if ((pte = pmap_pte(pmap, va)) != PT_ENTRY_NULL && PDT_VALID(pte)) + for (i = ptes_per_vm_page; i > 0; i--) { + + /* + * Invalidate pte temporarily to avoid being written back + * the modified bit and/or the reference bit by other cpu. + */ + spl_sav = splimp(); + opte.bits = invalidate_pte(pte); + opte.pte.prot = M88K_RO; + ((pte_template_t *)pte)->bits = opte.bits; + flush_atc_entry(users, va, kflush); + splx(spl_sav); + pte++; + va +=M88K_PGBYTES; + } + + PMAP_UNLOCK(pmap, spl); + +} /* pmap_redzone() */ + + + +/* + * Routine: PMAP_CLEAR_MODIFY + * + * Function: + * Clear the modify bits on the specified physical page. + * + * Parameters: + * phys physical address of page + * + * Extern/Global: + * pv_head_table, pv_lists + * pmap_modify_list + * + * Calls: + * PMAP_MANAGED + * SPLVM, SPLX + * PFIDX + * PFIDX_TO_PVH + * CHECK_PV_LIST + * simple_lock, simple_unlock + * pmap_pte + * panic + * + * For managed pages, the modify_list entry corresponding to the + * page's frame index will be zeroed. The PV list will be traversed. + * For each pmap/va the hardware 'modified' bit in the page descripter table + * entry inspected - and turned off if necessary. If any of the + * inspected bits were found on, an TLB flush will be performed. + */ +void +pmap_clear_modify(vm_offset_t phys) +{ + pv_entry_t pvl; + int pfi; + pv_entry_t pvep; + pt_entry_t *pte; + pmap_t pmap; + int spl, spl_sav; + vm_offset_t va; + int i; + unsigned users; + pte_template_t opte; + int kflush; + + if (!PMAP_MANAGED(phys)) { +#ifdef DBG + if (pmap_con_dbg & CD_CMOD) + printf("(pmap_clear_modify :%x) phys addr 0x%x not managed \n", curproc, phys); +#endif + return; + } + + SPLVM(spl); + +clear_modify_Retry: + pfi = PFIDX(phys); + pvl = PFIDX_TO_PVH(pfi); + CHECK_PV_LIST (phys, pvl, "pmap_clear_modify"); + + /* update correspoinding pmap_modify_list element */ + pmap_modify_list[pfi] = 0; + + if (pvl->pmap == PMAP_NULL) { +#ifdef DEBUG + if ((pmap_con_dbg & (CD_CMOD | CD_NORM)) == (CD_CMOD | CD_NORM)) + printf("(pmap_clear_modify :%x) phys addr 0x%x not mapped\n", curproc, phys); +#endif + + SPLX(spl); + return; + } + + /* for each listed pmap, trun off the page modified bit */ + pvep = pvl; + while (pvep != PV_ENTRY_NULL) { + pmap = pvep->pmap; + va = pvep->va; + if (!simple_lock_try(&pmap->lock)) { + goto clear_modify_Retry; + } + + users = 0; + if (pmap == kernel_pmap) { + kflush = 1; + } else { + kflush = 0; + } + + pte = pmap_pte(pmap, va); + if (pte == PT_ENTRY_NULL) + panic("pmap_clear_modify: bad pv list entry."); + + for (i = ptes_per_vm_page; i > 0; i--) { + + /* + * Invalidate pte temporarily to avoid being written back + * the modified bit and/or the reference bit by other cpu. + */ + spl_sav = splimp(); + opte.bits = invalidate_pte(pte); + /* clear modified bit */ + opte.pte.modified = 0; + ((pte_template_t *)pte)->bits = opte.bits; + flush_atc_entry(users, va, kflush); + splx(spl_sav); + pte++; + va += M88K_PGBYTES; + } + + simple_unlock(&pmap->lock); + + pvep = pvep->next; + } + + SPLX(spl); + +} /* pmap_clear_modify() */ + + + +/* + * Routine: PMAP_IS_MODIFIED + * + * Function: + * Return whether or not the specified physical page is modified + * by any physical maps. That is, whether the hardware has + * stored data into the page. + * + * Parameters: + * phys physical address og a page + * + * Extern/Global: + * pv_head_array, pv lists + * pmap_modify_list + * + * Calls: + * simple_lock, simple_unlock + * SPLVM, SPLX + * PMAP_MANAGED + * PFIDX + * PFIDX_TO_PVH + * pmap_pte + * + * If the physical address specified is not a managed page, this + * routine simply returns TRUE (looks like it is returning FALSE XXX). + * + * If the entry in the modify list, corresponding to the given page, + * is TRUE, this routine return TRUE. (This means at least one mapping + * has been invalidated where the MMU had set the modified bit in the + * page descripter table entry (PTE). + * + * Otherwise, this routine walks the PV list corresponding to the + * given page. For each pmap/va pair, the page descripter table entry is + * examined. If a modified bit is found on, the function returns TRUE + * immediately (doesn't need to walk remainder of list). + */ +boolean_t +pmap_is_modified(vm_offset_t phys) +{ + pv_entry_t pvl; + int pfi; + pv_entry_t pvep; + pt_entry_t *ptep; + int spl; + int i; + boolean_t modified_flag; + + if (!PMAP_MANAGED(phys)) { +#ifdef DBG + if (pmap_con_dbg & CD_IMOD) + printf("(pmap_is_modified :%x) phys addr 0x%x not managed\n", curproc, phys); +#endif + return(FALSE); + } + + SPLVM(spl); + + pfi = PFIDX(phys); + pvl = PFIDX_TO_PVH(pfi); + CHECK_PV_LIST (phys, pvl, "pmap_is_modified"); +is_mod_Retry: + + if ((boolean_t) pmap_modify_list[pfi]) { + /* we've already cached a modify flag for this page, + no use looking further... */ +#ifdef DBG + if ((pmap_con_dbg & (CD_IMOD | CD_NORM)) == (CD_IMOD | CD_NORM)) + printf("(pmap_is_modified :%x) already cached a modify flag for this page\n", curproc); +#endif + SPLX(spl); + return(TRUE); + } + + if (pvl->pmap == PMAP_NULL) { + /* unmapped page - get info from page_modified array + maintained by pmap_remove_range/ pmap_remove_all */ + modified_flag = (boolean_t) pmap_modify_list[pfi]; +#ifdef DBG + if ((pmap_con_dbg & (CD_IMOD | CD_NORM)) == (CD_IMOD | CD_NORM)) + printf("(pmap_is_modified :%x) phys addr 0x%x not mapped\n", curproc, phys); +#endif + SPLX(spl); + return(modified_flag); + } + + /* for each listed pmap, check modified bit for given page */ + pvep = pvl; + while (pvep != PV_ENTRY_NULL) { + if (!simple_lock_try(&pvep->pmap->lock)) { + UNLOCK_PVH(pfi); + goto is_mod_Retry; + } + + ptep = pmap_pte(pvep->pmap, pvep->va); + if (ptep == PT_ENTRY_NULL) { + printf("pmap_is_modified: pte from pv_list not in map virt = 0x%x\n", pvep->va); + panic("pmap_is_modified: bad pv list entry"); + } + for (i = ptes_per_vm_page; i > 0; i--) { + if (ptep->modified) { + simple_unlock(&pvep->pmap->lock); +#ifdef DBG + if ((pmap_con_dbg & (CD_IMOD | CD_FULL)) == (CD_IMOD | CD_FULL)) + printf("(pmap_is_modified :%x) modified page pte@0x%x\n", curproc, (unsigned)ptep); +#endif + SPLX(spl); + return(TRUE); + } + ptep++; + } + simple_unlock(&pvep->pmap->lock); + + pvep = pvep->next; + } + + SPLX(spl); + return(FALSE); + +} /* pmap_is_modified() */ + + + +/* + * Routine: PMAP_CLEAR_REFERECE + * + * History: + * '90. 7.16 Fuzzy unchanged + * '90. 7.19 Fuzzy comment "Calls:' add + * '90. 8.21 Fuzzy Debugging message add + * '93. 3. 1 jfriedl Added call to LOCK_PVH + * + * Function: + * Clear the reference bits on the specified physical page. + * + * Parameters: + * phys physical address of page + * + * Calls: + * PMAP_MANAGED + * SPLVM, SPLX + * PFIDX + * PFIDX_TO_PVH + * CHECK_PV_LIST + * simple_lock + * pmap_pte + * panic + * + * Extern/Global: + * pv_head_array, pv lists + * + * For managed pages, the coressponding PV list will be traversed. + * For each pmap/va the hardware 'used' bit in the page table entry + * inspected - and turned off if necessary. If any of the inspected bits + * werw found on, an TLB flush will be performed. + */ +void +pmap_clear_reference(vm_offset_t phys) +{ + pv_entry_t pvl; + int pfi; + pv_entry_t pvep; + pt_entry_t *pte; + pmap_t pmap; + int spl, spl_sav; + vm_offset_t va; + int i; + unsigned users; + pte_template_t opte; + int kflush; + + if (!PMAP_MANAGED(phys)) { +#ifdef DBG + if (pmap_con_dbg & CD_CREF) { + printf("(pmap_clear_reference :%x) phys addr 0x%x not managed\n", curproc,phys); + } +#endif + return; + } + + SPLVM(spl); + +clear_reference_Retry: + pfi = PFIDX(phys); + pvl = PFIDX_TO_PVH(pfi); + CHECK_PV_LIST(phys, pvl, "pmap_clear_reference"); + + + if (pvl->pmap == PMAP_NULL) { +#ifdef DBG + if ((pmap_con_dbg & (CD_CREF | CD_NORM)) == (CD_CREF | CD_NORM)) + printf("(pmap_clear_reference :%x) phys addr 0x%x not mapped\n", curproc,phys); +#endif + SPLX(spl); + return; + } + + /* for each listed pmap, turn off the page refrenced bit */ + pvep = pvl; + while (pvep != PV_ENTRY_NULL) { + pmap = pvep->pmap; + va = pvep->va; + if (!simple_lock_try(&pmap->lock)) { + goto clear_reference_Retry; + } + + users = 0; + if (pmap == kernel_pmap) { + kflush = 1; + } else { + kflush = 0; + } + + pte = pmap_pte(pmap, va); + if (pte == PT_ENTRY_NULL) + panic("pmap_clear_reference: bad pv list entry."); + + for (i = ptes_per_vm_page; i > 0; i--) { + + /* + * Invalidate pte temporarily to avoid being written back + * the modified bit and/or the reference bit by other cpu. + */ + spl_sav = splimp(); + opte.bits = invalidate_pte(pte); + /* clear reference bit */ + opte.pte.pg_used = 0; + ((pte_template_t *)pte)->bits = opte.bits; + flush_atc_entry(users, va, kflush); + splx(spl_sav); + pte++; + va += M88K_PGBYTES; + } + + simple_unlock(&pmap->lock); + + pvep = pvep->next; + } + + SPLX(spl); + +} /* pmap_clear_reference() */ + + + +/* + * Routine: PMAP_IS_REFERENCED + * + * History: + * '90. 7.16 Fuzzy + * '90. 7.19 Fuzzy comment 'Calls:' add + * + * Function: + * Retrun whether or not the specifeid physical page is referenced by + * any physical maps. That is, whether the hardware has touched the page. + * + * Parameters: + * phys physical address of a page + * + * Extern/Global: + * pv_head_array, pv lists + * + * Calls: + * PMAP_MANAGED + * SPLVM + * PFIDX + * PFIDX_TO_PVH + * CHECK_PV_LIST + * simple_lock + * pmap_pte + * + * If the physical address specified is not a managed page, this + * routine simply returns TRUE. + * + * Otherwise, this routine walks the PV list corresponding to the + * given page. For each pmap/va/ pair, the page descripter table entry is + * examined. If a used bit is found on, the function returns TRUE + * immediately (doesn't need to walk remainder of list). + */ +boolean_t +pmap_is_referenced(vm_offset_t phys) +{ + pv_entry_t pvl; + int pfi; + pv_entry_t pvep; + pt_entry_t *ptep; + int spl; + int i; + + if (!PMAP_MANAGED(phys)) + return(FALSE); + + SPLVM(spl); + + pfi = PFIDX(phys); + pvl = PFIDX_TO_PVH(pfi); + CHECK_PV_LIST(phys, pvl, "pmap_is_referenced"); + +is_ref_Retry: + + if (pvl->pmap == PMAP_NULL) { + SPLX(spl); + return(FALSE); + } + + /* for each listed pmap, check used bit for given page */ + pvep = pvl; + while (pvep != PV_ENTRY_NULL) { + if (!simple_lock_try(&pvep->pmap->lock)) { + UNLOCK_PVH(pfi); + goto is_ref_Retry; + } + + ptep = pmap_pte(pvep->pmap, pvep->va); + if (ptep == PT_ENTRY_NULL) + panic("pmap_is_referenced: bad pv list entry."); + for (i = ptes_per_vm_page; i > 0; i--) { + if (ptep->pg_used) { + simple_unlock(&pvep->pmap->lock); + SPLX(spl); + return(TRUE); + } + ptep++; + } + simple_unlock(&pvep->pmap->lock); + + pvep = pvep->next; + } + + SPLX(spl); + return(FALSE); +} /* pmap_is referenced() */ + +/* + * Routine: PMAP_VERIFY_FREE + * + * History: + * '90. 7.17 Fuzzy This routine extract vax's pmap.c. + * This do not exit in m68k's pmap.c. + * vm_page_alloc calls this. + * Variables changed below, + * vm_first_phys --> pmap_phys_start + * vm_last_phys --> pmap_phys_end + * Macro chnged below, + * pa_index --> PFIDX + * pai_to_pvh --> PFI_TO_PVH + * + * Calls: + * SPLVM, SPLX + * PFIDX + * PFI_TO_PVH + * + * Global/Extern: + * pmap_initialized + * pmap_phys_start + * pmap_phys_end + * TRUE, FALSE + * PMAP_NULL + * + * This routine check physical address if that have pmap modules. + * It returns TRUE/FALSE. + */ + +boolean_t +pmap_verify_free(vm_offset_t phys) +{ + pv_entry_t pv_h; + int spl; + boolean_t result; + + if (!pmap_initialized) + return(TRUE); + + if (!PMAP_MANAGED(phys)) + return(FALSE); + + SPLVM(spl); + + pv_h = PFIDX_TO_PVH(PFIDX(phys)); + + result = (pv_h->pmap == PMAP_NULL); + SPLX(spl); + + return(result); + +} /* pmap_verify_free */ + + +/* + * Routine: PMAP_VALID_PAGE + * + * The physical address space is dense... there are no holes. + * All addresses provided to vm_page_startup() are valid. + */ +boolean_t +pmap_valid_page(vm_offset_t p) +{ +#ifdef lint + p++; +#endif + return(TRUE); +} /* pmap_valid_page() */ + +/* + * Routine: PMAP_PAGE_PROTECT + * + * Calls: + * pmap_copy_on_write + * pmap_remove_all + * + * Lower the permission for all mappings to a given page. + */ +void +pmap_page_protect(vm_offset_t phys, vm_prot_t prot) +{ + switch (prot) { + case VM_PROT_READ: + case VM_PROT_READ|VM_PROT_EXECUTE: + pmap_copy_on_write(phys); + break; + case VM_PROT_ALL: + break; + default: + pmap_remove_all(phys); + break; + } +} + +#if FUTURE_MAYBE +/* + * Routine: PAGEMOVE + * + * Function: + * Move pages from one kernel virtual address to another. + * + * Parameters: + * from kernel virtual address of source + * to kernel virtual address of distination + * size size in bytes + * + * Calls: + * PMAP_LOCK + * PMAP_UNLOCK + * LOCK_PVH + * UNLOCK_PVH + * CHECK_PV_LIST + * pmap_pte + * pmap_expand_kmap + * cmmu_sflush + * + * Special Assumptions: + * size must be a multiple of CLBYTES (?) + */ +void +pagemove(vm_offset_t from, vm_offset_t to, int size) +{ + vm_offset_t pa; + pt_entry_t *srcpte, *dstpte; + int pfi; + pv_entry_t pvl; + int spl; + int i; + unsigned users; + pte_template_t opte; + + PMAP_LOCK(kernel_pmap, spl); + + users = 0; + + while (size > 0) { + + /* + * check if the source addr is mapped + */ + if ((srcpte = pmap_pte(kernel_pmap, (vm_offset_t)from)) == PT_ENTRY_NULL) { + printf("pagemove: source vaddr 0x%x\n", from); + panic("pagemove: Source addr not mapped"); + } + + /* + * + */ + if ((dstpte = pmap_pte(kernel_pmap, (vm_offset_t)to)) == PT_ENTRY_NULL) + if ((dstpte = pmap_expand_kmap((vm_offset_t)to, VM_PROT_READ | VM_PROT_WRITE)) + == PT_ENTRY_NULL) + panic("pagemove: Cannot allocate distination pte"); + /* + * + */ + if (dstpte->dtype == DT_VALID) { + printf("pagemove: distination vaddr 0x%x, pte = 0x%x\n", to, *((unsigned *)dstpte)); + panic("pagemove: Distination pte already valid"); + } + +#ifdef DEBUG + if ((pmap_con_dbg & (CD_PGMV | CD_NORM)) == (CD_PGMV | CD_NORM)) + printf("(pagemove :%x) from 0x%x to 0x%x\n", curproc, from, to); + if ((pmap_con_dbg & (CD_PGMV | CD_FULL)) == (CD_PGMV | CD_FULL)) + printf("(pagemove :%x) srcpte @ 0x%x = %x dstpte @ 0x%x = %x\n", curproc, (unsigned)srcpte, *(unsigned *)srcpte, (unsigned)dstpte, *(unsigned *)dstpte); + +#endif /* DEBUG */ + + /* + * Update pv_list + */ + pa = M88K_PTOB(srcpte->pfn); + if (PMAP_MANAGED(pa)) { + pfi = PFIDX(pa); + pvl = PFIDX_TO_PVH(pfi); + CHECK_PV_LIST(pa, pvl, "pagemove"); + pvl->va = (vm_offset_t)to; + } + + /* + * copy pte + */ + for (i = ptes_per_vm_page; i > 0; i--) { + /* + * Invalidate pte temporarily to avoid being written back + * the modified bit and/or the reference bit by other cpu. + */ + opte.bits = invalidate_pte(srcpte); + flush_atc_entry(users, from, 1); + ((pte_template_t *)dstpte)->bits = opte.bits; + from += M88K_PGBYTES; + to += M88K_PGBYTES; + srcpte++; dstpte++; + } + size -= PAGE_SIZE; + } + + PMAP_UNLOCK(kernel_pmap, spl); + +} /* pagemove */ + +#endif /* FUTURE_MAYBE */ +/* + * Routine: icache_flush + * + * Function: + * Invalidate instruction cache for all CPUs on specified + * physical address. Called when a page is removed from a + * vm_map. This is done because the Instruction CMMUs are not + * snooped, and if a page is subsequently used as a text page, + * we want the CMMUs to re-load the cache for the page. + * + * Parameters: + * pa physical address of the (vm) page + * + * Extern/globals: + * ptes_per_vm_page + * + * Calls: + * cachefall + * + * Called by: + * vm_remove_page + * + */ +void +icache_flush(vm_offset_t pa) +{ + int i; + int cpu = 0; + + for (i = ptes_per_vm_page; i > 0; i--, pa += M88K_PGBYTES) { + cmmu_flush_remote_inst_cache(cpu, pa, M88K_PGBYTES); + } + +} /* icache_flush */ + +/* + * Routine: pmap_dcache_flush + * + * Function: + * Flush DATA cache on specified virtual address. + * + * Parameters: + * pmap specify pmap + * va virtual address of the (vm) page to be flushed + * + * Extern/globals: + * pmap_pte + * ptes_per_vm_page + * + * Calls: + * dcacheflush + * + */ +void +pmap_dcache_flush(pmap_t pmap, vm_offset_t va) +{ + vm_offset_t pa; + int i; + int spl; + + if (pmap == PMAP_NULL) + panic("pmap_dcache_flush: pmap is NULL"); + + PMAP_LOCK(pmap, spl); + + pa = M88K_PTOB((pmap_pte(pmap, va))->pfn); + for (i = ptes_per_vm_page; i > 0; i--, pa += M88K_PGBYTES) { + cmmu_flush_data_cache(pa, M88K_PGBYTES); + } + + PMAP_UNLOCK(pmap, spl); + + +} /* pmap_dcache_flush */ + +STATIC void +cache_flush_loop(int mode, vm_offset_t pa, int size) +{ + int i; + int ncpus; + void (*cfunc)(int cpu, vm_offset_t physaddr, int size); + + switch (mode) { + default: + panic("bad cache_flush_loop mode"); + return; + + case FLUSH_CACHE: /* All caches, all CPUs */ + ncpus = NCPUS; + cfunc = cmmu_flush_remote_cache; + break; + + case FLUSH_CODE_CACHE: /* Instruction caches, all CPUs */ + ncpus = NCPUS; + cfunc = cmmu_flush_remote_inst_cache; + break; + + case FLUSH_DATA_CACHE: /* Data caches, all CPUs */ + ncpus = NCPUS; + cfunc = cmmu_flush_remote_data_cache; + break; + + case FLUSH_LOCAL_CACHE: /* Both caches, my CPU */ + ncpus = 1; + cfunc = cmmu_flush_remote_cache; + break; + + case FLUSH_LOCAL_CODE_CACHE: /* Instruction cache, my CPU */ + ncpus = 1; + cfunc = cmmu_flush_remote_inst_cache; + break; + + case FLUSH_LOCAL_DATA_CACHE: /* Data cache, my CPU */ + ncpus = 1; + cfunc = cmmu_flush_remote_data_cache; + break; + } + + if (ncpus == 1) { + (*cfunc)(cpu_number(), pa, size); + } + else { + for (i=0; i<NCPUS; i++) { + (*cfunc)(i, pa, size); + } + } +} + +/* + * pmap_cache_flush + * Internal function. + */ +void +pmap_cache_flush(pmap_t pmap, vm_offset_t virt, int bytes, int mode) +{ + vm_offset_t pa; + vm_offset_t va; + int i; + int spl; + + if (pmap == PMAP_NULL) + panic("pmap_dcache_flush: NULL pmap"); + + /* + * If it is more than a couple of pages, just blow the whole cache + * because of the number of cycles involved. + */ + if (bytes > 2*M88K_PGBYTES) { + cache_flush_loop(mode, 0, -1); + return; + } + + PMAP_LOCK(pmap, spl); + for(va = virt; bytes > 0; bytes -= M88K_PGBYTES,va += M88K_PGBYTES) { + pa = M88K_PTOB((pmap_pte(pmap, va))->pfn); + for (i = ptes_per_vm_page; i > 0; i--, pa += M88K_PGBYTES) { + cache_flush_loop(mode, pa, M88K_PGBYTES); + } + } + PMAP_UNLOCK(pmap, spl); +} /* pmap_cache_flush */ + +#ifdef DEBUG +/* + * DEBUGGING ROUTINES - check_pv_list and check_pmp_consistency are used + * only for debugging. They are invoked only + * through the macros CHECK_PV_LIST AND CHECK_PMAP_CONSISTENCY + * defined early in this sourcefile. + */ + +/* + * Routine: CHECK_PV_LIST (internal) + * + * Function: + * Debug-mode routine to check consistency of a PV list. First, it + * makes sure every map thinks the physical page is the same. This + * should be called by all routines which touch a PV list. + * + * Parameters: + * phys physical address of page whose PV list is + * to be checked + * pv_h pointer to head to the PV list + * who string containing caller's name to be + * printed if a panic arises + * + * Extern/Global: + * pv_head_array, pv lists + * + * Calls: + * pmap_extract + * + * Special Assumptions: + * No locking is required. + * + * This function walks the given PV list. For each pmap/va pair, + * pmap_extract is called to obtain the physical address of the page from + * the pmap in question. If the retruned physical address does not match + * that for the PV list being perused, the function panics. + */ + +STATIC void +check_pv_list(vm_offset_t phys, pv_entry_t pv_h, char *who) +{ + pv_entry_t pv_e; + pt_entry_t *pte; + vm_offset_t pa; + + if (pv_h != PFIDX_TO_PVH(PFIDX(phys))) { + printf("check_pv_list: incorrect pv_h supplied.\n"); + panic(who); + } + + if (!PAGE_ALIGNED(phys)) { + printf("check_pv_list: supplied phys addr not page aligned.\n"); + panic(who); + } + + if (pv_h->pmap == PMAP_NULL) { + if (pv_h->next != PV_ENTRY_NULL) { + printf("check_pv_list: first entry has null pmap, but list non-empty.\n"); + panic(who); + } + else return; /* proper empry lst */ + } + + pv_e = pv_h; + while (pv_e != PV_ENTRY_NULL) { + if (!PAGE_ALIGNED(pv_e->va)) { + printf("check_pv_list: non-aligned VA in entry at 0x%x.\n", pv_e); + panic(who); + } + /* + * We can't call pmap_extract since it requires lock. + */ + if ((pte = pmap_pte(pv_e->pmap, pv_e->va)) == PT_ENTRY_NULL) + pa = (vm_offset_t)0; + else + pa = M88K_PTOB(pte->pfn) | (pv_e->va & M88K_PGOFSET); + + if (pa != phys) { + printf("check_pv_list: phys addr diff in entry at 0x%x.\n", pv_e); + panic(who); + } + + pv_e = pv_e->next; + } + +} /* check_pv_list() */ + +/* + * Routine: CHECK_MAP (itnernal) + * + * Function: + * Debug mode routine to check consistency of map. + * Called by check_pmap_consistency only. + * + * Parameters: + * map pointer to pmap structure + * s start of range to be checked + * e end of range to be checked + * who string containing caller's name to be + * printed if a panic arises + * + * Extern/Global: + * pv_head_array, pv lists + * + * Calls: + * pmap_pte + * + * Special Assumptions: + * No locking required. + * + * This function sequences through the given range of addresses. For + * each page, pmap_pte is called to obtain the page table entry. If + * its valid, and the physical page it maps is managed, the PV list is + * searched for the corresponding pmap/va entry. If not found, the + * function panics. If duplicate PV list entries are found, the function + * panics. + */ + +STATIC void +check_map(pmap_t map, vm_offset_t s, vm_offset_t e, char *who) +{ + vm_offset_t va, + old_va, + phys; + pv_entry_t pv_h, + pv_e, + saved_pv_e; + pt_entry_t *ptep; + boolean_t found; + int loopcnt; + + + /* + * for each page in the address space, check to see if there's + * a valid mapping. If so makes sure it's listed in the PV_list. + */ + + if ((pmap_con_dbg & (CD_CHKM | CD_NORM)) == (CD_CHKM | CD_NORM)) + printf("(check_map) checking map at 0x%x\n", map); + + old_va = s; + for (va = s; va < e; va += PAGE_SIZE) { + /* check for overflow - happens if e=0xffffffff */ + if (va < old_va) + break; + else + old_va = va; + + if (va == phys_map_vaddr1 || va == phys_map_vaddr2) + /* don't try anything with these */ + continue; + + ptep = pmap_pte(map, va); + + if (ptep == PT_ENTRY_NULL) { + /* no page table, skip to next segment entry */ + va = SDT_NEXT(va)-PAGE_SIZE; + continue; + } + + if (!PDT_VALID(ptep)) + continue; /* no page mapping */ + + phys = M88K_PTOB(ptep->pfn); /* pick up phys addr */ + + if (!PMAP_MANAGED(phys)) + continue; /* no PV list */ + + /* note: vm_page_startup allocates some memory for itself + through pmap_map before pmap_init is run. However, + it doesn't adjust the physical start of memory. + So, pmap thinks those pages are managed - but they're + not actually under it's control. So, the following + conditional is a hack to avoid those addresses + reserved by vm_page_startup */ + /* pmap_init also allocate some memory for itself. */ + + if (map == kernel_pmap && + va < round_page((vm_offset_t)(pmap_modify_list + (pmap_phys_end - pmap_phys_start)))) + continue; + + pv_h = PFIDX_TO_PVH(PFIDX(phys)); + found = FALSE; + + if (pv_h->pmap != PMAP_NULL) { + + loopcnt = 10000; /* loop limit */ + pv_e = pv_h; + while(pv_e != PV_ENTRY_NULL) { + + if (loopcnt-- < 0) { + printf("check_map: loop in PV list at PVH 0x%x (for phys 0x%x)\n", pv_h, phys); + panic(who); + } + + if (pv_e->pmap == map && pv_e->va == va) { + if (found) { + printf("check_map: Duplicate PV list entries at 0x%x and 0x%x in PV list 0x%x.\n", saved_pv_e, pv_e, pv_h); + printf("check_map: for pmap 0x%x, VA 0x%x,phys 0x%x.\n", map, va, phys); + panic(who); + } + else { + found = TRUE; + saved_pv_e = pv_e; + } + } + pv_e = pv_e->next; + } + } + + if (!found) { + printf("check_map: Mapping for pmap 0x%x VA 0x%x Phys 0x%x does not appear in PV list 0x%x.\n", map, va, phys, pv_h); + } + } + + if ((pmap_con_dbg & (CD_CHKM | CD_NORM)) == (CD_CHKM | CD_NORM)) + printf("(check_map) done \n"); + +} /* check_map() */ + +/* + * Routine: CHECK_PMAP_CONSISTENCY (internal) + * + * Function: + * Debug mode routine which walks all pmap, checking for internal + * consistency. We are called UNLOCKED, so we'll take the write + * lock. + * + * Parameters: + * who string containing caller's name tobe + * printed if a panic arises + * + * Extern/Global: + * list of pmap structures + * + * Calls: + * check map + * check pv_list + * + * This function obtains the pmap write lock. Then, for each pmap + * structure in the pmap struct queue, it calls check_map to verify the + * consistency of its translation table hierarchy. + * + * Once all pmaps have been checked, check_pv_list is called to check + * consistency of the PV lists for each managed page. + * + * NOTE: Added by Sugai 10/29/90 + * There are some pages do not appaer in PV list. These pages are + * allocated for pv structures by kmem_alloc called in pmap_init. + * Though they are in the range of pmap_phys_start to pmap_phys_end, + * PV maniupulations had not been activated when these pages were alloceted. + * + */ + +STATIC void +check_pmap_consistency(char *who) +{ + pmap_t p; + int i; + vm_offset_t phys; + pv_entry_t pv_h; + int spl; + + if ((pmap_con_dbg & (CD_CHKPM | CD_NORM)) == (CD_CHKPM | CD_NORM)) + printf("check_pmap_consistency (%s :%x) start.\n", who, curproc); + + if (pv_head_table == PV_ENTRY_NULL) { + + printf("check_pmap_consistency (%s) PV head table not initialized.\n", who); + return; + } + + SPLVM(spl); + + p = kernel_pmap; + check_map(p, VM_MIN_KERNEL_ADDRESS, VM_MAX_KERNEL_ADDRESS, who); + + /* run through all pmaps. check consistency of each one... */ + i = PMAP_MAX; + for (p = kernel_pmap->next;p != kernel_pmap; p = p->next) { + if (i == 0) { /* can not read pmap list */ + printf("check_pmap_consistency: pmap strcut loop error.\n"); + panic(who); + } + check_map(p, VM_MIN_USER_ADDRESS, VM_MAX_USER_ADDRESS, who); + } + + /* run through all managed paes, check pv_list for each one */ + for (phys = pmap_phys_start; phys < pmap_phys_end; phys += PAGE_SIZE) { + pv_h = PFIDX_TO_PVH(PFIDX(phys)); + check_pv_list(phys, pv_h, who); + } + + SPLX(spl); + + if ((pmap_con_dbg & (CD_CHKPM | CD_NORM)) == (CD_CHKPM | CD_NORM)) + printf("check_pmap consistency (%s :%x): done.\n",who, curproc); + +} /* check_pmap_consistency() */ +#endif /* DEBUG */ + +/* + * PMAP PRINT MACROS AND ROUTINES FOR DEBUGGING + * These routines are called only from the debugger. + */ + +#define PRINT_SDT(p) \ + printf("%08x : ", \ + ((sdt_entry_template_t *)p)-> bits); \ + printf("table adress=0x%x, prot=%d, dtype=%d\n", \ + M88K_PTOB(p->table_addr), \ + p->prot, \ + p->dtype); + +#define PRINT_PDT(p) \ + printf("%08x : ", \ + ((pte_template_t *)p)-> bits); \ + printf("frame num=0x%x, prot=%d, dtype=%d, wired=%d, modified=%d, pg_used=%d\n", \ + p->pfn, \ + p->prot, \ + p->dtype, \ + p->wired, \ + p->modified, \ + p->pg_used); + +/* + * Routine: PMAP_PRINT + * + * History: + * + * Function: + * Print pmap stucture, including segment table. + * + * Parameters: + * pmap pointer to pmap structure + * + * Special Assumptions: + * No locking required. + * + * This function prints the fields of the pmap structure, then + * iterates through the segment translation table, printing each entry. + */ +void +pmap_print(pmap_t pmap) +{ + sdt_entry_t *sdtp; + sdt_entry_t *sdtv; + int i; + + printf("Pmap @ 0x%x:\n", (unsigned)pmap); + sdtp = pmap->sdt_paddr; + sdtv = pmap->sdt_vaddr; + printf(" sdt_paddr: 0x%x; sdt_vaddr: 0x%x; ref_count: %d;\n", + (unsigned)sdtp, (unsigned)sdtv, + pmap->ref_count); + +#ifdef statistics_not_yet_maintained + printf(" statistics: pagesize %d: free_count %d; " + "active_count %d; inactive_count %d; wire_count %d\n", + pmap->stats.pagesize, + pmap->stats.free_count, + pmap->stats.active_count, + pmap->stats.inactive_count, + pmap->stats.wire_count); + + printf(" zero_fill_count %d; reactiveations %d; " + "pageins %d; pageouts %d; faults %d\n", + pmap->stats.zero_fill_count, + pmap->stats.reactivations, + pmap->stats.pageins, + pmap->stats.pageouts, + pmap->stats.fault); + + printf(" cow_faults %d, lookups %d, hits %d\n", + pmap->stats.cow_faults, + pmap->stats.loopups, + pmap->stats.faults); +#endif + + sdtp = (sdt_entry_t *) pmap->sdt_vaddr; /* addr of physical table */ + sdtv = sdtp + SDT_ENTRIES; /* shadow table with virt address */ + if (sdtp == (sdt_entry_t *)0) + printf("Error in pmap - sdt_paddr is null.\n"); + else { + int count = 0; + printf(" Segment table at 0x%x (0x%x):\n", + (unsigned)sdtp, (unsigned)sdtv); + for (i = 0; i < SDT_ENTRIES; i++, sdtp++, sdtv++) { + if ((sdtp->table_addr != 0 ) || (sdtv->table_addr != 0)) { + if (count != 0) + printf("sdt entry %d skip !!\n", count); + count = 0; + printf(" (%x)phys: ", i); + PRINT_SDT(sdtp); + printf(" (%x)virt: ", i); + PRINT_SDT(sdtv); + } + else + count++; + } + if (count != 0) + printf("sdt entry %d skip !!\n", count); + } + +} /* pmap_print() */ + +/* + * Routine: PMAP_PRINT_TRACE + * + * Function: + * Using virt addr, derive phys addr, printing pmap tables along the way. + * + * Parameters: + * pmap pointer to pmap strucuture + * va virtual address whose translation is to be trace + * long_format flag indicating long from output is desired + * + * Special Assumptions: + * No locking required. + * + * This function chases down through the translation tree as + * appropriate for the given virtual address. each table entry + * encoutered is printed. If the long_format is desired, all entries of + * each table are printed, with special indication of the entries used in + * the translation. + */ +void +pmap_print_trace (pmap_t pmap, vm_offset_t va, boolean_t long_format) +{ + sdt_entry_t *sdtp; /* ptr to sdt table of physical addresses */ + sdt_entry_t *sdtv; /* ptr to sdt shadow table of virtual addresses */ + pt_entry_t *ptep; /* ptr to pte table of physical page addresses */ + + int i; /* table loop index */ + unsigned long prev_entry; /* keep track of value of previous table entry */ + int n_dup_entries; /* count contiguous duplicate entries */ + + printf("Trace of virtual address 0x%08x. Pmap @ 0x%08x.\n", + va, (unsigned)pmap); + + /*** SDT TABLES ***/ + /* get addrs of sdt tables */ + sdtp = (sdt_entry_t *)pmap->sdt_vaddr; + sdtv = sdtp + SDT_ENTRIES; + + if (sdtp == SDT_ENTRY_NULL) { + printf(" Segment table pointer (pmap.sdt_paddr) null, trace stops.\n"); + return; + } + + n_dup_entries = 0; + prev_entry = 0xFFFFFFFF; + + if (long_format) { + printf(" Segment table at 0x%08x (virt shadow at 0x%08x)\n", + (unsigned)sdtp, (unsigned)sdtv); + for (i = 0; i < SDT_ENTRIES; i++, sdtp++, sdtv++) { + if (prev_entry == ((sdt_entry_template_t *)sdtp)->bits + && SDTIDX(va) != i && i != SDT_ENTRIES-1) { + n_dup_entries++; + continue; /* suppress duplicate entry */ + } + if (n_dup_entries != 0) { + printf(" - %d duplicate entries skipped -\n",n_dup_entries); + n_dup_entries = 0; + } + prev_entry = ((pte_template_t *)sdtp)->bits; + if (SDTIDX(va) == i) { + printf(" >> (%x)phys: ", i); + } else { + printf(" (%x)phys: ", i); + } + PRINT_SDT(sdtp); + if (SDTIDX(va) == i) { + printf(" >> (%x)virt: ", i); + } else { + printf(" (%x)virt: ", i); + } + PRINT_SDT(sdtv); + } /* for */ + } else { + /* index into both tables for given VA */ + sdtp += SDTIDX(va); + sdtv += SDTIDX(va); + printf(" SDT entry index 0x%x at 0x%x (virt shadow at 0x%x)\n", + SDTIDX(va), (unsigned)sdtp, (unsigned)sdtv); + printf(" phys: "); + PRINT_SDT(sdtp); + printf(" virt: "); + PRINT_SDT(sdtv); + } + + /*** PTE TABLES ***/ + /* get addrs of page (pte) table (no shadow table) */ + + sdtp = ((sdt_entry_t *)pmap->sdt_vaddr) + SDTIDX(va); + #ifdef DBG + printf("*** DEBUG (sdtp) "); + PRINT_SDT(sdtp); + #endif + sdtv = sdtp + SDT_ENTRIES; + ptep = (pt_entry_t *)(M88K_PTOB(sdtv->table_addr)); + if (sdtp->dtype != DT_VALID) { + printf(" segment table entry invlid, trace stops.\n"); + return; + } + + n_dup_entries = 0; + prev_entry = 0xFFFFFFFF; + if (long_format) { + printf(" page table (ptes) at 0x%x\n", (unsigned)ptep); + for (i = 0; i < PDT_ENTRIES; i++, ptep++) { + if (prev_entry == ((pte_template_t *)ptep)->bits + && PDTIDX(va) != i && i != PDT_ENTRIES-1) { + n_dup_entries++; + continue; /* suppress suplicate entry */ + } + if (n_dup_entries != 0) { + printf(" - %d duplicate entries skipped -\n",n_dup_entries); + n_dup_entries = 0; + } + prev_entry = ((pte_template_t *)ptep)->bits; + if (PDTIDX(va) == i) { + printf(" >> (%x)pte: ", i); + } else { + printf(" (%x)pte: ", i); + } + PRINT_PDT(ptep); + } /* for */ + } else { + /* index into page table */ + ptep += PDTIDX(va); + printf(" pte index 0x%x\n", PDTIDX(va)); + printf(" pte: "); + PRINT_PDT(ptep); + } +} /* pmap_print_trace() */ + +/* + * Check whether the current transaction being looked at by dodexc() + * could have been the one that caused a fault. Given the virtual + * address, map, and transaction type, checks whether the page at that + * address is valid, and, for write transactions, whether it has write + * permission. + */ +boolean_t +pmap_check_transaction(pmap_t pmap, vm_offset_t va, vm_prot_t type) +{ + pt_entry_t *pte; + sdt_entry_t *sdt; + int spl; + + PMAP_LOCK(pmap, spl); + + if ((pte = pmap_pte(pmap, va)) == PT_ENTRY_NULL) { + PMAP_UNLOCK(pmap, spl); + return FALSE; + } + + if (!PDT_VALID(pte)) { + PMAP_UNLOCK(pmap, spl); + return FALSE; + } + + /* + * Valid pte. If the transaction was a read, there is no way it + * could have been a fault, so return true. For now, assume + * that a write transaction could have caused a fault. We need + * to check pte and sdt entries for write permission to really + * tell. + */ + + if (type == VM_PROT_READ) { + PMAP_UNLOCK(pmap, spl); + return TRUE; + } else { + sdt = SDTENT(pmap,va); + if (sdt->prot || pte->prot) { + PMAP_UNLOCK(pmap, spl); + return FALSE; + } else { + PMAP_UNLOCK(pmap, spl); + return TRUE; + } + } +} + +/* New functions to satisfy rpd - contributed by danner */ + +void +pmap_virtual_space(vm_offset_t *startp, vm_offset_t *endp) +{ + *startp = virtual_avail; + *endp = virtual_end; +} + +unsigned int +pmap_free_pages(void) +{ + return atop(avail_end - avail_next); +} + +boolean_t +pmap_next_page(vm_offset_t *addrp) +{ + if (avail_next == avail_end) + return FALSE; + + *addrp = avail_next; + avail_next += PAGE_SIZE; + return TRUE; +} + +#if USING_BATC +#ifdef OMRON_PMAP +/* + * Set BATC + */ +void +pmap_set_batc( + pmap_t pmap, + boolean_t data, + int i, + vm_offset_t va, + vm_offset_t pa, + boolean_t super, + boolean_t wt, + boolean_t global, + boolean_t ci, + boolean_t wp, + boolean_t valid) +{ + register batc_template_t batctmp; + + if (i < 0 || i > (BATC_MAX - 1)) { + panic("pmap_set_batc: illegal batc number\n"); + /* bad number */ + return; + } + + batctmp.field.lba = va >> 19; + batctmp.field.pba = pa >> 19; + batctmp.field.sup = super; + batctmp.field.wt = wt; + batctmp.field.g = global; + batctmp.field.ci = ci; + batctmp.field.wp = wp; + batctmp.field.v = valid; + + if (data) { + pmap->d_batc[i].bits = batctmp.bits; + } else { + pmap->i_batc[i].bits = batctmp.bits; + } +} + +void use_batc( + task_t task, + boolean_t data, /* for data-cmmu ? */ + int i, /* batc number */ + vm_offset_t va, /* virtual address */ + vm_offset_t pa, /* physical address */ + boolean_t s, /* for super-mode ? */ + boolean_t wt, /* is writethrough */ + boolean_t g, /* is global ? */ + boolean_t ci, /* is cache inhibited ? */ + boolean_t wp, /* is write-protected ? */ + boolean_t v) /* is valid ? */ +{ + pmap_t pmap; + pmap = vm_map_pmap(task->map); + pmap_set_batc(pmap, data, i, va, pa, s, wt, g, ci, wp, v); +} + +#endif +#endif /* USING_BATC */ +#if FUTURE_MAYBE +/* + * Machine-level page attributes + * + * The only attribute that may be controlled right now is cacheability. + * + * Obviously these attributes will be used in a sparse + * fashion, so we use a simple sorted list of address ranges + * which possess the attribute. + */ + +/* + * Destroy an attribute list. + */ +void +pmap_destroy_ranges(pmap_range_t *ranges) +{ + pmap_range_t this, next; + + this = *ranges; + while (this != 0) { + next = this->next; + pmap_range_free(this); + this = next; + } + *ranges = 0; +} + +/* + * Lookup an address in a sorted range list. + */ +boolean_t +pmap_range_lookup(pmap_range_t *ranges, vm_offset_t address) +{ + pmap_range_t range; + + for (range = *ranges; range != 0; range = range->next) { + if (address < range->start) + return FALSE; + if (address < range->end) + return TRUE; + } + return FALSE; +} + +/* + * Add a range to a list. + * The pmap must be locked. + */ +void +pmap_range_add(pmap_range_t *ranges, vm_offset_t start, vm_offset_t end) +{ + pmap_range_t range, *prev; + + /* look for the start address */ + + for (prev = ranges; (range = *prev) != 0; prev = &range->next) { + if (start < range->start) + break; + if (start <= range->end) + goto start_overlaps; + } + + /* start address is not present */ + + if ((range == 0) || (end < range->start)) { + /* no overlap; allocate a new range */ + + range = pmap_range_alloc(); + range->start = start; + range->end = end; + range->next = *prev; + *prev = range; + return; + } + + /* extend existing range forward to start */ + + range->start = start; + + start_overlaps: + assert((range->start <= start) && (start <= range->end)); + + /* delete redundant ranges */ + + while ((range->next != 0) && (range->next->start <= end)) { + pmap_range_t old; + + old = range->next; + range->next = old->next; + range->end = old->end; + pmap_range_free(old); + } + + /* extend existing range backward to end */ + + if (range->end < end) + range->end = end; +} + +/* + * Remove a range from a list. + * The pmap must be locked. + */ +void +pmap_range_remove(pmap_range_t *ranges, vm_offset_t start, vm_offset_t end) +{ + pmap_range_t range, *prev; + + /* look for start address */ + + for (prev = ranges; (range = *prev) != 0; prev = &range->next) { + if (start <= range->start) + break; + if (start < range->end) { + if (end < range->end) { + pmap_range_t new; + + /* split this range */ + + new = pmap_range_alloc(); + new->next = range->next; + new->start = end; + new->end = range->end; + + range->next = new; + range->end = start; + return; + } + + /* truncate this range */ + + range->end = start; + } + } + + /* start address is not in the middle of a range */ + + while ((range != 0) && (range->end <= end)) { + *prev = range->next; + pmap_range_free(range); + range = *prev; + } + + if ((range != 0) && (range->start < end)) + range->start = end; +} +#endif /* FUTURE_MAYBE */ diff --git a/sys/arch/mvme88k/mvme88k/process.S b/sys/arch/mvme88k/mvme88k/process.S new file mode 100644 index 00000000000..38db2e85b6f --- /dev/null +++ b/sys/arch/mvme88k/mvme88k/process.S @@ -0,0 +1,338 @@ +/* + * Copyright (c) 1996 Nivas Madhur + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by Nivas Madhur. + * 4. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ +#ifndef ASSEMBLER +#define ASSEMBLER +#endif + +#include "machine/asm.h" +#include "machine/psl.h" + +#ifndef NBPG +#define NBPG 4096 +#endif /* NBPG */ + + data + align 4 +Lsw0: + string "cpu_switch\n" + align 4 +swchanpanic: + string "switch wchan %x\n" + align 4 +swsrunpanic: + string "switch SRUN %x\n" + + text + align 8 +Lswchanpanic: + or.u r2, r0, hi16(swchanpanic) + or r2, r2, lo16(swchanpanic) + or r3, r0, r9 + bsr _panic + +Lswsrunpanic: + or.u r2, r0, hi16(swsrunpanic) + or r2, r2, lo16(swsrunpanic) + or r3, r0, r9 + bsr _panic +/* + * At exit of a process, do a cpu_switch for the last time. + * The mapping of the pcb at p->p_addr has already been deleted, + * and the memory for the pcb+stack has been freed. + * The ipl is high enough to prevent the memory from being reallocated. + */ + +ENTRY(switch_exit) + /* + * Change pcb to idle u. area, i.e., set r31 to top of stack + * and set curpcb to point to _idle_u. + */ + or.u r30, r0, hi16(_idle_u) + or r30, r30,lo16(_idle_u) + addu r31, r30, UPAGES * NBPG /* now on idle_u stack */ + or.u r10, r0, hi16(_curpcb) + st r30, r10,lo16(_curpcb) /* curpcb = &idle_u */ + or.u r10, r0, hi16(_curproc) + st r0, r10, lo16(_curproc) /* curproc = NULL */ + bsr.n _cpu_switch + or r2, r0, r10 + +#if 0 +/* + * When no processes are on the runq, switch + * idles here watiing for something to come ready. + */ +LABEL(idle) + or.u r10, r0, hi16(_curproc) + st r0, r10, lo16(_curproc) /* curproc = NULL */ + + bsr.n _setipl /* unblock all interrupts */ + or r2, r0, 0 + /* spin reading whichqs until != 0 */ +1: + or.u r10, r0, hi16(_whichqs) + ld r11, r10,lo16(_whichqs) + bcnd eq0, r11, 1b + bsr.n _setipl + or r2, r0, IPL_HIGH /* block all ints */ + br Lsw1 +#endif /* 0 */ +/* + * cpu_switch() + * XXX - Arg 1 is a proc pointer (curproc) but this doesn't use it. + * XXX - how about using stack for saving spl and last proc? + * XXX rewrite this whole mess in C nivas + */ +ENTRY(cpu_switch) + + /* + * Save state of previous process in its pcb. + */ + + or.u r10, r0, hi16(_curpcb) + ld r10,r10, lo16(_curpcb) + st r1, r10, PCB_PC /* save r1 in pcb */ + st.d r14,r10, PCB_R14 + st.d r16,r10, PCB_R16 + st.d r18,r10, PCB_R18 + st.d r20,r10, PCB_R20 + st.d r22,r10, PCB_R22 + st.d r24,r10, PCB_R24 + st.d r26,r10, PCB_R26 + st.d r28,r10, PCB_R28 + st.d r30,r10, PCB_R30 /* save frame pointer & stack pointer */ + + or r14,r10, 0 /* save r10 in r14 */ + + bsr _getipl + + st r2, r14, PCB_IPL /* save ipl in pcb */ + + or.u r11, r0, hi16(_curproc) + ld r11,r11, lo16(_curproc) + + or.u r12, r0, hi16(_lastproc) + st r11, r12, lo16(_lastproc)/* lastproc = curproc */ + + or.u r11, r0, hi16(_curproc) + st r0, r11, lo16(_curproc) /* curproc = NULL */ + + or.u r11, r0, hi16(_curpcb) + st r0, r11, lo16(_curpcb) /* curpcb = NULL */ + +Lidleloop: + + /* + * Find the highest-priority queue that isn't empty, + * then take the first proc from that queue. + */ + + or.u r7, r0, hi16(_whichqs) + ld r7, r7, lo16(_whichqs) + + bcnd ne0, r7, Ldoneloop + +Lloopchk: /* if whichqs is zero, keep checking */ + bsr.n _setipl /* enable all ints */ + or r2, r0, 0 + + br Lidleloop + +Ldoneloop: + + bsr.n _setipl /* disable ints */ + or r2, r0, IPL_HIGH + + or.u r7, r0, hi16(_whichqs) /* reload whichqs */ + ld r7, r7, lo16(_whichqs) + + bcnd eq0, r7, Lloopchk /* keep spinning for whichqs to be !=0*/ + + xor r6, r6, r6 /* set r6 to 0 */ + 1: bb1 0, r7, 2f /* if rightmost bit set, done */ + extu r7, r7, 0<1> /* else, right shift whichqs, */ + br.n 1b /* increment r6, and repeat */ + addu r6, r6, 1 + 2: + or.u r7, r0, hi16(_qs) + or r7, r7, lo16(_qs) + + /* + * Need to make + * p->p_forw->p_back = p->p_back and + * p->p_back->p_forw = p->p_forw where + * p is q->p_forw. + * Remember that q->p_forw == p and p->p_back == q. + */ + + lda.d r8, r7[r6] /* r8 = &qs[ff1(whichqs)] */ + ld r9, r8, P_FORW /* r8 is q, r9 is p */ + + ld r12, r9, P_FORW /* r12 = p->p_forw */ + st r8, r12, P_BACK /* p->p_forw->p_back = q (p->p_back) */ + st r12, r8, P_FORW /* q->p_forw = p->p_forw */ + lda.d r8, r7[r6] /* reload r8 with qs[ff1(whichqs)] */ + ld r12, r8, P_FORW /* q->p_forw */ + cmp r12, r12, r8 /* q == q->p_forw; anyone left on queue? */ + bb1 ne, r12, Lsw2 /* yes, skip clearing bit in whichqs */ + + or r12, r0, 1 /* r12 is 1 now */ + 1:bcnd eq0, r6, 2f + mak r12, r12, 0<1> /* shift left by 1 */ + br.n 1b + subu r6, r6, 1 /* keep doing this while r6 != 0 */ + 2: + /* + * NOTE: we could have just used "mak r12, r12, r6" instead of the + * loop above. But that will break if NQS is made > 32. I can use + * preprocessor to do the right thing, but that means I have to + * include sys/proc.h in this file. XXX nivas + */ + or.u r7, r0, hi16(_whichqs) + ld r8, r7, lo16(_whichqs) + and.c r8, r8, r12 /* whichqs &= ~the bit */ + st r8, r7, lo16(_whichqs) /* reset bit in whichqs */ +Lsw2: + ld r2, r9, P_WCHAN + bcnd ne0, r2, Lswchanpanic + ld.b r2, r9, P_STAT + cmp r2, r2, SRUN + bb1 ne, r2, Lswsrunpanic + + or.u r11, r0, hi16(_want_resched) + st r0, r11, lo16(_want_resched) /* clear want_resched */ + + or.u r11, r0, hi16(_curproc) + st r9, r11,lo16(_curproc) /* curproc = p */ + +#ifdef notyet + or.u r2, r0, hi16(_lastproc) + ld r2, r2, lo16(_lastproc) +#endif /* notyet */ + + /* huh??? */ + or.u r10, r0, hi16(_curpcb) + ld r10,r10, lo16(_curpcb) + +#ifdef notyet + cmp r2, r2, r9 + bb1 eq, r2, Lswsameproc +#endif /* notyet */ + + /* r9 is curproc */ + st r0, r9, P_BACK /* p->p_back = 0 */ + ld r3, r9, P_ADDR + or.u r10, r0, hi16(_curpcb) + st r3, r10, lo16(_curpcb) /* curpcb = p->p_addr */ + + /* see if pmap_activate needs to be called */ + ld r2, r9, P_VMSPACE /* vmspace = p->p_vmspace */ + addu r2, r2, VM_PMAP /* pmap = &vmspace.vm_pmap */ +#ifdef notyet + ld r5, r2, PM_STCHG /* pmap->st_changed? */ + bcnd eq0, r5, Lswnochg /* no, skip */ +#endif /* notyet */ + or r14, r0, r9 /* save p in r14 */ + subu r31, r31,48 + bsr _pmap_activate /* pmap_activate(pmap, pcb) */ + addu r31, r31,48 + or r9, r0, r14 /* restore p saved in r14 */ + +Lswnochg: + or.u r31, r0, hi16(_intstack_end) + or r31,r31, lo16(_intstack_end)/* now goto a tmp stack for NMI */ + subu r31, r31,48 + bsr.n _load_u_area /* load_u_area(p) */ + or r2, r0, r9 + addu r31, r31,48 + /* flush tlb of any user addresses */ + or r2, r0, 0 + or r3, r0, 0 + subu r31, r31,48 + bsr.n _cmmu_flush_tlb + or r4, r0, 0xffff /* cmmu_flush_tlb flushes entire tlb */ + /* for sizes > 4096 */ + addu r31, r31,48 + or.u r10, r0, hi16(_curpcb) + ld r10, r10, lo16(_curpcb) + /* XXX Is this correct/necessary? */ + st r10, r14, P_ADDR /* p->p_addr = curpcb; restore p_addr */ + + /* restore from the current context */ + ld r1,r10, PCB_PC + ld.d r14,r10, PCB_R14 + ld.d r16,r10, PCB_R16 + ld.d r18,r10, PCB_R18 + ld.d r20,r10, PCB_R20 + ld.d r22,r10, PCB_R22 + ld.d r24,r10, PCB_R24 + ld.d r26,r10, PCB_R26 + ld.d r28,r10, PCB_R28 + ld.d r30,r10, PCB_R30 /* restore frame pointer & stack */ + +/* XXX should we postpone restoring stack till after ipl is restored? The +stack access could fault */ +Lswsameproc: + subu r31,r31,48 + st r1, r31,36 /* save r1 on stack */ + ld r2, r10, PCB_IPL /* restore interrupt mask */ + bsr _setipl /* restore ipl */ + ld r1, r31,36 /* restore r1 from stack */ + addu r31,r31,48 + jmp.n r1 + or r2, r0, 1 /* return 1 (for alternate returns) */ + +/* + * savectx(pcb) + * Update pcb, saving current processor state. + */ +ENTRY(savectx) + /* get the spl mask */ + subu r31,r31,48 /* allocate stack for r1 and args */ + st r1,r31,36 /* save return address */ + st r2,r31,32 /* save r2 */ + bsr _getipl /* get the current interrupt mask */ + ld r1,r31,36 /* recover return address */ + ld r10,r31,32 /* recover r2 into r10 */ + addu r31,r31,48 /* put stack pointer back */ + st r1, r10, PCB_PC /* save return address */ + st.d r14,r10, PCB_R14 + st.d r16,r10, PCB_R16 + st.d r18,r10, PCB_R18 + st.d r20,r10, PCB_R20 + st.d r22,r10, PCB_R22 + st.d r24,r10, PCB_R24 + st.d r26,r10, PCB_R26 + st.d r28,r10, PCB_R28 + st.d r30,r10, PCB_R30 /* save frame pointer and sp */ + st r2, r10, PCB_IPL /* save interrupt mask */ + jmp.n r1 + or r2,r0,r0 diff --git a/sys/arch/mvme88k/mvme88k/process_machdep.c b/sys/arch/mvme88k/mvme88k/process_machdep.c new file mode 100644 index 00000000000..62a3ba89dfb --- /dev/null +++ b/sys/arch/mvme88k/mvme88k/process_machdep.c @@ -0,0 +1,155 @@ +/* $NetBSD: process_machdep.c,v 1.5 1994/11/20 20:54:37 deraadt Exp $ */ + +/* + * Copyright (c) 1993 The Regents of the University of California. + * Copyright (c) 1993 Jan-Simon Pendry + * All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Jan-Simon Pendry. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * from: Id: procfs_i386.c,v 4.1 1993/12/17 10:47:45 jsp Rel + */ + +/* + * This file may seem a bit stylized, but that so that it's easier to port. + * Functions to be implemented here are: + * + * process_read_regs(proc, regs) + * Get the current user-visible register set from the process + * and copy it into the regs structure (<machine/reg.h>). + * The process is stopped at the time read_regs is called. + * + * process_write_regs(proc, regs) + * Update the current register set from the passed in regs + * structure. Take care to avoid clobbering special CPU + * registers or privileged bits in the PSL. + * The process is stopped at the time write_regs is called. + * + * process_sstep(proc) + * Arrange for the process to trap after executing a single instruction. + * + * process_set_pc(proc) + * Set the process's program counter. + */ + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/time.h> +#include <sys/kernel.h> +#include <sys/proc.h> +#include <sys/user.h> +#include <sys/vnode.h> +#include <machine/psl.h> +#include <machine/reg.h> +#if 0 +#include <machine/frame.h> +#endif +#include <sys/ptrace.h> + +int +process_read_regs(p, regs) + struct proc *p; + struct reg *regs; +{ +#if 0 + /* NOTE: struct reg == struct trapframe */ + bcopy(p->p_md.md_tf, (caddr_t)regs, sizeof(struct reg)); +#endif + return (0); +} + +int +process_write_regs(p, regs) + struct proc *p; + struct reg *regs; +{ +#if 0 + int psr = p->p_md.md_tf->tf_psr & ~PSR_ICC; + bcopy((caddr_t)regs, p->p_md.md_tf, sizeof(struct reg)); + p->p_md.md_tf->tf_psr = psr | (regs->r_psr & PSR_ICC); +#endif + return (0); +} + +int +process_sstep(p, sstep) + struct proc *p; +{ +#if 0 + if (sstep) + return EINVAL; +#endif + return (0); +} + +int +process_set_pc(p, addr) + struct proc *p; + caddr_t addr; +{ +#if 0 + p->p_md.md_tf->tf_pc = (u_int)addr; + p->p_md.md_tf->tf_npc = (u_int)addr + 4; +#endif + return (0); +} + +int +process_read_fpregs(p, regs) +struct proc *p; +struct fpreg *regs; +{ +#if 0 + extern struct fpstate initfpstate; + struct fpstate *statep = &initfpstate; + + /* NOTE: struct fpreg == struct fpstate */ + if (p->p_md.md_fpstate) + statep = p->p_md.md_fpstate; + bcopy(statep, regs, sizeof(struct fpreg)); +#endif + return 0; +} + +int +process_write_fpregs(p, regs) +struct proc *p; +struct fpreg *regs; +{ +#if 0 + if (p->p_md.md_fpstate == NULL) + return EINVAL; + + bcopy(regs, p->p_md.md_fpstate, sizeof(struct fpreg)); +#endif + return 0; +} diff --git a/sys/arch/mvme88k/mvme88k/swapgeneric.c b/sys/arch/mvme88k/mvme88k/swapgeneric.c new file mode 100644 index 00000000000..1172a180ef6 --- /dev/null +++ b/sys/arch/mvme88k/mvme88k/swapgeneric.c @@ -0,0 +1,237 @@ +/* + * Copyright (c) 1982, 1986 Regents of the University of California. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)swapgeneric.c 7.5 (Berkeley) 5/7/91 + * $Id: swapgeneric.c,v 1.3 1997/03/03 20:21:50 rahnds Exp $ + */ + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/conf.h> +#include <sys/buf.h> +#include <sys/reboot.h> +#include <sys/device.h> +#include <sys/disklabel.h> +#include <sys/fcntl.h> /* XXXX and all that uses it */ +#include <sys/proc.h> /* XXXX and all that uses it */ +#include <sys/disk.h> + +#include "sd.h" +#include "cd.h" + +/* + * Only boot on ufs. (XXX?) + */ +int ffs_mountroot(); +int (*mountroot)() = ffs_mountroot; + +/* + * Generic configuration; all in one + */ +dev_t rootdev = NODEV; +dev_t dumpdev = NODEV; + +struct swdevt swdevt[] = { + { NODEV, 1, 0 }, + { NODEV, 0, 0 }, +}; + +#if NSD > 0 +extern struct cfdriver sdcd; +#endif +#if NCD > 0 +extern struct cfdriver cdcd; +#endif + +struct genericconf { + struct cfdriver *gc_driver; + dev_t gc_root; +}; + +/* + * the system will assign rootdev to the first partition 'a' + * found with FS_BSDFFS fstype. so these should be ordered + * in prefernece of boot. however it does walk units backwards + * to remain compatible with the old amiga method of picking + * the last root found. + */ +struct genericconf genericconf[] = { +#if NSD > 0 + {&sdcd, makedev(4, 0)}, +#endif +#if NCD > 0 + {&cdcd, makedev(6, 0)}, +#endif + { 0 }, +}; + +struct genericconf * +getgenconf(bp) + char *bp; +{ + char *cp; + struct genericconf *gc; + + for (;;) { + printf("root device> "); + gets(bp); + for (gc = genericconf; gc->gc_driver; gc++) + if (gc->gc_driver->cd_name[0] == bp[0] && + gc->gc_driver->cd_name[1] == bp[1]) + break; + if (gc->gc_driver == NULL) { + printf("use one of:"); + for (gc = genericconf; gc->gc_driver; gc++) + printf(" %s%%d", gc->gc_driver->cd_name); + printf("\n"); + continue; + } + cp = bp + 2; + if (*cp >= '0' && *cp <= '9') + break; + printf("bad/missing unit number\n"); + } + return(gc); +} + +setconf() +{ + struct dkdevice *dkp; + struct partition *pp; + struct genericconf *gc; + struct bdevsw *bdp; + int unit, swaponroot; + char name[128]; + char *cp; + + swaponroot = 0; + + if (rootdev != NODEV) + goto justdoswap; + + unit = 0; + if (boothowto & RB_ASKNAME) { + gc = getgenconf(name); + cp = name + 2; + while (*cp >= '0' && *cp <= '9') + unit = 10 * unit + *cp++ - '0'; + if (*cp == '*') + swaponroot = 1; + unit &= 0x7; + goto found; + } + for (gc = genericconf; gc->gc_driver; gc++) { + for (unit = gc->gc_driver->cd_ndevs - 1; unit >= 0; unit--) { + if (gc->gc_driver->cd_devs[unit] == NULL) + continue; + /* + * this is a hack these drivers should use + * dk_dev and not another instance directly above. + */ + dkp = (struct dkdevice *) + ((struct device *)gc->gc_driver->cd_devs[unit] + 1); + if (dkp->dk_driver == NULL || + dkp->dk_driver->d_strategy == NULL) + continue; + for (bdp = bdevsw; bdp < (bdevsw + nblkdev); bdp++) + if (bdp->d_strategy == + dkp->dk_driver->d_strategy) + break; + if (bdp->d_open(MAKEDISKDEV(major(gc->gc_root), + unit, 0), FREAD | FNONBLOCK, 0, curproc)) + continue; + bdp->d_close(MAKEDISKDEV(major(gc->gc_root), unit, + 0), FREAD | FNONBLOCK, 0, curproc); + pp = &dkp->dk_label.d_partitions[0]; + if (pp->p_size == 0 || pp->p_fstype != FS_BSDFFS) + continue; + goto found; + } + } + printf("no suitable root\n"); + asm("or r9,r0,0x0063"); + asm("tb0 0,r0,0x1f0"); + /*NOTREACHED*/ +found: + + gc->gc_root = MAKEDISKDEV(major(gc->gc_root), unit, 0); + rootdev = gc->gc_root; + +justdoswap: + swdevt[0].sw_dev = MAKEDISKDEV(major(rootdev), + DISKUNIT(rootdev), 1); + /* + swdevt[0].sw_dev = dumpdev = MAKEDISKDEV(major(rootdev), + DISKUNIT(rootdev), 1); + */ + /* swap size and dumplo set during autoconfigure */ + if (swaponroot) + rootdev = swdevt[0].sw_dev; +} + +gets(cp) + char *cp; +{ + register char *lp; + register c; + + lp = cp; + for (;;) { + cnputc(c = cngetc()); + switch (c) { + case '\n': + case '\r': + *lp = 0; + return; + case '\b': + case '\177': + if (lp > cp) { + lp--; + cnputc(' '); + cnputc('\b'); + } + continue; + case '#': + lp--; + if (lp < cp) + lp = cp; + continue; + case '@': + case 'u'&037: + lp = cp; + cnputc('\n'); + continue; + default: + *lp++ = c; + } + } +} diff --git a/sys/arch/mvme88k/mvme88k/syscall.stub b/sys/arch/mvme88k/mvme88k/syscall.stub new file mode 100644 index 00000000000..4a1055556d1 --- /dev/null +++ b/sys/arch/mvme88k/mvme88k/syscall.stub @@ -0,0 +1,29 @@ + /* + * system call will look like: + * ld r10, r31, 32; r10,r11,r12 might be garbage. + * ld r11, r31, 36 + * ld r12, r31, 40 + * or r13, r0, <code> + * tb0 0, r0, <128> <- xip + * br err <- nip + * jmp r1 <- fip + * err: or.u r3, r0, hi16(errno) + * st r2, r3, lo16(errno) + * subu r2, r0, 1 + * jmp r1 + * + * So, when we take syscall trap, sxip/snip/sfip will be as + * shown above. + * Given this, + * 1. If the system call returned 0, need to skip nip. + * nip = fip, fip += 4 + * (doesn't matter what fip + 4 will be but we will never + * execute this since jmp r1 at nip will change the execution flow.) + * 2. If the system call returned an errno > 0, plug the value + * in r2, and leave nip and fip unchanged. This will have us + * executing "br err" on return to user space. + * 3. If the system call code returned ERESTART or EJUSTRETURN, + * we need to rexecute the trap instruction. Back up the pipe + * line. + * fip = nip, nip = xip + */ diff --git a/sys/arch/mvme88k/mvme88k/timerreg.h b/sys/arch/mvme88k/mvme88k/timerreg.h new file mode 100644 index 00000000000..3bafa844c02 --- /dev/null +++ b/sys/arch/mvme88k/mvme88k/timerreg.h @@ -0,0 +1,8 @@ +struct ticktimer { + u_int ttcmpreg; /* Timer compare register */ + u_int ttcounter; /* Timer counter */ + u_int tticr; /* Timer control register */ +}; + +struct timers { +}; diff --git a/sys/arch/mvme88k/mvme88k/trap.c b/sys/arch/mvme88k/mvme88k/trap.c new file mode 100644 index 00000000000..bcd339794ca --- /dev/null +++ b/sys/arch/mvme88k/mvme88k/trap.c @@ -0,0 +1,723 @@ +/* + * Copyright (c) 1996 Nivas Madhur + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by Nivas Madhur. + * 4. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ +/* + * Mach Operating System + * Copyright (c) 1991 Carnegie Mellon University + * Copyright (c) 1991 OMRON Corporation + * All Rights Reserved. + * + * Permission to use, copy, modify and distribute this software and its + * documentation is hereby granted, provided that both the copyright + * notice and this permission notice appear in all copies of the + * software, derivative works or modified versions, and any portions + * thereof, and that both notices appear in supporting documentation. + * + */ + +#include <sys/types.h> +#include <vm/vm.h> +#include <vm/vm_kern.h> /* kernel_map */ + +#include <sys/param.h> +#include <sys/proc.h> +#include <sys/user.h> +#include <sys/syscall.h> +#include <sys/ktrace.h> +#include <machine/cpu.h> /* DMT_VALID, etc. */ +#include <machine/m88100.h> /* DMT_VALID, etc. */ +#include <machine/trap.h> +#include <machine/psl.h> /* FIP_E, etc. */ + +#include <sys/systm.h> + +#if (DDB) +#include <machine/db_machdep.h> +#endif /* DDB */ + +#define TRAPTRACE +#if defined(TRAPTRACE) +unsigned traptrace = 0; +#endif + +#if DDB +#define DEBUG_MSG db_printf +#else +#define DEBUG_MSG printf +#endif /* DDB */ + +#define USERMODE(PSR) (((struct psr*)&(PSR))->psr_mode == 0) +#define SYSTEMMODE(PSR) (((struct psr*)&(PSR))->psr_mode != 0) + +/* XXX MAJOR CLEANUP REQUIRED TO PORT TO BSD */ + +char *trap_type[] = { + "Reset", + "Interrupt Exception", + "Instruction Access", + "Data Access Exception", + "Misaligned Access", + "Unimplemented Opcode", + "Privileg Violation", + "Bounds Check Violation", + "Illegal Integer Divide", + "Integer Overflow", + "Error Exception", +}; + +char *pbus_exception_type[] = { + "Success (No Fault)", + "", + "", + "Bus Error", + "Segment Fault", + "Page Fault", + "Supervisor Violation", + "Write Violation", +}; + +int trap_types = sizeof trap_type / sizeof trap_type[0]; + +static inline void +userret(struct proc *p, struct m88100_saved_state *frame, u_quad_t oticks) +{ + int sig; + int s; + + /* take pending signals */ + while ((sig = CURSIG(p)) != 0) + postsig(sig); + p->p_priority = p->p_usrpri; + + if (want_resched) { + /* + * Since we are curproc, clock will normally just change + * our priority without moving us from one queue to another + * (since the running process is not on a queue.) + * If that happened after we put ourselves on the run queue + * but before we switched, we might not be on the queue + * indicated by our priority. + */ + s = splstatclock(); + setrunqueue(p); + p->p_stats->p_ru.ru_nivcsw++; + mi_switch(); + (void) splx(s); + while ((sig = CURSIG(p)) != 0) + postsig(sig); + } + + /* + * If profiling, charge recent system time to the trapped pc. + */ + if (p->p_flag & P_PROFIL) + addupc_task(p, frame->sxip & ~3, + (int)(p->p_sticks - oticks)); + + curpriority = p->p_priority; +} + +void +panictrap(int type, struct m88100_saved_state *frame) +{ + static int panicing = 0; + + if (panicing++ == 0) { + if (type == 2) { /* instruction exception */ + printf("Instr access fault (%s) v = %x, frame %x\n", + pbus_exception_type[(frame->ipfsr >> 16) & 0x7], + frame->sxip & ~3, frame); + } else if (type == 3) { /* data access exception */ + printf("Data access fault (%s) v = %x, frame %x\n", + pbus_exception_type[(frame->dpfsr >> 16) & 0x7], + frame->sxip & ~3, frame); + } else + printf("trap type %d, v = %x, frame %x\n", type, frame->sxip & ~3, frame); + regdump(frame); + } + if ((u_int)type < trap_types) + panic(trap_type[type]); + panic("trap"); + /*NOTREACHED*/ +} + +/*ARGSUSED*/ +void +trap(unsigned type, struct m88100_saved_state *frame) +{ + struct proc *p; + u_quad_t sticks = 0; + vm_map_t map; + vm_offset_t va; + vm_prot_t ftype; + int fault_type; + u_long fault_code; + unsigned nss, fault_addr; + struct vmspace *vm; + int result; + int sig = 0; + + extern vm_map_t kernel_map; + extern int fubail(), subail(); + extern unsigned guarded_access_start; + extern unsigned guarded_access_end; + extern unsigned guarded_access_bad; + + cnt.v_trap++; + if ((p = curproc) == NULL) + p = &proc0; + + if (USERMODE(frame->epsr)) { + sticks = p->p_sticks; + type += T_USER; + p->p_md.md_tf = frame; /* for ptrace/signals */ + fault_type = 0; + fault_code = 0; + } + + switch(type) + { + default: + panictrap(frame->vector, frame); + /*NOTREACHED*/ + +#if defined(DDB) + case T_KDB_BREAK: + /*FALLTHRU*/ + case T_KDB_BREAK+T_USER: + { + int s = db_splhigh(); + db_enable_interrupt(); + ddb_break_trap(T_KDB_BREAK,(db_regs_t*)frame); + db_disable_interrupt(); + db_splx(s); + return; + } + case T_KDB_ENTRY: + /*FALLTHRU*/ + case T_KDB_ENTRY+T_USER: + { + int s = db_splhigh(); + db_enable_interrupt(); + ddb_entry_trap(T_KDB_ENTRY,(db_regs_t*)frame); + db_disable_interrupt(); + db_splx(s); + return; + } + +#if 0 + case T_ILLFLT: + { + int s = db_splhigh(); + db_enable_interrupt(); + ddb_error_trap(type == T_ILLFLT ? "unimplemented opcode" : + "error fault", (db_regs_t*)frame); + db_disable_interrupt(); + db_splx(s); + return; + } +#endif /* 0 */ +#endif /* DDB */ + + case T_MISALGNFLT: + DEBUG_MSG("kernel misalgined " + "access exception @ 0x%08x\n", frame->sxip); + panictrap(frame->vector, frame); + break; + + case T_INSTFLT: + /* kernel mode instruction access fault. + * Should never, never happen for a non-paged kernel. + */ + DEBUG_MSG("kernel mode instruction " + "page fault @ 0x%08x\n", frame->sxip); + panictrap(frame->vector, frame); + break; + + case T_DATAFLT: + /* kernel mode data fault */ + /* + * If the faulting address is in user space, handle it in + * the context of the user process. Else, use kernel map. + */ + + if (type == T_DATAFLT) { + fault_addr = frame->dma0; + if (frame->dmt0 & (DMT_WRITE|DMT_LOCKBAR)) { + ftype = VM_PROT_READ|VM_PROT_WRITE; + fault_code = VM_PROT_WRITE; + } else { + ftype = VM_PROT_READ; + fault_code = VM_PROT_READ; + } + } else { + fault_addr = frame->sxip & XIP_ADDR; + ftype = VM_PROT_READ; + fault_code = VM_PROT_READ; + } + + va = trunc_page((vm_offset_t)fault_addr); + + vm = p->p_vmspace; + map = &vm->vm_map; + + /* data fault on a kernel address... */ + if (frame->dmt0 & DMT_DAS) + map = kernel_map; + + /* + * We don't want to call vm_fault() if it is fuwintr() or + * suwintr(). These routines are for copying from interrupt + * context and vm_fault() can potentially sleep. You may + * wonder if it isn't bad karma for an interrupt handler to + * touch the current process. Indeed it is, but clock interrupt + * does it while doing profiling. It is OK in that context. + */ + + if (p->p_addr->u_pcb.pcb_onfault == (int)fubail || + p->p_addr->u_pcb.pcb_onfault == (int)subail) + goto outtahere; + + /* data fault on the user address */ + if (type == T_DATAFLT && (frame->dmt0 & DMT_DAS) == 0) + { + type = T_DATAFLT + T_USER; + goto user_fault; + } + + /* + * If it is a guarded access, bus error is OK. + */ + + if ((frame->dpfsr >> 16 & 0x7) == 0x3) { +#ifdef DIAGNOSTIC + printf("sxip %x dpfsr %x\n", frame->sxip, frame->dpfsr); + gimmeabreak(); +#endif + } + + if ((frame->dpfsr >> 16 & 0x7) == 0x3 && /* bus error */ + (frame->sxip & ~3) >= (unsigned)&guarded_access_start && + (frame->sxip & ~3) <= (unsigned)&guarded_access_end) { + + frame->snip = ((unsigned)&guarded_access_bad ) | FIP_V; + frame->sfip = ((unsigned)&guarded_access_bad + 4) | FIP_V; + frame->sxip = 0; + frame->dmt0 = 0;/* XXX what about other trans. in data unit */ + frame->dpfsr = 0; + return; + } + /* + * On a segment or a page fault, call vm_fault() to resolve + * the fault. + */ + + if ((frame->dpfsr >> 16 & 0x7) == 0x4 /* seg fault */ + || (frame->dpfsr >> 16 & 0x7) == 0x5) { /* page fault */ + result = vm_fault(map, va, ftype, FALSE); + + if (result == KERN_SUCCESS) { + /* + * We could resolve the fault. Call + * data_access_emulation to drain the data unit pipe + * line and reset dmt0 so that trap won't get called + * again. For inst faults, back up the pipe line. + */ + if (type == T_DATAFLT) { + data_access_emulation(frame); + frame->dmt0 = 0; + frame->dpfsr = 0; + } else { + frame->sfip = frame->snip & ~FIP_E; + frame->snip = frame->sxip & ~NIP_E; + } + return; + } + } + + /* + * if still the fault is not resolved ... + */ + if (!p->p_addr->u_pcb.pcb_onfault) + panictrap(frame->vector, frame); + + outtahere: + frame->snip = ((unsigned)p->p_addr->u_pcb.pcb_onfault ) | FIP_V; + frame->sfip = ((unsigned)p->p_addr->u_pcb.pcb_onfault + 4) | FIP_V; + frame->sxip = 0; + frame->dmt0 = 0; /* XXX what about other trans. in data unit */ + frame->dpfsr = 0; + return; + + case T_INSTFLT+T_USER: + /* User mode instruction access fault */ + /*FALLTHRU*/ + case T_DATAFLT+T_USER: + user_fault: + + if (type == T_INSTFLT+T_USER) + fault_addr = frame->sxip & XIP_ADDR; + else + fault_addr = frame->dma0; + + if (frame->dmt0 & (DMT_WRITE|DMT_LOCKBAR)) { + ftype = VM_PROT_READ|VM_PROT_WRITE; + fault_code = VM_PROT_WRITE; + } else { + ftype = VM_PROT_READ; + fault_code = VM_PROT_READ; + } + + va = trunc_page((vm_offset_t)fault_addr); + + vm = p->p_vmspace; + map = &vm->vm_map; + + /* Call vm_fault() to resolve non-bus error faults */ + + if ((frame->ipfsr >> 16 & 0x7) != 0x3 && + (frame->dpfsr >> 16 & 0x7) != 0x3) { + + result = vm_fault(map, va, ftype, FALSE); + frame->ipfsr = frame->dpfsr = 0; + + } + + + if ((caddr_t)va >= vm->vm_maxsaddr) { + if (result == KERN_SUCCESS) { + nss = clrnd(btoc(USRSTACK - va));/* XXX check this */ + if (nss > vm->vm_ssize) + vm->vm_ssize = nss; + } else if (result == KERN_PROTECTION_FAILURE) + result = KERN_INVALID_ADDRESS; + } + + if (result == KERN_SUCCESS) { + if (type == T_DATAFLT+T_USER) { + /* + * We could resolve the fault. Call + * data_access_emulation to drain the data unit + * pipe line and reset dmt0 so that trap won't + * get called again. + */ + data_access_emulation(frame); + frame->dmt0 = 0; + frame->dpfsr = 0; + } else { + /* back up SXIP, SNIP clearing the the Error bit */ + frame->sfip = frame->snip & ~FIP_E; + frame->snip = frame->sxip & ~NIP_E; + } + } else { + sig = result == KERN_PROTECTION_FAILURE ? SIGBUS : SIGSEGV; + fault_type = result == KERN_PROTECTION_FAILURE ? BUS_ADRERR + : SEGV_MAPERR; + } + + break; + + case T_MISALGNFLT+T_USER: + sig = SIGBUS; + fault_type = BUS_ADRALN; + break; + + case T_PRIVINFLT+T_USER: + case T_ILLFLT+T_USER: + sig = SIGILL; + break; + + case T_BNDFLT+T_USER: + sig = SIGFPE; + break; + case T_ZERODIV+T_USER: + sig = SIGFPE; + fault_type = FPE_INTDIV; + break; + case T_OVFFLT+T_USER: + sig = SIGFPE; + fault_type = FPE_INTOVF; + break; + + case T_FPEPFLT+T_USER: + case T_FPEIFLT+T_USER: + sig = SIGFPE; + break; + + case T_SIGTRAP+T_USER: + sig = SIGTRAP; + fault_type = TRAP_TRACE; + break; + + case T_STEPBPT+T_USER: + /* + * This trap is used by the kernel to support single-step + * debugging (although any user could generate this trap + * which should probably be handled differently). When a + * process is continued by a debugger with the PT_STEP + * function of ptrace (single step), the kernel inserts + * one or two breakpoints in the user process so that only + * one instruction (or two in the case of a delayed branch) + * is executed. When this breakpoint is hit, we get the + * T_STEPBPT trap. + */ + frame->sfip = frame->snip; /* set up next FIP */ + frame->snip = frame->sxip; /* set up next NIP */ + break; + + case T_USERBPT+T_USER: + /* + * This trap is meant to be used by debuggers to implement + * breakpoint debugging. When we get this trap, we just + * return a signal which gets caught by the debugger. + */ + + frame->sfip = frame->snip; /* set up the next FIP */ + frame->snip = frame->sxip; /* set up the next NIP */ + sig = SIGTRAP; + fault_type = TRAP_BRKPT; + break; + + case T_ASTFLT+T_USER: + want_ast = 0; + if (p->p_flag & P_OWEUPC) { + p->p_flag &= ~P_OWEUPC; + ADDUPROF(p); + } + break; + } + + /* + * If trap from supervisor mode, just return + */ + if (SYSTEMMODE(frame->epsr)) + return; + + if (sig) { + trapsignal(p, sig, fault_code, fault_type, (caddr_t)fault_addr); + /* + * don't want multiple faults - we are going to + * deliver signal. + */ + frame->dmt0 = 0; + frame->dpfsr = 0; + } + + userret(p, frame, sticks); +} + +void +error_fault(struct m88100_saved_state *frame) +{ + DEBUG_MSG("\n[ERROR FAULT (Bad News[tm]) frame 0x%08x]\n", frame); +#if DDB + gimmeabreak(); + DEBUG_MSG("[you really can't restart after an error fault.]\n"); + gimmeabreak(); +#endif /* DDB */ +} + +syscall(register_t code, struct m88100_saved_state *tf) +{ + register int i, nsys, *ap, nap; + register struct sysent *callp; + register struct proc *p; + int error, new; + struct args { + int i[8]; + } args; + int rval[2]; + u_quad_t sticks; + extern struct pcb *curpcb; + + cnt.v_syscall++; + + p = curproc; + + callp = p->p_emul->e_sysent; + nsys = p->p_emul->e_nsysent; + +#ifdef DIAGNOSTIC + if (USERMODE(tf->epsr) == 0) + panic("syscall"); + if (curpcb != &p->p_addr->u_pcb) + panic("syscall curpcb/ppcb"); + if (tf != (struct trapframe *)&curpcb->user_state) + panic("syscall trapframe"); +#endif + + sticks = p->p_sticks; + p->p_md.md_tf = tf; + + /* + * For 88k, all the arguments are passed in the registers (r2-r12) + * For syscall (and __syscall), r2 (and r3) has the actual code. + * __syscall takes a quad syscall number, so that other + * arguments are at their natural alignments. + */ + ap = &tf->r[2]; + nap = 6; + + switch (code) { + case SYS_syscall: + code = *ap++; + nap--; + break; + case SYS___syscall: + if (callp != sysent) + break; + code = ap[_QUAD_LOWWORD]; + ap += 2; + nap -= 2; + break; + } + + /* Callp currently points to syscall, which returns ENOSYS. */ + + if (code < 0 || code >= nsys) + callp += p->p_emul->e_nosys; + else { + callp += code; + i = callp->sy_argsize / sizeof(register_t); + if (i > 8) + panic("syscall nargs"); + /* + * just copy them; syscall stub made sure all the + * args are moved from user stack to registers. + */ + bcopy((caddr_t)ap, (caddr_t)args.i, i * sizeof(register_t)); + } +#ifdef SYSCALL_DEBUG + scdebug_call(p, code, args.i); +#endif +#ifdef KTRACE + if (KTRPOINT(p, KTR_SYSCALL)) + ktrsyscall(p->p_tracep, code, callp->sy_argsize, args.i); +#endif + rval[0] = 0; + rval[1] = 0; + error = (*callp->sy_call)(p, &args, rval); + /* + * system call will look like: + * ld r10, r31, 32; r10,r11,r12 might be garbage. + * ld r11, r31, 36 + * ld r12, r31, 40 + * or r13, r0, <code> + * tb0 0, r0, <128> <- xip + * br err <- nip + * jmp r1 <- fip + * err: or.u r3, r0, hi16(errno) + * st r2, r3, lo16(errno) + * subu r2, r0, 1 + * jmp r1 + * + * So, when we take syscall trap, sxip/snip/sfip will be as + * shown above. + * Given this, + * 1. If the system call returned 0, need to skip nip. + * nip = fip, fip += 4 + * (doesn't matter what fip + 4 will be but we will never + * execute this since jmp r1 at nip will change the execution flow.) + * 2. If the system call returned an errno > 0, plug the value + * in r2, and leave nip and fip unchanged. This will have us + * executing "br err" on return to user space. + * 3. If the system call code returned ERESTART, + * we need to rexecute the trap instruction. Back up the pipe + * line. + * fip = nip, nip = xip + * 4. If the system call returned EJUSTRETURN, don't need to adjust + * any pointers. + */ + + if (error == 0) { + /* + * If fork succeeded and we are the child, our stack + * has moved and the pointer tf is no longer valid, + * and p is wrong. Compute the new trapframe pointer. + * (The trap frame invariably resides at the + * tippity-top of the u. area.) + */ + p = curproc; + tf = USER_REGS(p); + tf->r[2] = rval[0]; + tf->r[3] = rval[1]; + tf->epsr &= ~PSR_C; + tf->snip = tf->sfip & ~FIP_E; + tf->sfip = tf->snip + 4; + } else if (error > 0) { + /* error != ERESTART && error != EJUSTRETURN*/ + tf->r[2] = error; + tf->epsr |= PSR_C; /* fail */ + tf->snip = tf->snip & ~NIP_E; + tf->sfip = tf->sfip & ~FIP_E; + } else if (error == ERESTART) { + /* + * If (error == ERESTART), back up the pipe line. This + * will end up reexecuting the trap. + */ + tf->epsr &= ~PSR_C; + tf->sfip = tf->snip & ~NIP_E; + tf->snip = tf->sxip & ~NIP_E; + } else { + /* if (error == EJUSTRETURN), leave the ip's alone */ + tf->epsr &= ~PSR_C; + } +#ifdef SYSCALL_DEBUG + scdebug_ret(p, code, error, rval); +#endif + userret(p, tf, sticks); +#ifdef KTRACE + if (KTRPOINT(p, KTR_SYSRET)) + ktrsysret(p->p_tracep, code, error, rval[0]); +#endif +} + +/* + * Set up return-value registers as fork() libc stub expects, + * and do normal return-to-user-mode stuff. + */ +void +child_return(struct proc *p) +{ + struct trapframe *tf; + + tf = USER_REGS(p); + tf->r[2] = 0; + tf->r[3] = 0; + tf->epsr &= ~PSR_C; + tf->snip = tf->sfip & ~3; + tf->sfip = tf->snip + 4; + + userret(p, tf, p->p_sticks); +#ifdef KTRACE + if (KTRPOINT(p, KTR_SYSRET)) + ktrsysret(p->p_tracep, SYS_fork, 0, 0); +#endif +} diff --git a/sys/arch/mvme88k/mvme88k/vm_machdep.c b/sys/arch/mvme88k/mvme88k/vm_machdep.c new file mode 100644 index 00000000000..eaba81506db --- /dev/null +++ b/sys/arch/mvme88k/mvme88k/vm_machdep.c @@ -0,0 +1,466 @@ +/* + * Copyright (c) 1996 Nivas Madhur + * Copyright (c) 1993 Adam Glass + * Copyright (c) 1988 University of Utah. + * Copyright (c) 1982, 1986, 1990 The Regents of the University of California. + * All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * the Systems Programming Group of the University of Utah Computer + * Science Department. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * from: Utah $Hdr: vm_machdep.c 1.21 91/04/06$ + * from: @(#)vm_machdep.c 7.10 (Berkeley) 5/7/91 + * vm_machdep.c,v 1.3 1993/07/07 07:09:32 cgd Exp + * $Id: vm_machdep.c,v 1.3 1997/03/03 20:21:54 rahnds Exp $ + */ + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/proc.h> +#include <sys/malloc.h> +#include <sys/buf.h> +#include <sys/user.h> +#include <sys/vnode.h> + +#include <vm/vm.h> +#include <vm/vm_kern.h> +#include <vm/vm_map.h> + +#include <machine/cpu.h> + +#ifdef XXX_FUTURE +extern struct map *iomap; +#endif + +/* + * Finish a fork operation, with process p2 nearly set up. + * Copy and update the kernel stack and pcb, making the child + * ready to run, and marking it so that it can return differently + * than the parent. Returns 1 in the child process, 0 in the parent. + * We currently double-map the user area so that the stack is at the same + * address in each process; in the future we will probably relocate + * the frame pointers on the stack after copying. + */ + +#ifdef __FORK_BRAINDAMAGE +int +#else +void +#endif +cpu_fork(struct proc *p1, struct proc *p2) +{ + struct switchframe *p2sf; + int off, ssz; + struct ksigframe { + void (*func)(struct proc *); + void *proc; + } *ksfp; + extern void proc_do_uret(), child_return(); + extern void proc_trampoline(); + + savectx(p1->p_addr); + + bcopy((void *)&p1->p_addr->u_pcb, (void *)&p2->p_addr->u_pcb, sizeof(struct pcb)); + p2->p_addr->u_pcb.kernel_state.pcb_ipl = 0; + + p2->p_md.md_tf = USER_REGS(p2); + + /*XXX these may not be necessary nivas */ + save_u_area(p2, p2->p_addr); +#ifdef notneeded + PMAP_ACTIVATE(&p2->p_vmspace->vm_pmap, &p2->p_addr->u_pcb, 0); +#endif /* notneeded */ + + /* + * Create a switch frame for proc 2 + */ + p2sf = (struct switchframe *)((char *)p2->p_addr + USPACE - 8) - 1; + p2sf->sf_pc = (u_int)proc_do_uret; + p2sf->sf_proc = p2; + p2->p_addr->u_pcb.kernel_state.pcb_sp = (u_int)p2sf; + + ksfp = (struct ksigframe *)p2->p_addr->u_pcb.kernel_state.pcb_sp - 1; + + ksfp->func = child_return; + ksfp->proc = p2; + + /* + * When this process resumes, r31 will be ksfp and + * the process will be at the beginning of proc_trampoline(). + * proc_trampoline will execute the function func, pop off + * ksfp frame, and call the function in the switchframe + * now exposed. + */ + + p2->p_addr->u_pcb.kernel_state.pcb_sp = (u_int)ksfp; + p2->p_addr->u_pcb.kernel_state.pcb_pc = (u_int)proc_trampoline; + +#ifdef __FORK_BRAINDAMAGE + return(0); +#else + return; +#endif +} + +void +cpu_set_kpc(struct proc *p, void (*func)(struct proc *)) +{ + /* + * override func pointer in ksigframe with func. + */ + + struct ksigframe { + void (*func)(struct proc *); + void *proc; + } *ksfp; + + ksfp = (struct ksigframe *)p->p_addr->u_pcb.kernel_state.pcb_sp; + + ksfp->func = func; + +} + +/* + * cpu_exit is called as the last action during exit. + * We release the address space and machine-dependent resources, + * including the memory for the user structure and kernel stack. + * Once finished, we call switch_exit, which switches to a temporary + * pcb and stack and never returns. We block memory allocation + * until switch_exit has made things safe again. + */ +volatile void +cpu_exit(struct proc *p) +{ + extern volatile void switch_exit(); + vmspace_free(p->p_vmspace); + + (void) splimp(); + kmem_free(kernel_map, (vm_offset_t)p->p_addr, ctob(UPAGES)); + switch_exit(p); + /* NOTREACHED */ +} + +int +cpu_coredump(struct proc *p, struct vnode *vp, struct ucred *cred, struct core *corep) +{ + + return (vn_rdwr(UIO_WRITE, vp, (caddr_t) p->p_addr, ctob(UPAGES), + (off_t)0, UIO_SYSSPACE, IO_NODELOCKED|IO_UNIT, cred, (int *)NULL, + p)); +} + +/* + * Finish a swapin operation. + * We neded to update the cached PTEs for the user area in the + * machine dependent part of the proc structure. + */ + +void +cpu_swapin(struct proc *p) +{ + save_u_area(p, (vm_offset_t)p->p_addr); +} + +extern vm_map_t phys_map; + +/* + * Map an IO request into kernel virtual address space. Requests fall into + * one of five catagories: + * + * B_PHYS|B_UAREA: User u-area swap. + * Address is relative to start of u-area (p_addr). + * B_PHYS|B_PAGET: User page table swap. + * Address is a kernel VA in usrpt (Usrptmap). + * B_PHYS|B_DIRTY: Dirty page push. + * Address is a VA in proc2's address space. + * B_PHYS|B_PGIN: Kernel pagein of user pages. + * Address is VA in user's address space. + * B_PHYS: User "raw" IO request. + * Address is VA in user's address space. + * + * All requests are (re)mapped into kernel VA space via phys_map + * + * XXX we allocate KVA space by using kmem_alloc_wait which we know + * allocates space without backing physical memory. This implementation + * is a total crock, the multiple mappings of these physical pages should + * be reflected in the higher-level VM structures to avoid problems. + */ +void +vmapbuf(struct buf *bp, vm_size_t len) +{ + register caddr_t addr; + register vm_offset_t pa, kva, off; + struct proc *p; + + if ((bp->b_flags & B_PHYS) == 0) + panic("vmapbuf"); + + addr = (caddr_t)trunc_page(bp->b_saveaddr = bp->b_data); + off = (vm_offset_t)bp->b_saveaddr & PGOFSET; + len = round_page(off + len); + p = bp->b_proc; + + /* + * You may ask: Why phys_map? kernel_map should be OK - after all, + * we are mapping user va to kernel va or remapping some + * kernel va to another kernel va. The answer is TLB flushing + * when the address gets a new mapping. + */ + + kva = kmem_alloc_wait(phys_map, len); + + /* + * Flush the TLB for the range [kva, kva + off]. Strictly speaking, + * we should do this in vunmapbuf(), but we do it lazily here, when + * new pages get mapped in. + */ + + cmmu_flush_tlb(1, kva, len); + + bp->b_data = (caddr_t)(kva + off); + while (len > 0) { + pa = pmap_extract(vm_map_pmap(&p->p_vmspace->vm_map), + (vm_offset_t)addr); + if (pa == 0) + panic("vmapbuf: null page frame"); + pmap_enter(vm_map_pmap(phys_map), kva, pa, + VM_PROT_READ|VM_PROT_WRITE, TRUE); + addr += PAGE_SIZE; + kva += PAGE_SIZE; + len -= PAGE_SIZE; + } +} + +/* + * Free the io map PTEs associated with this IO operation. + * We also restore the original b_addr. + */ +void +vunmapbuf(struct buf *bp, vm_size_t len) +{ + register vm_offset_t addr, off; + + if ((bp->b_flags & B_PHYS) == 0) + panic("vunmapbuf"); + + addr = trunc_page(bp->b_data); + off = (vm_offset_t)bp->b_data & PGOFSET; + len = round_page(off + len); + kmem_free_wakeup(phys_map, addr, len); + bp->b_data = bp->b_saveaddr; + bp->b_saveaddr = 0; +} + +#ifdef XXX_FUTURE +/* + * Map a range [pa, pa+len] in the given map to a kernel address + * in iomap space. + * + * Note: To be flexible, I did not put a restriction on the alignment + * of pa. However, it is advisable to have pa page aligned since otherwise, + * we might have several mappings for a given chunk of the IO page. + */ +vm_offset_t +iomap_mapin(vm_offset_t pa, vm_size_t len, boolean_t canwait) +{ + vm_offset_t iova, tva, off; + register int npf, s; + + if (len == 0) + return NULL; + + off = (u_long)pa & PGOFSET; + + len = round_page(off + len); + + s = splimp(); + for (;;) { + iova = rmalloc(iomap, len); + if (iova != 0) + break; + if (canwait) { + (void)tsleep(iomap, PRIBIO+1, "iomapin", 0); + continue; + } + splx(s); + return NULL; + } + splx(s); + + tva = iova; + pa = trunc_page(pa); + + while (len) { + pmap_enter(kernel_pmap, tva, pa, + VM_PROT_READ|VM_PROT_WRITE, 1); + len -= PAGE_SIZE; + tva += PAGE_SIZE; + pa += PAGE_SIZE; + } + return (iova + off); +} + +/* + * Free up the mapping in iomap. + */ +int +iomap_mapout(vm_offset_t kva, vm_size_t len) +{ + register int s; + vm_offset_t off; + + off = kva & PGOFSET; + kva = trunc_page(kva); + len = round_page(off + len); + + pmap_remove(pmap_kernel(), kva, kva + len); + + s = splimp(); + rmfree(iomap, len, kva); + wakeup(iomap); + splx(s); +} +#endif /* XXX_FUTURE */ +/* + * Map the given physical IO address into the kernel temporarily. + * Maps one page. + * Should have some sort of lockig for the use of phys_map_vaddr. XXX nivas + */ + +vm_offset_t +mapiospace(caddr_t pa, int len) +{ + int off = (u_long)pa & PGOFSET; + extern vm_offset_t phys_map_vaddr1; + + pa = (caddr_t)trunc_page(pa); + + pmap_enter(kernel_pmap, phys_map_vaddr1, (vm_offset_t)pa, + VM_PROT_READ|VM_PROT_WRITE, 1); + + return (phys_map_vaddr1 + off); +} + +/* + * Unmap the address from above. + */ + +void +unmapiospace(vm_offset_t va) +{ + va = trunc_page(va); + + pmap_remove(kernel_pmap, va, va + NBPG); +} + +int +badvaddr(vm_offset_t va, int size) +{ + register int x; + + if (badaddr(va, size)) { + return -1; + } + + switch (size) { + case 1: + x = *(volatile unsigned char *)va; + break; + case 2: + x = *(volatile unsigned short *)va; + break; + case 4: + x = *(volatile unsigned long *)va; + break; + default: + break; + } + return(x); +} + +int +badpaddr(caddr_t pa, int size) +{ + vm_offset_t va; + int val; + + /* + * Do not allow crossing the page boundary. + */ + if (((int)pa & PGOFSET) + size > NBPG) { + return -1; + } + + va = mapiospace(pa, NBPG); + val = badvaddr(va, size); + unmapiospace(va); + return (val); +} + +/* + * Move pages from one kernel virtual address to another. + * Size must be a multiple of CLSIZE. + */ +void +pagemove(caddr_t from, caddr_t to, size_t size) +{ + register vm_offset_t pa; + +#ifdef DEBUG + if (size & CLOFSET) + panic("pagemove"); +#endif + while (size > 0) { + pa = pmap_extract(kernel_pmap, (vm_offset_t)from); +#ifdef DEBUG + if (pa == 0) + panic("pagemove 2"); + if (pmap_extract(kernel_pmap, (vm_offset_t)to) != 0) + panic("pagemove 3"); +#endif + pmap_remove(kernel_pmap, + (vm_offset_t)from, (vm_offset_t)from + NBPG); + pmap_enter(kernel_pmap, + (vm_offset_t)to, pa, VM_PROT_READ|VM_PROT_WRITE, 1); + from += NBPG; + to += NBPG; + size -= NBPG; + } +} + +u_int +kvtop(vm_offset_t va) +{ + extern pmap_t kernel_pmap; + + return ((u_int)pmap_extract(kernel_pmap, va)); +} diff --git a/sys/arch/mvme88k/stand/Makefile b/sys/arch/mvme88k/stand/Makefile new file mode 100644 index 00000000000..63fc38c07f6 --- /dev/null +++ b/sys/arch/mvme88k/stand/Makefile @@ -0,0 +1,5 @@ +# $Id: Makefile,v 1.3 1997/03/03 20:21:57 rahnds Exp $ + +SUBDIR= netboot sboot bootsd bootst libsa bugcrt libbug wrtvid + +.include <bsd.subdir.mk> diff --git a/sys/arch/mvme88k/stand/boot/Makefile b/sys/arch/mvme88k/stand/boot/Makefile new file mode 100644 index 00000000000..df343d81f70 --- /dev/null +++ b/sys/arch/mvme88k/stand/boot/Makefile @@ -0,0 +1,30 @@ +all: boot boot.out +CFLAGS+=-fwritable-strings -I${.CURDIR}/../include +CFLAGS+=-I${.CURDIR}/../.. -I${.CURDIR}/../../machine +CFLAGS+=-I/usr/src/sys +LDFLAGS+= -L ${.CURDIR}/../libbug -L/usr/local/lib +BOOT=FC0000 +#BOOT=1000000 + +LIBBUG!= cd $(.CURDIR)/../libbug; \ + printf "xxx:\n\techo \$${.OBJDIR}/libbug.a\n" | ${MAKE} -r -s -f - xxx + +LDADD+=${LIBBUG} #/usr/local/lib/libgcc.a +SRCS+=bugcrt.c bugio.c main.c + +.PATH: ${.CURDIR}/../bugcrt ${.CURDIR}/../libbug ${.CURDIR}/../../../../lib/libc_sa ${.CURDIR}/${MACHINE_ARCH} + +boot: bugcrt.o main.o bcopy.o memset.o printf.o ${LIBBUG} +# ld -o {.TARGET} -x -n -Ttext ${BOOT} bugcrt.o bugio.o main.o bcopy.o memset.o printf.o /usr/local/lib/libgcc.a + ld -o ${.TARGET} -x -N -Ttext ${BOOT} ${.ALLSRC} ${LDADD} + +boot.out: + ${.CURDIR}/wrtvid ${.OBJDIR}/boot && mv ${.OBJDIR}/boot.? ${.CURDIR} + +#main.o: main.c +# ${CC} ${CFLAGS} -c -O ${.ALLSRC} +# ${LD} -x -r ${.TARGET} +# ${LD} -x ${.TARGET} +# mv a.out ${.TARGET} + +.include <bsd.prog.mk> diff --git a/sys/arch/mvme88k/stand/boot/main.c b/sys/arch/mvme88k/stand/boot/main.c new file mode 100644 index 00000000000..1fbc9f65390 --- /dev/null +++ b/sys/arch/mvme88k/stand/boot/main.c @@ -0,0 +1,267 @@ +#include <sys/param.h> +#include <sys/reboot.h> +#include "bug.h" +#include "bugio.h" +#include "machine/exec.h" + +int readblk __P((int, char *)); +int loados __P((void)); +void putchar __P((char)); +void _main __P((void)); +void tapefileseek __P((int)); + +char Clun, Dlun; + +#define DEV_BSIZE 512 +#define KERNEL_LOAD_ADDR 0x10000 +#if !defined(BUG_BLKSIZE) +#define BUG_BLKSIZE 256 +#endif /* BUG_BLKSIZE */ +#define sec2blk(x) ((x) * (DEV_BSIZE/BUG_BLKSIZE)) + +struct kernel { + void *entry; + void *symtab; + void *esym; + int bflags; + int bdev; + char *kname; + void *smini; + void *emini; + unsigned int end_loaded; +} kernel; + +int howto = 0; +int bootdev = 0; +int *miniroot; + +void +putchar(char c) +{ + bugoutchr(c); +} + +main(struct bugenv *env) +{ + printf("Clun %x Dlun %x\n", env->clun, env->dlun); + Clun = (char)env->clun; + Dlun = (char)env->dlun; + loados(); + return; +} + + +loados(void) +{ + int i, size; + register char *loadaddr = (char *)KERNEL_LOAD_ADDR; /* load addr 64k*/ + struct exec *hdr; + int (*fptr)(); + int *esym; + int cnt, strtablen, ret; + char *addr; + + howto |= RB_SINGLE|RB_KDB; + + tapefileseek(2); /* seek to file 2 - the OS */ + if (readblk(1, loadaddr) == -1) { + printf("Unable to read blk 0\n"); + return 1; + } + hdr = (struct exec *)loadaddr; + + /* We only deal with ZMAGIC files */ + if ((int)hdr->a_entry != (int)(loadaddr + sizeof(struct exec))) { + printf("a_entry != loadaddr + exec size\n"); + } + size = hdr->a_text + hdr->a_data; + size -= DEV_BSIZE; /* account for the block already read */ + + printf("Loading [%x+%x", hdr->a_text, hdr->a_data); + if (readblk(size / DEV_BSIZE, loadaddr + DEV_BSIZE) == -1) { + printf("Error reading the OS\n"); + return 1; + } + + /* zero out BSS */ + + printf("+%x]", hdr->a_bss); + printf("zero'd out %x (%x)\n", loadaddr + hdr->a_text + hdr->a_data, + hdr->a_bss); + /*memset(loadaddr + hdr->a_text + hdr->a_data, 0, hdr->a_bss); */ + bzero(loadaddr + hdr->a_text + hdr->a_data, hdr->a_bss); + + addr = loadaddr + hdr->a_text + hdr->a_data + hdr->a_bss; + + if (hdr->a_syms != 0 /* && !(kernel.bflags & RB_NOSYM)*/) { + /* + * DDB expects the following layout: + * no. of syms + * symbols + * size of strtab + * entries of strtab + * esym->... + * Where as size of strtab is part of strtab, we need + * to prepend the size of symtab to satisfy ddb. + * esym is expected to point past the last byte of + * string table, rouded up to an int. + */ + bcopy(&hdr->a_syms, addr, sizeof(hdr->a_syms)); + addr += 4; /* account for a_syms copied above */ + printf (" + [ %x",hdr->a_syms); + + cnt = (hdr->a_syms + DEV_BSIZE - 1) & ~(DEV_BSIZE - 1); + + ret = readblk(cnt / DEV_BSIZE, addr); + if (ret != 0) { + printf("unable to load kernel\n"); + return 1; + } + + esym = (void *) ((int)addr + hdr->a_syms); + + if ((int)addr + cnt <= (int)esym) { + printf("missed loading count of symbols\n\r"); + return 1; + } + + addr += cnt; + + strtablen = *esym; +#if 0 + printf("start load %x end load %x %x\n", addr, + len, addr +len); + printf("esym %x *esym %x\n",esym, len); +#endif + /* + * If symbol table size is not a sector multiple, we + * already read part of the string table. Look at the + * part already read, and figure out the string table + * size. Also, adjust the size yet to read. + */ + if (hdr->a_syms != cnt) { + /* already read part of the string table */ + strtablen -= (cnt - hdr->a_syms); + } + + if (strtablen > 0) { + printf(" + %x",*esym); + + cnt = (strtablen + DEV_BSIZE -1) & ~(DEV_BSIZE - 1); + + ret = readblk(cnt / DEV_BSIZE, addr); + if (ret != 0) { + printf("unable to load kernel\n"); + return 1; + } + addr += strtablen; + printf(" ]\n"); + } else { + printf("+ %x ]\n", *esym); + } + esym = (int *)(((int)esym) + *esym); + esym = (int *)(((int)esym + 4 - 1) & ~3); + + kernel.symtab = (void *)hdr->a_syms; + kernel.esym = esym; + } else { + kernel.symtab = 0; + kernel.esym = 0; + } + + kernel.end_loaded = (unsigned int)addr; + miniroot = (int *)esym; + miniroot = (int *)(((int)miniroot + 0x1000 - 1) & ~0xFFF); + tapefileseek(3); /* seek to file 3 - minroot */ +#if 0 + if (readblk(1000, miniroot) != 0) { /* 5 Mb */ + printf("miniroot not loaded\n"); + addr = (char *)miniroot; + } else { + addr = (char *)((int)miniroot + 1000 * DEV_BSIZE); + } +#endif /* 0 */ + readblk(4096, miniroot); /* 2 Mb */ + addr = (char *)((int)miniroot + 4096 * DEV_BSIZE); + printf("esym %x miniroot @ %x (ends @ %x)\n", esym, miniroot, addr); +#if 0 + { + char *symaddr = (char *)0x01F00000; + int i; + + tapefileseek(4); /* seek to file 4 - syms */ + readblk(1, symaddr); + i = *symaddr; + i = (i * 0x1C + 4 + DEV_BSIZE) & ~(DEV_BSIZE - 1); + printf("loading %d symbols (%d sectors)\n", + *symaddr, (i + 1) * DEV_BSIZE); + readblk(i / DEV_BSIZE, symaddr + DEV_BSIZE); + readblk(100, 0x01F00000); + } +#endif + + fptr = (int (*)())hdr->a_entry; + /* + * Args are passed as + * r2 howto + * r3 end addr + * r4 (Clun << 8) | Dlun & FF + * r5 esym + * r6 miniroot + */ + bootdev = ((Clun << 8) & 0xFF00 | Dlun & 0xFF) & 0xFFFF; +#if 0 + asm volatile ("or r2, r0, %0\n\tor r3, r0, %1\n\tor r4, r0, %2\n\tor r5, r0, %3\n\tor r6, r0, %4\n\tor r7, r0, %5" + : /* no outputs */ + : "r" (howto), "r" (addr), "r" (Clun), "r" (Dlun), "r" (esym), "r" (miniroot) + : "r2", "r3", "r4", "r5", "r6", "r7"); +#endif /* 0 */ + (*fptr)(howto, addr, bootdev, esym, miniroot); + return 0; +} + +int +readblk(int n, char *addr) +{ + struct bugdisk_io io; + + io.clun = Clun; + io.dlun = Dlun; + io.status = 0; + io.addr = (void *)addr; + io.fileno = 0; /* for tape reads, start io at current pos */ + io.nblks = sec2blk(n); + io.flag = IGNOREFILENO; + io.am = 0; + bugdskrd(&io); + if (io.status) + return -1; + return 0; +} + +void +_main(void) +{ + return; +} + +void +tapefileseek(int i) +{ + struct bugdisk_io io; + void *addr = (void *)KERNEL_LOAD_ADDR; /* some number - don't care */ + + io.clun = Clun; + io.dlun = Dlun; + io.status = 0; + io.addr = addr; + io.fileno = i; /* for tape reads, this is the file no. */ + io.nblks = 0; + io.flag = 0; /* we want to turn off IFN and EOF bits */ + io.am = 0; + bugdskrd(&io); +} + +__main() +{ +} diff --git a/sys/arch/mvme88k/stand/boot/obj.m88k/boot b/sys/arch/mvme88k/stand/boot/obj.m88k/boot Binary files differdeleted file mode 100644 index 789b981caf1..00000000000 --- a/sys/arch/mvme88k/stand/boot/obj.m88k/boot +++ /dev/null diff --git a/sys/arch/mvme88k/stand/boot/wrtvid.c b/sys/arch/mvme88k/stand/boot/wrtvid.c new file mode 100644 index 00000000000..6161ccaa85a --- /dev/null +++ b/sys/arch/mvme88k/stand/boot/wrtvid.c @@ -0,0 +1,108 @@ +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <unistd.h> +#include <stdio.h> +#include "vid.h" + +#define sec2blk(x) ((x) * 2) + +main(int argc, char **argv) +{ + struct vid *pvid; + struct cfg *pcfg; + struct stat stat; + int exe_file; + int tape_vid; + int tape_exe; + unsigned int exe_addr; + unsigned short exe_addr_u; + unsigned short exe_addr_l; + char *filename; + char fileext[256]; + + if (argc == 0){ + filename = "a.out"; + } else { + filename = argv[1]; + } + exe_file = open(filename, O_RDONLY,0444); + if (exe_file == -1) + { + printf("file %s does not exist\n",filename); + exit(2); + } + sprintf (fileext,"%s%s",filename,".1"); + tape_vid = open(fileext, O_WRONLY|O_CREAT|O_TRUNC,0644); + sprintf (fileext,"%s%s",filename,".2"); + tape_exe = open(fileext, O_WRONLY|O_CREAT|O_TRUNC,0644); + + pvid = (struct vid *) malloc(sizeof (struct vid)); + + memset(pvid,0,sizeof(struct vid)); + + strcpy(pvid->vid_id, "NBSD"); + + fstat (exe_file,&stat); + /* size in 512 byte blocks round up after a.out header removed */ + /* Actually, blocks == 256 bytes */ + + pvid->vid_oss = 1; + pvid->vid_osl = (short)sec2blk((stat.st_size - 0x20 + 511) / 512); + + lseek(exe_file,0x14,SEEK_SET); + read(exe_file,&exe_addr,4); + { + union { + struct { + short osa_u; + short osa_l; + } osa_u_l; + int osa; + } u; + u.osa = exe_addr; + pvid->vid_osa_u = u.osa_u_l.osa_u; + pvid->vid_osa_l = u.osa_u_l.osa_l; + } + pvid->vid_cas = 1; + pvid->vid_cal = 1; + /* do not want to write past end of structure, not null terminated */ + strcpy(pvid->vid_mot,"MOTOROL"); + pvid->vid_mot[7] = 'A'; + + write(tape_vid,pvid,sizeof(struct vid)); + + free(pvid); + + pcfg = (struct cfg *) malloc (sizeof(struct cfg)); + + memset(pcfg,0,sizeof(struct cfg)); + + pcfg->cfg_rec = 0x100; + pcfg->cfg_psm = 0x200; + + write(tape_vid,pcfg,sizeof(struct cfg)); + + free(pcfg); + + copy_exe(exe_file,tape_exe); + close (exe_file); + close (tape_vid); + close (tape_exe); +} + +#define BUF_SIZ 512 +copy_exe(exe_file,tape_exe) +{ + char *buf; + int cnt = 0; + + buf = (char *)malloc (BUF_SIZ); + + lseek (exe_file,0x20,SEEK_SET); + while (BUF_SIZ == (cnt = read(exe_file, buf , BUF_SIZ))) { + write (tape_exe,buf,cnt); + } + memset (&buf[cnt],0,BUF_SIZ-cnt); + write (tape_exe,buf,BUF_SIZ); +} diff --git a/sys/arch/mvme88k/stand/bootsd/bootsd b/sys/arch/mvme88k/stand/bootsd/bootsd Binary files differdeleted file mode 100644 index 5289b6e0087..00000000000 --- a/sys/arch/mvme88k/stand/bootsd/bootsd +++ /dev/null diff --git a/sys/arch/mvme88k/stand/bootsd/bootsd.bin b/sys/arch/mvme88k/stand/bootsd/bootsd.bin Binary files differdeleted file mode 100644 index 4ea194d6a22..00000000000 --- a/sys/arch/mvme88k/stand/bootsd/bootsd.bin +++ /dev/null diff --git a/sys/arch/mvme88k/stand/bootsd/bootsd.bug b/sys/arch/mvme88k/stand/bootsd/bootsd.bug Binary files differdeleted file mode 100644 index 52ba1e9769b..00000000000 --- a/sys/arch/mvme88k/stand/bootsd/bootsd.bug +++ /dev/null diff --git a/sys/arch/mvme88k/stand/bootsd/sdboot b/sys/arch/mvme88k/stand/bootsd/sdboot Binary files differdeleted file mode 100644 index a79942fc568..00000000000 --- a/sys/arch/mvme88k/stand/bootsd/sdboot +++ /dev/null diff --git a/sys/arch/mvme88k/stand/bootst/bak.c b/sys/arch/mvme88k/stand/bootst/bak.c deleted file mode 100644 index a93d9bc5d49..00000000000 --- a/sys/arch/mvme88k/stand/bootst/bak.c +++ /dev/null @@ -1,382 +0,0 @@ -#include "bug.h" -#include <sys/types.h> -#include <sys/param.h> -#include <sys/reboot.h> -#include <sys/exec.h> -/* -#include <sys/exec_aout.h> -*/ - -#define KERNEL_LOAD_ADDRESS ((void *)0x4000) -#define BUG_BLOCK_SIZE 512 -#define VERSION 0x0000 - -#define RB_NOSYM 0x400 - - - -void memset(void *,char,size_t); -void printf(char *,...); -void parse_args(struct bugargs *pbugargs); -int read_tape_block(short ctrl, short dev, short *status, void *addr, - int *cnt, int blk_num, unsigned char *flags,int verbose); -int load_kern(); - -struct kernel { - void *entry; - void *symtab; - void *esym; - int bflags; - int bdev; - char *kname; - void *smini; - void *emini; - u_int end_loaded; -} kernel; - -typedef (* kernel_entry)(struct bugargs *,struct kernel *); - -void main(struct bugargs *pbugargs) -{ - kernel_entry addr; - - /* - print_bugargs(pbugargs); - print_time(); - print_brdid(); - print_memory(); - */ - parse_args(pbugargs); - if (1 == load_kern(pbugargs)) { - printf("unsuccessful in loading kernel\n\r"); - } else { - addr = kernel.entry; - printf("kernel loaded at %x\n\r",addr); - printf("kernel.entry %x\n\r",kernel.entry); - printf("kernel.symtab %x\n\r",kernel.symtab); - printf("kernel.esym %x\n\r",kernel.esym); - printf("kernel.bflags %x\n\r",kernel.bflags); - printf("kernel.bdev %x\n\r",kernel.bdev); - if (kernel.kname) { - printf("kernel.kname <%s>\n\r",kernel.kname); - } else { - printf("kernel.kname <null>\n\r"); - } - printf("kernel.end_loaded %x\n\r",kernel.end_loaded); - - if (kernel.bflags & RB_MINIROOT) { - loadmini(kernel.end_loaded,pbugargs); - } - - printf("kernel.smini %x\n\r",kernel.smini); - printf("kernel.emini %x\n\r",kernel.emini); - printf("kernel.end_loaded %x\n\r",kernel.end_loaded); - if (kernel.bflags & RB_HALT) - bug_return(); - (addr)(pbugargs,&kernel); - } - - return; -} -#define BUG_SCALE (512/BUG_BLOCK_SIZE) -int -read_tape_block(short ctrl, short dev, short *status, void *addr, - int *cnt, int blk_num, unsigned char *flags,int verbose) -{ - struct bug_dskio dio; - int ret; - int len, len1; - - len = *cnt; - do { - if (len > 16 * 1024) { - len1 = 16 * 1024; - }else{ - len1 = len; - } - dio.ctrl_lun = ctrl; - dio.dev_lun = dev; - dio.status = *status; - dio.pbuffer = addr; - dio.blk_num = blk_num; - dio.blk_cnt = len1 /(512/BUG_SCALE); - dio.flag = *flags; - dio.addr_mod = 0; - - if (verbose){ - printf("saddr %x eaddr %x", dio.pbuffer, - (int)dio.pbuffer + (dio.blk_cnt * BUG_BLOCK_SIZE)); - } - - ret = bug_diskrd(&dio); - - *status = dio.status; - *cnt += (dio.blk_cnt/BUG_SCALE)*512; - if (verbose) { - printf("status %x ret %d ",*status, ret); - printf("flags %x\n\r",*flags); - } - len -= len1; - addr += len1; - blk_num += len1 /(512/BUG_SCALE); - } while (len > 0); - return ret; -} -int verbose = 1; -int -load_kern(struct bugargs *pbugargs) -{ - int ret; - char *addr; - unsigned char flags; - short status = 0; - int blk_num; - struct exec *pexec; - int magic; - int *esym; - int *symtab; - int cnt, len; - char buf[512]; - - blk_num = 2; - /* flags = IGNORE_FILENUM ; */ - flags = 0; - cnt = 512 ; - ret = read_tape_block(pbugargs->ctrl_lun, pbugargs->dev_lun, &status, buf, - &cnt, blk_num, &flags, verbose); - if (ret != 0) { - printf("unable to load kernel 1\n\r"); - return 1; - } - pexec = (struct exec *) buf; - if ((N_GETMID(*pexec) != MID_M68K) && - ( N_GETMID(*pexec) != MID_M68K4K )) - { - printf("invalid mid on kernel\n\r"); - return 1; - } - { - short *pversion = (void *)(KERNEL_LOAD_ADDRESS+0x20); - if (VERSION != *pversion) { - printf("invalid version of kernel/loader\n\r"); - bug_return(); - } - } - magic = N_GETMAGIC(*pexec); - switch (magic) { - case ZMAGIC: - break; - case NMAGIC: - printf ("NMAGIC not yet supported"); - case OMAGIC: - case QMAGIC: - default: - printf("Unknown or unsupported magic type <%x>\n\r", - magic); - return 1; - break; - } - if ( magic == ZMAGIC ) { - - status = 0; - addr = pexec->a_entry & ~0x0FFF; - bcopy(&buf, addr, 512); - /* 2nd block of exe */ - addr += 512; - - if ((int)pexec->a_entry != (int)KERNEL_LOAD_ADDRESS + 0x22) { - printf ("warning kernel start address not %x, %x\n\r", - (int)KERNEL_LOAD_ADDRESS + 0x22,pexec->a_entry); - printf ("kernel loaded at %x\n\r",KERNEL_LOAD_ADDRESS); - - } - printf ("text 0x%x data 0x%x bss 0x%x\n\r", - pexec->a_text, pexec->a_data, pexec->a_bss); - - len = (pexec->a_text - 512) ; /* XXX */ - len += (pexec->a_data ); - - printf ("loading [ %x + %x ",pexec->a_text,pexec->a_data); - - cnt = len; - flags = IGNORE_FILENUM ; - ret = read_tape_block(pbugargs->ctrl_lun, pbugargs->dev_lun, - &status, addr, &cnt, blk_num, &flags, verbose); - if (ret != 0 || cnt != len) { - printf("unable to load kernel 2\n\r"); - return 1; - } - addr += len; - - /* Skip over text and data and zero bss. */ - len = pexec->a_bss; - printf ("+ %x",len); - memset (KERNEL_LOAD_ADDRESS + (pexec->a_text + pexec->a_data), - 0, pexec->a_bss); - addr +=len; - - if (pexec->a_syms != 0 && !(kernel.bflags & RB_NOSYM)) { - printf (" + [ %x",pexec->a_syms); - addr += 4; /* skip over _end symbol */ - symtab = (void *)pexec->a_syms; - len = pexec->a_syms; - cnt = len; - flags = IGNORE_FILENUM ; - ret = read_tape_block(pbugargs->ctrl_lun, - pbugargs->dev_lun, &status, addr, - &cnt, blk_num, &flags, verbose); - if (ret != 0 || cnt != len) - { - printf("unable to load kernel 3\n\r"); - return 1; - } - - /* this value should have already been loaded XXX */ - esym = (void *) ((u_int)addr + pexec->a_syms); - if ((int)addr +cnt <= (int) esym) { - printf("missed loading count of symbols\n\r"); - return 1; - } - addr +=cnt ; - - - len = *esym; -#if 0 - printf("start load %x end load %x %x\n\r", addr, - len, addr +len); - printf("esym %x *esym %x\n\r",esym, len); -#endif - /* dont load tail of already loaded */ - len -= (u_int)addr - (u_int)esym; - - if (len > 0) { - printf(" + %x",*esym); - esym = (void *)(addr + len); - cnt = len; - flags = IGNORE_FILENUM ; - ret = read_tape_block(pbugargs->ctrl_lun, pbugargs->dev_lun, &status, addr, - &cnt, blk_num, &flags, verbose); - if (ret != 0 || cnt != len) - { - printf("unable to load kernel 4\n\r"); - return 1; - } - addr += len; - printf(" ]"); - } else { - printf("+ %x ]",*esym); - } - esym = (int *)(((int)esym) + *esym); - - kernel.symtab = symtab; - kernel.esym = esym; - } else { - kernel.symtab = 0; - kernel.esym = 0; - } - kernel.end_loaded = (int)addr; - flags = IGNORE_FILENUM | END_OF_FILE; - cnt = 8192; - printf ("removing pad ["); - ret = read_tape_block(pbugargs->ctrl_lun, pbugargs->dev_lun, &status, addr, - &cnt, blk_num, &flags, verbose); - if (ret != 0) { - printf("unable to load kernel 5\n\r"); - return 1; - } - printf (" %d ]",cnt); - - printf("]\n\r"); - } - - - kernel.entry = (void *)pexec->a_entry; - return 0; -} -loadmini(u_int addr,struct bugargs *pbugargs) -{ - int ret; - unsigned char flags; - short status = 0; - int verbose = 0; - int blk_num; - int cnt; - blk_num = 3; - /* align addr to some boundary */ -#define ALIGN_F 0x4 - addr = (u_int)((((int)addr + ALIGN_F -1)/ALIGN_F) * ALIGN_F); -#undef ALIGN_F - flags = END_OF_FILE; - cnt = 6144 * 512 ; /* some abserdly large value. (3meg) */ - printf("loading miniroot[ "); - ret = read_tape_block(4, pbugargs->dev_lun, &status, (void*)addr, - &cnt, blk_num, &flags, verbose); - if (ret != 0) { - printf("unable to load miniroot\n\r"); - return 1; - } - kernel.smini = (void *)addr; - printf("%d ]\n\r",(BUG_BLOCK_SIZE * cnt)); - kernel.emini = (void*)((u_int)addr + (BUG_BLOCK_SIZE * cnt)); - kernel.end_loaded = (u_int)kernel.emini; -} -void -parse_args(struct bugargs *pargs) -{ - char * ptr = pargs->arg_start; - char c, *name; - int howto; - howto = ( 0 | RB_DFLTROOT ); - name = NULL; - - if (pargs->arg_start != pargs->arg_end) { - while (c = *ptr) { - while (c == ' ') - c = *++ptr; - if (!c) - return; - if (c == '-') - while ((c = *++ptr) && c != ' ') { - if (c == 'a') - howto |= RB_ASKNAME; - else if (c == 'b') - howto |= RB_HALT; - else if (c == 'y') - howto |= RB_NOSYM; -#ifdef CHECKSUM - else if (c == 'c') - cflag = 1; -#endif - else if (c == 'd') - howto |= RB_KDB; - else if (c == 'm') - howto |= RB_MINIROOT; - else if (c == 'r') -/* change logic to have force root to config device UNLESS arg given */ - howto &= ~RB_DFLTROOT; - else if (c == 's') - howto |= RB_SINGLE; - } - else { - name = ptr; - while ((c = *++ptr) && c != ' '); - if (c) - *ptr++ = 0; - } - } - if (RB_NOSYM & howto) printf("RB_NOSYM\n\r"); - if (RB_AUTOBOOT & howto) printf("RB_AUTOBOOT\n\r"); - if (RB_SINGLE & howto) printf("RB_SINGLE\n\r"); - if (RB_NOSYNC & howto) printf("RB_NOSYNC\n\r"); - if (RB_HALT & howto) printf("RB_HALT\n\r"); - if (RB_DFLTROOT & howto) printf("RB_DFLTROOT\n\r"); - if (RB_KDB & howto) printf("RB_KDB\n\r"); - if (RB_RDONLY & howto) printf("RB_RDONLY\n\r"); - if (RB_DUMP & howto) printf("RB_DUMP\n\r"); - if (RB_MINIROOT & howto) printf("RB_MINIROOT\n\r"); - - } - kernel.bflags = howto; - kernel.kname = name; -} - diff --git a/sys/arch/mvme88k/stand/bootst/bootst b/sys/arch/mvme88k/stand/bootst/bootst Binary files differdeleted file mode 100644 index 53c7665552c..00000000000 --- a/sys/arch/mvme88k/stand/bootst/bootst +++ /dev/null diff --git a/sys/arch/mvme88k/stand/bootst/bootst.bug b/sys/arch/mvme88k/stand/bootst/bootst.bug Binary files differdeleted file mode 100644 index 34dbd2763ba..00000000000 --- a/sys/arch/mvme88k/stand/bootst/bootst.bug +++ /dev/null diff --git a/sys/arch/mvme88k/stand/bootst/stboot b/sys/arch/mvme88k/stand/bootst/stboot Binary files differdeleted file mode 100644 index a6b19b34db4..00000000000 --- a/sys/arch/mvme88k/stand/bootst/stboot +++ /dev/null diff --git a/sys/arch/mvme88k/stand/bugcrt/Makefile b/sys/arch/mvme88k/stand/bugcrt/Makefile new file mode 100644 index 00000000000..19d6add99b3 --- /dev/null +++ b/sys/arch/mvme88k/stand/bugcrt/Makefile @@ -0,0 +1,24 @@ +# $Id: Makefile,v 1.3 1997/03/03 20:22:14 rahnds Exp $ + +CFLAGS+=-I${.CURDIR}/../../include + +.include "${MACHINE_ARCH}/Makefile.inc" + +.PATH: ${.CURDIR}/${MACHINE_ARCH} + +OBJS=bugcrt.o + +CLEANFILES+=a.out + +all: ${OBJS} + +bugcrt.o: bugcrt.c + ${CC} ${CFLAGS} -c ${.ALLSRC} + ${LD} -x -r ${.TARGET} + mv a.out ${.TARGET} + +install: + +lint tags: + +.include <bsd.prog.mk> diff --git a/sys/arch/mvme88k/stand/bugexec/Makefile b/sys/arch/mvme88k/stand/bugexec/Makefile new file mode 100644 index 00000000000..3ed0ff02de6 --- /dev/null +++ b/sys/arch/mvme88k/stand/bugexec/Makefile @@ -0,0 +1,26 @@ +all: hello +SRCS= hello.c +OBJS= hello.o + +CFLAGS+=-I${.CURDIR}/include -I${.CURDIR}/${MACHINE_ARCH} +CFLAGS+=-I${.CURDIR}/../include -I${.CURDIR}/../.. -I/usr/src/sys +CFLAGS+=-fwritable-strings + +LIBBUG!= cd $(.CURDIR)/../libbug; \ + printf "xxx:\n\techo \$${.OBJDIR}/libbug.a\n" | ${MAKE} -r -s -f - xxx + +BUGCRT!= cd $(.CURDIR)/../bugcrt; \ + printf "xxx:\n\techo \$${.OBJDIR}/bugcrt.o\n" | ${MAKE} -r -s -f - xxx + +KERNCRT!= cd $(.CURDIR)/../kerncrt; \ + printf "xxx:\n\techo \$${.OBJDIR}/kerncrt.o\n" | ${MAKE} -r -s -f - xxx + +LDADD+=${LIBBUG} /usr/local/lib/libgcc.a + +hello: $(OBJS) ${LIBBUG} + ${LD} -x -Ttext 10020 ${KERNCRT} $(OBJS) ${LDADD} -o ${.TARGET} +clean: + rm -f a.out *.core + rm -f hello.o hello.bug hello.bug.1 hello.bug.2 + +.include <bsd.prog.mk> diff --git a/sys/arch/mvme88k/stand/bugexec/hello.c b/sys/arch/mvme88k/stand/bugexec/hello.c new file mode 100644 index 00000000000..08ab75d2a27 --- /dev/null +++ b/sys/arch/mvme88k/stand/bugexec/hello.c @@ -0,0 +1,54 @@ +#include "bug.h" +#include "bugio.h" + +void putchar __P((char)); +int bcd2int __P((unsigned int)); + +void +putchar(char c) +{ + bugoutchr(c); +} + +main(struct bugenv *env) +{ + struct bugrtc rtc; + struct bugbrdid brdid; + + bugrtcrd(&rtc); + printf("From RTC:\n"); + printf("Year %d\tMonth %d\tDay %d\tDay of Week %d\n", + bcd2int(rtc.Y), bcd2int(rtc.M), bcd2int(rtc.D), bcd2int(rtc.d)); + printf("Hour %d\tMin %d\tSec %d\tCal %d\n", + bcd2int(rtc.H), bcd2int(rtc.m), bcd2int(rtc.s), bcd2int(rtc.c)); + printf("From BRDID:\n"); + bugbrdid(&brdid); +/* printf("Eye catcher %c%c%c%c\n", brdid.eye[0], brdid.eye[1], + brdid.eye[2], brdid.eye[3]); */ + printf("Board no %d (%d) \tsuffix %c%c\n", bcd2int(brdid.brdno), + brdid.brdno, brdid.brdsuf[0], brdid.brdsuf[1]); +/* printf("Clun %x\tdlun %x\n", brdid.clun, brdid.dlun); */ + return 0; +} + +ipow(int base, int i) +{ + int cnt = 1; + while (i--) { + cnt *= base; + } + return cnt; +} + +int +bcd2int(unsigned int i) +{ + unsigned val = 0; + int cnt = 0; + while (i) { + val += (i&0xf) * ipow(10,cnt); + cnt++; + i >>= 4; + } + return val; +} diff --git a/sys/arch/mvme88k/stand/bugexec/wrtos.c b/sys/arch/mvme88k/stand/bugexec/wrtos.c new file mode 100644 index 00000000000..1e01b697399 --- /dev/null +++ b/sys/arch/mvme88k/stand/bugexec/wrtos.c @@ -0,0 +1,64 @@ +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <unistd.h> +#include <stdio.h> +#include "vid.h" + +#define sec2blk(x) ((x) * 2) +#define BUF_SIZ 512 + +main(int argc, char **argv) +{ + struct vid *pvid; + struct cfg *pcfg; + struct stat stat; + int exe_file; + int tape_vid; + int tape_exe; + char *filename; + char fileext[256]; + char hdrbuf[BUF_SIZ]; + + if (argc == 0){ + filename = "a.out"; + } else { + filename = argv[1]; + } + exe_file = open(filename, O_RDONLY,0444); + if (exe_file == -1) + { + printf("file %s does not exist\n",filename); + exit(2); + } + sprintf (fileext,"%s%s",filename,".1"); + tape_vid = open(fileext, O_WRONLY|O_CREAT|O_TRUNC,0644); + sprintf (fileext,"%s%s",filename,".2"); + tape_exe = open(fileext, O_WRONLY|O_CREAT|O_TRUNC,0644); + + lseek(exe_file,0,SEEK_SET); + memset (hdrbuf,0,BUF_SIZ); + read(exe_file,hdrbuf, 0x20); /* read the header */ + + write(tape_vid,hdrbuf,BUF_SIZ); + + copy_exe(exe_file,tape_exe); + close (exe_file); + close (tape_vid); + close (tape_exe); +} + +copy_exe(exe_file,tape_exe) +{ + char *buf; + int cnt = 0; + + buf = (char *)malloc (BUF_SIZ); + + lseek (exe_file,0x20,SEEK_SET); + while (BUF_SIZ == (cnt = read(exe_file, buf , BUF_SIZ))) { + write (tape_exe,buf,cnt); + } + memset (&buf[cnt],0,BUF_SIZ-cnt); + write (tape_exe,buf,BUF_SIZ); +} diff --git a/sys/arch/mvme88k/stand/include/bug.h b/sys/arch/mvme88k/stand/include/bug.h new file mode 100644 index 00000000000..93fe1e6ccd5 --- /dev/null +++ b/sys/arch/mvme88k/stand/include/bug.h @@ -0,0 +1,8 @@ +struct bugenv { + int clun; + int dlun; + int ipl; + int (*entry)(); + char bootargs[256]; +}; + diff --git a/sys/arch/mvme88k/stand/include/bugio.h b/sys/arch/mvme88k/stand/include/bugio.h new file mode 100644 index 00000000000..74bb77bd336 --- /dev/null +++ b/sys/arch/mvme88k/stand/include/bugio.h @@ -0,0 +1,62 @@ +#include "sys/cdefs.h" + +struct bugdisk_io { + char clun; + char dlun; + short status; + void *addr; + int blkno; +#define fileno blkno + short nblks; + char flag; +#define FILEMARKFLAG 0x80 +#define IGNOREFILENO 0x02 +#define ENDOFFILE 0x01 + char am; +}; + +/* values are in BCD {upper nibble+lower nibble} */ + +struct bugrtc { + unsigned char Y; + unsigned char M; + unsigned char D; + unsigned char d; + unsigned char H; + unsigned char m; + unsigned char s; + unsigned char c; +}; + +/* Board ID - lots of info */ + +struct bugbrdid { + unsigned char eye[4]; + char rev; + char month; + char day; + char year; + short packetsize; + short dummy; + short brdno; + unsigned char brdsuf[2]; + char options[3]; + char family:4; + char cpu:4; + short clun; + short dlun; + short type; + short dev; + int option; +}; + +char buginchr __P((void)); +int buginstat __P((void)); +int bugoutchr __P((unsigned char)); +int bugoutstr __P((char *, char *)); +int bugpcrlf __P((void)); +int bugdskrd __P((struct bugdisk_io *)); +int bugdskwr __P((struct bugdisk_io *)); +int bugrtcrd __P((struct bugrtc *)); +int bugreturn __P((void)); +int bugbrdid __P((struct bugbrdid *)); diff --git a/sys/arch/mvme88k/stand/kerncrt/Makefile b/sys/arch/mvme88k/stand/kerncrt/Makefile new file mode 100644 index 00000000000..9645605f8aa --- /dev/null +++ b/sys/arch/mvme88k/stand/kerncrt/Makefile @@ -0,0 +1,9 @@ +OBJ=kerncrt.o +CFLAGS+=-I${.CURDIR}/../include +CFLAGS+=-I${.CURDIR}/../.. +CFLAGS+=-I/usr/src/sys + +SRCS=kerncrt.c +all: kerncrt.o + +.include <bsd.prog.mk> diff --git a/sys/arch/mvme88k/stand/kerncrt/kerncrt.c b/sys/arch/mvme88k/stand/kerncrt/kerncrt.c new file mode 100644 index 00000000000..a5f04d2398a --- /dev/null +++ b/sys/arch/mvme88k/stand/kerncrt/kerncrt.c @@ -0,0 +1,11 @@ +#include "bug.h" +start(struct bugenv *bugarea) +{ + main(bugarea); + bugreturn(); +} + +__main() +{ + return; +} diff --git a/sys/arch/mvme88k/stand/libbug/Makefile b/sys/arch/mvme88k/stand/libbug/Makefile new file mode 100644 index 00000000000..ba775e5693d --- /dev/null +++ b/sys/arch/mvme88k/stand/libbug/Makefile @@ -0,0 +1,14 @@ +LIB=bug + +NOPIC= +NOPROFILE= + +CFLAGS+=-I${.CURDIR}/../../include + +SRCS=delay.c diskrd.c diskwr.c getbrdid.c instat.c outln.c outstr.c \ + return.c rtc_rd.c +.PATH: ${.CURDIR}/../../../../lib/libc_sa ${.CURDIR}/${MACHINE_ARCH} + +install: + +.include <bsd.lib.mk> diff --git a/sys/arch/mvme88k/stand/libbug/bugio.c b/sys/arch/mvme88k/stand/libbug/bugio.c new file mode 100644 index 00000000000..6406dac3e13 --- /dev/null +++ b/sys/arch/mvme88k/stand/libbug/bugio.c @@ -0,0 +1,101 @@ +#include "bugio.h" + +#define INCHR "0x0000" +#define INSTAT "0x0001" +#define INLN "0x0002" +#define READSTR "0x0003" +#define READLN "0x0004" +#define DSKRD "0x0010" +#define DSKWR "0x0011" +#define DSKCFIG "0x0012" +#define OUTCHR "0x0020" +#define PCRLF "0x0026" +#define TMDISP "0x0042" +#define DELAY "0x0043" +#define RTC_DSP "0x0052" +#define RTC_RD "0x0053" +#define RETURN "0x0063" +#define BRD_ID "0x0070" +#define BUGTRAP "0x01F0" + +char +buginchr(void) +{ + register int cc asm("r2"); + asm("or r9,r0," INCHR); + asm("tb0 0,r0,0x1F0"); + /*asm("or %0,r0,r2" : "=r" (cc) : );*/ + return ((char)cc & 0xFF); +} + +/* return 1 if not empty else 0 */ + +buginstat(void) +{ + int ret; + asm("or r9,r0," INSTAT); + asm("tb0 0,r0,0x1F0"); + asm("or %0,r0,r2" : "=r" (ret) : ); + return (ret & 0x40 ? 1 : 0); +} + +bugoutchr(unsigned char c) +{ + unsigned char cc; + + if ((cc = c) == '\n') { + bugpcrlf(); + return; + } + asm("or r2,r0,%0" : : "r" (cc)); + asm("or r9,r0," OUTCHR); + asm("tb0 0,r0,0x1F0"); +} + +bugpcrlf(void) +{ + asm("or r9,r0," PCRLF); + asm("tb0 0,r0,0x1F0"); +} +/* return 0 on success */ + +bugdskrd(struct bugdisk_io *arg) +{ + int ret; + asm("or r9,r0, " DSKRD); + asm("tb0 0,r0,0x1F0"); + asm("or %0,r0,r2" : "=r" (ret) : ); + return ((ret&0x4) == 0x4 ? 1 : 0); +} + +/* return 0 on success */ + +bugdskwr(struct bugdisk_io *arg) +{ + int ret; + asm("or r9,r0, " DSKWR); + asm("tb0 0,r0,0x1F0"); + asm("or %0,r0,r2" : "=r" (ret) : ); + return ((ret&0x4) == 0x4 ? 1 : 0); +} + +bugrtcrd(struct bugrtc *rtc) +{ + asm("or r9,r0, " RTC_RD); + asm("tb0 0,r0,0x1F0"); +} + +bugreturn(void) +{ + asm("or r9,r0, " RETURN); + asm("tb0 0,r0,0x1F0"); +} + +bugbrdid(struct bugbrdid *id) +{ + struct bugbrdid *ptr; + asm("or r9,r0, " BRD_ID); + asm("tb0 0,r0,0x1F0"); + asm("or %0,r0,r2" : "=r" (ptr) : ); + bcopy(ptr, id, sizeof(struct bugbrdid)); +} diff --git a/sys/arch/mvme88k/stand/libbug/log1 b/sys/arch/mvme88k/stand/libbug/log1 deleted file mode 100644 index 448b6b71f94..00000000000 --- a/sys/arch/mvme88k/stand/libbug/log1 +++ /dev/null @@ -1,9 +0,0 @@ -delay.o delay.o -diskrd.o diskrd.o -diskwr.o diskwr.o -getbrdid.o getbrdid.o -instat.o instat.o -outln.o outln.o -outstr.o outstr.o -return.o return.o -rtc_rd.o rtc_rd.o diff --git a/sys/arch/mvme88k/stand/libbug/log2 b/sys/arch/mvme88k/stand/libbug/log2 deleted file mode 100644 index 7a8950e635f..00000000000 --- a/sys/arch/mvme88k/stand/libbug/log2 +++ /dev/null @@ -1,9 +0,0 @@ -rtc_rd.o -return.o -outstr.o -outln.o -instat.o -getbrdid.o -diskwr.o -diskrd.o -delay.o diff --git a/sys/arch/mvme88k/stand/libsa/log1 b/sys/arch/mvme88k/stand/libsa/log1 deleted file mode 100644 index 17047779eef..00000000000 --- a/sys/arch/mvme88k/stand/libsa/log1 +++ /dev/null @@ -1,130 +0,0 @@ -nfs.o nfs.o -rpc.o rpc.o -net.o net.o -ether.o ether.o -arp.o arp.o -in_cksum.o in_cksum.o -netif.o netif.o -bootparam.o bootparam.o -rarp.o rarp.o -alloc.o alloc.o -bcopy.o bcopy.o -memcpy.o memcpy.o -close.o close.o -getfile.o getfile.o -open.o open.o -printf.o printf.o -read.o read.o -strerror.o strerror.o -ufs.o ufs.o -globals.o globals.o -lseek.o lseek.o -closeall.o closeall.o -dev.o dev.o -dkcksum.o dkcksum.o -nullfs.o nullfs.o -fstat.o fstat.o -ashrdi3.o ashrdi3.o -bcmp.o bcmp.o -bzero.o bzero.o -strcmp.o strcmp.o -strlen.o strlen.o -exec_sun.o exec_sun.o -clock.o clock.o -devopen.o devopen.o -dvma.o dvma.o -gets.o gets.o -panic.o panic.o -promboot.o promboot.o -promcons.o promcons.o -ufs.o ashrdi3.o -dvma.o alloc.o -nfs.o alloc.o -ufs.o alloc.o -net.o arp.o -net.o arp.o -arp.o globals.o -ether.o globals.o -rarp.o globals.o -arp.o bcmp.o -ether.o bcmp.o -rarp.o bcmp.o -arp.o bcopy.o -bootparam.o bcopy.o -ether.o bcopy.o -exec_sun.o bcopy.o -memcpy.o bcopy.o -net.o bcopy.o -nfs.o bcopy.o -rarp.o bcopy.o -ufs.o bcopy.o -arp.o bzero.o -net.o bzero.o -netif.o bzero.o -nfs.o bzero.o -rarp.o bzero.o -rpc.o bzero.o -ufs.o bzero.o -closeall.o close.o -exec_sun.o close.o -open.o devopen.o -dvma.o alloc.o -nfs.o alloc.o -ufs.o alloc.o -gets.o promcons.o -getfile.o gets.o -net.o clock.o -net.o in_cksum.o -arp.o net.o -ether.o netif.o -ether.o netif.o -net.o globals.o -rarp.o globals.o -exec_sun.o open.o -getfile.o open.o -arp.o panic.o -exec_sun.o panic.o -net.o panic.o -netif.o panic.o -arp.o printf.o -bootparam.o printf.o -exec_sun.o printf.o -getfile.o printf.o -net.o printf.o -netif.o printf.o -nfs.o printf.o -panic.o printf.o -rarp.o printf.o -rpc.o printf.o -gets.o promcons.o -printf.o promcons.o -exec_sun.o read.o -arp.o ether.o -net.o ether.o -rarp.o ether.o -rpc.o net.o -bootparam.o rpc.o -nfs.o rpc.o -bootparam.o rpc.o -bootparam.o rpc.o -bootparam.o rpc.o -nfs.o rpc.o -arp.o ether.o -net.o ether.o -rarp.o ether.o -arp.o net.o -rarp.o net.o -rpc.o net.o -rpc.o net.o -bootparam.o netif.o -nfs.o netif.o -rarp.o netif.o -strerror.o printf.o -ufs.o strcmp.o -rpc.o strerror.o -bootparam.o strlen.o -nfs.o strlen.o -ufs.o strlen.o -nfs.o printf.o -read.o printf.o -ufs.o printf.o diff --git a/sys/arch/mvme88k/stand/libsa/log2 b/sys/arch/mvme88k/stand/libsa/log2 deleted file mode 100644 index 31ecde33da0..00000000000 --- a/sys/arch/mvme88k/stand/libsa/log2 +++ /dev/null @@ -1,39 +0,0 @@ -promboot.o -dvma.o -exec_sun.o -fstat.o -nullfs.o -dkcksum.o -dev.o -closeall.o -lseek.o -ufs.o -read.o -getfile.o -close.o -memcpy.o -rarp.o -bootparam.o -nfs.o -gets.o -strlen.o -strcmp.o -ashrdi3.o -open.o -alloc.o -rpc.o -devopen.o -strerror.o -arp.o -net.o -clock.o -in_cksum.o -ether.o -bcmp.o -globals.o -bcopy.o -netif.o -panic.o -bzero.o -printf.o -promcons.o diff --git a/sys/arch/mvme88k/stand/netboot/netboot b/sys/arch/mvme88k/stand/netboot/netboot Binary files differdeleted file mode 100644 index a2fe675457c..00000000000 --- a/sys/arch/mvme88k/stand/netboot/netboot +++ /dev/null diff --git a/sys/arch/mvme88k/stand/netboot/netboot.bin b/sys/arch/mvme88k/stand/netboot/netboot.bin Binary files differdeleted file mode 100644 index 2c1b35d8fa7..00000000000 --- a/sys/arch/mvme88k/stand/netboot/netboot.bin +++ /dev/null diff --git a/sys/arch/mvme88k/stand/obj.m88k/boot b/sys/arch/mvme88k/stand/obj.m88k/boot Binary files differdeleted file mode 100644 index 30d5f26c387..00000000000 --- a/sys/arch/mvme88k/stand/obj.m88k/boot +++ /dev/null diff --git a/sys/arch/mvme88k/stand/obj.m88k/boot.1 b/sys/arch/mvme88k/stand/obj.m88k/boot.1 Binary files differdeleted file mode 100644 index 112b445d07d..00000000000 --- a/sys/arch/mvme88k/stand/obj.m88k/boot.1 +++ /dev/null diff --git a/sys/arch/mvme88k/stand/obj.m88k/boot.2 b/sys/arch/mvme88k/stand/obj.m88k/boot.2 Binary files differdeleted file mode 100644 index 6248ab12051..00000000000 --- a/sys/arch/mvme88k/stand/obj.m88k/boot.2 +++ /dev/null diff --git a/sys/arch/mvme88k/stand/openbsd/bootsd/bootsd b/sys/arch/mvme88k/stand/openbsd/bootsd/bootsd Binary files differdeleted file mode 100644 index cee266d758c..00000000000 --- a/sys/arch/mvme88k/stand/openbsd/bootsd/bootsd +++ /dev/null diff --git a/sys/arch/mvme88k/stand/openbsd/bootsd/bootsd.bin b/sys/arch/mvme88k/stand/openbsd/bootsd/bootsd.bin Binary files differdeleted file mode 100644 index 7f1662f5309..00000000000 --- a/sys/arch/mvme88k/stand/openbsd/bootsd/bootsd.bin +++ /dev/null diff --git a/sys/arch/mvme88k/stand/openbsd/bootsd/bootsd.bug b/sys/arch/mvme88k/stand/openbsd/bootsd/bootsd.bug Binary files differdeleted file mode 100644 index ec762438c25..00000000000 --- a/sys/arch/mvme88k/stand/openbsd/bootsd/bootsd.bug +++ /dev/null diff --git a/sys/arch/mvme88k/stand/openbsd/bootsd/sdboot b/sys/arch/mvme88k/stand/openbsd/bootsd/sdboot Binary files differdeleted file mode 100644 index baf73ee5fdf..00000000000 --- a/sys/arch/mvme88k/stand/openbsd/bootsd/sdboot +++ /dev/null diff --git a/sys/arch/mvme88k/stand/openbsd/bootst/bootst b/sys/arch/mvme88k/stand/openbsd/bootst/bootst Binary files differdeleted file mode 100644 index 53c7665552c..00000000000 --- a/sys/arch/mvme88k/stand/openbsd/bootst/bootst +++ /dev/null diff --git a/sys/arch/mvme88k/stand/openbsd/bootst/bootst.bug b/sys/arch/mvme88k/stand/openbsd/bootst/bootst.bug Binary files differdeleted file mode 100644 index 34dbd2763ba..00000000000 --- a/sys/arch/mvme88k/stand/openbsd/bootst/bootst.bug +++ /dev/null diff --git a/sys/arch/mvme88k/stand/openbsd/bootst/stboot b/sys/arch/mvme88k/stand/openbsd/bootst/stboot Binary files differdeleted file mode 100644 index a6b19b34db4..00000000000 --- a/sys/arch/mvme88k/stand/openbsd/bootst/stboot +++ /dev/null diff --git a/sys/arch/mvme88k/stand/openbsd/libbug/log1 b/sys/arch/mvme88k/stand/openbsd/libbug/log1 deleted file mode 100644 index 448b6b71f94..00000000000 --- a/sys/arch/mvme88k/stand/openbsd/libbug/log1 +++ /dev/null @@ -1,9 +0,0 @@ -delay.o delay.o -diskrd.o diskrd.o -diskwr.o diskwr.o -getbrdid.o getbrdid.o -instat.o instat.o -outln.o outln.o -outstr.o outstr.o -return.o return.o -rtc_rd.o rtc_rd.o diff --git a/sys/arch/mvme88k/stand/openbsd/libbug/log2 b/sys/arch/mvme88k/stand/openbsd/libbug/log2 deleted file mode 100644 index 7a8950e635f..00000000000 --- a/sys/arch/mvme88k/stand/openbsd/libbug/log2 +++ /dev/null @@ -1,9 +0,0 @@ -rtc_rd.o -return.o -outstr.o -outln.o -instat.o -getbrdid.o -diskwr.o -diskrd.o -delay.o diff --git a/sys/arch/mvme88k/stand/openbsd/libsa/log1 b/sys/arch/mvme88k/stand/openbsd/libsa/log1 deleted file mode 100644 index 17047779eef..00000000000 --- a/sys/arch/mvme88k/stand/openbsd/libsa/log1 +++ /dev/null @@ -1,130 +0,0 @@ -nfs.o nfs.o -rpc.o rpc.o -net.o net.o -ether.o ether.o -arp.o arp.o -in_cksum.o in_cksum.o -netif.o netif.o -bootparam.o bootparam.o -rarp.o rarp.o -alloc.o alloc.o -bcopy.o bcopy.o -memcpy.o memcpy.o -close.o close.o -getfile.o getfile.o -open.o open.o -printf.o printf.o -read.o read.o -strerror.o strerror.o -ufs.o ufs.o -globals.o globals.o -lseek.o lseek.o -closeall.o closeall.o -dev.o dev.o -dkcksum.o dkcksum.o -nullfs.o nullfs.o -fstat.o fstat.o -ashrdi3.o ashrdi3.o -bcmp.o bcmp.o -bzero.o bzero.o -strcmp.o strcmp.o -strlen.o strlen.o -exec_sun.o exec_sun.o -clock.o clock.o -devopen.o devopen.o -dvma.o dvma.o -gets.o gets.o -panic.o panic.o -promboot.o promboot.o -promcons.o promcons.o -ufs.o ashrdi3.o -dvma.o alloc.o -nfs.o alloc.o -ufs.o alloc.o -net.o arp.o -net.o arp.o -arp.o globals.o -ether.o globals.o -rarp.o globals.o -arp.o bcmp.o -ether.o bcmp.o -rarp.o bcmp.o -arp.o bcopy.o -bootparam.o bcopy.o -ether.o bcopy.o -exec_sun.o bcopy.o -memcpy.o bcopy.o -net.o bcopy.o -nfs.o bcopy.o -rarp.o bcopy.o -ufs.o bcopy.o -arp.o bzero.o -net.o bzero.o -netif.o bzero.o -nfs.o bzero.o -rarp.o bzero.o -rpc.o bzero.o -ufs.o bzero.o -closeall.o close.o -exec_sun.o close.o -open.o devopen.o -dvma.o alloc.o -nfs.o alloc.o -ufs.o alloc.o -gets.o promcons.o -getfile.o gets.o -net.o clock.o -net.o in_cksum.o -arp.o net.o -ether.o netif.o -ether.o netif.o -net.o globals.o -rarp.o globals.o -exec_sun.o open.o -getfile.o open.o -arp.o panic.o -exec_sun.o panic.o -net.o panic.o -netif.o panic.o -arp.o printf.o -bootparam.o printf.o -exec_sun.o printf.o -getfile.o printf.o -net.o printf.o -netif.o printf.o -nfs.o printf.o -panic.o printf.o -rarp.o printf.o -rpc.o printf.o -gets.o promcons.o -printf.o promcons.o -exec_sun.o read.o -arp.o ether.o -net.o ether.o -rarp.o ether.o -rpc.o net.o -bootparam.o rpc.o -nfs.o rpc.o -bootparam.o rpc.o -bootparam.o rpc.o -bootparam.o rpc.o -nfs.o rpc.o -arp.o ether.o -net.o ether.o -rarp.o ether.o -arp.o net.o -rarp.o net.o -rpc.o net.o -rpc.o net.o -bootparam.o netif.o -nfs.o netif.o -rarp.o netif.o -strerror.o printf.o -ufs.o strcmp.o -rpc.o strerror.o -bootparam.o strlen.o -nfs.o strlen.o -ufs.o strlen.o -nfs.o printf.o -read.o printf.o -ufs.o printf.o diff --git a/sys/arch/mvme88k/stand/openbsd/libsa/log2 b/sys/arch/mvme88k/stand/openbsd/libsa/log2 deleted file mode 100644 index 31ecde33da0..00000000000 --- a/sys/arch/mvme88k/stand/openbsd/libsa/log2 +++ /dev/null @@ -1,39 +0,0 @@ -promboot.o -dvma.o -exec_sun.o -fstat.o -nullfs.o -dkcksum.o -dev.o -closeall.o -lseek.o -ufs.o -read.o -getfile.o -close.o -memcpy.o -rarp.o -bootparam.o -nfs.o -gets.o -strlen.o -strcmp.o -ashrdi3.o -open.o -alloc.o -rpc.o -devopen.o -strerror.o -arp.o -net.o -clock.o -in_cksum.o -ether.o -bcmp.o -globals.o -bcopy.o -netif.o -panic.o -bzero.o -printf.o -promcons.o diff --git a/sys/arch/mvme88k/stand/openbsd/netboot/netboot b/sys/arch/mvme88k/stand/openbsd/netboot/netboot Binary files differdeleted file mode 100644 index a2fe675457c..00000000000 --- a/sys/arch/mvme88k/stand/openbsd/netboot/netboot +++ /dev/null diff --git a/sys/arch/mvme88k/stand/openbsd/netboot/netboot.bin b/sys/arch/mvme88k/stand/openbsd/netboot/netboot.bin Binary files differdeleted file mode 100644 index 2c1b35d8fa7..00000000000 --- a/sys/arch/mvme88k/stand/openbsd/netboot/netboot.bin +++ /dev/null diff --git a/sys/arch/mvme88k/stand/openbsd/sboot/rboot b/sys/arch/mvme88k/stand/openbsd/sboot/rboot deleted file mode 100644 index e3a83b1327e..00000000000 --- a/sys/arch/mvme88k/stand/openbsd/sboot/rboot +++ /dev/null @@ -1,204 +0,0 @@ -S00A0000000072626F6F74CF -S32500004000424F4F540000003C00000044564D453134372072626F6F7420436F70797269671F -S325000040206874202863292031393935205468656F2064652052616164740000004EF9FFA047 -S325000040400046229C0000207C000040207000421853806A00FFFA247CFFA01908227C00005C -S325000040604000700012DA53806A00FFFA6000000213FC00000000463C600813FC00010000FD -S32500004080463C2E7C00006FF04EB9FFA000B84E750A73626F6F743A204D564D4531343720F2 -S325000040A0626F6F7473747261702070726F6772616D0A003E3E3E20004E56FF802F0A61FF64 -S325000040C0FFFFFFCE1D7C0030FF80487AFFC461FF0000159E584F45EEFF80487AFFD761FFDE -S325000040E00000158E2F0A61FF000013F82F0A610001CA504F584F60E24E714E5600004E4F86 -S3250000410000634E5E4E754D7920697020616464726573732069733A2025642E25642E2564B5 -S325000041202E25640A0053657276657220697020616464726573732069733A2025642E2564AC -S325000041402E25642E25640A004661696C65642E0A0065786974696E6720746F20524F4D0A51 -S3250000416000446F776E6C6F6164204661696C65640A00446F776E6C6F61642077617320616E -S325000041802073756363657373210A00636C69656E7420495020616464726573732025642EC0 -S325000041A025642E25642E25640A0073657276657220495020616464726573732025642E25A6 -S325000041C0642E25642E25640A005245564152503A204661696C65642E0A00726563656976D8 -S325000041E06564207365636F6E6461727920626F6F742070726F6772616D2E0A0062736400AB -S3250000420076616C696420636F6D6D616E64730A0061202D2073656E64206120524152500AB4 -S325000042200062202D20626F6F74207468652073797374656D0A0071202D2065786974207499 -S325000042406F20524F4D0A0066202D206674702074686520626F6F742066696C650A0067202E -S325000042602D20657865637574652074686520626F6F742066696C650A0068202D2068656CEB -S32500004280700A0069202D20696E6974204C414E434520656E657420636869700A0073626FB3 -S325000042A06F743A2025733A20556E6B6E6F776E20636F6D6D616E640A00004E5600002F0BF2 -S325000042C02F0A246E000810120C000067670001F26E2E0C000062670000F86E180C000061BA -S325000042E067364A00670001EC0C00003F67000192600001D40C000066670000AE600001C853 -S325000043000C000069670001B26D0001760C00007167000084600001B061FF0000054C4A8030 -S325000043206766428010390000465F2F00428010390000465E2F00428010390000465D2F0010 -S32500004340428010390000465C2F00487AFDBA45F9FFA0166E4E92428010390000463B2F0006 -S32500004360428010390000463A2F0042801039000046392F0042801039000046382F00487A4A -S32500004380FDA54E926000014C487AFDBE61FF000012E06000013E487AFDB961FF000012D2BE -S325000043A06100FD586000012C61FF000007127201B280660E487AFDAB61FF000012B4600032 -S325000043C00112487AFDAE61FF000012A66000010461FF00000F8061FF0000048E4A80660EBB -S325000043E0487AFDE761FF00001288600000E6428010390000465F2F00428010390000465E43 -S325000044002F00428010390000465D2F00428010390000465C2F00487AFD7347F9FFA0166E19 -S325000044204E93428010390000463B2F00428010390000463A2F0042801039000046392F0067 -S3250000444042801039000046382F00487AFD5E4E93DEFC002861FF000006667201B2806608BF -S32500004460487AFCFF4E93606A487AFD7061FF00001200584F524A4A12664645FAFD80604086 -S32500004480487AFD7E45F9FFA0166E4E92487AFD824E92487AFD8D4E92487AFD9C4E92487A4E -S325000044A0FDA74E92487AFDB84E92487AFDCD4E92487AFDD14E92601A61FF00000E9860124D -S325000044C02F0A613C600C2F0A487AFDD361FF000011A0246EFFF8266EFFFC4E5E4E756A7552 -S325000044E06D70696E6720746F20626F6F742070726F6772616D20617420307825782E0A001A -S325000045004E56000048E7003C246E00083A7C70002F0D487AFFCA61FF0000115642804281B3 -S32500004520264A2F0A61FF0000108ED5C0284A4ED54CEE3C00FFF04E5E4E7500000000001FB1 -S32500004540003B005A0078009700B500D400F301110130014E4E56000048E73F30266E0008C5 -S325000045602C2E000C2A2E0010282E0014262E0018242E001C200BE880244045F20C00200ABF -S32500004580720F2E0BC287244147F20A002006E880244045F20C00200A720FC286244145F2A6 -S325000045A00A002C0A2005E880244045F20C00200A720FC285244145F20A002A0A2004E88029 -S325000045C0244045F20C00200A720FC284244145F20A00280A2003E880244045F20C00200A09 -S325000045E0720FC283244145F20A00260A2002E880720FC282244045F20C00200A244145F25D -S325000046000A44240A7E45BE826D027446200353807E0BBE80650A200453807E1EBE80640487 -S325000046204280607293C97046B4806F1C307C016E223C0000016DE8C007826604D3C8600290 -S32500004640D3C15280B4806EEE41FAFEF030703A00D1C443F098FFE8C0078266087E02BE839C -S325000046606C02524943F19A0020092200E98192802401E9829481EF822005E7809085EB8074 -S32500004680D085E9802042D1C02006E980908641F00C002008D08B4CEE0CFCFFE04E5E4E756E -S325000046A04E56000048E73E0020790000400010100000004010801C2800011A280002182851 -S325000046C000031628000514280006122800071010020000BF108042A71F41000342A71F4204 -S325000046E0000342A71F43000342A71F44000342A71F45000342A71F4600036100FE584CEE82 -S32500004700007CFFEC4E5E4E754E5600002F0A428020790000400411BC00FF08005280720524 -S32500004720B2806CEC487800062239000040045C812F0148790000465445F9FFA015D04E927A -S32500004740207900004004317C8035000C20790000400830BC0001317C08000002117C0006F0 -S325000047600004207900004008117C00040005207900004008317C0003000648780006223900 -S325000047800000400850812F014879000046544E92487800067212D2B9000040082F01487981 -S325000047A0000046544E924280DEFC0024207900004008423008184230080E52807203B28045 -S325000047C06CEA4878004C48790000402861FF00000910246EFFFC4E5E4E754E5600002F0AF6 -S325000047E0487800064878060048790000402861FF00000A6E207900004004504F584F0C688F -S325000048008035000C66562079000040080C680004000666484878000448790000465C721857 -S32500004820D2882F0145F9FFA015D04E9248780004487900004638720ED2B9000040082F01C0 -S325000048404E924878000648790000463022390000400850812F014E92700160024280246ECA -S32500004860FFFC4E5E4E754E5600002F0242826100FE986100FF664A8067047001600A52828E -S325000048807204B2826CE84280242EFFFC4E5E4E75000178787878787878782E6D766D6536BC -S325000048A0386B006F6374657400003031323334353637383941424344454600004E56FFFCEF -S325000048C048E73038242E0008663228790000401447EC001961FFFFFFFDCA33C0000046406A -S325000048E00C7903E7000046406208067903E80000464033FC00450000462C60082679000076 -S325000049004018584B487800062F390000400448790000463045F9FFA015D04E924878000685 -S325000049202639000040045C832F034879000046544E92207900004004317C0800000C20794B -S325000049400000400C7604EFD0300420790000400C7605EFD0310420790000400C42280001F4 -S3250000496020790000400C42680004317C40000006117C0003000820790000400C117C001190 -S32500004980000948780004760CD6B90000400C2F0348790000465C4E92DEFC00202EBC00008E -S325000049A000047610D6B90000400C2F034879000046384E9220790000400C4268000A384B1F -S325000049C098F90000400E314C000242A7487800142F0861FF00000A5C20790000400C46404E -S325000049E03140000A20790000401030B90000464031790000462C000242680006DEFC00181E -S32500004A004A82671020790000401830BC000431420002605448780004486EFFFC487900000D -S32500004A20465C45F9FFA015D04E92487800192F3900004014487AFE5A4E927209DEFC001830 -S32500004A4043FAFE68207900004014700FC0AEFFFC11B108001800202EFFFCE8882D40FFFCD5 -S32500004A6053817601B68165DC207900004010384B98F900004012314C000497FC00004028A2 -S32500004A802F0B48790000402861FF000006544CEE1C0CFFE84E5E4E750A002578200D005413 -S32500004AA04654503A20446F776E6C6F6164206572726F722025643A2025730A004E560000E1 -S32500004AC048E73C304282283C0000700042B90000462842A76100FDE6584F428348780005D6 -S32500004AE04878060048790000402861FF00000772504F584F4A8066304AB900004628670862 -S32500004B002F3900004628600242A76100FDB0584F52827A05BA826CC4487AFF7E61FF00005B -S32500004B200B5070016000010020790000401C3628000220037A09EBA02F00487AFF5E61FF0E -S32500004B4000000B2E207900004004504F0C680800000C667820790000400C0C280011000901 -S32500004B60666A0C7900450000462C660C20790000401033D00000462C20790000401C0C5002 -S32500004B800005661E2A0858852F054280302800022F00487AFF0B61FF00000AD6700160001B -S32500004BA0008620790000401C4280302800022239000046285281B28067186F042F00600603 -S32500004BC02F39000046286100FCF4584F52826000FF0C4282203900004628528023C0000082 -S32500004BE04628207900004010366800042F006100FCCC45EBFFF42F0A2F042A390000401C10 -S32500004C0058852F0561FF000009CAD88A504F504FB7FC0000020B6E00FEC4487AFE7C61FF1E -S32500004C2000000A4E42804CEE0C3CFFE84E5E4E756C65303A206265656E20626162626C690B -S32500004C406E672C20666F756E6420627920272573270A006C65303A206D656D6F727920658D -S32500004C6072726F7220696E20272573270A004E5600002F0A2F02242E0008246E000C30121A -S32500004C800800000E67142F02487AFFA661FF000009E061FFFFFFF466504F30120800000DEE -S32500004CA0670434BC200030120800000C670434BC100030120800000B67122F02487AFF955D -S32500004CC061FF000009AC61FFFFFFF432242EFFF8246EFFFC4E5E4E756C65303A20696E6955 -S32500004CE0742074696D656F75742C2073746174203D20307825780A004E56000048E73C3CF4 -S32500004D00246E0008287900004644267900004648283C000186A0426C000238BC00044878A8 -S32500004D2035BE2F0B61FF000008E64253176A0001000217520003176A00030004176A000262 -S32500004D400005176A00050006176A0004000742AB000842AB000C7418D48B2002424048402B -S32500004D600040600037400012374200107458D48B2002424048403740001637420014397C55 -S32500004D8000010002388B397C00020002200B42404840388091C8504F4BF08A00200DEB804C -S32500004DA09088E78090884BF30A60240D2208E7813782181817BC0080181A20024240484051 -S32500004DC01780181B37BCFA12181C4273181E52487A07BA886CC291C8327C2FD04BF08A008F -S32500004DE0200DEB809088E78090884BF10A00200D240BD4802208E781378218584233185AE6 -S32500004E002002424048401780185B4273185C4273185E52484A886FC4397C0003000238BCB5 -S32500004E200004426C000238BC00015384660E2F03487AFEA661FF00000838600C30144283CB -S32500004E4036000803000867E238BC010042B90000464C42B900004650426C000238BC000201 -S32500004E604CEE3C3CFFE04E5E4E756C655F706F6C6C006C65305F706F6C6C3A20726D642071 -S32500004E8073746174757320307825780A006C655F706F6C6C3A20636861696E6564207061FB -S32500004EA0636B65740A0063737230207768656E20626164207468696E6773206861707065CF -S32500004EC06E3A2025780A00004E56000048E72038267900004644287900004648426B00022B -S32500004EE030130800000A670436BC040020390000464C45F40E18102A00026C0642806000DC -S32500004F0000F630136C0C2F0B487AFF606100FD60504F102A0002080000066718102A00021D -S32500004F2042A71F400003487AFF4A61FF0000074242826078102A0002020000030C00000380 -S32500004F406712487AFF4961FF0000072661FFFFFFF1AC584F302A0006428234000C820000B3 -S32500004F6005ED6F1A428230133F004267487AFF3861FF000006FC61FFFFFFF182602E4A823B -S32500004F80672A59824A826F242F022F2E000820790000464C43F08A002009EB809088E780AF -S32500004FA0908848740A6061FF0000062820790000464C43F08A002009EB809088E78090880C -S32500004FC049F40A60200C34804240484015400003357CFA12000441F90000464C428072071A -S32500004FE0B290670820390000464C52802080157C0080000220024CEE1C04FFF04E5E4E75B0 -S325000050006C655F70757428776179206265666F726520786D697429006C65303A206F757437 -S325000050207075742062756666657220627573790A006C655F707574286265666F72652078CE -S325000050406D697429006C655F70757428616674657220786D697429006C65303A2074726167 -S325000050606E736D69742074696D656F75742C2073746174203D20307825780A006C655F7064 -S3250000508075742874696D656F757429006C655F7075743A20786D6974206572726F722C208E -S325000050A06275662025640A006C655F70757428786D6974206572726F7229006C65303A20B9 -S325000050C07472616E736D6974206572726F722C206572726F72203D20307825780A004E5628 -S325000050E0000048E73838282E000C247900004644287900004648263C000186A0426A00021C -S3250000510030126C0C2F0A487AFEF86100FB62504F20390000465047F40E58600C487AFEFACB -S3250000512061FF0000054C584F102B00026DEE2F0420790000465043F08A002009EB809088AE -S32500005140E7809088D080068000002FD0487408002F2E000861FF0000047A504F584F723FF7 -S32500005160B2846508377CFFC0000460083004444037400004426B000630126C0C2F0A487A0D -S32500005180FEB16100FAEA504F177C0083000220790000465043F08A002009EB809088E7805F -S325000051A09088D080068000002FD0D08C3680424048401740000334BC000830126C0C2F0A9B -S325000051C0487AFE836100FAA8504F538366202F02487AFE8661FF000004983012504F6C1AAE -S325000051E02F0A487AFE986100FA86504F600C3012428234000802000967D034BC0200301274 -S325000052006C2A3012024078000C40200067122F3900004650487AFE7661FF00000454504F86 -S325000052202F0A487AFE846100FA46504F42B900004650102B000208000006660420046014CD -S32500005240302B00063F004267487AFE7161FF0000042070FF4CEE1C1CFFE84E5E4E754E566F -S32500005260000048E73E20246E00082C2E000C242E001061FFFFFFF42C2A00DA8242844283AA -S3250000528061FFFFFFF41E2400BA826F624A83665E2F062F0A6100FC322600504FB484670273 -S325000052A028024A8367DA1212B2390000465466CE122A0001B2390000465566C2122A0002AA -S325000052C0B2390000465666B6122A0003B2390000465766AA122A0004B23900004658669E81 -S325000052E0122A0005B239000046596794609020034CEE047CFFE84E5E4E754552524F523AFB -S325000053002065746865726E65742061646472657373206E6F74207365742120205573652077 -S325000053204C5341442E0A006C65303A2065746865726E657420616464726573733A20257854 -S325000053403A25783A25783A25783A25783A25780A00004E5600002F0A2F022439FFFE077823 -S32500005360200202802FFFFF000C802FFFFF006612487AFF8861FF000002F861FFFFFFED7EB9 -S32500005380584F45F90000465414BC000842390000465513FC003E00004656E08A43F900000B -S325000053A046591282E08A41F9000046581082E08A13C200004657428010112F004280101010 -S325000053C02F002F024878003E42A748780008487AFF5761FF0000029A487800104879000013 -S325000053E0464461FF0000022823FCFFFE1800000046442239FFFE07740681FFF0000023C1A8 -S3250000540000004648DEFC00202E8A6100F8EC242EFFF8246EFFFC4E5E4E754E56000020797F -S32500005420000046444268000230BC00044E5E4E75206F0004222F0008202F000C2F02080150 -S3250000544000006674080100016600008A2401EC8902820000003C4482023C000F4EFB284252 -S325000054602418D1822418D1822418D1822418D1822418D1822418D1822418D1822418D182AE -S325000054802418D1822418D1822418D1822418D1822418D1822418D1822418D1822418D1828E -S325000054A051C9FFBE22004841D1416402524002800000FFFF241F4E75080100016708428297 -S325000054C0343018FDD0824282143018FFE18AD0826000FF7A4282343018FED0826000FF6EE9 -S325000054E04E56000048E73038262E0008264349F9FFA018E261FF000003C2747FC4802F023E -S325000055004E94584F7215B282670000886D20720AB282670000946D087208B2826738602ACE -S32500005520720DB282677C7212B2826740601C7223B28267306D087217B2826756600C724087 -S32500005540B282674E727FB282670416C260A6487800084E94584F487800204E944878000813 -S325000055604E94504FB68B648C534B60884878000A4E942443584FB7CA6300FF7A121A49C1A0 -S325000055802F0161FF0000035E584FB7CA62EE6000FF644878000A61FF0000034A584F60005B -S325000055A0FF4C4878000A4E9442134CEE1C0CFFEC4E5E4E754E560000226E000820494A11DD -S325000055C0670652484A1066FA200890894E5E4E754E560000222E0010226E0008206E000C1E -S325000055E0B1C9631AD3C1D1C1200153814A8067161121200153814A8066F6600A10D920018B -S3250000560053814A8066F64E5E4E7500004E560000206E0008202E000C538072FFB280670C9E -S32500005620421851C8FFFC4240538064F44E5E4E754E56000020790000402410AE000B52B965 -S32500005640000040244E5E4E754E56000023EE000800004024486E00102F2E000C487AFFD28E -S32500005660612420790000402442104E5E4E754E560000486E000C2F2E00084879FFA018E2BC -S3250000568061044E5E4E754E56000048E7303C2A6E0008286E000C266E0010594B600C4A822F -S325000056A0670001782F024E95584F141C49C27625B68266EA95CA141C49C2224241E9FF9E26 -S325000056C07616B6886500013A303B8A064EFB0002003400A200CA013001300130013001307F -S325000056E001300130002E0130013000EE01300130013000AE0130010401300130011A347C20 -S32500005700000160B2584B241B2453161A49C32F032F022F0D61000120504F584F4A82678AB7 -S3250000572091C8603A53817001E3A0C082672A703C4A886702702C2F004E95584F60082F0101 -S325000057404E95584F524A121249C17620B6816DEE307C00016008524A0C1200206EF8121A46 -S3250000576049C166C04A886700FF424878003E6000FF36584B767FC6932F036000FF2A584B97 -S325000057802453141A49C26700FF222F024E95584F141A49C266F46000FF12584B24136C0ABC -S325000057A04878002D4E954482584F4878000A2F022F0D61000082504F584F6000FEEE584B57 -S325000057C02413487800082F022F0D616A504F584F6000FED8584B24134878000A2F022F0DFF -S325000057E06154504F584F6000FEC2584B2413487800102F022F0D613E504F584F6000FEAC82 -S32500005800487800254E95584F4A8A6700FE984878006C4E95584F6000FE8C4CEE3C0CFFE839 -S325000058204E5E4E753031323334353637383961626364656600004E56FFF448E73038286ECD -S325000058400008222E000C242E001045EEFFF441FAFFD44C42100014F008004A8166F447EE44 -S32500005860FFF4162249C32F034E94584FB7CA65F24CEE1C0CFFE04E5E4E757C2F2D5C000074 -S325000058804E5600002F0A7003C0B90000402041FAFFEA1030080049C02F0052B900004020CA -S325000058A045F9FFA018E24E92487800084E92246EFFFC4E5E4E7500004E5600001F3C000088 -S325000058C04E4F0000101F49C04E5E4E754E56000042814E4F000167000004720142804E5E2D -S325000058E04E754E5600002F02242E0008700AB08266064878000D61EA1F024E4F0020242E50 -S32500005900FFFC4E5E4E750000FFFE07F80000402800004036000040360000404A00004052AB -S30D00005920000040520000405255 -S70300004000BB diff --git a/sys/arch/mvme88k/stand/openbsd/sboot/rboot.tmp b/sys/arch/mvme88k/stand/openbsd/sboot/rboot.tmp Binary files differdeleted file mode 100644 index db9793dc097..00000000000 --- a/sys/arch/mvme88k/stand/openbsd/sboot/rboot.tmp +++ /dev/null diff --git a/sys/arch/mvme88k/stand/openbsd/sboot/sboot b/sys/arch/mvme88k/stand/openbsd/sboot/sboot deleted file mode 100644 index 5d797b7368b..00000000000 --- a/sys/arch/mvme88k/stand/openbsd/sboot/sboot +++ /dev/null @@ -1,200 +0,0 @@ -S00A0000000073626F6F74CE -S3250000400013FC000000005ED4600813FC000100005ED42E7C00006FF04EB9000040484E7554 -S325000040200A73626F6F743A204D564D4531343720626F6F7473747261702070726F67726175 -S325000040406D0A003E3E3E20004E56FF802F0A61FFFFFFFFCE1D7C0030FF80487AFFC461FF55 -S325000040600000159E584F45EEFF80487AFFD761FF0000158E2F0A61FF000013F82F0A610055 -S3250000408001CA504F584F60E24E714E5600004E4F00634E5E4E754D7920697020616464727B -S325000040A06573732069733A2025642E25642E25642E25640A005365727665722069702061B0 -S325000040C06464726573732069733A2025642E25642E25642E25640A004661696C65642E0ACA -S325000040E00065786974696E6720746F20524F4D0A00446F776E6C6F6164204661696C65640A -S325000041000A00446F776E6C6F61642077617320612073756363657373210A00636C69656E1C -S325000041207420495020616464726573732025642E25642E25642E25640A00736572766572D7 -S3250000414020495020616464726573732025642E25642E25642E25640A005245564152503AB8 -S32500004160204661696C65642E0A007265636569766564207365636F6E6461727920626F6F0D -S32500004180742070726F6772616D2E0A006273640076616C696420636F6D6D616E64730A0090 -S325000041A061202D2073656E64206120524152500A0062202D20626F6F7420746865207379B1 -S325000041C07374656D0A0071202D206578697420746F20524F4D0A0066202D206674702074B2 -S325000041E0686520626F6F742066696C650A0067202D20657865637574652074686520626F35 -S325000042006F742066696C650A0068202D2068656C700A0069202D20696E6974204C414E439B -S325000042204520656E657420636869700A0073626F6F743A2025733A20556E6B6E6F776E2016 -S32500004240636F6D6D616E640A00004E5600002F0B2F0A246E000810120C000067670001F2CF -S325000042606E2E0C000062670000F86E180C00006167364A00670001EC0C00003F670001925C -S32500004280600001D40C000066670000AE600001C80C000069670001B26D0001760C00007143 -S325000042A067000084600001B061FF0000054C4A8067664280103900005EF72F00428010391A -S325000042C000005EF62F004280103900005EF52F004280103900005EF42F00487AFDBA45F985 -S325000042E0000055FE4E924280103900005ED32F004280103900005ED22F00428010390000A5 -S325000043005ED12F004280103900005ED02F00487AFDA54E926000014C487AFDBE61FF000003 -S3250000432012E06000013E487AFDB961FF000012D26100FD586000012C61FF000007127201FB -S32500004340B280660E487AFDAB61FF000012B460000112487AFDAE61FF000012A660000104C4 -S3250000436061FF00000F8061FF0000048E4A80660E487AFDE761FF00001288600000E6428070 -S32500004380103900005EF72F004280103900005EF62F004280103900005EF52F004280103924 -S325000043A000005EF42F00487AFD7347F9000055FE4E934280103900005ED32F00428010395A -S325000043C000005ED22F004280103900005ED12F004280103900005ED02F00487AFD5E4E93A9 -S325000043E0DEFC002861FF000006667201B2806608487AFCFF4E93606A487AFD7061FF0000DF -S325000044001200584F524A4A12664645FAFD806040487AFD7E45F9000055FE4E92487AFD82EE -S325000044204E92487AFD8D4E92487AFD9C4E92487AFDA74E92487AFDB84E92487AFDCD4E9226 -S32500004440487AFDD14E92601A61FF00000E9860122F0A613C600C2F0A487AFDD361FF000087 -S3250000446011A0246EFFF8266EFFFC4E5E4E756A756D70696E6720746F20626F6F742070722B -S325000044806F6772616D20617420307825782E0A004E56000048E7003C246E00083A7C70009F -S325000044A02F0D487AFFCA61FF0000115642804281264A2F0A61FF0000108ED5C0284A4ED512 -S325000044C04CEE3C00FFF04E5E4E7500000000001F003B005A0078009700B500D400F30111B1 -S325000044E00130014E4E56000048E73F30266E00082C2E000C2A2E0010282E0014262E0018B4 -S32500004500242E001C200BE880244045F20C00200A720F2E0BC287244147F20A002006E8808A -S32500004520244045F20C00200A720FC286244145F20A002C0A2005E880244045F20C00200AA1 -S32500004540720FC285244145F20A002A0A2004E880244045F20C00200A720FC284244145F2F3 -S325000045600A00280A2003E880244045F20C00200A720FC283244145F20A00260A2002E88077 -S32500004580720FC282244045F20C00200A244145F20A44240A7E45BE826D0274462003538045 -S325000045A07E0BBE80650A200453807E1EBE8064044280607293C97046B4806F1C307C016E06 -S325000045C0223C0000016DE8C007826604D3C86002D3C15280B4806EEE41FAFEF030703A0078 -S325000045E0D1C443F098FFE8C0078266087E02BE836C02524943F19A0020092200E981928058 -S325000046002401E9829481EF822005E7809085EB80D085E9802042D1C02006E980908641F0EB -S325000046200C002008D08B4CEE0CFCFFE04E5E4E754E56000048E73E0020790000589810109B -S325000046400000004010801C2800011A280002182800031628000514280006122800071010D2 -S32500004660020000BF108042A71F41000342A71F42000342A71F43000342A71F44000342A7C4 -S325000046801F45000342A71F4600036100FE584CEE007CFFEC4E5E4E754E5600002F0A4280F6 -S325000046A020790000589C11BC00FF080052807205B2806CEC4878000622390000589C5C81CE -S325000046C02F01487900005EEC45F9000055604E9220790000589C317C8035000C2079000032 -S325000046E058A030BC0001317C08000002117C000600042079000058A0117C000400052079C1 -S32500004700000058A0317C00030006487800062239000058A050812F01487900005EEC4E92E0 -S32500004720487800067212D2B9000058A02F01487900005EEC4E924280DEFC00242079000032 -S3250000474058A0423008184230080E52807203B2806CEA4878004C4879000058C061FF00002D -S325000047600910246EFFFC4E5E4E754E5600002F0A48780006487806004879000058C061FF7C -S3250000478000000A6E20790000589C504F584F0C688035000C66562079000058A00C680004CE -S325000047A00006664848780004487900005EF47218D2882F0145F9000055604E9248780004BD -S325000047C0487900005ED0720ED2B9000058A02F014E9248780006487900005EC822390000C9 -S325000047E058A050812F014E92700160024280246EFFFC4E5E4E754E5600002F02428261004F -S32500004800FE986100FF664A8067047001600A52827204B2826CE84280242EFFFC4E5E4E75D6 -S32500004820000178787878787878782E6D766D6536386B006F637465740000303132333435A7 -S325000048403637383941424344454600004E56FFFC48E73038242E000866322879000058AC12 -S3250000486047EC001961FFFFFFFDCA33C000005ED80C7903E700005ED86208067903E800001F -S325000048805ED833FC004500005EC460082679000058B0584B487800062F390000589C4879B1 -S325000048A000005EC845F9000055604E924878000626390000589C5C832F03487900005EECC4 -S325000048C04E9220790000589C317C0800000C2079000058A47604EFD030042079000058A40D -S325000048E07605EFD031042079000058A4422800012079000058A442680004317C400000060D -S32500004900117C000300082079000058A4117C0011000948780004760CD6B9000058A42F03BA -S32500004920487900005EF44E92DEFC00202EBC000000047610D6B9000058A42F034879000092 -S325000049405ED04E922079000058A44268000A384B98F9000058A6314C000242A748780014AC -S325000049602F0861FF00000A5C2079000058A446403140000A2079000058A830B900005ED8E6 -S32500004980317900005EC4000242680006DEFC00184A8267102079000058B030BC000431425A -S325000049A00002605448780004486EFFFC487900005EF445F9000055604E92487800192F399F -S325000049C0000058AC487AFE5A4E927209DEFC001843FAFE682079000058AC700FC0AEFFFC3E -S325000049E011B108001800202EFFFCE8882D40FFFC53817601B68165DC2079000058A8384BCF -S32500004A0098F9000058AA314C000497FC000058C02F0B4879000058C061FF000006544CEECA -S32500004A201C0CFFE84E5E4E750A002578200D00544654503A20446F776E6C6F616420657257 -S32500004A40726F722025643A2025730A004E56000048E73C304282283C0000700042B9000086 -S32500004A605EC042A76100FDE6584F428348780005487806004879000058C061FF000007723C -S32500004A80504F584F4A8066304AB900005EC067082F3900005EC0600242A76100FDB0584F54 -S32500004AA052827A05BA826CC4487AFF7E61FF00000B507001600001002079000058B4362862 -S32500004AC0000220037A09EBA02F00487AFF5E61FF00000B2E20790000589C504F0C6808000E -S32500004AE0000C66782079000058A40C2800110009666A0C79004500005EC4660C207900001C -S32500004B0058A833D000005EC42079000058B40C500005661E2A0858852F0542803028000281 -S32500004B202F00487AFF0B61FF00000AD67001600000862079000058B44280302800022239C1 -S32500004B4000005EC05281B28067186F042F0060062F3900005EC06100FCF4584F52826000F3 -S32500004B60FF0C4282203900005EC0528023C000005EC02079000058A8366800042F0061004B -S32500004B80FCCC45EBFFF42F0A2F042A39000058B458852F0561FF000009CAD88A504F504F65 -S32500004BA0B7FC0000020B6E00FEC4487AFE7C61FF00000A4E42804CEE0C3CFFE84E5E4E7571 -S32500004BC06C65303A206265656E20626162626C696E672C20666F756E642062792027257347 -S32500004BE0270A006C65303A206D656D6F7279206572726F7220696E20272573270A004E5695 -S32500004C0000002F0A2F02242E0008246E000C30120800000E67142F02487AFFA661FF000061 -S32500004C2009E061FFFFFFF466504F30120800000D670434BC200030120800000C670434BCAB -S32500004C40100030120800000B67122F02487AFF9561FF000009AC61FFFFFFF432242EFFF807 -S32500004C60246EFFFC4E5E4E756C65303A20696E69742074696D656F75742C207374617420D4 -S32500004C803D20307825780A004E56000048E73C3C246E0008287900005EDC267900005EE0C5 -S32500004CA0283C000186A0426C000238BC0004487835BE2F0B61FF000008E64253176A000169 -S32500004CC0000217520003176A00030004176A00020005176A00050006176A0004000742AB4B -S32500004CE0000842AB000C7418D48B2002424048400040600037400012374200107458D48BB9 -S32500004D002002424048403740001637420014397C00010002388B397C00020002200B424066 -S32500004D204840388091C8504F4BF08A00200DEB809088E78090884BF30A60240D2208E781D6 -S32500004D403782181817BC0080181A2002424048401780181B37BCFA12181C4273181E524831 -S32500004D607A07BA886CC291C8327C2FD04BF08A00200DEB809088E78090884BF10A00200DCF -S32500004D80240BD4802208E781378218584233185A2002424048401780185B4273185C4273D4 -S32500004DA0185E52484A886FC4397C0003000238BC0004426C000238BC00015384660E2F0304 -S32500004DC0487AFEA661FF00000838600C3014428336000803000867E238BC010042B90000D0 -S32500004DE05EE442B900005EE8426C000238BC00024CEE3C3CFFE04E5E4E756C655F706F6C09 -S32500004E006C006C65305F706F6C6C3A20726D642073746174757320307825780A006C655F09 -S32500004E20706F6C6C3A20636861696E6564207061636B65740A0063737230207768656E2083 -S32500004E40626164207468696E67732068617070656E3A2025780A00004E56000048E72038B0 -S32500004E60267900005EDC287900005EE0426B000230130800000A670436BC040020390000B6 -S32500004E805EE445F40E18102A00026C064280600000F630136C0C2F0B487AFF606100FD60D1 -S32500004EA0504F102A0002080000066718102A000242A71F400003487AFF4A61FF0000074249 -S32500004EC042826078102A0002020000030C0000036712487AFF4961FF0000072661FFFFFF72 -S32500004EE0F1AC584F302A0006428234000C82000005ED6F1A428230133F004267487AFF381F -S32500004F0061FF000006FC61FFFFFFF182602E4A82672A59824A826F242F022F2E0008207904 -S32500004F2000005EE443F08A002009EB809088E780908848740A6061FF0000062820790000F4 -S32500004F405EE443F08A002009EB809088E780908849F40A60200C3480424048401540000338 -S32500004F60357CFA12000441F900005EE442807207B2906708203900005EE452802080157C64 -S32500004F800080000220024CEE1C04FFF04E5E4E756C655F70757428776179206265666F727F -S32500004FA06520786D697429006C65303A206F75747075742062756666657220627573790AE8 -S32500004FC0006C655F707574286265666F726520786D697429006C655F70757428616674654B -S32500004FE07220786D697429006C65303A207472616E736D69742074696D656F75742C20737B -S32500005000746174203D20307825780A006C655F7075742874696D656F757429006C655F70F4 -S3250000502075743A20786D6974206572726F722C206275662025640A006C655F7075742878B6 -S325000050406D6974206572726F7229006C65303A207472616E736D6974206572726F722C202A -S325000050606572726F72203D20307825780A004E56000048E73838282E000C247900005EDCB8 -S32500005080287900005EE0263C000186A0426A000230126C0C2F0A487AFEF86100FB62504FEC -S325000050A0203900005EE847F40E58600C487AFEFA61FF0000054C584F102B00026DEE2F0461 -S325000050C0207900005EE843F08A002009EB809088E7809088D080068000002FD0487408006A -S325000050E02F2E000861FF0000047A504F584F723FB2846508377CFFC0000460083004444037 -S3250000510037400004426B000630126C0C2F0A487AFEB16100FAEA504F177C00830002207962 -S3250000512000005EE843F08A002009EB809088E7809088D080068000002FD0D08C36804240D2 -S3250000514048401740000334BC000830126C0C2F0A487AFE836100FAA8504F538366202F020A -S32500005160487AFE8661FF000004983012504F6C1A2F0A487AFE986100FA86504F600C3012C1 -S32500005180428234000802000967D034BC020030126C2A3012024078000C40200067122F39B4 -S325000051A000005EE8487AFE7661FF00000454504F2F0A487AFE846100FA46504F42B900005E -S325000051C05EE8102B000208000006660420046014302B00063F004267487AFE7161FF00005C -S325000051E0042070FF4CEE1C1CFFE84E5E4E754E56000048E73E20246E00082C2E000C242ECB -S32500005200001061FFFFFFF42C2A00DA824284428361FFFFFFF41E2400BA826F624A83665EB7 -S325000052202F062F0A6100FC322600504FB484670228024A8367DA1212B23900005EEC66CE40 -S32500005240122A0001B23900005EED66C2122A0002B23900005EEE66B6122A0003B2390000F2 -S325000052605EEF66AA122A0004B23900005EF0669E122A0005B23900005EF1679460902003C5 -S325000052804CEE047CFFE84E5E4E754552524F523A2065746865726E65742061646472657322 -S325000052A073206E6F7420736574212020557365204C5341442E0A006C65303A20657468658D -S325000052C0726E657420616464726573733A2025783A25783A25783A25783A25783A25780AD5 -S325000052E000004E5600002F0A2F022439FFFE0778200202802FFFFF000C802FFFFF006612BF -S32500005300487AFF8861FF000002F861FFFFFFED7E584F45F900005EEC14BC00084239000099 -S325000053205EED13FC003E00005EEEE08A43F900005EF11282E08A41F900005EF01082E08A0C -S3250000534013C200005EEF428010112F00428010102F002F024878003E42A748780008487A60 -S32500005360FF5761FF0000029A48780010487900005EDC61FF0000022823FCFFFE180000004C -S325000053805EDC2239FFFE07740681FFF0000023C100005EE0DEFC00202E8A6100F8EC242E19 -S325000053A0FFF8246EFFFC4E5E4E754E560000207900005EDC4268000230BC00044E5E4E7572 -S325000053C0206F0004222F0008202F000C2F02080100006674080100016600008A2401EC89D8 -S325000053E002820000003C4482023C000F4EFB28422418D1822418D1822418D1822418D182E5 -S325000054002418D1822418D1822418D1822418D1822418D1822418D1822418D1822418D1820E -S325000054202418D1822418D1822418D1822418D18251C9FFBE22004841D1416402524002801C -S325000054400000FFFF241F4E750801000167084282343018FDD0824282143018FFE18AD0825E -S325000054606000FF7A4282343018FED0826000FF6E4E56000048E73038262E0008264349F9AE -S325000054800000587261FF000003C2747FC4802F024E94584F7215B282670000886D20720A73 -S325000054A0B282670000946D087208B2826738602A720DB282677C7212B2826740601C722365 -S325000054C0B28267306D087217B2826756600C7240B282674E727FB282670416C260A64878D7 -S325000054E000084E94584F487800204E94487800084E94504FB68B648C534B60884878000A89 -S325000055004E942443584FB7CA6300FF7A121A49C12F0161FF0000035E584FB7CA62EE600039 -S32500005520FF644878000A61FF0000034A584F6000FF4C4878000A4E9442134CEE1C0CFFECEB -S325000055404E5E4E754E560000226E000820494A11670652484A1066FA200890894E5E4E7565 -S325000055604E560000222E0010226E0008206E000CB1C9631AD3C1D1C1200153814A80671696 -S325000055801121200153814A8066F6600A10D9200153814A8066F64E5E4E7500004E56000037 -S325000055A0206E0008202E000C538072FFB280670C421851C8FFFC4240538064F44E5E4E7582 -S325000055C04E5600002079000058BC10AE000B52B9000058BC4E5E4E754E56000023EE000860 -S325000055E0000058BC486E00102F2E000C487AFFD261242079000058BC42104E5E4E754E5638 -S325000056000000486E000C2F2E000848790000587261044E5E4E754E56000048E7303C2A6E27 -S325000056200008286E000C266E0010594B600C4A82670001782F024E95584F141C49C27625C9 -S32500005640B68266EA95CA141C49C2224241E9FF9E7616B6886500013A303B8A064EFB000247 -S32500005660003400A200CA0130013001300130013001300130002E0130013000EE013001304D -S32500005680013000AE0130010401300130011A347C000160B2584B241B2453161A49C32F03E8 -S325000056A02F022F0D61000120504F584F4A82678A91C8603A53817001E3A0C082672A703CB8 -S325000056C04A886702702C2F004E95584F60082F014E95584F524A121249C17620B6816DEE20 -S325000056E0307C00016008524A0C1200206EF8121A49C166C04A886700FF424878003E60001B -S32500005700FF36584B767FC6932F036000FF2A584B2453141A49C26700FF222F024E95584F0C -S32500005720141A49C266F46000FF12584B24136C0A4878002D4E954482584F4878000A2F02D7 -S325000057402F0D61000082504F584F6000FEEE584B2413487800082F022F0D616A504F584F72 -S325000057606000FED8584B24134878000A2F022F0D6154504F584F6000FEC2584B2413487827 -S3250000578000102F022F0D613E504F584F6000FEAC487800254E95584F4A8A6700FE98487897 -S325000057A0006C4E95584F6000FE8C4CEE3C0CFFE84E5E4E753031323334353637383961625B -S325000057C06364656600004E56FFF448E73038286E0008222E000C242E001045EEFFF441FA46 -S325000057E0FFD44C42100014F008004A8166F447EEFFF4162249C32F034E94584FB7CA65F202 -S325000058004CEE1C0CFFE04E5E4E757C2F2D5C00004E5600002F0A7003C0B9000058B841FA8A -S32500005820FFEA1030080049C02F0052B9000058B845F9000058724E92487800084E92246EBC -S32500005840FFFC4E5E4E7500004E5600001F3C00004E4F0000101F49C04E5E4E754E560000F1 -S3250000586042814E4F000167000004720142804E5E4E754E5600002F02242E0008700AB082D7 -S3250000588066064878000D61EA1F024E4F0020242EFFFC4E5E4E750000FFFE07F8000058C0D0 -S31D000058A0000058CE000058CE000058E2000058EA000058EA000058EA9E -S70300004000BB diff --git a/sys/arch/mvme88k/stand/openbsd/sboot/sboot.tmp b/sys/arch/mvme88k/stand/openbsd/sboot/sboot.tmp Binary files differdeleted file mode 100644 index a55acd6ea70..00000000000 --- a/sys/arch/mvme88k/stand/openbsd/sboot/sboot.tmp +++ /dev/null diff --git a/sys/arch/mvme88k/stand/openbsd/sboot/srec b/sys/arch/mvme88k/stand/openbsd/sboot/srec Binary files differdeleted file mode 100644 index a60b3c76852..00000000000 --- a/sys/arch/mvme88k/stand/openbsd/sboot/srec +++ /dev/null diff --git a/sys/arch/mvme88k/stand/openbsd/wrtvid/wrtvid b/sys/arch/mvme88k/stand/openbsd/wrtvid/wrtvid Binary files differdeleted file mode 100644 index 565965fdee3..00000000000 --- a/sys/arch/mvme88k/stand/openbsd/wrtvid/wrtvid +++ /dev/null diff --git a/sys/arch/mvme88k/stand/prtvid/chklabel b/sys/arch/mvme88k/stand/prtvid/chklabel Binary files differdeleted file mode 100644 index 05637c518f5..00000000000 --- a/sys/arch/mvme88k/stand/prtvid/chklabel +++ /dev/null diff --git a/sys/arch/mvme88k/stand/prtvid/prtvid b/sys/arch/mvme88k/stand/prtvid/prtvid Binary files differdeleted file mode 100644 index 10a4f710289..00000000000 --- a/sys/arch/mvme88k/stand/prtvid/prtvid +++ /dev/null diff --git a/sys/arch/mvme88k/stand/wrtvid/Makefile,v b/sys/arch/mvme88k/stand/wrtvid/Makefile,v deleted file mode 100644 index 994362b6ddb..00000000000 --- a/sys/arch/mvme88k/stand/wrtvid/Makefile,v +++ /dev/null @@ -1,30 +0,0 @@ -head 1.1; -access; -symbols; -locks - drahn:1.1; strict; -comment @# @; - - -1.1 -date 95.09.28.19.00.28; author drahn; state Exp; -branches; -next ; - - -desc -@@ - - -1.1 -log -@Initial revision -@ -text -@PROG= wrtvid -NOMAN= - -install: - -.include <bsd.prog.mk> -@ diff --git a/sys/arch/mvme88k/stand/wrtvid/wrtvid b/sys/arch/mvme88k/stand/wrtvid/wrtvid Binary files differdeleted file mode 100644 index d27d4efdd86..00000000000 --- a/sys/arch/mvme88k/stand/wrtvid/wrtvid +++ /dev/null |