Index: head/sys/riscv/include/intr.h =================================================================== --- head/sys/riscv/include/intr.h (revision 298635) +++ head/sys/riscv/include/intr.h (revision 298636) @@ -1,66 +1,68 @@ /*- * Copyright (c) 2015-2016 Ruslan Bukin * All rights reserved. * * Portions of this software were developed by SRI International and the * University of Cambridge Computer Laboratory under DARPA/AFRL contract * FA8750-10-C-0237 ("CTSRD"), as part of the DARPA CRASH research programme. * * Portions of this software were developed by the University of Cambridge * Computer Laboratory as part of the CTSRD Project, with support from the * UK Higher Education Innovation Fund (HEIF). * * 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 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 AUTHOR 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. * * $FreeBSD$ */ #ifndef _MACHINE_INTR_MACHDEP_H_ #define _MACHINE_INTR_MACHDEP_H_ struct trapframe; void riscv_init_interrupts(void); int riscv_teardown_intr(void *); int riscv_config_intr(u_int, enum intr_trigger, enum intr_polarity); int riscv_setup_intr(const char *, driver_filter_t *, driver_intr_t *, void *, int, int, void **); void riscv_cpu_intr(struct trapframe *); typedef unsigned long * riscv_intrcnt_t; riscv_intrcnt_t riscv_intrcnt_create(const char *); void riscv_intrcnt_setname(riscv_intrcnt_t, const char *); #ifdef SMP void riscv_setup_ipihandler(driver_filter_t *); void riscv_unmask_ipi(void); #endif enum { IRQ_SOFTWARE, IRQ_TIMER, IRQ_HTIF, + IRQ_COP, /* lowRISC only */ + IRQ_UART, /* lowRISC only */ NIRQS }; #endif /* !_MACHINE_INTR_MACHDEP_H_ */ Index: head/sys/riscv/include/riscvreg.h =================================================================== --- head/sys/riscv/include/riscvreg.h (revision 298635) +++ head/sys/riscv/include/riscvreg.h (revision 298636) @@ -1,165 +1,167 @@ /*- * Copyright (c) 2015-2016 Ruslan Bukin * All rights reserved. * * Portions of this software were developed by SRI International and the * University of Cambridge Computer Laboratory under DARPA/AFRL contract * FA8750-10-C-0237 ("CTSRD"), as part of the DARPA CRASH research programme. * * Portions of this software were developed by the University of Cambridge * Computer Laboratory as part of the CTSRD Project, with support from the * UK Higher Education Innovation Fund (HEIF). * * 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 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 AUTHOR 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. * * $FreeBSD$ */ #ifndef _MACHINE_RISCVREG_H_ #define _MACHINE_RISCVREG_H_ /* Machine mode requests */ #define ECALL_MTIMECMP 0x01 #define ECALL_CLEAR_PENDING 0x02 #define ECALL_HTIF_CMD 0x03 #define ECALL_HTIF_GET_ENTRY 0x04 #define ECALL_MCPUID_GET 0x05 #define ECALL_MIMPID_GET 0x06 #define ECALL_SEND_IPI 0x07 #define ECALL_CLEAR_IPI 0x08 #define ECALL_HTIF_LOWPUTC 0x09 -#define ECALL_MIE_SET 0x10 +#define ECALL_MIE_SET 0x0a +#define ECALL_IO_IRQ_MASK 0x0b #define EXCP_SHIFT 0 #define EXCP_MASK (0xf << EXCP_SHIFT) #define EXCP_INSTR_ADDR_MISALIGNED 0 #define EXCP_INSTR_ACCESS_FAULT 1 #define EXCP_INSTR_ILLEGAL 2 #define EXCP_INSTR_BREAKPOINT 3 #define EXCP_LOAD_ADDR_MISALIGNED 4 #define EXCP_LOAD_ACCESS_FAULT 5 #define EXCP_STORE_ADDR_MISALIGNED 6 #define EXCP_STORE_ACCESS_FAULT 7 #define EXCP_UMODE_ENV_CALL 8 #define EXCP_SMODE_ENV_CALL 9 #define EXCP_HMODE_ENV_CALL 10 #define EXCP_MMODE_ENV_CALL 11 #define EXCP_INTR (1 << 31) #define EXCP_INTR_SOFTWARE 0 #define EXCP_INTR_TIMER 1 #define EXCP_INTR_HTIF 2 #define SSTATUS_IE (1 << 0) #define SSTATUS_PIE (1 << 3) #define SSTATUS_PS (1 << 4) #define MSTATUS_MPRV (1 << 16) #define MSTATUS_PRV_SHIFT 1 #define MSTATUS_PRV1_SHIFT 4 #define MSTATUS_PRV2_SHIFT 7 #define MSTATUS_PRV_MASK (0x3 << MSTATUS_PRV_SHIFT) #define MSTATUS_PRV_U 0 /* user */ #define MSTATUS_PRV_S 1 /* supervisor */ #define MSTATUS_PRV_H 2 /* hypervisor */ #define MSTATUS_PRV_M 3 /* machine */ #define MSTATUS_VM_SHIFT 17 #define MSTATUS_VM_MASK 0x1f #define MSTATUS_VM_MBARE 0 #define MSTATUS_VM_MBB 1 #define MSTATUS_VM_MBBID 2 #define MSTATUS_VM_SV32 8 #define MSTATUS_VM_SV39 9 #define MSTATUS_VM_SV48 10 #define MIE_SSIE (1 << 1) #define MIE_HSIE (1 << 2) #define MIE_MSIE (1 << 3) #define MIE_STIE (1 << 5) #define MIE_HTIE (1 << 6) #define MIE_MTIE (1 << 7) #define MIP_SSIP (1 << 1) #define MIP_HSIP (1 << 2) #define MIP_MSIP (1 << 3) #define MIP_STIP (1 << 5) #define MIP_HTIP (1 << 6) #define MIP_MTIP (1 << 7) #define SR_IE (1 << 0) #define SR_IE1 (1 << 3) #define SR_IE2 (1 << 6) #define SR_IE3 (1 << 9) #define SIE_SSIE (1 << 1) #define SIE_STIE (1 << 5) /* Note: sip register has no SIP_STIP bit in Spike simulator */ #define SIP_SSIP (1 << 1) #define SIP_STIP (1 << 5) #define NCSRS 4096 #define CSR_IPI 0x783 +#define CSR_IO_IRQ 0x7c0 /* lowRISC only? */ #define XLEN 8 #define INSN_SIZE 4 #define CSR_ZIMM(val) \ (__builtin_constant_p(val) && ((u_long)(val) < 32)) #define csr_swap(csr, val) \ ({ if (CSR_ZIMM(val)) \ __asm __volatile("csrrwi %0, " #csr ", %1" \ : "=r" (val) : "i" (val)); \ else \ __asm __volatile("csrrw %0, " #csr ", %1" \ : "=r" (val) : "r" (val)); \ val; \ }) #define csr_write(csr, val) \ ({ if (CSR_ZIMM(val)) \ __asm __volatile("csrwi " #csr ", %0" :: "i" (val)); \ else \ __asm __volatile("csrw " #csr ", %0" :: "r" (val)); \ }) #define csr_set(csr, val) \ ({ if (CSR_ZIMM(val)) \ __asm __volatile("csrsi " #csr ", %0" :: "i" (val)); \ else \ __asm __volatile("csrs " #csr ", %0" :: "r" (val)); \ }) #define csr_clear(csr, val) \ ({ if (CSR_ZIMM(val)) \ __asm __volatile("csrci " #csr ", %0" :: "i" (val)); \ else \ __asm __volatile("csrc " #csr ", %0" :: "r" (val)); \ }) #define csr_read(csr) \ ({ u_long val; \ __asm __volatile("csrr %0, " #csr : "=r" (val)); \ val; \ }) #endif /* !_MACHINE_RISCVREG_H_ */ Index: head/sys/riscv/riscv/exception.S =================================================================== --- head/sys/riscv/riscv/exception.S (revision 298635) +++ head/sys/riscv/riscv/exception.S (revision 298636) @@ -1,594 +1,609 @@ /*- * Copyright (c) 2015-2016 Ruslan Bukin * All rights reserved. * * Portions of this software were developed by SRI International and the * University of Cambridge Computer Laboratory under DARPA/AFRL contract * FA8750-10-C-0237 ("CTSRD"), as part of the DARPA CRASH research programme. * * Portions of this software were developed by the University of Cambridge * Computer Laboratory as part of the CTSRD Project, with support from the * UK Higher Education Innovation Fund (HEIF). * * 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 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 AUTHOR 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. */ #include __FBSDID("$FreeBSD$"); #include "assym.s" #include #include .macro save_registers el addi sp, sp, -(TF_SIZE) sd ra, (TF_RA)(sp) sd tp, (TF_TP)(sp) .if \el == 0 /* We came from userspace. Load our pcpu */ sd gp, (TF_GP)(sp) ld gp, (TF_SIZE)(sp) .endif sd t0, (TF_T + 0 * 8)(sp) sd t1, (TF_T + 1 * 8)(sp) sd t2, (TF_T + 2 * 8)(sp) sd t3, (TF_T + 3 * 8)(sp) sd t4, (TF_T + 4 * 8)(sp) sd t5, (TF_T + 5 * 8)(sp) sd t6, (TF_T + 6 * 8)(sp) sd s0, (TF_S + 0 * 8)(sp) sd s1, (TF_S + 1 * 8)(sp) sd s2, (TF_S + 2 * 8)(sp) sd s3, (TF_S + 3 * 8)(sp) sd s4, (TF_S + 4 * 8)(sp) sd s5, (TF_S + 5 * 8)(sp) sd s6, (TF_S + 6 * 8)(sp) sd s7, (TF_S + 7 * 8)(sp) sd s8, (TF_S + 8 * 8)(sp) sd s9, (TF_S + 9 * 8)(sp) sd s10, (TF_S + 10 * 8)(sp) sd s11, (TF_S + 11 * 8)(sp) sd a0, (TF_A + 0 * 8)(sp) sd a1, (TF_A + 1 * 8)(sp) sd a2, (TF_A + 2 * 8)(sp) sd a3, (TF_A + 3 * 8)(sp) sd a4, (TF_A + 4 * 8)(sp) sd a5, (TF_A + 5 * 8)(sp) sd a6, (TF_A + 6 * 8)(sp) sd a7, (TF_A + 7 * 8)(sp) #if 0 /* XXX: temporary test: spin if stack is not kernel one */ .if \el == 1 /* kernel */ mv t0, sp srli t0, t0, 63 1: beqz t0, 1b .endif #endif .if \el == 1 /* Store kernel sp */ sd sp, (TF_SP)(sp) .else /* Store user sp */ csrr t0, sscratch sd t0, (TF_SP)(sp) .endif li t0, 0 csrw sscratch, t0 csrr t0, sepc sd t0, (TF_SEPC)(sp) csrr t0, sstatus sd t0, (TF_SSTATUS)(sp) csrr t0, sbadaddr sd t0, (TF_SBADADDR)(sp) csrr t0, scause sd t0, (TF_SCAUSE)(sp) .endm .macro load_registers el ld t0, (TF_SSTATUS)(sp) .if \el == 0 /* Ensure user interrupts will be enabled on eret. */ ori t0, t0, SSTATUS_PIE .else /* * Disable interrupts for supervisor mode exceptions. * For user mode exceptions we have already done this * in do_ast. */ li t1, ~SSTATUS_IE and t0, t0, t1 .endif csrw sstatus, t0 ld t0, (TF_SEPC)(sp) csrw sepc, t0 .if \el == 0 /* We go to userspace. Load user sp */ ld t0, (TF_SP)(sp) csrw sscratch, t0 /* And store our pcpu */ sd gp, (TF_SIZE)(sp) ld gp, (TF_GP)(sp) .endif ld ra, (TF_RA)(sp) ld tp, (TF_TP)(sp) ld t0, (TF_T + 0 * 8)(sp) ld t1, (TF_T + 1 * 8)(sp) ld t2, (TF_T + 2 * 8)(sp) ld t3, (TF_T + 3 * 8)(sp) ld t4, (TF_T + 4 * 8)(sp) ld t5, (TF_T + 5 * 8)(sp) ld t6, (TF_T + 6 * 8)(sp) ld s0, (TF_S + 0 * 8)(sp) ld s1, (TF_S + 1 * 8)(sp) ld s2, (TF_S + 2 * 8)(sp) ld s3, (TF_S + 3 * 8)(sp) ld s4, (TF_S + 4 * 8)(sp) ld s5, (TF_S + 5 * 8)(sp) ld s6, (TF_S + 6 * 8)(sp) ld s7, (TF_S + 7 * 8)(sp) ld s8, (TF_S + 8 * 8)(sp) ld s9, (TF_S + 9 * 8)(sp) ld s10, (TF_S + 10 * 8)(sp) ld s11, (TF_S + 11 * 8)(sp) ld a0, (TF_A + 0 * 8)(sp) ld a1, (TF_A + 1 * 8)(sp) ld a2, (TF_A + 2 * 8)(sp) ld a3, (TF_A + 3 * 8)(sp) ld a4, (TF_A + 4 * 8)(sp) ld a5, (TF_A + 5 * 8)(sp) ld a6, (TF_A + 6 * 8)(sp) ld a7, (TF_A + 7 * 8)(sp) addi sp, sp, (TF_SIZE) .endm .macro do_ast /* Disable interrupts */ csrr a4, sstatus 1: csrci sstatus, SSTATUS_IE ld a1, PC_CURTHREAD(gp) lw a2, TD_FLAGS(a1) li a3, (TDF_ASTPENDING|TDF_NEEDRESCHED) and a2, a2, a3 beqz a2, 2f /* Restore interrupts */ andi a4, a4, SSTATUS_IE csrs sstatus, a4 /* Handle the ast */ mv a0, sp call _C_LABEL(ast) /* Re-check for new ast scheduled */ j 1b 2: .endm ENTRY(cpu_exception_handler_supervisor) save_registers 1 mv a0, sp call _C_LABEL(do_trap_supervisor) load_registers 1 eret END(cpu_exception_handler_supervisor) ENTRY(cpu_exception_handler_user) csrrw sp, sscratch, sp save_registers 0 mv a0, sp call _C_LABEL(do_trap_user) do_ast load_registers 0 csrrw sp, sscratch, sp eret END(cpu_exception_handler_user) /* * Trap handlers */ .text bad_trap: j bad_trap user_trap: /* Save state */ csrrw sp, mscratch, sp addi sp, sp, -64 sd t0, (8 * 0)(sp) sd t1, (8 * 1)(sp) sd t2, (8 * 2)(sp) sd t3, (8 * 3)(sp) sd t4, (8 * 4)(sp) sd t5, (8 * 5)(sp) sd a0, (8 * 7)(sp) la t2, _C_LABEL(cpu_exception_handler_user) csrr t0, mcause bltz t0, machine_interrupt j exit_mrts supervisor_trap: /* Save state */ csrrw sp, mscratch, sp addi sp, sp, -64 sd t0, (8 * 0)(sp) sd t1, (8 * 1)(sp) sd t2, (8 * 2)(sp) sd t3, (8 * 3)(sp) sd t4, (8 * 4)(sp) sd t5, (8 * 5)(sp) sd a0, (8 * 7)(sp) la t2, _C_LABEL(cpu_exception_handler_supervisor) csrr t0, mcause bltz t0, machine_interrupt li t1, EXCP_SMODE_ENV_CALL beq t0, t1, supervisor_call j exit_mrts machine_interrupt: /* Type of interrupt ? */ csrr t0, mcause - andi t0, t0, 3 + andi t0, t0, EXCP_MASK li t1, 0 beq t1, t0, software_interrupt li t1, 1 beq t1, t0, timer_interrupt li t1, 2 beq t1, t0, htif_interrupt + li t1, 4 + beq t1, t0, io_interrupt /* lowRISC only */ /* not reached */ 1: j 1b +io_interrupt: + /* Disable IO interrupts so we can go to supervisor mode */ + csrwi CSR_IO_IRQ, 0 + + /* Handle the trap in supervisor mode */ + j exit_mrts + software_interrupt: li t0, MIP_MSIP csrc mip, t0 li t0, MIP_SSIP csrs mip, t0 /* If PRV1 is PRV_U (user) then serve the trap */ csrr t0, mstatus li t1, (MSTATUS_PRV_M << MSTATUS_PRV1_SHIFT) and t0, t0, t1 beqz t0, 1f /* * If PRV1 is supervisor and interrupts were enabled, * then serve the trap. */ csrr t0, mstatus li t1, (SR_IE1 | (MSTATUS_PRV_M << MSTATUS_PRV1_SHIFT)) and t0, t0, t1 li t1, (SR_IE1 | (MSTATUS_PRV_S << MSTATUS_PRV1_SHIFT)) beq t0, t1, 1f j exit 1: - /* Serve a trap in supervisor mode */ + /* Handle the trap in supervisor mode */ j exit_mrts timer_interrupt: /* Disable machine timer interrupts */ li t0, MIE_MTIE csrc mie, t0 /* Clear machine pending */ li t0, MIP_MTIP csrc mip, t0 /* Post supervisor timer interrupt */ li t0, MIP_STIP csrs mip, t0 /* If PRV1 is PRV_U (user) then serve the trap */ csrr t0, mstatus li t1, (MSTATUS_PRV_M << MSTATUS_PRV1_SHIFT) and t0, t0, t1 beqz t0, 1f /* * If PRV1 is supervisor and interrupts were enabled, * then serve the trap. */ csrr t0, mstatus li t1, (SR_IE1 | (MSTATUS_PRV_M << MSTATUS_PRV1_SHIFT)) and t0, t0, t1 li t1, (SR_IE1 | (MSTATUS_PRV_S << MSTATUS_PRV1_SHIFT)) beq t0, t1, 1f j exit 1: /* Serve a trap in supervisor mode */ j exit_mrts htif_interrupt: 1: li t5, 0 csrrw t5, mfromhost, t5 beqz t5, 3f /* Console PUT intr ? */ mv t1, t5 li t0, 0x101 srli t1, t1, 48 bne t1, t0, 2f /* Yes */ la t0, console_intr li t1, 1 sd t1, 0(t0) /* Check if there is any other pending event */ j 1b 2: /* Save entry */ la t0, htif_ring csrr t1, mhartid li t4, (HTIF_RING_SIZE + 16) mulw t4, t4, t1 add t0, t0, t4 li t4, (HTIF_RING_SIZE) add t0, t0, t4 /* t0 == htif_ring_cursor */ ld t1, 0(t0) /* load ptr to cursor */ sd t5, 0(t1) /* put entry */ li t4, 1 sd t4, 8(t1) /* mark used */ ld t4, 16(t1) /* take next */ /* Update cursor */ sd t4, 0(t0) /* Post supervisor software interrupt */ li t0, MIP_SSIP csrs mip, t0 /* Check if there is any other pending event */ j 1b 3: j exit supervisor_call: csrr t1, mepc addi t1, t1, 4 /* Next instruction in t1 */ li t4, ECALL_HTIF_CMD beq t5, t4, htif_cmd li t4, ECALL_HTIF_GET_ENTRY beq t5, t4, htif_get_entry li t4, ECALL_MTIMECMP beq t5, t4, set_mtimecmp li t4, ECALL_CLEAR_PENDING beq t5, t4, clear_pending li t4, ECALL_MCPUID_GET beq t5, t4, mcpuid_get li t4, ECALL_MIMPID_GET beq t5, t4, mimpid_get li t4, ECALL_SEND_IPI beq t5, t4, send_ipi li t4, ECALL_CLEAR_IPI beq t5, t4, clear_ipi li t4, ECALL_HTIF_LOWPUTC beq t5, t4, htif_lowputc li t4, ECALL_MIE_SET beq t5, t4, mie_set + li t4, ECALL_IO_IRQ_MASK + beq t5, t4, io_irq_mask + j exit_next_instr + +io_irq_mask: + csrw CSR_IO_IRQ, t6 j exit_next_instr mie_set: csrs mie, t6 j exit_next_instr mcpuid_get: csrr t6, mcpuid j exit_next_instr mimpid_get: csrr t6, mimpid j exit_next_instr send_ipi: /* CPU mmio base in t6 */ mv t0, t6 li t2, (CSR_IPI * XLEN) add t0, t0, t2 /* t0 = CSR_IPI */ li t2, 1 sd t2, 0(t0) j exit_next_instr clear_ipi: /* Do only clear if there are no new entries in HTIF ring */ la t0, htif_ring csrr t2, mhartid li t4, (HTIF_RING_SIZE + 16) mulw t4, t4, t2 add t0, t0, t4 li t4, (HTIF_RING_SIZE) add t0, t0, t4 /* t0 == ptr to htif_ring_cursor */ ld t2, 8(t0) /* load htif_ring_last */ ld t2, 8(t2) /* load used */ bnez t2, 1f /* Clear supervisor software interrupt pending bit */ li t0, MIP_SSIP csrc mip, t0 1: j exit_next_instr htif_get_entry: /* Get a htif_ring for current core */ la t0, htif_ring csrr t2, mhartid li t4, (HTIF_RING_SIZE + 16) mulw t4, t4, t2 add t0, t0, t4 li t4, (HTIF_RING_SIZE + 8) add t0, t0, t4 /* t0 == htif_ring_last */ /* Check for new entries */ li t6, 0 /* preset return value */ ld t2, 0(t0) /* load ptr to last */ ld t4, 8(t2) /* get used */ beqz t4, 1f /* No new entries. Exit */ /* Get one */ ld t6, 0(t2) /* get entry */ li t4, 0 sd t4, 8(t2) /* mark free */ sd t4, 0(t2) /* free entry, just in case */ ld t4, 16(t2) /* take next */ sd t4, 0(t0) /* update ptr to last */ 1: /* Exit. Result is stored in t6 */ j exit_next_instr htif_cmd: 1: mv t0, t6 csrrw t0, mtohost, t0 bnez t0, 1b j exit_next_instr htif_lowputc: 1: mv t0, t6 csrrw t0, mtohost, t0 bnez t0, 1b 2: li t4, 0 csrrw t5, mfromhost, t4 beqz t5, 2b /* Console PUT intr ? */ mv t2, t5 srli t2, t2, 48 li t3, 0x0101 beq t2, t3, 3f /* Not a console PUT, so save entry */ la t0, htif_ring csrr t2, mhartid li t4, (HTIF_RING_SIZE + 16) mulw t4, t4, t2 add t0, t0, t4 li t4, (HTIF_RING_SIZE) add t0, t0, t4 /* t0 == htif_ring_cursor */ ld t2, 0(t0) /* load ptr to cursor */ sd t5, 0(t2) /* put entry */ li t4, 1 sd t4, 8(t2) /* mark used */ ld t4, 16(t2) /* take next */ /* Update cursor */ sd t4, 0(t0) /* Post supervisor software interrupt */ li t0, MIP_SSIP csrs mip, t0 /* Wait for console intr again */ j 2b 3: j exit_next_instr set_mtimecmp: csrr t2, stime add t6, t6, t2 csrw mtimecmp, t6 /* Enable interrupts */ li t0, (MIE_MTIE | MIE_STIE) csrs mie, t0 j exit_next_instr clear_pending: li t0, MIP_STIP csrc mip, t0 j exit_next_instr /* * Trap exit functions */ exit_next_instr: /* Next instruction is in t1 */ csrw mepc, t1 exit: /* Restore state */ ld t0, (8 * 0)(sp) ld t1, (8 * 1)(sp) ld t2, (8 * 2)(sp) ld t3, (8 * 3)(sp) ld t4, (8 * 4)(sp) ld t5, (8 * 5)(sp) ld a0, (8 * 7)(sp) addi sp, sp, 64 csrrw sp, mscratch, sp eret /* * Redirect to supervisor */ exit_mrts: /* Setup exception handler */ li t1, KERNBASE add t2, t2, t1 csrw stvec, t2 /* Restore state */ ld t0, (8 * 0)(sp) ld t1, (8 * 1)(sp) ld t2, (8 * 2)(sp) ld t3, (8 * 3)(sp) ld t4, (8 * 4)(sp) ld t5, (8 * 5)(sp) ld a0, (8 * 7)(sp) addi sp, sp, 64 csrrw sp, mscratch, sp /* Redirect to supervisor */ mrts Index: head/sys/riscv/riscv/intr_machdep.c =================================================================== --- head/sys/riscv/riscv/intr_machdep.c (revision 298635) +++ head/sys/riscv/riscv/intr_machdep.c (revision 298636) @@ -1,297 +1,304 @@ /*- * Copyright (c) 2015-2016 Ruslan Bukin * All rights reserved. * * Portions of this software were developed by SRI International and the * University of Cambridge Computer Laboratory under DARPA/AFRL contract * FA8750-10-C-0237 ("CTSRD"), as part of the DARPA CRASH research programme. * * Portions of this software were developed by the University of Cambridge * Computer Laboratory as part of the CTSRD Project, with support from the * UK Higher Education Innovation Fund (HEIF). * * 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 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 AUTHOR 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. */ #include __FBSDID("$FreeBSD$"); #include #include #include #include #include #include #include #include #include #include #include #ifdef SMP #include #endif u_long intrcnt[NIRQS]; size_t sintrcnt = sizeof(intrcnt); char intrnames[NIRQS * (MAXCOMLEN + 1) * 2]; size_t sintrnames = sizeof(intrnames); static struct intr_event *intr_events[NIRQS]; static riscv_intrcnt_t riscv_intr_counters[NIRQS]; static int intrcnt_index; riscv_intrcnt_t riscv_intrcnt_create(const char* name) { riscv_intrcnt_t counter; counter = &intrcnt[intrcnt_index++]; riscv_intrcnt_setname(counter, name); return (counter); } void riscv_intrcnt_setname(riscv_intrcnt_t counter, const char *name) { int i; i = (counter - intrcnt); KASSERT(counter != NULL, ("riscv_intrcnt_setname: NULL counter")); snprintf(intrnames + (MAXCOMLEN + 1) * i, MAXCOMLEN + 1, "%-*s", MAXCOMLEN, name); } static void riscv_mask_irq(void *source) { uintptr_t irq; irq = (uintptr_t)source; switch (irq) { case IRQ_TIMER: csr_clear(sie, SIE_STIE); break; case IRQ_SOFTWARE: csr_clear(sie, SIE_SSIE); break; + case IRQ_UART: + machine_command(ECALL_IO_IRQ_MASK, 0); + break; default: panic("Unknown irq %d\n", irq); } } static void riscv_unmask_irq(void *source) { uintptr_t irq; irq = (uintptr_t)source; switch (irq) { case IRQ_TIMER: csr_set(sie, SIE_STIE); break; case IRQ_SOFTWARE: csr_set(sie, SIE_SSIE); break; + case IRQ_UART: + machine_command(ECALL_IO_IRQ_MASK, 1); + break; default: panic("Unknown irq %d\n", irq); } } void riscv_init_interrupts(void) { char name[MAXCOMLEN + 1]; int i; for (i = 0; i < NIRQS; i++) { snprintf(name, MAXCOMLEN + 1, "int%d:", i); riscv_intr_counters[i] = riscv_intrcnt_create(name); } } int riscv_setup_intr(const char *name, driver_filter_t *filt, void (*handler)(void*), void *arg, int irq, int flags, void **cookiep) { struct intr_event *event; int error; if (irq < 0 || irq >= NIRQS) panic("%s: unknown intr %d", __func__, irq); event = intr_events[irq]; if (event == NULL) { error = intr_event_create(&event, (void *)(uintptr_t)irq, 0, irq, riscv_mask_irq, riscv_unmask_irq, NULL, NULL, "int%d", irq); if (error) return (error); intr_events[irq] = event; riscv_unmask_irq((void*)(uintptr_t)irq); } error = intr_event_add_handler(event, name, filt, handler, arg, intr_priority(flags), flags, cookiep); if (error) { printf("Failed to setup intr: %d\n", irq); return (error); } riscv_intrcnt_setname(riscv_intr_counters[irq], event->ie_fullname); return (0); } int riscv_teardown_intr(void *ih) { /* TODO */ return (0); } int riscv_config_intr(u_int irq, enum intr_trigger trig, enum intr_polarity pol) { /* There is no configuration for interrupts */ return (0); } void riscv_cpu_intr(struct trapframe *frame) { struct intr_event *event; int active_irq; critical_enter(); KASSERT(frame->tf_scause & EXCP_INTR, ("riscv_cpu_intr: wrong frame passed")); active_irq = (frame->tf_scause & EXCP_MASK); switch (active_irq) { + case IRQ_UART: case IRQ_SOFTWARE: case IRQ_TIMER: event = intr_events[active_irq]; /* Update counters */ atomic_add_long(riscv_intr_counters[active_irq], 1); PCPU_INC(cnt.v_intr); break; case IRQ_HTIF: /* HTIF interrupts are only handled in machine mode */ panic("%s: HTIF interrupt", __func__); break; default: event = NULL; } if (!event || TAILQ_EMPTY(&event->ie_handlers) || (intr_event_handle(event, frame) != 0)) printf("stray interrupt %d\n", active_irq); critical_exit(); } #ifdef SMP void riscv_setup_ipihandler(driver_filter_t *filt) { riscv_setup_intr("ipi", filt, NULL, NULL, IRQ_SOFTWARE, INTR_TYPE_MISC, NULL); } void riscv_unmask_ipi(void) { csr_set(sie, SIE_SSIE); } /* Sending IPI */ static void ipi_send(struct pcpu *pc, int ipi) { CTR3(KTR_SMP, "%s: cpu=%d, ipi=%x", __func__, pc->pc_cpuid, ipi); atomic_set_32(&pc->pc_pending_ipis, ipi); machine_command(ECALL_SEND_IPI, pc->pc_reg); CTR1(KTR_SMP, "%s: sent", __func__); } void ipi_all_but_self(u_int ipi) { cpuset_t other_cpus; other_cpus = all_cpus; CPU_CLR(PCPU_GET(cpuid), &other_cpus); CTR2(KTR_SMP, "%s: ipi: %x", __func__, ipi); ipi_selected(other_cpus, ipi); } void ipi_cpu(int cpu, u_int ipi) { cpuset_t cpus; CPU_ZERO(&cpus); CPU_SET(cpu, &cpus); CTR3(KTR_SMP, "%s: cpu: %d, ipi: %x\n", __func__, cpu, ipi); ipi_send(cpuid_to_pcpu[cpu], ipi); } void ipi_selected(cpuset_t cpus, u_int ipi) { struct pcpu *pc; CTR1(KTR_SMP, "ipi_selected: ipi: %x", ipi); STAILQ_FOREACH(pc, &cpuhead, pc_allcpu) { if (CPU_ISSET(pc->pc_cpuid, &cpus)) { CTR3(KTR_SMP, "%s: pc: %p, ipi: %x\n", __func__, pc, ipi); ipi_send(pc, ipi); } } } #endif