summaryrefslogtreecommitdiff
path: root/sys/arch/loongson
diff options
context:
space:
mode:
authorVisa Hankala <visa@cvs.openbsd.org>2018-04-20 14:36:43 +0000
committerVisa Hankala <visa@cvs.openbsd.org>2018-04-20 14:36:43 +0000
commitec7677f0c1cf4c5c826b0fbbf535d65a596a17ea (patch)
tree3fe0691167fd70b85218cca480d881c4004e4286 /sys/arch/loongson
parent4bce035997bab2457b9b27c13cea881f72f45a2b (diff)
Add a workaround that lets loongson bootblocks work with PMON that
uses the O32 calling convention. Such firmware comes at least on some Loongson 3A development boards. This differs from the LS2F-based machines made by Lemote whose PMON uses the GCC O64 calling convention.
Diffstat (limited to 'sys/arch/loongson')
-rw-r--r--sys/arch/loongson/loongson/pmon32.S139
-rw-r--r--sys/arch/loongson/stand/boot/start.S4
2 files changed, 137 insertions, 6 deletions
diff --git a/sys/arch/loongson/loongson/pmon32.S b/sys/arch/loongson/loongson/pmon32.S
index 7c961a8ac2c..a58d407578a 100644
--- a/sys/arch/loongson/loongson/pmon32.S
+++ b/sys/arch/loongson/loongson/pmon32.S
@@ -1,4 +1,4 @@
-/* $OpenBSD: pmon32.S,v 1.4 2010/02/18 18:53:33 miod Exp $ */
+/* $OpenBSD: pmon32.S,v 1.5 2018/04/20 14:36:42 visa Exp $ */
/*
* Copyright (c) 2009 Miodrag Vallat.
@@ -19,16 +19,19 @@
/*
* Wrapper routines to invoke PMON2000 functions from 64-bit code.
*
- * PMON is compiled as 64 bit code, using the gcc o64 ABI (similar to the o32
- * ABI, but using 64 bit registers).
+ * PMON is compiled either as 32 or 64 bit code. 32 bit code uses the o32 ABI,
+ * while 64 bit code uses the gcc o64 ABI (similar to the o32 ABI, but using
+ * 64 bit registers).
*
* As a result, only up to four arguments to functions will be passed through
* registers. It's up to the caller to never invoke pmon_printf() with more
- * than four arguments; other functions are not affected.
+ * than four arguments or with a 64 bit argument; other functions are not
+ * affected.
*/
#include <machine/param.h>
#include <machine/asm.h>
+#include <mips64/mips_cpu.h>
#ifndef _STANDALONE
#include "assym.h"
@@ -41,6 +44,9 @@
pmon_callvec:
.word 0
+pmon_o32:
+ .word 0
+
.text
/*
@@ -86,9 +92,132 @@ PMON_WRAP(pmon_gets, 7)
PMON_WRAP(pmon_open, 0)
PMON_WRAP(pmon_close, 1)
PMON_WRAP(pmon_read, 2)
-PMON_WRAP(pmon_lseek, 4)
PMON_WRAP(pmon_cacheflush, 6)
#endif
#if 0 /* unused */
PMON_WRAP(pmon_write, 3)
#endif
+
+/*
+ * pmon_lseek() is defined separately to work around the 64-bit code's
+ * incompatibility with the o32 ABI.
+ */
+NNON_LEAF(pmon_lseek, FRAMESZ(CF_SZ + 9 * REGSZ), ra)
+ PTR_SUBU sp, sp, FRAMESZ(CF_SZ + 9 * REGSZ)
+ REG_S ra, CF_RA_OFFS(sp)
+ .mask 0xc0ff0000, (CF_RA_OFFS - FRAMESZ(CF_SZ + 9 * REGSZ))
+ REG_S s0, (0 * REGSZ + CF_SZ)(sp)
+ REG_S s1, (1 * REGSZ + CF_SZ)(sp)
+ REG_S s2, (2 * REGSZ + CF_SZ)(sp)
+ REG_S s3, (3 * REGSZ + CF_SZ)(sp)
+ REG_S s4, (4 * REGSZ + CF_SZ)(sp)
+ REG_S s5, (5 * REGSZ + CF_SZ)(sp)
+ REG_S s6, (6 * REGSZ + CF_SZ)(sp)
+ REG_S s7, (7 * REGSZ + CF_SZ)(sp)
+ REG_S s8, (8 * REGSZ + CF_SZ)(sp)
+ lw t0, pmon_callvec
+ lw t0, 4 * 4 (t0)
+ lw t1, pmon_o32
+ bne t1, zero, 1f
+ nop
+ /* gcc o64 ABI call. */
+ jalr t0
+ nop
+ b 2f
+ nop
+1:
+ /* o32 ABI call. The parameters have to be rearranged. */
+ sw a2, 4 * 4 (sp)
+ sll a2, a1, 0 # get the low 32 bits
+ dsrl a3, a1, 32 # get the high 32 bits
+ jalr t0
+ nop
+ /* Rearrange the return value. */
+ dsll v0, v0, 32 # clear any sign extension
+ dsrl v0, v0, 32
+ dsll v1, v1, 32
+ or v0, v0, v1
+2:
+ REG_L s8, (8 * REGSZ + CF_SZ)(sp)
+ REG_L s7, (7 * REGSZ + CF_SZ)(sp)
+ REG_L s6, (6 * REGSZ + CF_SZ)(sp)
+ REG_L s5, (5 * REGSZ + CF_SZ)(sp)
+ REG_L s4, (4 * REGSZ + CF_SZ)(sp)
+ REG_L s3, (3 * REGSZ + CF_SZ)(sp)
+ REG_L s2, (2 * REGSZ + CF_SZ)(sp)
+ REG_L s1, (1 * REGSZ + CF_SZ)(sp)
+ REG_L s0, (0 * REGSZ + CF_SZ)(sp)
+ REG_L ra, CF_RA_OFFS(sp)
+ PTR_ADDU sp, sp, FRAMESZ(CF_SZ + 9 * REGSZ)
+ jr ra
+ nop
+END(pmon_lseek)
+
+/*
+ * Probe if PMON is compiled to use the o32 ABI.
+ */
+NNON_LEAF(pmon_probe_abi, FRAMESZ(CF_SZ + 9 * REGSZ), ra)
+ PTR_SUBU sp, sp, FRAMESZ(CF_SZ + 9 * REGSZ)
+ REG_S ra, CF_RA_OFFS(sp)
+ .mask 0xc0ff0000, (CF_RA_OFFS - FRAMESZ(CF_SZ + 9 * REGSZ))
+ REG_S s0, (0 * REGSZ + CF_SZ)(sp)
+ REG_S s1, (1 * REGSZ + CF_SZ)(sp)
+ REG_S s2, (2 * REGSZ + CF_SZ)(sp)
+ REG_S s3, (3 * REGSZ + CF_SZ)(sp)
+ REG_S s4, (4 * REGSZ + CF_SZ)(sp)
+ REG_S s5, (5 * REGSZ + CF_SZ)(sp)
+ REG_S s6, (6 * REGSZ + CF_SZ)(sp)
+ REG_S s7, (7 * REGSZ + CF_SZ)(sp)
+ REG_S s8, (8 * REGSZ + CF_SZ)(sp)
+ /* Skip probing on pre-LS3A machines. They are not affected. */
+ mfc0 t0, COP_0_PRID
+ and t1, t0, 0xff00
+ li t2, 0x6300
+ bne t1, t2, 1f
+ and t1, t0, 0x00ff
+ li t2, 0x0005
+ blt t1, t2, 1f
+ nop
+ /*
+ * Call lseek() with an invalid fd. The call should fail with return
+ * value -1. The value is in register pair v1:v0 if the o32 ABI is
+ * in use, while the gcc o64 ABI uses register v0 only.
+ *
+ * Zero v0 and v1, and if both contain value -1 when the call returns,
+ * assume that PMON uses the o32 ABI. This relies on the fact that
+ * the firmware detects the invalid fd and returns before value -1
+ * could accidentally be assigned to both registers.
+ */
+ li a0, 0x10000
+ move a1, zero
+ move a2, zero
+ move a3, zero
+ sw zero, 4 * 4 (sp)
+ move v0, zero
+ move v1, zero
+ lw t0, pmon_callvec
+ lw t0, 4 * 4 (t0)
+ jalr t0
+ nop
+ /* Check the return value. */
+ li t0, -1
+ bne v0, t0, 1f
+ nop
+ bne v1, t0, 1f
+ li t1, 1
+ sw t1, pmon_o32
+1:
+ REG_L s8, (8 * REGSZ + CF_SZ)(sp)
+ REG_L s7, (7 * REGSZ + CF_SZ)(sp)
+ REG_L s6, (6 * REGSZ + CF_SZ)(sp)
+ REG_L s5, (5 * REGSZ + CF_SZ)(sp)
+ REG_L s4, (4 * REGSZ + CF_SZ)(sp)
+ REG_L s3, (3 * REGSZ + CF_SZ)(sp)
+ REG_L s2, (2 * REGSZ + CF_SZ)(sp)
+ REG_L s1, (1 * REGSZ + CF_SZ)(sp)
+ REG_L s0, (0 * REGSZ + CF_SZ)(sp)
+ REG_L ra, CF_RA_OFFS(sp)
+ PTR_ADDU sp, sp, FRAMESZ(CF_SZ + 9 * REGSZ)
+ jr ra
+ nop
+END(pmon_probe_abi)
diff --git a/sys/arch/loongson/stand/boot/start.S b/sys/arch/loongson/stand/boot/start.S
index 33a0273d8bb..4fd44b6ebb5 100644
--- a/sys/arch/loongson/stand/boot/start.S
+++ b/sys/arch/loongson/stand/boot/start.S
@@ -1,4 +1,4 @@
-/* $OpenBSD: start.S,v 1.2 2016/10/09 03:07:25 visa Exp $ */
+/* $OpenBSD: start.S,v 1.3 2018/04/20 14:36:42 visa Exp $ */
/*
* Copyright (c) 2010 Miodrag Vallat.
@@ -41,6 +41,8 @@ __start:
move sp, t0
jal pmon_init # pmon_init(argc, argv, envp, callvec,
mfc0 a4, COP_0_PRID # prid)
+ jal pmon_probe_abi
+ nop
jal main
nop
/* FALLTHROUGH */