aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSimon Atanasyan <simon@atanasyan.com>2018-05-03 17:17:46 +0100
committerMaciej W. Rozycki <macro@mips.com>2018-05-03 17:17:46 +0100
commit3be08ea4728b56d35e136af4e6fd3086ade17764 (patch)
tree0982e7e0d5c68f187b90bc0967cf7402793f6eb6
parentbd732259bd3bec9494a2f1f39f74255dd4a9be85 (diff)
downloadbinutils-3be08ea4728b56d35e136af4e6fd3086ade17764.zip
binutils-3be08ea4728b56d35e136af4e6fd3086ade17764.tar.gz
binutils-3be08ea4728b56d35e136af4e6fd3086ade17764.tar.bz2
BFD: Prevent writing the MIPS _gp_disp symbol into symbol tables
The _gp_disp is a magic symbol, always implicitly defined by the linker. It does not make a sense to write it into symbol tables for output files. Moreover, now if the linker gets a version script, the _gp_disp symbol gets zero version definition index. The zero index means[1]: "The symbol is local, not available outside the object." But the _gp_disp symbol has GLOBAL binding. That confuses some tools like for example the LLD linker when they get such files as inputs. This patch fixes the problem - it prevents writing the _gp_disp symbol in regular and dynamic symbol tables. This was tested by running LD test suite on a mipsel-linux board. References: [1] "Linux Standard Base Specification", Section "10.7.2 Symbol Version Table", p. 32 2018-05-03 Simon Atanasyan <simon@atanasyan.com> bfd/ * elf32-mips.c: (elf32_mips_fixup_symbol): New function. (elf_backend_fixup_symbol): New macro. * elfxx-mips.c: (mips_elf_output_extsym): Discard _gp_disp handling. (_bfd_mips_elf_finish_dynamic_symbol): Likewise. ld/ * testsuite/ld-mips-elf/gp-disp-sym.d: New test. * testsuite/ld-mips-elf/gp-disp-sym.s: New test source. * testsuite/ld-mips-elf/mips-elf.exp: Run the new test. * testsuite/ld-mips-elf/mips16-pic-2.ad: Update for _gp_disp symbol removal. * testsuite/ld-mips-elf/mips16-pic-2.nd: Likewise. * testsuite/ld-mips-elf/pic-and-nonpic-3a.dd: Likewise. * testsuite/ld-mips-elf/tlslib-o32-hidden.got: Likewise. * testsuite/ld-mips-elf/tlslib-o32-ver.got: Likewise. * testsuite/ld-mips-elf/tlslib-o32.got: Likewise.
-rw-r--r--bfd/ChangeLog8
-rw-r--r--bfd/elf32-mips.c12
-rw-r--r--bfd/elfxx-mips.c12
-rw-r--r--ld/ChangeLog13
-rw-r--r--ld/testsuite/ld-mips-elf/gp-disp-sym.d9
-rw-r--r--ld/testsuite/ld-mips-elf/gp-disp-sym.s5
-rw-r--r--ld/testsuite/ld-mips-elf/mips-elf.exp4
-rw-r--r--ld/testsuite/ld-mips-elf/mips16-pic-2.ad4
-rw-r--r--ld/testsuite/ld-mips-elf/mips16-pic-2.nd10
-rw-r--r--ld/testsuite/ld-mips-elf/pic-and-nonpic-3a.dd2
-rw-r--r--ld/testsuite/ld-mips-elf/tlslib-o32-hidden.got10
-rw-r--r--ld/testsuite/ld-mips-elf/tlslib-o32-ver.got12
-rw-r--r--ld/testsuite/ld-mips-elf/tlslib-o32.got12
13 files changed, 76 insertions, 37 deletions
diff --git a/bfd/ChangeLog b/bfd/ChangeLog
index 11baf5d..94f28b1 100644
--- a/bfd/ChangeLog
+++ b/bfd/ChangeLog
@@ -1,3 +1,11 @@
+2018-05-03 Simon Atanasyan <simon@atanasyan.com>
+
+ * elf32-mips.c: (elf32_mips_fixup_symbol): New function.
+ (elf_backend_fixup_symbol): New macro.
+ * elfxx-mips.c: (mips_elf_output_extsym): Discard _gp_disp
+ handling.
+ (_bfd_mips_elf_finish_dynamic_symbol): Likewise.
+
2018-04-30 Francois H. Theron <francois.theron@netronome.com>
* Makefile.am: Added NFP files to build.
diff --git a/bfd/elf32-mips.c b/bfd/elf32-mips.c
index 87147b5..23a5712 100644
--- a/bfd/elf32-mips.c
+++ b/bfd/elf32-mips.c
@@ -2420,6 +2420,17 @@ elf32_mips_write_core_note (bfd *abfd, char *buf, int *bufsiz, int note_type,
}
}
}
+
+/* Remove the magic _gp_disp symbol from the symbol tables. */
+
+static bfd_boolean
+elf32_mips_fixup_symbol (struct bfd_link_info *info,
+ struct elf_link_hash_entry *h)
+{
+ if (strcmp (h->root.root.string, "_gp_disp") == 0)
+ _bfd_elf_link_hash_hide_symbol (info, h, TRUE);
+ return TRUE;
+}
/* Depending on the target vector we generate some version of Irix
executables or "normal" MIPS ELF ABI executables. */
@@ -2523,6 +2534,7 @@ static const struct ecoff_debug_swap mips_elf32_ecoff_debug_swap = {
#define elf_backend_gc_mark_hook _bfd_mips_elf_gc_mark_hook
#define elf_backend_copy_indirect_symbol \
_bfd_mips_elf_copy_indirect_symbol
+#define elf_backend_fixup_symbol elf32_mips_fixup_symbol
#define elf_backend_grok_prstatus elf32_mips_grok_prstatus
#define elf_backend_grok_psinfo elf32_mips_grok_psinfo
#define elf_backend_ecoff_debug_swap &mips_elf32_ecoff_debug_swap
diff --git a/bfd/elfxx-mips.c b/bfd/elfxx-mips.c
index ce64581..e349e8a 100644
--- a/bfd/elfxx-mips.c
+++ b/bfd/elfxx-mips.c
@@ -2903,12 +2903,6 @@ mips_elf_output_extsym (struct mips_elf_link_hash_entry *h, void *data)
h->esym.asym.value =
mips_elf_hash_table (einfo->info)->procedure_count;
}
- else if (strcmp (name, "_gp_disp") == 0 && ! NEWABI_P (einfo->abfd))
- {
- h->esym.asym.sc = scAbs;
- h->esym.asym.st = stLabel;
- h->esym.asym.value = elf_gp (einfo->abfd);
- }
else
h->esym.asym.sc = scUndefined;
}
@@ -10976,12 +10970,6 @@ _bfd_mips_elf_finish_dynamic_symbol (bfd *output_bfd,
sym->st_info = ELF_ST_INFO (STB_GLOBAL, STT_SECTION);
sym->st_value = 1;
}
- else if (strcmp (name, "_gp_disp") == 0 && ! NEWABI_P (output_bfd))
- {
- sym->st_shndx = SHN_ABS;
- sym->st_info = ELF_ST_INFO (STB_GLOBAL, STT_SECTION);
- sym->st_value = elf_gp (output_bfd);
- }
else if (SGI_COMPAT (output_bfd))
{
if (strcmp (name, mips_elf_dynsym_rtproc_names[0]) == 0
diff --git a/ld/ChangeLog b/ld/ChangeLog
index d11cd06..55daa0d 100644
--- a/ld/ChangeLog
+++ b/ld/ChangeLog
@@ -1,3 +1,16 @@
+2018-05-03 Simon Atanasyan <simon@atanasyan.com>
+
+ * testsuite/ld-mips-elf/gp-disp-sym.d: New test.
+ * testsuite/ld-mips-elf/gp-disp-sym.s: New test source.
+ * testsuite/ld-mips-elf/mips-elf.exp: Run the new test.
+ * testsuite/ld-mips-elf/mips16-pic-2.ad: Update for _gp_disp
+ symbol removal.
+ * testsuite/ld-mips-elf/mips16-pic-2.nd: Likewise.
+ * testsuite/ld-mips-elf/pic-and-nonpic-3a.dd: Likewise.
+ * testsuite/ld-mips-elf/tlslib-o32-hidden.got: Likewise.
+ * testsuite/ld-mips-elf/tlslib-o32-ver.got: Likewise.
+ * testsuite/ld-mips-elf/tlslib-o32.got: Likewise.
+
2018-04-27 Maciej W. Rozycki <macro@mips.com>
* testsuite/ld-mips-elf/bal-jalx-pic.d: Only run for
diff --git a/ld/testsuite/ld-mips-elf/gp-disp-sym.d b/ld/testsuite/ld-mips-elf/gp-disp-sym.d
new file mode 100644
index 0000000..00f19cc
--- /dev/null
+++ b/ld/testsuite/ld-mips-elf/gp-disp-sym.d
@@ -0,0 +1,9 @@
+#name: MIPS _gp_disp removal from symbol tables
+#ld: -shared
+#objdump: -tT
+#target: [check_shared_lib_support]
+
+#failif
+#...
+.*_gp_disp
+#pass
diff --git a/ld/testsuite/ld-mips-elf/gp-disp-sym.s b/ld/testsuite/ld-mips-elf/gp-disp-sym.s
new file mode 100644
index 0000000..c6380ba
--- /dev/null
+++ b/ld/testsuite/ld-mips-elf/gp-disp-sym.s
@@ -0,0 +1,5 @@
+ .global foo
+ .text
+foo:
+ lui $t0, %hi(_gp_disp)
+ addi $t0, $t0, %lo(_gp_disp)
diff --git a/ld/testsuite/ld-mips-elf/mips-elf.exp b/ld/testsuite/ld-mips-elf/mips-elf.exp
index 95d677e..6668e22 100644
--- a/ld/testsuite/ld-mips-elf/mips-elf.exp
+++ b/ld/testsuite/ld-mips-elf/mips-elf.exp
@@ -1255,3 +1255,7 @@ run_dump_test "mips-abiflags-1"
run_dump_test "mips-abiflags-1r"
run_dump_test "mips-abiflags-2"
run_dump_test "mips-abiflags-2r"
+
+# Test that _gp_disp symbol is not present in symbol tables.
+run_dump_test "gp-disp-sym" [list [list as $abi_asflags(o32)] \
+ [list ld $abi_ldflags(o32)]]
diff --git a/ld/testsuite/ld-mips-elf/mips16-pic-2.ad b/ld/testsuite/ld-mips-elf/mips16-pic-2.ad
index 52d3ea4..689f0c2 100644
--- a/ld/testsuite/ld-mips-elf/mips16-pic-2.ad
+++ b/ld/testsuite/ld-mips-elf/mips16-pic-2.ad
@@ -1,6 +1,6 @@
# [MIPS_GOTSYM, MIPS_SYMTABNO) covers used4...used7.
#...
- .* \(MIPS_SYMTABNO\) * 8
+ .* \(MIPS_SYMTABNO\) * 7
#...
- .* \(MIPS_GOTSYM\) * 0x4
+ .* \(MIPS_GOTSYM\) * 0x3
#pass
diff --git a/ld/testsuite/ld-mips-elf/mips16-pic-2.nd b/ld/testsuite/ld-mips-elf/mips16-pic-2.nd
index bc2cd38..a2a5794 100644
--- a/ld/testsuite/ld-mips-elf/mips16-pic-2.nd
+++ b/ld/testsuite/ld-mips-elf/mips16-pic-2.nd
@@ -1,9 +1,9 @@
# used8 should come before MIPS_GOTSYM.
#...
- +3: 000405bc +36 +FUNC +GLOBAL +DEFAULT .* used8
- +4: 00040574 +36 +FUNC +GLOBAL +DEFAULT .* used6
- +5: 00040598 +36 +FUNC +GLOBAL +DEFAULT .* used7
- +6: 00040550 +36 +FUNC +GLOBAL +DEFAULT .* used5
- +7: 0004052c +36 +FUNC +GLOBAL +DEFAULT .* used4
+ +2: 000405bc +36 +FUNC +GLOBAL +DEFAULT .* used8
+ +3: 00040574 +36 +FUNC +GLOBAL +DEFAULT .* used6
+ +4: 00040598 +36 +FUNC +GLOBAL +DEFAULT .* used7
+ +5: 00040550 +36 +FUNC +GLOBAL +DEFAULT .* used5
+ +6: 0004052c +36 +FUNC +GLOBAL +DEFAULT .* used4
#pass
diff --git a/ld/testsuite/ld-mips-elf/pic-and-nonpic-3a.dd b/ld/testsuite/ld-mips-elf/pic-and-nonpic-3a.dd
index 3dcfe12..b286f13 100644
--- a/ld/testsuite/ld-mips-elf/pic-and-nonpic-3a.dd
+++ b/ld/testsuite/ld-mips-elf/pic-and-nonpic-3a.dd
@@ -35,5 +35,5 @@ Disassembly of section \.MIPS\.stubs:
c00: 8f998010 lw t9,-32752\(gp\)
c04: 03e07825 move t7,ra
c08: 0320f809 jalr t9
- c0c: 24180005 li t8,5
+ c0c: 24180004 li t8,4
\.\.\.
diff --git a/ld/testsuite/ld-mips-elf/tlslib-o32-hidden.got b/ld/testsuite/ld-mips-elf/tlslib-o32-hidden.got
index 563d8bb..a746031 100644
--- a/ld/testsuite/ld-mips-elf/tlslib-o32-hidden.got
+++ b/ld/testsuite/ld-mips-elf/tlslib-o32-hidden.got
@@ -4,11 +4,11 @@
DYNAMIC RELOCATION RECORDS
OFFSET TYPE VALUE
00000000 R_MIPS_NONE \*ABS\*
-000403bc R_MIPS_TLS_TPREL32 \*ABS\*
-000403c0 R_MIPS_TLS_DTPMOD32 \*ABS\*
-000403c8 R_MIPS_TLS_DTPMOD32 \*ABS\*
+0004039c R_MIPS_TLS_TPREL32 \*ABS\*
+000403a0 R_MIPS_TLS_DTPMOD32 \*ABS\*
+000403a8 R_MIPS_TLS_DTPMOD32 \*ABS\*
Contents of section .got:
- 403b0 00000000 80000000 00000380 00000008 ................
- 403c0 00000000 ffff8004 00000000 00000000 ................
+ 40390 00000000 80000000 00000360 00000008 ................
+ 403a0 00000000 ffff8004 00000000 00000000 ................
diff --git a/ld/testsuite/ld-mips-elf/tlslib-o32-ver.got b/ld/testsuite/ld-mips-elf/tlslib-o32-ver.got
index e675f9f..17a6385 100644
--- a/ld/testsuite/ld-mips-elf/tlslib-o32-ver.got
+++ b/ld/testsuite/ld-mips-elf/tlslib-o32-ver.got
@@ -4,12 +4,12 @@
DYNAMIC RELOCATION RECORDS
OFFSET TYPE VALUE
00000000 R_MIPS_NONE \*ABS\*
-000404d8 R_MIPS_TLS_DTPMOD32 \*ABS\*
-000404d0 R_MIPS_TLS_DTPMOD32 tlsvar_gd@@VER_1
-000404d4 R_MIPS_TLS_DTPREL32 tlsvar_gd@@VER_1
-000404cc R_MIPS_TLS_TPREL32 tlsvar_ie@@VER_1
+000404b8 R_MIPS_TLS_DTPMOD32 \*ABS\*
+000404b0 R_MIPS_TLS_DTPMOD32 tlsvar_gd@@VER_1
+000404b4 R_MIPS_TLS_DTPREL32 tlsvar_gd@@VER_1
+000404ac R_MIPS_TLS_TPREL32 tlsvar_ie@@VER_1
Contents of section .got:
- 404c0 00000000 80000000 00000490 00000000 ................
- 404d0 00000000 00000000 00000000 00000000 ................
+ 404a0 00000000 80000000 00000470 00000000 ................
+ 404b0 00000000 00000000 00000000 00000000 ................
diff --git a/ld/testsuite/ld-mips-elf/tlslib-o32.got b/ld/testsuite/ld-mips-elf/tlslib-o32.got
index ad90fb0..a389c30 100644
--- a/ld/testsuite/ld-mips-elf/tlslib-o32.got
+++ b/ld/testsuite/ld-mips-elf/tlslib-o32.got
@@ -4,12 +4,12 @@ tmpdir/tlslib-o32.so: file format elf32-tradbigmips
DYNAMIC RELOCATION RECORDS
OFFSET TYPE VALUE
00000000 R_MIPS_NONE \*ABS\*
-00040448 R_MIPS_TLS_DTPMOD32 \*ABS\*
-00040440 R_MIPS_TLS_DTPMOD32 tlsvar_gd
-00040444 R_MIPS_TLS_DTPREL32 tlsvar_gd
-0004043c R_MIPS_TLS_TPREL32 tlsvar_ie
+00040428 R_MIPS_TLS_DTPMOD32 \*ABS\*
+00040420 R_MIPS_TLS_DTPMOD32 tlsvar_gd
+00040424 R_MIPS_TLS_DTPREL32 tlsvar_gd
+0004041c R_MIPS_TLS_TPREL32 tlsvar_ie
Contents of section .got:
- 40430 00000000 80000000 00000400 00000000 ................
- 40440 00000000 00000000 00000000 00000000 ................
+ 40410 00000000 80000000 000003e0 00000000 ................
+ 40420 00000000 00000000 00000000 00000000 ................
='#n1832'>1832 1833 1834 1835 1836 1837 1838 1839 1840 1841 1842 1843 1844 1845 1846 1847 1848 1849 1850 1851 1852 1853 1854 1855 1856 1857 1858 1859 1860 1861 1862 1863 1864 1865 1866 1867 1868 1869 1870 1871 1872 1873 1874 1875 1876 1877 1878 1879 1880 1881 1882 1883 1884 1885 1886 1887 1888 1889 1890 1891 1892 1893 1894 1895 1896 1897 1898 1899 1900 1901 1902 1903 1904 1905 1906 1907 1908 1909 1910 1911 1912 1913 1914
/* QEMU Emulation PALcode.

   Copyright (C) 2011 Richard Henderson

   This file is part of QEMU PALcode.

   This program is free software; you can redistribute it and/or modify
   it under the terms of the GNU General Public License as published by
   the Free Software Foundation; either version 2 of the License or
   (at your option) any later version.

   This program is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the text
   of the GNU General Public License for more details.

   You should have received a copy of the GNU General Public License
   along with this program; see the file COPYING.  If not see
   <http://www.gnu.org/licenses/>.  */

	.set		noat
	.set		nomacro
	.text

#include "pal.h"
#include "osf.h"
#include SYSTEM_H

/*
 * Create a standard kernel entry stack frame.
 */

.macro	STACK_FRAME save_ps, save_pc, temp, do_ps
	// Test if we're currently in user mode
	and	\save_ps, PS_M_CM, \temp
	beq	\temp, 0f
	// Switch to kernel mode
.ifne \do_ps
	mtpr	$31, qemu_ps
.endif
	mtpr	$sp, qemu_usp
	mfpr	$sp, ptKsp
	// Allocate the stack frame
0:	lda	$sp, -FRM_K_SIZE($sp)
	stq	\save_ps, FRM_Q_PS($sp)
	stq	\save_pc, FRM_Q_PC($sp)
	stq	$gp, FRM_Q_GP($sp)
	stq	a0, FRM_Q_A0($sp)
	stq	a1, FRM_Q_A1($sp)
	stq	a2, FRM_Q_A2($sp)
.endm

/*
 * Allocate a 1 page stack for use by the console.
 */
#define STACK_SIZE	8192

/*
 * QEMU emulator "hardware" entry points.
 */

/*
 * Reset
 * 
 * INPUT PARAMETERS:
 * 
 *	trap_arg0 = Memory size
 *	trap_arg1 = Kernel entry (if loaded)
 */ 
        .org	0x0000
	.globl	__start
__start:
	// Initialize GP.
	br	$gp, .+4
	ldah	$gp, 0($gp)			!gpdisp!1
	lda	$gp, 0($gp)			!gpdisp!1
	mtpr	$gp, ptPgp

	// Disable interrupts; kernel mode
	lda	t0, IPL_K_HIGH
	mtpr	t0, qemu_ps

	// Initialize Stack.
	SYS_WHAMI a0
	lda	t0, STACK_SIZE
	addq	a0, 1, t1
	mull	t0, t1, t0
	ldah	t1, stack($gp)			!gprelhigh
	lda	t1, stack(t1)			!gprellow
	addq	t0, t1, $sp

	// Do any necessary system setup required for PALmode,
	// e.g. setting up ptSys[01].
	bsr	$26, Sys_Setup

	// Non-boot CPUs can go wait now.
	bne	a0, 1f

	// Load boot arguments
	mfpr	a0, qemu_trap_arg0
	mfpr	a1, qemu_trap_arg1
	mfpr	a2, qemu_trap_arg2

	// Continue in do_start, outside PALmode.
	ldah	$27, do_start($gp)		!gprelhigh
	lda	$27, do_start($27)		!gprellow
	hw_ret	($27)

1:	ldah	$27, do_start_wait($gp)		!gprelhigh
	lda	$27, do_start_wait($27)		!gprellow
	hw_ret	($27)
ENDFN	__start

/*
 * Machine Check
 *
 * INPUT PARAMETERS:
 * 
 *	trap_arg0 = 
 *	trap_arg1 = 
 *	trap_arg2 = 
 */
	.org	0x0080
Pal_Mchk:
	halt
ENDFN	Pal_Mchk

/*
 * Interprocessor Interrupt
 *
 * INPUT PARAMETERS:
 *
 *	trap_arg0 = 
 *	trap_arg1 =
 *	trap_arg2 =
 *
 * The interprocessor interrupt is special, in that PALcode is supposed
 * to clear the interupt and not wait for the OS to do it.
 */
	.org	0x0100
Pal_Smp_Interrupt:
	mfpr	p6, qemu_exc_addr

	SYS_ACK_SMP p0, p1, p2

	mfpr	p0, qemu_ps

	STACK_FRAME p0, p6, p2, 0

	mov	IPL_K_IP, p0		// Raise IPL
	mtpr	p0, qemu_ps

	mfpr	p6, ptEntInt
	mfpr	$gp, ptKgp
	lda	a0, INT_K_IP
	lda	a1, 0
	lda	a2, 0

	hw_ret	(p6)
ENDFN	Pal_Smp_Interrupt

/*
 * Clock Interrupt
 *
 * INPUT PARAMETERS:
 *
 *	trap_arg0 = 
 *	trap_arg1 =
 *	trap_arg2 =
 *
 * The clock interrupt is special, in that PALcode is supposed
 * to clear the interupt and not wait for the OS to do it.
 */
	.org	0x0180
Pal_Clk_Interrupt:
	mfpr	p6, qemu_exc_addr

	SYS_ACK_CLK p0, p1, p2

	mfpr	p0, qemu_ps

	STACK_FRAME p0, p6, p2, 0

	mov	IPL_K_CLK, p0		// Raise IPL
	mtpr	p0, qemu_ps

	mfpr	p6, ptEntInt
	mfpr	$gp, ptKgp
	lda	a0, INT_K_CLK
	lda	a1, 0
	lda	a2, 0

9:	hw_ret	(p6)
ENDFN	Pal_Clk_Interrupt

/*
 * Device Interrupt
 *
 * INPUT PARAMETERS:
 *
 *	trap_arg0 = 
 *	trap_arg1 =
 *	trap_arg2 =
 */ 
	.org	0x0200
Pal_Dev_Interrupt:
	mfpr	p6, qemu_exc_addr
	mfpr	p0, qemu_ps

	STACK_FRAME p0, p6, p2, 0

	mov	IPL_K_DEV1, p0		// Raise IPL
	mtpr	p0, qemu_ps

	mfpr	p7, ptEntInt
	mfpr	$gp, ptKgp

	lda	a0, INT_K_DEV
	lda	a2, 0

	SYS_DEV_VECTOR a1

	hw_ret	(p7)
ENDFN	Pal_Dev_Interrupt

/*
 * Memory Fault
 *
 * INPUT PARAMETERS:
 *
 *	trap_arg0 = faulting address
 *	trap_arg1 = fault type (TNV, ACV, FOR, FOW, FOE)
 *	trap_arg2 = access type (exec=-1, read=0, write=1)
 */ 
	.org	0x0280
Pal_MMFault:
	mfpr	p0, qemu_ps
	mfpr	p6, qemu_exc_addr
	blbs	p6, MchkBugCheck

	STACK_FRAME p0, p6, p2, 1

	mfpr	p0, ptEntMM
	mfpr	$gp, ptKgp
	mfpr	a0, qemu_trap_arg0
	mfpr	a1, qemu_trap_arg1
	mfpr	a2, qemu_trap_arg2
	hw_ret	(p0)
ENDFN	Pal_MMFault

/*
 * Unaligned Data
 * 
 * INPUT PARAMETERS:
 *
 *	trap_arg0 = faulting address
 *	trap_arg1 = opcode of faulting insn
 *	trap_arg2 = src/dst register number
 */ 
	.org	0x0300
Pal_Unalign:
	mfpr	p0, qemu_ps
	mfpr	p6, qemu_exc_addr
	addq	p6, 4, p1		// increment past the faulting insn
	blbs	p6, MchkBugCheck

	STACK_FRAME p0, p1, p2, 1

	mfpr	p0, ptEntUna
	mfpr	$gp, ptKgp
	mfpr	a0, qemu_trap_arg0
	mfpr	a1, qemu_trap_arg1
	mfpr	a2, qemu_trap_arg2
	hw_ret	(p0)
ENDFN	Pal_Unalign

/*
 * Illegal Opcode
 *
 * INPUT PARAMETERS:
 *
 *	trap_arg0 = UNDEFINED
 *	trap_arg1 = UNDEFINED
 *	trap_arg2 = UNDEFINED
 *
 * OUTPUT PARAMETERS:
 *
 *	r16 (a0) = Instruction fault code
 *	r17 (a1) = UNPREDICTABLE
 *	r18 (a2) = UNPREDICTABLE
 */ 
	.org	0x0380
Pal_OpcDec:
	mfpr	p0, qemu_ps
	mfpr	p6, qemu_exc_addr
	addq	p6, 4, p1		// increment past the faulting insn
	blbs	p6, MchkBugCheck

	STACK_FRAME p0, p1, p2, 1

	mfpr	p0, ptEntIF
	mfpr	$gp, ptKgp
	mov	IF_K_OPCDEC, a0
	hw_ret	(p0)
ENDFN	Pal_OpcDec

/*
 * Arithmetic Trap
 *
 * INPUT PARAMETERS:
 *
 *	trap_arg0 = exception type
 *	trap_arg1 = register modification mask
 *	trap_arg2 = UNDEFINED
 */
	.org	0x0400
Pal_Arith:
	mfpr	p0, qemu_ps
	mfpr	p6, qemu_exc_addr
	blbs	p6, MchkBugCheck

	STACK_FRAME p0, p6, p2, 1

	mfpr	p0, ptEntArith
	mfpr	$gp, ptKgp
	mfpr	a0, qemu_trap_arg0
	mfpr	a1, qemu_trap_arg1
	hw_ret	(p0)
ENDFN	Pal_Arith

/*
 * Floating Point Disabled
 *
 * INPUT PARAMETERS:
 *
 *	trap_arg0 = UNDEFINED
 *	trap_arg1 = UNDEFINED
 *	trap_arg2 = UNDEFINED
 *
 * OUTPUT PARAMETERS:
 *
 *	r16 (a0) = Instruction fault code
 *	r17 (a1) = UNPREDICTABLE
 *	r18 (a2) = UNPREDICTABLE
 */ 
	.org	0x0480
Pal_Fen:
	mfpr	p0, qemu_ps
	mfpr	p6, qemu_exc_addr
	blbs	p6, MchkBugCheck

	STACK_FRAME p0, p6, p2, 1

	mfpr	p0, ptEntIF
	mfpr	$gp, ptKgp
	mov	IF_K_FEN, a0
	hw_ret	(p0)
ENDFN	Pal_Fen

/*
 * OSF/1 Privileged CALL_PAL Entry Points
 */

#define ORG_CALL_PAL_PRIV(X)	.org	0x1000+64*X

/*
 * Halt
 *
 * SIDE EFFECTS:
 *
 *	We either power down the system or re-enter the console.
 *	But given that we're not returning to the kernel, there's
 *	no reason to continue processing in assembler.  Go to C.
 */
	ORG_CALL_PAL_PRIV(0x00)
CallPal_Halt:
	bsr	p7, UpdatePCB		// Save kernel data
	lda	v0, HLT_K_SW_HALT	// FIXME store this somewhere.

	mtpr	$31, qemu_halt

	br	Sys_EnterConsole
ENDFN	CallPal_Halt

/*
 * Cache Flush
 *
 * For QEMU, this is of course a no-op.
 */
	ORG_CALL_PAL_PRIV(0x01)
CallPal_Cflush:
	hw_rei
ENDFN	CallPal_Cflush

/*
 * Drain Aborts
 *
 * For QEMU, this is of course a no-op.
 */
        ORG_CALL_PAL_PRIV(0x02)
CallPal_Draina:
	hw_rei
ENDFN	CallPal_Draina

	ORG_CALL_PAL_PRIV(0x03)
CallPal_OpcDec03:
	br	CallPal_OpcDec
ENDFN	CallPal_OpcDec03

	ORG_CALL_PAL_PRIV(0x04)
CallPal_OpcDec04:
	br	CallPal_OpcDec
ENDFN	CallPal_OpcDec04

	ORG_CALL_PAL_PRIV(0x05)
CallPal_OpcDec05:
	br	CallPal_OpcDec
ENDFN	CallPal_OpcDec05

	ORG_CALL_PAL_PRIV(0x06)
CallPal_OpcDec06:
	br	CallPal_OpcDec
ENDFN	CallPal_OpcDec06

	ORG_CALL_PAL_PRIV(0x07)
CallPal_OpcDec07:
	br	CallPal_OpcDec
ENDFN	CallPal_OpcDec07

	ORG_CALL_PAL_PRIV(0x08)
CallPal_OpcDec08:
	br	CallPal_OpcDec
ENDFN	CallPal_OpcDec08

/*
 * Console Service
 * 
 * INPUT PARAMETERS:
 * 
 *	r16 (a0)          = Option selector
 *	r17..r21 (a1..a5) = Implementation specific entry parameters
 *
 * SIDE EFFECTS:
 *
 *	Registers a0..a5, and v0 are UNPREDICTABLE upon return.
 */ 
	ORG_CALL_PAL_PRIV(0x09)
CallPal_Cserve:
	// Most of the entries are densely clustered around 0.
	mov	0, v0
	cmpule	a0, 6, p0
	cmovne	p0, a0, v0
	br	p0, 1f
1:	lda	p0, Cserve_Table-1b(p0)
	s8addq	v0, p0, p0
	jmp	$31, (p0), 0
ENDFN	CallPal_Cserve

	.text	1
	.align	3
/* Note that the entries in the following table are all 2 insns.
   The first entry is unused, and is also where all out-of-range
   commands are vectored.  */
Cserve_Table:
	br	CallPal_Cserve_Cont
	nop
Cserve_Ldqp:
	ldq_p	v0, 0(a1)
	hw_rei
ENDFN	Cserve_Ldqp
Cserve_Stqp:
	stq_p	a2, 0(a1)
	hw_rei
ENDFN	Cserve_Stqp
Cserve_Get_Wall_Time:
	mfpr	v0, qemu_walltime
	hw_rei
ENDFN	Cserve_Get_Wall_Time
Cserve_Get_Alarm:
	mfpr	v0, qemu_alarm
	hw_rei
ENDFN	Cserve_Get_Alarm
Cserve_Set_Alarm_Rel:
	// Cheating here: create the absolute time and fall thru.
	mfpr	p0, qemu_walltime
	addq	p0, a1, a1
ENDFN	Cserve_Set_Alarm_Rel
Cserve_Set_Alarm_Abs:
	mtpr	a1, qemu_alarm
	hw_rei
ENDFN	Cserve_Set_Alarm_Abs

CallPal_Cserve_Cont:
	// ??? For SRM compatibility and their use within Linux, use 52/53
	// for these.  Anyone know what other "standard" SRM Cserve entry
	// points are?  Certainly we don't want to be compatible with MILO,
	// which puts the selector at A2.
	cmpeq	a0, 52, v0
	bne	v0, Cserve_Ena
	cmpeq	a0, 53, v0
	bne	v0, Cserve_Dis
	hw_rei
ENDFN	CallPal_Cserve_Cont
	.previous

/*
 * Swap PALcode
 *
 * FUNCTIONAL DESCRIPTION:
 *
 *	The swap PALcode (swppal) function replaces the current 
 *	(active) PALcode by the specified new PALcode image.  
 *	This function is intended for use by operating systems 
 *	only during bootstraps and restarts, or during transitions 
 *	to console I/O mode.
 * 
 *	The PALcode descriptor passed in a0 is interpreted as
 *	either a PALcode variant or the base physical address
 *	of the new PALcode image.  If a variant, the PALcode
 *	image must have been previously loaded.  No PALcode
 *	loading occurs as a result of this function. 
 *
 *	NOTE:
 *	This implementation of SWPPAL does not support PALcode
 *	variants.  If a variant is specified in a0, a check is
 *	performed to determine whether the variant is OSF/1 or
 *	not and the returned status is either unknown variant
 *	(if not OSF/1) or variant not loaded.
 *
 * INPUT PARAMETERS:
 *
 *	r16 (a0) = New PALcode variant or base physical address
 *	r17 (a1) = New PC
 *	r18 (a2) = New PCB
 *	r19 (a3) = New VptPtr
 * 
 * OUTPUT PARAMETERS:
 *
 *	r0 (v0) = Returned status indicating:
 *			0 - Success (PALcode was switched)
 *			1 - Unknown PALcode variant
 *			2 - Known PALcode variant, but PALcode not loaded
 *
 *	r26 (ra) = r27 (pv) = New PC
 *		Note that this is non-architected, but is relied on by
 *		the usage of SwpPal within our own console code in order
 *		to simplify its use within C code.
 *
 */
	ORG_CALL_PAL_PRIV(0x0A)
CallPal_SwpPal:
	// Save a copy of the return address in case of machine check.
	mfpr	p6, qemu_exc_addr

	// Accept swapping to OSF PALcode.  The side effect here is to
	// load the other parameters for the kernel.
	cmpeq	a0, 2, v0
	bne	v0, CallPal_SwpPal_Cont

	// Return as an unknown PALcode variant
	mov	1, v0
	hw_rei
ENDFN	CallPal_SwpPal

	.text	1
CallPal_SwpPal_Cont:
	rpcc	p0
	mtpr	a2, ptPcbb
	mtpr	a3, qemu_vptptr

	ldq_p	$sp, PCB_Q_KSP(a2)
	ldq_p	t0, PCB_Q_USP(a2)
	ldq_p	t1, PCB_Q_PTBR(a2)
	ldl_p	t2, PCB_L_PCC(a2)
	ldq_p	t3, PCB_Q_UNIQUE(a2)
	ldq_p	t4, PCB_Q_FEN(a2)

	mtpr	t0, qemu_usp

	sll	t1, VA_S_OFF, t1
	mtpr	t1, qemu_ptbr

	subl	t2, p0, t2
	mtpr	t2, qemu_pcc_ofs

	mtpr	t3, qemu_unique

	and	t4, 1, t4
	mtpr	t4, qemu_fen

	mtpr	$31, qemu_tbia		// Flush TLB for new PTBR

	mov	a1, $26
	mov	a1, $27
	hw_ret	(a1)
ENDFN	CallPal_SwpPal_Cont
	.previous

	ORG_CALL_PAL_PRIV(0x0B)
CallPal_OpcDec0B:
	br	CallPal_OpcDec
ENDFN	CallPal_OpcDec0B

	ORG_CALL_PAL_PRIV(0x0C)
CallPal_OpcDec0C:
	br	CallPal_OpcDec
ENDFN	CallPal_OpcDec0C

/*
 * Write Interprocessor Interrupt Request
 *
 * INPUT PARAMETERS:
 *
 *	r16 (a0) = target processor number 
 * 
 * OUTPUT PARAMETERS:
 *
 * SIDE EFFECTS:
 * 
 */ 
        ORG_CALL_PAL_PRIV(0x0D)
CallPal_WrIpir:
	// Save a copy of the return address in case of machine check.
	mfpr	p6, qemu_exc_addr

	SYS_WRIPIR	a0, p0, p1, p2

	hw_rei
ENDFN	CallPal_WrIpir

	ORG_CALL_PAL_PRIV(0x0E)
CallPal_OpcDec0E:
	br	CallPal_OpcDec
ENDFN	CallPal_OpcDec0E

	ORG_CALL_PAL_PRIV(0x0F)
CallPal_OpcDec0F:
	br	CallPal_OpcDec
ENDFN	CallPal_OpcDec0F

/*
 * Read Machine Check Error Summary
 *
 * INPUT PARAMETERS:
 * 
 * OUTPUT PARAMETERS:
 *
 *	r0 (v0) = returned MCES value
 * 
 * SIDE EFFECTS:
 *
 */ 
        ORG_CALL_PAL_PRIV(0x10)
CallPal_RdMces:
	mfpr	v0, ptMces		// Get current MCES value
	and	v0, MCES_M_ALL, v0	// Clear all other bits
	hw_rei
ENDFN	CallPal_RdMces

/*
 * Write Machine Check Error Summary
 *
 * INPUT PARAMETERS:
 * 
 *	r16 (a0) = MCES<DPC> <- a0<3>,  MCES<DSC> <- a0<4>
 * 
 * OUTPUT PARAMETERS:
 *
 * SIDE EFFECTS:
 *
 *	Registers t0, t8..t11, and a0 are UNPREDICTABLE upon return.
 */ 
        ORG_CALL_PAL_PRIV(0x11)
CallPal_WrMces:
	// Clear MIP, SCE, PCE
	and	a0, (MCES_M_MIP | MCES_M_SCE | MCES_M_PCE), p0
	mfpr	p1, ptMces
	bic	p1, p0, p1

	// Copy DPC and DSC
	and	a0, (MCES_M_DPC | MCES_M_DSC), p0
	bic	p1, (MCES_M_DPC | MCES_M_DSC), p1
	or	p1, p0, p1

	mtpr	p1, ptMces
	hw_rei
ENDFN	CallPal_WrMces

	ORG_CALL_PAL_PRIV(0x12)
CallPal_OpcDec12:
	br	CallPal_OpcDec
ENDFN	CallPal_OpcDec12

	ORG_CALL_PAL_PRIV(0x13)
CallPal_OpcDec13:
	br	CallPal_OpcDec
ENDFN	CallPal_OpcDec13

	ORG_CALL_PAL_PRIV(0x14)
CallPal_OpcDec14:
	br	CallPal_OpcDec
ENDFN	CallPal_OpcDec14

	ORG_CALL_PAL_PRIV(0x15)
CallPal_OpcDec15:
	br	CallPal_OpcDec
ENDFN	CallPal_OpcDec15

	ORG_CALL_PAL_PRIV(0x16)
CallPal_OpcDec16:
	br	CallPal_OpcDec
ENDFN	CallPal_OpcDec16

	ORG_CALL_PAL_PRIV(0x17)
CallPal_OpcDec17:
	br	CallPal_OpcDec
ENDFN	CallPal_OpcDec17

	ORG_CALL_PAL_PRIV(0x18)
CallPal_OpcDec18:
	br	CallPal_OpcDec
ENDFN	CallPal_OpcDec18

	ORG_CALL_PAL_PRIV(0x19)
CallPal_OpcDec19:
	br	CallPal_OpcDec
ENDFN	CallPal_OpcDec19

	ORG_CALL_PAL_PRIV(0x1A)
CallPal_OpcDec1A:
	br	CallPal_OpcDec
ENDFN	CallPal_OpcDec1A

	ORG_CALL_PAL_PRIV(0x1B)
CallPal_OpcDec1B:
	br	CallPal_OpcDec
ENDFN	CallPal_OpcDec1B

	ORG_CALL_PAL_PRIV(0x1C)
CallPal_OpcDec1C:
	br	CallPal_OpcDec
ENDFN	CallPal_OpcDec1C

	ORG_CALL_PAL_PRIV(0x1D)
CallPal_OpcDec1D:
	br	CallPal_OpcDec
ENDFN	CallPal_OpcDec1D

	ORG_CALL_PAL_PRIV(0x1E)
CallPal_OpcDec1E:
	br	CallPal_OpcDec
ENDFN	CallPal_OpcDec1E

	ORG_CALL_PAL_PRIV(0x1F)
CallPal_OpcDec1F:
	br	CallPal_OpcDec
ENDFN	CallPal_OpcDec1F

	ORG_CALL_PAL_PRIV(0x20)
CallPal_OpcDec20:
	br	CallPal_OpcDec
ENDFN	CallPal_OpcDec20

	ORG_CALL_PAL_PRIV(0x21)
CallPal_OpcDec21:
	br	CallPal_OpcDec
ENDFN	CallPal_OpcDec21

	ORG_CALL_PAL_PRIV(0x22)
CallPal_OpcDec22:
	br	CallPal_OpcDec
ENDFN	CallPal_OpcDec22

	ORG_CALL_PAL_PRIV(0x23)
CallPal_OpcDec23:
	br	CallPal_OpcDec
ENDFN	CallPal_OpcDec23

	ORG_CALL_PAL_PRIV(0x24)
CallPal_OpcDec24:
	br	CallPal_OpcDec
ENDFN	CallPal_OpcDec24

	ORG_CALL_PAL_PRIV(0x25)
CallPal_OpcDec25:
	br	CallPal_OpcDec
ENDFN	CallPal_OpcDec25

	ORG_CALL_PAL_PRIV(0x26)
CallPal_OpcDec26:
	br	CallPal_OpcDec
ENDFN	CallPal_OpcDec26

	ORG_CALL_PAL_PRIV(0x27)
CallPal_OpcDec27:
	br	CallPal_OpcDec
ENDFN	CallPal_OpcDec27

	ORG_CALL_PAL_PRIV(0x28)
CallPal_OpcDec28:
	br	CallPal_OpcDec
ENDFN	CallPal_OpcDec28

	ORG_CALL_PAL_PRIV(0x29)
CallPal_OpcDec29:
	br	CallPal_OpcDec
ENDFN	CallPal_OpcDec29

	ORG_CALL_PAL_PRIV(0x2A)
CallPal_OpcDec2A:
	br	CallPal_OpcDec
ENDFN	CallPal_OpcDec2A

/*
 * Write Floating Point Enable
 *
 * INPUT PARAMETERS:
 * 
 *	r16 (a0) = ICSR<FPE> <- a0<0>
 * 
 * SIDE EFFECTS:
 *
 *	Registers t0, t8..t11, and a0 are UNPREDICTABLE upon return.
 */ 
        ORG_CALL_PAL_PRIV(0x2B)
CallPal_WrFen:
	mfpr	p0, ptPcbb		// Get PCBB
	and	a0, 1, a0		// Clean new FEN value to single bit
	mtpr	a0, qemu_fen
	stl_p	a0, PCB_Q_FEN(p0)	// Write new PCB<FEN>
	hw_rei
ENDFN	CallPal_WrFen

	ORG_CALL_PAL_PRIV(0x2C)
CallPal_OpcDec2C:
	br	CallPal_OpcDec
ENDFN	CallPal_OpcDec2C

/*
 * Write Virtual Page Table Pointer
 *
 * INPUT PARAMETERS:
 *
 *	r16 (a0) = New virtual page table pointer 
 *
 * SIDE EFFECTS:
 *
 *	Registers t0, t8..t11, and a0 are UNPREDICTABLE upon return.
 */ 
        ORG_CALL_PAL_PRIV(0x2D)
CallPal_WrVptPtr:
	mtpr	a0, qemu_vptptr
	hw_rei
ENDFN	CallPal_WrVptPtr

	ORG_CALL_PAL_PRIV(0x2E)
CallPal_OpcDec2E:
	br	CallPal_OpcDec
ENDFN	CallPal_OpcDec2E

	ORG_CALL_PAL_PRIV(0x2F)
CallPal_OpcDec2F:
	br	CallPal_OpcDec
ENDFN	CallPal_OpcDec2F

/*
 * Swap Process Context
 *
 * FUNCTIONAL DESCRIPTION:
 *
 *	The swap process context (swpctx) function saves 
 *	the current process data in the current PCB, then 
 *	switches to the PCB passed in a0 and loads the
 *	new process context.  The old PCB is returned in v0.	
 * 
 * INPUT PARAMETERS:
 * 
 *	r16 (a0) = New PCBB 
 * 
 * OUTPUT PARAMETERS:
 *
 *	r0  (v0) = Old PCBB
 * 
 * SIDE EFFECTS:
 *
 *	Registers t0, t8..t11, and a0 are UNPREDICTABLE upon return.
 */ 
	ORG_CALL_PAL_PRIV(0x30)
CallPal_SwpCtx:
	rpcc	p5			// Get cycle counter
	mfpr	p6, qemu_exc_addr	// Save exc_addr for machine check

	mfpr	v0, ptPcbb		// Get current PCBB
	mtpr	a0, ptPcbb		// Save new PCBB
	srl	p5, 32, p7		// Move CC<OFFSET> to low longword

	addl	p5, p7, p7		// Accumulate time for old pcb
	stl_p	p7, PCB_L_PCC(v0)

	ldl_p	t9, PCB_L_PCC(a0)	// Get new PCC
	subl	t9, p5, p5		// Generate and ...
	mtpr	p5, qemu_pcc_ofs	// .. set new CC<OFFSET> bits

	stq_p	$sp, PCB_Q_KSP(v0)	// Store old kernel stack pointer
	mfpr	t10, qemu_usp		// Save old user stack pointer
	stq_p	t10, PCB_Q_USP(v0)

	br	CallPal_SwpCtx_Cont
ENDFN	CallPal_SwpCtx

	.text	1
CallPal_SwpCtx_Cont:
	ldq_p	$sp, PCB_Q_KSP(a0)	// Install new stack pointers
	ldq_p	t10, PCB_Q_USP(a0)
	mtpr	t10, qemu_usp

	mfpr	t10, qemu_unique	// Save old unique value
	stq_p	t10, PCB_Q_UNIQUE(v0)
	ldq_p	t10, PCB_Q_UNIQUE(a0)	// Install new unique value
	mtpr	t10, qemu_unique

	ldq_p	t8, PCB_Q_FEN(a0)	// Install new FEN
	and	t8, 1, t8
	mtpr	t8, qemu_fen

	// QEMU does not implement an ASN; skip that.

	ldq_p	t10, PCB_Q_PTBR(a0)	// Install new page tables
	sll	t10, VA_S_OFF, t10
	mtpr	t10, qemu_ptbr
	mtpr	$31, qemu_tbia		// Flush TLB, since we don't do ASNs

	hw_rei
ENDFN	CallPal_SwpCtx_Cont
	.previous

/*
 * Write System Value
 *
 * INPUT PARAMETERS:
 *
 *	r16 (a0) = New system value 
 * 
 * SIDE EFFECTS:
 *
 *	Registers t0, t8..t11, and a0 are UNPREDICTABLE upon return.
 */ 
        ORG_CALL_PAL_PRIV(0x31)
CallPal_WrVal:
	mtpr	a0, qemu_sysval
	hw_rei
ENDFN	CallPal_WrVal

/*
 * Read System Value
 *
 * OUTPUT PARAMETERS:
 *
 *	r0 (v0) = Returned system value
 * 
 * SIDE EFFECTS:
 *
 *	Registers t0 and t8..t11 are UNPREDICTABLE upon return.
 */ 
        ORG_CALL_PAL_PRIV(0x32)
CallPal_RdVal:
	mfpr	v0, qemu_sysval
	hw_rei
ENDFN	CallPal_RdVal

/*
 * Translation Buffer Invalidate
 * 
 * INPUT PARAMETERS:
 * 
 *	r16 (a0) = tbi selector type:
 *
 *		-2 - Flush all TB entries (tbia)
 *		-1 - Invalidate all TB entries with ASM=0 (tbiap)
 *		 1 - Invalidate ITB entry for va=a1 (tbisi)
 *		 2 - Invalidate DTB entry for va=a1 (tbisd)
 *		 3 - Invalidate both ITB and DTB entry for va=a1 (tbis)
 *
 *	r17 (a1) = VA for TBISx types
 *
 * Qemu does not implement ASNs or split I/D tlbs.  Therefore these
 * collapse to tbia and tbis.
 * 
 * SIDE EFFECTS:
 *
 *	Registers t0, t8..t11, and a0 are UNPREDICTABLE upon return.
 */ 
        ORG_CALL_PAL_PRIV(0x33)
CallPal_Tbi:
	bge	a0, 1f

	mtpr	$31, qemu_tbia
	hw_rei

1:	mtpr	a1, qemu_tbis
	hw_rei
ENDFN	CallPal_Tbi

/*
 * Write System Entry Address
 *
 * INPUT PARAMETERS:
 *
 *	r16 (a0) = VA of system entry point
 *	r17 (a1) = System entry point selector 
 * 
 * SIDE EFFECTS:
 *
 *	Registers t0, t8..t11, and a0..a1 are UNPREDICTABLE
 *	upon return.
 */ 
        ORG_CALL_PAL_PRIV(0x34)
CallPal_WrEnt:
	andnot	a0, 3, a0		// Clean PC<1:0>

	cmpult	a1, 6, t8		// Bound the input
	cmoveq	t8, 6, a1

	br	t0, 1f
1:	lda	t0, WrEnt_Table-1b(t0)
	s8addq	a1, t0, t0
	jmp	$31, (t0), 0
ENDFN	CallPal_WrEnt

	.text	1
WrEnt_Table:
0:	mtpr	a0, ptEntInt
	hw_rei
1:	mtpr	a0, ptEntArith
	hw_rei
2:	mtpr	a0, ptEntMM
	hw_rei
3:	mtpr	a0, ptEntIF
	hw_rei
4:	mtpr	a0, ptEntUna
	hw_rei
5:	mtpr	a0, ptEntSys
	hw_rei
6:	nop
	hw_rei
ENDFN	WrEnt_Table
	.previous

/*
 * Swap Interrupt Priority Level
 * 
 * INPUT PARAMETERS:
 * 
 *	r16 (a0) = New IPL
 * 
 * OUTPUT PARAMETERS:
 *
 *	r0  (v0) = Old IPL
 * 
 * SIDE EFFECTS:
 *
 *	Registers t0, t8..t11, and a0 are UNPREDICTABLE upon return.
 */ 
        ORG_CALL_PAL_PRIV(0x35)
CallPal_SwpIpl:
	mfpr	v0, qemu_ps
	and	a0, PS_M_IPL, a0
	and	v0, PS_M_IPL, v0
	mtpr	a0, qemu_ps
	hw_rei
ENDFN	CallPal_SwpIpl

/*
 * Read Processor Status
 *
 * OUTPUT PARAMETERS:
 *
 *	r0 (v0) = Current PS
 * 
 * SIDE EFFECTS:
 *
 *	Registers t0, t8..t11 are UNPREDICTABLE upon return.
 */ 
        ORG_CALL_PAL_PRIV(0x36)
CallPal_RdPs:
	mfpr	v0, qemu_ps
	hw_rei
ENDFN	CallPal_RdPs

/*
 * Write Kernel Global Pointer
 *
 * INPUT PARAMETERS:
 * 
 *	r16 (a0) = New KGP value
 *
 * SIDE EFFECTS:
 *
 *	Registers t0, t8..t11, and a0 are UNPREDICTABLE upon return.
 */ 
        ORG_CALL_PAL_PRIV(0x37)
CallPal_WrKgp:
	mtpr	a0, ptKgp
	hw_rei
ENDFN	CallPal_WrKgp

/*
 * Write User Stack Pointer
 * 
 * INPUT PARAMETERS:
 * 
 *	r16 (a0) = New user stack pointer value
 * 
 * SIDE EFFECTS:
 *
 *	Registers t0, t8..t11, and a0 are UNPREDICTABLE upon return.
 */ 
        ORG_CALL_PAL_PRIV(0x38)
CallPal_WrUsp:
	mtpr	a0, qemu_usp
	hw_rei
ENDFN	CallPal_WrUsp

/*
 * Write Performance Monitor
 *
 * INPUT PARAMETERS:
 * 
 *	r16 (a0) = New user stack pointer value
 * 
 * SIDE EFFECTS:
 *
 *	Registers t0, t8..t11, and a0 are UNPREDICTABLE upon return.
 */
	ORG_CALL_PAL_PRIV(0x39)
CallPal_WrPerfMon:
	// Not implemented
	hw_rei
ENDFN	CallPal_WrPerfMon

/*
 * Read User Stack Pointer
 * 
 * OUTPUT PARAMETERS:
 *
 *	r0 (v0) = User stack pointer value
 * 
 * SIDE EFFECTS:
 *
 *	Registers t0, and t8..t11 are UNPREDICTABLE upon return.
 */ 
        ORG_CALL_PAL_PRIV(0x3A)
CallPal_RdUsp:
	mfpr	v0, qemu_usp
	hw_rei
ENDFN	CallPal_RdUsp

	ORG_CALL_PAL_PRIV(0x3B)
CallPal_OpcDec3B:
	br	CallPal_OpcDec
ENDFN	CallPal_OpcDec3B

/*
 * Who Am I
 * 
 * OUTPUT PARAMETERS:
 *
 *	r0 (v0) = Current processor number
 * 
 * SIDE EFFECTS:
 *
 *	Registers t0 and t8..t11 are UNPREDICTABLE upon return.
 */ 
        ORG_CALL_PAL_PRIV(0x3C)
CallPal_Whami:
	SYS_WHAMI v0
	hw_rei
ENDFN	CallPal_Whami

/*
 * Return From System Call
 *
 * INPUT PARAMETERS:
 * 
 *	r30 (sp) = Pointer to the top of the kernel stack
 * 
 * OUTPUT PARAMETERS:
 *
 *	r29 (gp) = Restored user mode global pointer
 *	r30 (sp) = User stack pointer
 * 
 * SIDE EFFECTS:
 *
 *	Registers t0 and t8..t11 are UNPREDICTABLE upon return.
 */ 
        ORG_CALL_PAL_PRIV(0x3D)
CallPal_RetSys:
	ldq	t9, FRM_Q_PC($sp)	// Pop the return address
	ldq	$gp, FRM_Q_GP($sp)	// Get the user mode global pointer
	lda	t8, FRM_K_SIZE($sp)
	mtpr	t8, ptKsp

	mov	PS_K_USER, t8		// Set new mode to user
	mtpr	t8, qemu_ps

	mfpr	$sp, qemu_usp		// Get the user stack pointer

	andnot	t9, 3, t9		// Clean return PC<1:0>
	hw_ret	(t9)
ENDFN	CallPal_RetSys

/*
 * Wait For Interrupt
 *
 * FUNCTIONAL DESCRIPTION:
 *
 *	If possible, wait for the first of either of the following
 *	conditions before returning: any interrupt other than a clock
 *	tick; or the first clock tick after a specified number of clock
 *	ticks have bbeen skipped.
 *
 * INPUT PARAMETERS:
 * 
 *	r16 (a0) = Maximum number of clock ticks to skip
 * 
 * OUTPUT PARAMETERS:
 *
 *	r0 (v0) = Number of clock ticks actually skipped.
 */
	ORG_CALL_PAL_PRIV(0x3E)
CallPal_WtInt:
	mtpr	$31, qemu_wait
	mov	0, v0
	hw_rei
ENDFN	CallPal_WtInt

/*
 * Return From Trap, Fault, or Interrupt
 *
 * INPUT PARAMETERS:
 * 
 *	r30 (sp) = Pointer to the top of the kernel stack
 * 
 * OUTPUT PARAMETERS:
 *
 *	ps       <- (sp+00)
 *	pc       <- (sp+08)
 *	r29 (gp) <- (sp+16)
 *	r16 (a0) <- (sp+24)
 *	r17 (a1) <- (sp+32)
 *	r18 (a2) <- (sp+40)
 */ 
        ORG_CALL_PAL_PRIV(0x3F)
CallPal_Rti:
	mfpr	p6, qemu_exc_addr	// Save exc_addr for machine check

	ldq	p4, FRM_Q_PS($sp)	// Get the PS
	ldq	p5, FRM_Q_PC($sp)	// Get the return PC
	ldq	$gp, FRM_Q_GP($sp)	// Get gp
	ldq	a0, FRM_Q_A0($sp)	// Get a0
	ldq	a1, FRM_Q_A1($sp)	// Get a1
	ldq	a2, FRM_Q_A2($sp)	// Get a2
	lda	$sp, FRM_K_SIZE($sp)	// Pop the stack

	andnot	p5, 3, p5		// Clean return PC<1:0>

	and	p4, PS_M_CM, p3
	bne	p3, CallPal_Rti_ToUser

	and	p4, PS_M_IPL, p4
	mtpr	p4, qemu_ps
	hw_ret	(p5)
ENDFN	CallPal_Rti

	.text	1
CallPal_Rti_ToUser:
	mtpr	p3, qemu_ps
	mtpr	$sp, ptKsp
	mfpr	$sp, qemu_usp
	hw_ret	(p5)
ENDFN	CallPal_Rti_ToUser
	.previous

/*
 * OSF/1 Unprivileged CALL_PAL Entry Points
 */

#define ORG_CALL_PAL_UNPRIV(X)	.org	0x2000+64*(X-0x80)

/*
 * A helper routine for the unprivaledged kernel entry points, since the
 * actual stack frame setup code is just a tad too large to fit inline.
 *
 * INPUT PARAMETERS:
 *
 *	p5 = ps
 *	p6 = exc_addr
 *	p7 = return address
 *
 * SIDE EFFECTS:
 *
 *	p0 is clobbered
 *
 */
	.text	1
CallPal_Stack_Frame:
	// Test if we're currently in user mode
	and	p5, PS_M_CM, p0
	beq	p0, 0f
CallPal_Stack_Frame_FromUser:
	// Switch to kernel mode
	mtpr	$31, qemu_ps
	mtpr	$sp, qemu_usp
	mfpr	$sp, ptKsp
0:
	// Allocate the stack frame
	lda	$sp, -FRM_K_SIZE($sp)
	stq	p5, FRM_Q_PS($sp)
	stq	p6, FRM_Q_PC($sp)
	stq	$gp, FRM_Q_GP($sp)
	stq	a0, FRM_Q_A0($sp)
	stq	a1, FRM_Q_A1($sp)
	stq	a2, FRM_Q_A2($sp)
	ret	$31, (p7), 0
ENDFN	CallPal_Stack_Frame
	.previous

/*
 * Breakpoint Trap
 *
 * OUTPUT PARAMETERS:
 *
 *	r16 (a0) = Code for bpt (0)
 *	r17 (a1) = UNPREDICTABLE
 *	r18 (a2) = UNPREDICTABLE
 */ 
        ORG_CALL_PAL_UNPRIV(0x80)
CallPal_Bpt:
	mfpr	p5, qemu_ps
	mfpr	p6, qemu_exc_addr
	bsr	p7, CallPal_Stack_Frame

	mfpr	p0, ptEntIF
	mfpr	$gp, ptKgp
	mov	IF_K_BPT, a0
	hw_ret	(p0)
ENDFN	CallPal_Bpt

/*
 * Bugcheck Trap
 * 
 * OUTPUT PARAMETERS:
 *
 *	r16 (a0) = Code for bugchk (1)
 *	r17 (a1) = UNPREDICTABLE
 *	r18 (a2) = UNPREDICTABLE
 */ 
        ORG_CALL_PAL_UNPRIV(0x81)
CallPal_BugChk:
	mfpr	p5, qemu_ps
	mfpr	p6, qemu_exc_addr
	bsr	p7, CallPal_Stack_Frame

	mfpr	p0, ptEntIF
	mfpr	$gp, ptKgp
	mov	IF_K_BUGCHK, a0
	hw_ret	(p0)
ENDFN	CallPal_BugChk


	ORG_CALL_PAL_UNPRIV(0x82)
CallPal_OpcDec82:
	br	CallPal_OpcDec
ENDFN	CallPal_OpcDec82

/*
 * System Call
 */ 
        ORG_CALL_PAL_UNPRIV(0x83)
CallPal_CallSys:
	mfpr	p5, qemu_ps
	mfpr	p6, qemu_exc_addr

	and	p5, PS_M_CM, p0
	beq	p0, 0f

	bsr	p7, CallPal_Stack_Frame_FromUser

	mfpr	p0, ptEntSys
	mfpr	$gp, ptKgp
	hw_ret	(p0)

0:	subq	p6, 4, p6		// Get PC of CALL_PAL insn
	br	MchkOSBugCheck
ENDFN	CallPal_CallSys

	ORG_CALL_PAL_UNPRIV(0x84)
CallPal_OpcDec84:
	br	CallPal_OpcDec
ENDFN	CallPal_OpcDec84

	ORG_CALL_PAL_UNPRIV(0x85)
CallPal_OpcDec85:
	br	CallPal_OpcDec
ENDFN	CallPal_OpcDec85


/*
 * I-Stream Memory Barrier
 *
 * For QEMU, this is of course a no-op.
 */ 
        ORG_CALL_PAL_UNPRIV(0x86)
CallPal_Imb:
	hw_rei
ENDFN	CallPal_Imb


	ORG_CALL_PAL_UNPRIV(0x87)
CallPal_OpcDec87:
	br	CallPal_OpcDec
ENDFN	CallPal_OpcDec87

	ORG_CALL_PAL_UNPRIV(0x88)
CallPal_OpcDec88:
	br	CallPal_OpcDec
ENDFN	CallPal_OpcDec88

	ORG_CALL_PAL_UNPRIV(0x89)
CallPal_OpcDec89:
	br	CallPal_OpcDec
ENDFN	CallPal_OpcDec89

	ORG_CALL_PAL_UNPRIV(0x8A)
CallPal_OpcDec8A:
	br	CallPal_OpcDec
ENDFN	CallPal_OpcDec8A

	ORG_CALL_PAL_UNPRIV(0x8B)
CallPal_OpcDec8B:
	br	CallPal_OpcDec
ENDFN	CallPal_OpcDec8B

	ORG_CALL_PAL_UNPRIV(0x8C)
CallPal_OpcDec8C:
	br	CallPal_OpcDec
ENDFN	CallPal_OpcDec8C

	ORG_CALL_PAL_UNPRIV(0x8D)
CallPal_OpcDec8D:
	br	CallPal_OpcDec
ENDFN	CallPal_OpcDec8D

	ORG_CALL_PAL_UNPRIV(0x8E)
CallPal_OpcDec8E:
	br	CallPal_OpcDec
ENDFN	CallPal_OpcDec8E

	ORG_CALL_PAL_UNPRIV(0x8F)
CallPal_OpcDec8F:
	br	CallPal_OpcDec
ENDFN	CallPal_OpcDec8F

	ORG_CALL_PAL_UNPRIV(0x90)
CallPal_OpcDec90:
	br	CallPal_OpcDec
ENDFN	CallPal_OpcDec90

	ORG_CALL_PAL_UNPRIV(0x91)
CallPal_OpcDec91:
	br	CallPal_OpcDec
ENDFN	CallPal_OpcDec91

	ORG_CALL_PAL_UNPRIV(0x92)
CallPal_OpcDec92:
	br	CallPal_OpcDec
ENDFN	CallPal_OpcDec92

	ORG_CALL_PAL_UNPRIV(0x93)
CallPal_OpcDec93:
	br	CallPal_OpcDec
ENDFN	CallPal_OpcDec93

	ORG_CALL_PAL_UNPRIV(0x94)
CallPal_OpcDec94:
	br	CallPal_OpcDec
ENDFN	CallPal_OpcDec94

	ORG_CALL_PAL_UNPRIV(0x95)
CallPal_OpcDec95:
	br	CallPal_OpcDec
ENDFN	CallPal_OpcDec95

	ORG_CALL_PAL_UNPRIV(0x96)
CallPal_OpcDec96:
	br	CallPal_OpcDec
ENDFN	CallPal_OpcDec96

	ORG_CALL_PAL_UNPRIV(0x97)
CallPal_OpcDec97:
	br	CallPal_OpcDec
ENDFN	CallPal_OpcDec97

	ORG_CALL_PAL_UNPRIV(0x98)
CallPal_OpcDec98:
	br	CallPal_OpcDec
ENDFN	CallPal_OpcDec98

	ORG_CALL_PAL_UNPRIV(0x99)
CallPal_OpcDec99:
	br	CallPal_OpcDec
ENDFN	CallPal_OpcDec99

	ORG_CALL_PAL_UNPRIV(0x9A)
CallPal_OpcDec9A:
	br	CallPal_OpcDec
ENDFN	CallPal_OpcDec9A

	ORG_CALL_PAL_UNPRIV(0x9B)
CallPal_OpcDec9B:
	br	CallPal_OpcDec
ENDFN	CallPal_OpcDec9B

	ORG_CALL_PAL_UNPRIV(0x9C)
CallPal_OpcDec9C:
	br	CallPal_OpcDec
ENDFN	CallPal_OpcDec9C

	ORG_CALL_PAL_UNPRIV(0x9D)
CallPal_OpcDec9D:
	br	CallPal_OpcDec
ENDFN	CallPal_OpcDec9D

/*
 * Read Unique Value
 * 
 * OUTPUT PARAMETERS:
 *
 *	r0 (v0) = Returned process unique value
*/ 
        ORG_CALL_PAL_UNPRIV(0x9E)
CallPal_RdUnique:
	mfpr	v0, qemu_unique
	hw_rei
ENDFN	CallPal_RdUnique

/*
 * Write Unique Value
 * 
 * INPUT PARAMETERS:
 * 
 *	r16 (a0) = New process unique value
 */ 
        ORG_CALL_PAL_UNPRIV(0x9F)
CallPal_WrUnique:
	mtpr	a0, qemu_unique
	hw_rei
ENDFN	CallPal_WrUnique

	ORG_CALL_PAL_UNPRIV(0xA0)
CallPal_OpcDecA0:
	br	CallPal_OpcDec
ENDFN	CallPal_OpcDecA0

	ORG_CALL_PAL_UNPRIV(0xA1)
CallPal_OpcDecA1:
	br	CallPal_OpcDec
ENDFN	CallPal_OpcDecA1

	ORG_CALL_PAL_UNPRIV(0xA2)
CallPal_OpcDecA2:
	br	CallPal_OpcDec
ENDFN	CallPal_OpcDecA2

	ORG_CALL_PAL_UNPRIV(0xA3)
CallPal_OpcDecA3:
	br	CallPal_OpcDec
ENDFN	CallPal_OpcDecA3

	ORG_CALL_PAL_UNPRIV(0xA4)
CallPal_OpcDecA4:
	br	CallPal_OpcDec
ENDFN	CallPal_OpcDecA4

	ORG_CALL_PAL_UNPRIV(0xA5)
CallPal_OpcDecA5:
	br	CallPal_OpcDec
ENDFN	CallPal_OpcDecA5

	ORG_CALL_PAL_UNPRIV(0xA6)
CallPal_OpcDecA6:
	br	CallPal_OpcDec
ENDFN	CallPal_OpcDecA6

	ORG_CALL_PAL_UNPRIV(0xA7)
CallPal_OpcDecA7:
	br	CallPal_OpcDec
ENDFN	CallPal_OpcDecA7

	ORG_CALL_PAL_UNPRIV(0xA8)
CallPal_OpcDecA8:
	br	CallPal_OpcDec
ENDFN	CallPal_OpcDecA8

	ORG_CALL_PAL_UNPRIV(0xA9)
CallPal_OpcDecA9:
	br	CallPal_OpcDec
ENDFN	CallPal_OpcDecA9

/*
 * Generate Trap
 *
 * OUTPUT PARAMETERS:
 *
 *	r16 (a0) = Code for gentrap (2)
 *	r17 (a1) = UNPREDICTABLE
 *	r18 (a2) = UNPREDICTABLE
 */ 
        ORG_CALL_PAL_UNPRIV(0xAA)
CallPal_GenTrap:
	mfpr	p5, qemu_ps
	mfpr	p6, qemu_exc_addr
	bsr	p7, CallPal_Stack_Frame

	mfpr	p0, ptEntIF
	mfpr	$gp, ptKgp
	mov	IF_K_GENTRAP, a0
	hw_ret	(p0)
ENDFN	CallPal_GenTrap

	ORG_CALL_PAL_UNPRIV(0xAB)
CallPal_OpcDecAB:
	br	CallPal_OpcDec
ENDFN	CallPal_OpcDecAB

	ORG_CALL_PAL_UNPRIV(0xAC)
CallPal_OpcDecAC:
	br	CallPal_OpcDec
ENDFN	CallPal_OpcDecAC

	ORG_CALL_PAL_UNPRIV(0xAD)
CallPal_OpcDecAD:
	br	CallPal_OpcDec
ENDFN	CallPal_OpcDecAD

	ORG_CALL_PAL_UNPRIV(0xAE)
CallPal_OpcDecAE:
	br	CallPal_OpcDec
ENDFN	CallPal_OpcDecAE

	ORG_CALL_PAL_UNPRIV(0xAF)
CallPal_OpcDecAF:
	br	CallPal_OpcDec
ENDFN	CallPal_OpcDecAF

	ORG_CALL_PAL_UNPRIV(0xB0)
CallPal_OpcDecB0:
	br	CallPal_OpcDec
ENDFN	CallPal_OpcDecB0

	ORG_CALL_PAL_UNPRIV(0xB1)
CallPal_OpcDecB1:
	br	CallPal_OpcDec
ENDFN	CallPal_OpcDecB1

	ORG_CALL_PAL_UNPRIV(0xB2)
CallPal_OpcDecB2:
	br	CallPal_OpcDec
ENDFN	CallPal_OpcDecB2

	ORG_CALL_PAL_UNPRIV(0xB3)
CallPal_OpcDecB3:
	br	CallPal_OpcDec
ENDFN	CallPal_OpcDecB3

	ORG_CALL_PAL_UNPRIV(0xB4)
CallPal_OpcDecB4:
	br	CallPal_OpcDec
ENDFN	CallPal_OpcDecB4

	ORG_CALL_PAL_UNPRIV(0xB5)
CallPal_OpcDecB5:
	br	CallPal_OpcDec
ENDFN	CallPal_OpcDecB5

	ORG_CALL_PAL_UNPRIV(0xB6)
CallPal_OpcDecB6:
	br	CallPal_OpcDec
ENDFN	CallPal_OpcDecB6

	ORG_CALL_PAL_UNPRIV(0xB7)
CallPal_OpcDecB7:
	br	CallPal_OpcDec
ENDFN	CallPal_OpcDecB7

	ORG_CALL_PAL_UNPRIV(0xB8)
CallPal_OpcDecB8:
	br	CallPal_OpcDec
ENDFN	CallPal_OpcDecB8

	ORG_CALL_PAL_UNPRIV(0xB9)
CallPal_OpcDecB9:
	br	CallPal_OpcDec
ENDFN	CallPal_OpcDecB9

	ORG_CALL_PAL_UNPRIV(0xBA)
CallPal_OpcDecBA:
	br	CallPal_OpcDec
ENDFN	CallPal_OpcDecBA

	ORG_CALL_PAL_UNPRIV(0xBB)
CallPal_OpcDecBB:
	br	CallPal_OpcDec
ENDFN	CallPal_OpcDecBB

	ORG_CALL_PAL_UNPRIV(0xBC)
CallPal_OpcDecBC:
	br	CallPal_OpcDec
ENDFN	CallPal_OpcDecBC

	ORG_CALL_PAL_UNPRIV(0xBD)
CallPal_OpcDecBD:
	br	CallPal_OpcDec
ENDFN	CallPal_OpcDecBD

	ORG_CALL_PAL_UNPRIV(0xBE)
CallPal_OpcDecBE:
	br	CallPal_OpcDec
ENDFN	CallPal_OpcDecBE

	ORG_CALL_PAL_UNPRIV(0xBF)
CallPal_OpcDec:
	mfpr	p5, qemu_ps
	mfpr	p6, qemu_exc_addr
	bsr	p7, CallPal_Stack_Frame

	mfpr	p0, ptEntIF
	mfpr	$gp, ptKgp
	mov	IF_K_OPCDEC, a0
	hw_ret	(p0)
ENDFN	CallPal_OpcDec

	.org	0x3000
	.text	1
/*
 * PALcode detected processor machine check handler.
 *
 *      The PALcode-detected machine check handler loads a code
 *      indicating the type of machine check error, loads 
 *      the System Control Block (SCB) vector for the 
 *      processor machine check service routine, sets the 
 *      Machine-Check-In-Progress (MIP) flag in the Machine
 *      Check Error Summary register (MCES), and merges
 *      with the common machine check flow.
 *
 *      If a second processor machine check error condition 
 *      is detected while the MIP flag is set, the processor 
 *      is forced into console I/O mode indicating "double 
 *      error abort encountered" as the reason for the halt. 
 * 
 * CALLING SEQUENCE:
 * 
 *      Called when an internal processor error is detected
 *      that cannot be successfully corrected by hardware or
 *      PALcode.
 * 
 * INPUT PARAMETERS:
 *
 *      r14 (p6) = Exception address 
 * 
 * OUTPUT PARAMETERS:
 *
 *      ptMchk0         = saved v0
 *      ptMchk1         = saved t0
 *      ptMchk2         = saved t3
 *      ptMchk3         = saved t4
 *      ptMchk4         = saved t5
 *	ptMchk5		= saved exc_addr
 *      ptMisc<47:32>   = MCHK code
 *      ptMisc<31:16>   = SCB vector
 *      ptMces<MIP>     = Set
 * 
 * SIDE EFFECTS:
 *
 *      r0 (v0), r1 (t0), and r4..r6 (t3..t5) are saved in
 *      PAL temporaries and are available for use as scratch
 *      registers by the system specific machine check 
 *      handler.
 */

MchkBugCheck:
MchkOSBugCheck:
	halt
ENDFN	MchkBugCheck

/*
 * Common Machine Check Handler
 *
 * INPUT STATE:
 *
 *      ptMchk0		Saved v0
 *      ptMchk1		Saved t0
 *      ptMchk2		Saved t3
 *      ptMchk3		Saved t4
 *      ptMchk4		Saved t5
 *      ptMchk5		Saved exc_addr
 *      ptMisc<47:32>	MCHK code
 *      ptMisc<31:16>	SCB vector
 *      ptMces<MIP>	Set
 *
 * Registers v0, t0, and t3 .. t5 are available for use, in
 * addition to the shadow registers.
 */

MchkCommon:
	halt
ENDFN	MchkCommon

/*
 * Build Machine Check Logout Frame
 *
 *      This portion of the  machine check handler builds a logout frame
 *      in the PAL impure scratch area, builds a stack frame on the kernel
 *      stack (already built if there was an interrupt machine check),
 *      loads the GP with the KGP, loads the machine check entry 
 *      code in a0, loads a platform-specific interrupt vector 
 *      (typically the same value as the SCB offset) in a1, loads 
 *      the kseg address of the logout area in a2, and dispatches 
 *      to the kernel interrupt handler pointed to by the entInt 
 *      operating system entry point.
 *
 * OUTPUT PARAMETERS:
 * 
 *      a0 (r16) = Machine check entry type
 *      a1 (r17) = Platform-specific interrupt vector
 *      a2 (r18) = Pointer to logout area
 */

.macro	STORE_IPR	which, offset, base
	mfpr	v0, \which
	stq_p	v0, \offset(\base)
.endm

MchkLogOut:
	halt
ENDFN	MchkLogOut

MchkDouble:
	bsr	p7, UpdatePCB
	lda	v0, HLT_K_DBL_MCHK
	br	Sys_EnterConsole
ENDFN	MchkDouble

MchkFromPal:
	bsr	p7, UpdatePCB
	lda	v0, HLT_K_MCHK_FROM_PAL
	br	Sys_EnterConsole
ENDFN	MchkFromPal

MchkKspInvalid:
	bsr	p7, UpdatePCB
	lda	v0, HLT_K_KSP_INVAL
	br	Sys_EnterConsole
ENDFN	MchkKspInvalid

/*
 * Update the current PCB with new SP and CC info.
 *
 * INPUT PARAMETERS:
 *
 *	p7	= return linkage
 */

UpdatePCB:
	rpcc	p5
	mfpr	p4, ptPcbb

	mfpr	p3, qemu_ps		// Check current mode
	and	p3, PS_M_CM, p3
	beq	p3, 1f

	mtpr	$sp, qemu_usp		// Save user stack pointer
	stq_p	$sp, PCB_Q_USP(p4)
	br	2f

1:	mtpr	$sp, ptKsp		// Save kernel stack pointer
	stq_p	$sp, PCB_Q_KSP(p4)

2:	srl	p5, 32, p3		// Merge for new time
	addl	p5, p3, p3
	stl_p	p3, PCB_L_PCC(p4)	// Store new time

	mfpr	p5, qemu_unique		// Save unique
	stq_p	p5, PCB_Q_UNIQUE(p4)

	ret	$31, (p7), 0
ENDFN	UpdatePCB

/*
 * FIXME
 */
Sys_EnterConsole:
	halt

/*
 * Allocate the initial bootup stack.
 */

	.section .bss
	.align 3
	.globl	stack
	.type	stack,@object
	.size	stack,STACK_SIZE
stack:	.skip	STACK_SIZE