1/* $OpenBSD: pmon32.S,v 1.5 2018/04/20 14:36:42 visa Exp $ */ 2 3/* 4 * Copyright (c) 2009 Miodrag Vallat. 5 * 6 * Permission to use, copy, modify, and distribute this software for any 7 * purpose with or without fee is hereby granted, provided that the above 8 * copyright notice and this permission notice appear in all copies. 9 * 10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17 */ 18 19/* 20 * Wrapper routines to invoke PMON2000 functions from 64-bit code. 21 * 22 * PMON is compiled either as 32 or 64 bit code. 32 bit code uses the o32 ABI, 23 * while 64 bit code uses the gcc o64 ABI (similar to the o32 ABI, but using 24 * 64 bit registers). 25 * 26 * As a result, only up to four arguments to functions will be passed through 27 * registers. It's up to the caller to never invoke pmon_printf() with more 28 * than four arguments or with a 64 bit argument; other functions are not 29 * affected. 30 */ 31 32#include <machine/param.h> 33#include <machine/asm.h> 34#include <mips64/mips_cpu.h> 35 36#ifndef _STANDALONE 37#include "assym.h" 38#endif 39 40 .set mips3 41 42 .data 43 .globl pmon_callvec 44pmon_callvec: 45 .word 0 46 47pmon_o32: 48 .word 0 49 50 .text 51 52/* 53 * Note that we need to provide a CF_SZ untouched area above sp, or we'll risk 54 * our stack being corrupted upon return. 55 */ 56#define PMON_WRAP(name, index) \ 57 NNON_LEAF(name, FRAMESZ(CF_SZ + 9 * REGSZ), ra); \ 58 PTR_SUBU sp, sp, FRAMESZ(CF_SZ + 9 * REGSZ); \ 59 REG_S ra, CF_RA_OFFS(sp); \ 60 .mask 0xc0ff0000, (CF_RA_OFFS - FRAMESZ(CF_SZ + 9 * REGSZ)); \ 61 REG_S s0, (0 * REGSZ + CF_SZ)(sp); \ 62 REG_S s1, (1 * REGSZ + CF_SZ)(sp); \ 63 REG_S s2, (2 * REGSZ + CF_SZ)(sp); \ 64 REG_S s3, (3 * REGSZ + CF_SZ)(sp); \ 65 REG_S s4, (4 * REGSZ + CF_SZ)(sp); \ 66 REG_S s5, (5 * REGSZ + CF_SZ)(sp); \ 67 REG_S s6, (6 * REGSZ + CF_SZ)(sp); \ 68 REG_S s7, (7 * REGSZ + CF_SZ)(sp); \ 69 REG_S s8, (8 * REGSZ + CF_SZ)(sp); \ 70 lw t0, pmon_callvec; \ 71 lw t0, (index) * 4 (t0); \ 72 jalr t0; \ 73 nop; \ 74 REG_L s8, (8 * REGSZ + CF_SZ)(sp); \ 75 REG_L s7, (7 * REGSZ + CF_SZ)(sp); \ 76 REG_L s6, (6 * REGSZ + CF_SZ)(sp); \ 77 REG_L s5, (5 * REGSZ + CF_SZ)(sp); \ 78 REG_L s4, (4 * REGSZ + CF_SZ)(sp); \ 79 REG_L s3, (3 * REGSZ + CF_SZ)(sp); \ 80 REG_L s2, (2 * REGSZ + CF_SZ)(sp); \ 81 REG_L s1, (1 * REGSZ + CF_SZ)(sp); \ 82 REG_L s0, (0 * REGSZ + CF_SZ)(sp); \ 83 REG_L ra, CF_RA_OFFS(sp); \ 84 PTR_ADDU sp, sp, FRAMESZ(CF_SZ + 9 * REGSZ); \ 85 jr ra; \ 86 nop; \ 87 END(name) 88 89PMON_WRAP(pmon_printf, 5) 90PMON_WRAP(pmon_gets, 7) 91#ifdef _STANDALONE 92PMON_WRAP(pmon_open, 0) 93PMON_WRAP(pmon_close, 1) 94PMON_WRAP(pmon_read, 2) 95PMON_WRAP(pmon_cacheflush, 6) 96#endif 97#if 0 /* unused */ 98PMON_WRAP(pmon_write, 3) 99#endif 100 101/* 102 * pmon_lseek() is defined separately to work around the 64-bit code's 103 * incompatibility with the o32 ABI. 104 */ 105NNON_LEAF(pmon_lseek, FRAMESZ(CF_SZ + 9 * REGSZ), ra) 106 PTR_SUBU sp, sp, FRAMESZ(CF_SZ + 9 * REGSZ) 107 REG_S ra, CF_RA_OFFS(sp) 108 .mask 0xc0ff0000, (CF_RA_OFFS - FRAMESZ(CF_SZ + 9 * REGSZ)) 109 REG_S s0, (0 * REGSZ + CF_SZ)(sp) 110 REG_S s1, (1 * REGSZ + CF_SZ)(sp) 111 REG_S s2, (2 * REGSZ + CF_SZ)(sp) 112 REG_S s3, (3 * REGSZ + CF_SZ)(sp) 113 REG_S s4, (4 * REGSZ + CF_SZ)(sp) 114 REG_S s5, (5 * REGSZ + CF_SZ)(sp) 115 REG_S s6, (6 * REGSZ + CF_SZ)(sp) 116 REG_S s7, (7 * REGSZ + CF_SZ)(sp) 117 REG_S s8, (8 * REGSZ + CF_SZ)(sp) 118 lw t0, pmon_callvec 119 lw t0, 4 * 4 (t0) 120 lw t1, pmon_o32 121 bne t1, zero, 1f 122 nop 123 /* gcc o64 ABI call. */ 124 jalr t0 125 nop 126 b 2f 127 nop 1281: 129 /* o32 ABI call. The parameters have to be rearranged. */ 130 sw a2, 4 * 4 (sp) 131 sll a2, a1, 0 # get the low 32 bits 132 dsrl a3, a1, 32 # get the high 32 bits 133 jalr t0 134 nop 135 /* Rearrange the return value. */ 136 dsll v0, v0, 32 # clear any sign extension 137 dsrl v0, v0, 32 138 dsll v1, v1, 32 139 or v0, v0, v1 1402: 141 REG_L s8, (8 * REGSZ + CF_SZ)(sp) 142 REG_L s7, (7 * REGSZ + CF_SZ)(sp) 143 REG_L s6, (6 * REGSZ + CF_SZ)(sp) 144 REG_L s5, (5 * REGSZ + CF_SZ)(sp) 145 REG_L s4, (4 * REGSZ + CF_SZ)(sp) 146 REG_L s3, (3 * REGSZ + CF_SZ)(sp) 147 REG_L s2, (2 * REGSZ + CF_SZ)(sp) 148 REG_L s1, (1 * REGSZ + CF_SZ)(sp) 149 REG_L s0, (0 * REGSZ + CF_SZ)(sp) 150 REG_L ra, CF_RA_OFFS(sp) 151 PTR_ADDU sp, sp, FRAMESZ(CF_SZ + 9 * REGSZ) 152 jr ra 153 nop 154END(pmon_lseek) 155 156/* 157 * Probe if PMON is compiled to use the o32 ABI. 158 */ 159NNON_LEAF(pmon_probe_abi, FRAMESZ(CF_SZ + 9 * REGSZ), ra) 160 PTR_SUBU sp, sp, FRAMESZ(CF_SZ + 9 * REGSZ) 161 REG_S ra, CF_RA_OFFS(sp) 162 .mask 0xc0ff0000, (CF_RA_OFFS - FRAMESZ(CF_SZ + 9 * REGSZ)) 163 REG_S s0, (0 * REGSZ + CF_SZ)(sp) 164 REG_S s1, (1 * REGSZ + CF_SZ)(sp) 165 REG_S s2, (2 * REGSZ + CF_SZ)(sp) 166 REG_S s3, (3 * REGSZ + CF_SZ)(sp) 167 REG_S s4, (4 * REGSZ + CF_SZ)(sp) 168 REG_S s5, (5 * REGSZ + CF_SZ)(sp) 169 REG_S s6, (6 * REGSZ + CF_SZ)(sp) 170 REG_S s7, (7 * REGSZ + CF_SZ)(sp) 171 REG_S s8, (8 * REGSZ + CF_SZ)(sp) 172 /* Skip probing on pre-LS3A machines. They are not affected. */ 173 mfc0 t0, COP_0_PRID 174 and t1, t0, 0xff00 175 li t2, 0x6300 176 bne t1, t2, 1f 177 and t1, t0, 0x00ff 178 li t2, 0x0005 179 blt t1, t2, 1f 180 nop 181 /* 182 * Call lseek() with an invalid fd. The call should fail with return 183 * value -1. The value is in register pair v1:v0 if the o32 ABI is 184 * in use, while the gcc o64 ABI uses register v0 only. 185 * 186 * Zero v0 and v1, and if both contain value -1 when the call returns, 187 * assume that PMON uses the o32 ABI. This relies on the fact that 188 * the firmware detects the invalid fd and returns before value -1 189 * could accidentally be assigned to both registers. 190 */ 191 li a0, 0x10000 192 move a1, zero 193 move a2, zero 194 move a3, zero 195 sw zero, 4 * 4 (sp) 196 move v0, zero 197 move v1, zero 198 lw t0, pmon_callvec 199 lw t0, 4 * 4 (t0) 200 jalr t0 201 nop 202 /* Check the return value. */ 203 li t0, -1 204 bne v0, t0, 1f 205 nop 206 bne v1, t0, 1f 207 li t1, 1 208 sw t1, pmon_o32 2091: 210 REG_L s8, (8 * REGSZ + CF_SZ)(sp) 211 REG_L s7, (7 * REGSZ + CF_SZ)(sp) 212 REG_L s6, (6 * REGSZ + CF_SZ)(sp) 213 REG_L s5, (5 * REGSZ + CF_SZ)(sp) 214 REG_L s4, (4 * REGSZ + CF_SZ)(sp) 215 REG_L s3, (3 * REGSZ + CF_SZ)(sp) 216 REG_L s2, (2 * REGSZ + CF_SZ)(sp) 217 REG_L s1, (1 * REGSZ + CF_SZ)(sp) 218 REG_L s0, (0 * REGSZ + CF_SZ)(sp) 219 REG_L ra, CF_RA_OFFS(sp) 220 PTR_ADDU sp, sp, FRAMESZ(CF_SZ + 9 * REGSZ) 221 jr ra 222 nop 223END(pmon_probe_abi) 224