/* $OpenBSD: lcore_access.S,v 1.10 2007/05/20 14:34:23 miod Exp $ */
/*
* Copyright (c) 2001-2003 Opsycon AB (www.opsycon.se / www.opsycon.com)
*
* 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.
*
* 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/errno.h>
#include <sys/syscall.h>
#include <machine/param.h>
#include <machine/psl.h>
#include <machine/asm.h>
#include <machine/cpu.h>
#include <machine/regnum.h>
#include <machine/cpustate.h>
#include <machine/trap.h>
#include "assym.h"
.set mips3
.set noreorder # Noreorder is default style!
/*
* Primitives
*/
/*
* This table is indexed by u.u_pcb.pcb_onfault in trap().
* The reason for using this table rather than storing an address in
* u.u_pcb.pcb_onfault is simply to make the code faster.
* This table must match with definitions in trap.h.
*/
.globl onfault_table
.data
.align 3
onfault_table:
PTR_VAL 0 # invalid index number
PTR_VAL _copyerr
PTR_VAL _copyerr
#if defined(DDB) || defined(DEBUG)
PTR_VAL kt_ddberr
#else
PTR_VAL 0
#endif
.text
/*
* This code is copied the user's stack for returning from signal handlers
* (see sendsig() and sigreturn()). We have to compute the address
* of the sigcontext struct for the sigreturn call.
*/
.globl sigcode
sigcode:
PTR_ADDU a0, sp, 4*REGSZ # address of sigcontext
LI v0, SYS_sigreturn # sigreturn(scp)
syscall
break 0 # just in case sigreturn fails
.globl esigcode
esigcode:
/* Mips o32 ABI sigcode. 32 bit pointers. */
.globl sigcode_o32
sigcode_o32:
addu a0, sp, 16 # address of sigcontext
li v0, SYS_sigreturn # sigreturn(scp)
syscall
break 0 # just in case sigreturn fails
.globl esigcode_o32
esigcode_o32:
/*
* Copy a null terminated string within the kernel address space.
* Maxlength may be null if count not wanted.
* copystr(fromaddr, toaddr, maxlength, &lencopied)
* caddr_t fromaddr;
* caddr_t toaddr;
* u_int maxlength;
* u_long *lencopied;
*/
LEAF(copystr, 0)
move t2, a2 # Save the number of bytes
1:
lbu t0, 0(a0)
PTR_SUBU a2, a2, 1
beq t0, zero, 2f
sb t0, 0(a1)
PTR_ADDU a0, a0, 1
bne a2, zero, 1b
PTR_ADDU a1, a1, 1
2:
beq a3, zero, 3f
PTR_SUBU a2, t2, a2 # compute length copied
REG_S a2, 0(a3)
3:
j ra
move v0, zero
END(copystr)
#ifndef __LP64__
/*
* Read 64 bits from bus in non LP64 mode.
* XXX ints should be disabled!
*/
LEAF(lp32_read8, 0)
#if defined(__MIPSEB__)
ld v1, 0(a0)
jr ra
dsrl v0, v1, 32
#else
ld v0, 0(a0)
jr ra
dsrl v1, v0, 32
#endif
END(lp32_read8)
/*
* Write 64 bits to bus in non LP64 mode.
* XXX ints should be disabled!
*/
LEAF(lp32_write8, 0)
#if defined(__MIPSEB__)
dsll a2, 32
dsll a3, 32
dsrl a3, 32
or a2, a3
#else
dsll a3, 32
dsll a2, 32
dsrl a2, 32
or a3, a2
#endif
jr ra
sd a2, 0(a0)
END(lp32_write8)
#endif
/*
* fillw(pat, addr, count)
*/
LEAF(fillw, 0)
1:
PTR_ADDU a2, a2, -1
sh a0, 0(a1)
bne a2,zero, 1b
PTR_ADDU a1, a1, 2
jr ra
nop
END(fillw)
/*
* Optimized memory zero code.
* mem_zero_page(addr);
*/
LEAF(mem_zero_page, 0)
LI v0, NBPG
1:
PTR_SUBU v0, 8
sd zero, 0(a0)
bne zero, v0, 1b
PTR_ADDU a0, 8
jr ra
nop
END(mem_zero_page)
/*
* Block I/O routines mainly used by I/O drivers.
*
* Args as: a0 = port
* a1 = memory address
* a2 = count
*/
LEAF(insb, 0)
beq a2, zero, 2f
PTR_ADDU a2, a1
1:
lbu v0, 0(a0)
PTR_ADDU a1, 1
bne a1, a2, 1b
sb v0, -1(a1)
2:
jr ra
nop
END(insb)
LEAF(insw, 0)
beq a2, zero, 2f
PTR_ADDU a2, a2
PTR_ADDU a2, a1
1:
lhu v0, 0(a0)
PTR_ADDU a1, 2
bne a1, a2, 1b
sh v0, -2(a1)
2:
jr ra
nop
END(insw)
LEAF(insl, 0)
beq a2, zero, 2f
PTR_SLL a2, 2
PTR_ADDU a2, a1
1:
lw v0, 0(a0)
PTR_ADDU a1, 4
bne a1, a2, 1b
sw v0, -4(a1)
2:
jr ra
nop
END(insl)
LEAF(outsb, 0)
beq a2, zero, 2f
PTR_ADDU a2, a1
1:
lbu v0, 0(a1)
PTR_ADDU a1, 1
bne a1, a2, 1b
sb v0, 0(a0)
2:
jr ra
nop
END(outsb)
LEAF(outsw, 0)
beq a2, zero, 2f
PTR_ADDU a2, a2
LI v0, 1
and v0, a1
bne v0, zero, 3f # arghh, unaligned.
PTR_ADDU a2, a1
1:
lhu v0, 0(a1)
PTR_ADDU a1, 2
bne a1, a2, 1b
sh v0, 0(a0)
2:
jr ra
nop
3:
LWHI v0, 0(a1)
LWLO v0, 3(a1)
PTR_ADDU a1, 2
bne a1, a2, 3b
sh v0, 0(a0)
jr ra
nop
END(outsw)
LEAF(outsl, 0)
beq a2, zero, 2f
PTR_SLL a2, 2
LI v0, 3
and v0, a1
bne v0, zero, 3f # arghh, unaligned.
PTR_ADDU a2, a1
1:
lw v0, 0(a1)
PTR_ADDU a1, 4
bne a1, a2, 1b
sw v0, 0(a0)
2:
jr ra
nop
3:
LWHI v0, 0(a1)
LWLO v0, 3(a1)
PTR_ADDU a1, 4
bne a1, a2, 3b
sw v0, 0(a0)
jr ra
nop
END(outsl)
/*
* Copy a null terminated string from the user address space into
* the kernel address space.
*
* copyinstr(fromaddr, toaddr, maxlength, &lencopied)
* caddr_t fromaddr;
* caddr_t toaddr;
* u_int maxlength;
* u_int *lencopied;
*/
NON_LEAF(copyinstr, FRAMESZ(CF_SZ), ra)
PTR_SUBU sp, sp, FRAMESZ(CF_SZ)
.mask 0x80000000, (CF_RA_OFFS - FRAMESZ(CF_SZ))
PTR_S ra, CF_RA_OFFS(sp)
blt a0, zero, _copyerr # make sure address is in user space
li v0, KT_COPYERR
PTR_L t3, curprocpaddr
jal copystr
sw v0, PCB_ONFAULT(t3)
PTR_L ra, CF_RA_OFFS(sp)
PTR_L t3, curprocpaddr
sw zero, PCB_ONFAULT(t3)
PTR_ADDU sp, sp, FRAMESZ(CF_SZ)
j ra
move v0, zero
END(copyinstr)
/*
* Copy a null terminated string from the kernel address space into
* the user address space.
*
* copyoutstr(fromaddr, toaddr, maxlength, &lencopied)
* caddr_t fromaddr;
* caddr_t toaddr;
* u_int maxlength;
* u_int *lencopied;
*/
NON_LEAF(copyoutstr, FRAMESZ(CF_SZ), ra)
PTR_SUBU sp, sp, FRAMESZ(CF_SZ)
.mask 0x80000000, (CF_RA_OFFS - FRAMESZ(CF_SZ))
PTR_S ra, CF_RA_OFFS(sp)
blt a1, zero, _copyerr # make sure address is in user space
li v0, KT_COPYERR
PTR_L t3, curprocpaddr
jal copystr
sw v0, PCB_ONFAULT(t3)
PTR_L ra, CF_RA_OFFS(sp)
PTR_L t3, curprocpaddr
sw zero, PCB_ONFAULT(t3)
PTR_ADDU sp, sp, FRAMESZ(CF_SZ)
j ra
move v0, zero
END(copyoutstr)
/*
* Copy specified amount of data from user space into the kernel
* copyin(from, to, len)
* caddr_t *from; (user source address)
* caddr_t *to; (kernel destination address)
* unsigned len;
*/
NON_LEAF(copyin, FRAMESZ(CF_SZ), ra)
PTR_SUBU sp, sp, FRAMESZ(CF_SZ)
.mask 0x80000000, (CF_RA_OFFS - FRAMESZ(CF_SZ))
PTR_S ra, CF_RA_OFFS(sp)
blt a0, zero, _copyerr # make sure address is in user space
li v0, KT_COPYERR
PTR_L t3, curprocpaddr
jal bcopy
sw v0, PCB_ONFAULT(t3)
PTR_L ra, CF_RA_OFFS(sp)
PTR_L t3, curprocpaddr
sw zero, PCB_ONFAULT(t3)
PTR_ADDU sp, sp, FRAMESZ(CF_SZ)
j ra
move v0, zero
END(copyin)
/*
* Copy specified amount of data from kernel to the user space
* copyout(from, to, len)
* caddr_t *from; (kernel source address)
* caddr_t *to; (user destination address)
* unsigned len;
*/
NON_LEAF(copyout, FRAMESZ(CF_SZ), ra)
PTR_SUBU sp, sp, FRAMESZ(CF_SZ)
.mask 0x80000000, (CF_RA_OFFS - FRAMESZ(CF_SZ))
PTR_S ra, CF_RA_OFFS(sp)
blt a1, zero, _copyerr # make sure address is in user space
li v0, KT_COPYERR
PTR_L t3, curprocpaddr
jal bcopy
sw v0, PCB_ONFAULT(t3)
PTR_L ra, CF_RA_OFFS(sp)
PTR_L t3, curprocpaddr
sw zero, PCB_ONFAULT(t3)
PTR_ADDU sp, sp, FRAMESZ(CF_SZ)
j ra
move v0, zero
END(copyout)
_copyerr:
PTR_L ra, CF_RA_OFFS(sp)
PTR_L t3, curprocpaddr
sw zero, PCB_ONFAULT(t3)
PTR_ADDU sp, sp, FRAMESZ(CF_SZ)
j ra
li v0, EFAULT # return error
/*
* kcopy is a wrapper around bcopy that catches bad memory references.
*/
NON_LEAF(kcopy, FRAMESZ(CF_SZ), ra)
PTR_SUBU sp, sp, FRAMESZ(CF_SZ)
.mask 0x80000000, (CF_RA_OFFS - FRAMESZ(CF_SZ))
PTR_S ra, CF_RA_OFFS(sp)
li v0, KT_KCOPYERR
PTR_L t3, curprocpaddr
jal bcopy
sw v0, PCB_ONFAULT(t3)
PTR_L ra, CF_RA_OFFS(sp)
PTR_L t3, curprocpaddr
sw zero, PCB_ONFAULT(t3)
PTR_ADDU sp, sp, FRAMESZ(CF_SZ)
j ra
move v0, zero
END(kcopy)