diff --git a/repos/base-hw/lib/mk/spec/riscv/core-hw-riscv_qemu.mk b/repos/base-hw/lib/mk/spec/riscv/core-hw-riscv_qemu.mk index 71966f0d76..cd1659bb65 100644 --- a/repos/base-hw/lib/mk/spec/riscv/core-hw-riscv_qemu.mk +++ b/repos/base-hw/lib/mk/spec/riscv/core-hw-riscv_qemu.mk @@ -12,6 +12,7 @@ SRC_CC += spec/riscv/kernel/cpu.cc SRC_CC += spec/riscv/kernel/interface.cc SRC_CC += spec/riscv/kernel/pd.cc SRC_CC += spec/riscv/cpu.cc +SRC_CC += spec/riscv/pic.cc SRC_CC += spec/riscv/platform_support.cc SRC_CC += spec/riscv/timer.cc SRC_CC += spec/64bit/memory_map.cc diff --git a/repos/base-hw/src/bootstrap/spec/riscv/platform.cc b/repos/base-hw/src/bootstrap/spec/riscv/platform.cc index 7d74f0dd4f..b0c3996831 100644 --- a/repos/base-hw/src/bootstrap/spec/riscv/platform.cc +++ b/repos/base-hw/src/bootstrap/spec/riscv/platform.cc @@ -20,7 +20,7 @@ using namespace Board; Bootstrap::Platform::Board::Board() : early_ram_regions(Memory_region { RAM_BASE, RAM_SIZE } ), - core_mmio() + core_mmio(Memory_region { PLIC_BASE, PLIC_SIZE }) { } unsigned Bootstrap::Platform::enable_mmu() diff --git a/repos/base-hw/src/core/board/riscv_qemu/plic.h b/repos/base-hw/src/core/board/riscv_qemu/plic.h new file mode 100644 index 0000000000..9a4a300bf9 --- /dev/null +++ b/repos/base-hw/src/core/board/riscv_qemu/plic.h @@ -0,0 +1,38 @@ +/** + * \brief Platform-level interrupt controller layout (PLIC) + * \author Sebastian Sumpf + * \date 2021-03-05 + */ + +/* + * Copyright (C) 2021 Genode Labs GmbH + * + * This file is part of the Genode OS framework, which is distributed + * under the terms of the GNU Affero General Public License version 3. + */ + +#ifndef _CORE__SPEC__RISCV_QEMU__PLIC_H_ +#define _CORE__SPEC__RISCV_QEMU__PLIC_H_ + +namespace Board { class Plic; } + +struct Board::Plic : Genode::Mmio +{ + enum { NR_OF_IRQ = 32 }; + + struct Enable : Register_array<0x80, 32, 32, 1> { }; + struct Id : Register<0x1ff004, 32> { }; + + Plic(Genode::addr_t const base) + : + Mmio(base) { } + + void enable(unsigned value, unsigned irq) + { + write(value, irq); + } + + void el(unsigned, unsigned) { } +}; + +#endif /* _CORE__SPEC__RISCV_QEMU__PLIC_H_ */ diff --git a/repos/base-hw/src/core/kernel/thread.cc b/repos/base-hw/src/core/kernel/thread.cc index 1c45c55566..88e98a5b28 100644 --- a/repos/base-hw/src/core/kernel/thread.cc +++ b/repos/base-hw/src/core/kernel/thread.cc @@ -644,7 +644,7 @@ void Thread::_call_new_irq() } Genode::Irq_session::Trigger trigger = - (Genode::Irq_session::Trigger) (user_arg_3() & 0b1100); + (Genode::Irq_session::Trigger) ((user_arg_3() >> 2) & 0b11); Genode::Irq_session::Polarity polarity = (Genode::Irq_session::Polarity) (user_arg_3() & 0b11); diff --git a/repos/base-hw/src/core/spec/riscv/kernel/thread.cc b/repos/base-hw/src/core/spec/riscv/kernel/thread.cc index f3b2c0e8b9..ce8d342be8 100644 --- a/repos/base-hw/src/core/spec/riscv/kernel/thread.cc +++ b/repos/base-hw/src/core/spec/riscv/kernel/thread.cc @@ -28,8 +28,13 @@ void Thread::exception(Cpu & cpu) using Stval = Genode::Cpu::Stval; if (regs->is_irq()) { - /* there are only cpu-local timer interrupts right now */ - cpu.interrupt(cpu.timer().interrupt_id()); + /* cpu-local timer interrupt */ + if (regs->irq() == cpu.timer().interrupt_id()) { + cpu.interrupt(cpu.timer().interrupt_id()); + } else { + /* interrupt controller */ + _interrupt(0); + } return; } diff --git a/repos/base-hw/src/core/spec/riscv/pic.cc b/repos/base-hw/src/core/spec/riscv/pic.cc new file mode 100644 index 0000000000..9689f33423 --- /dev/null +++ b/repos/base-hw/src/core/spec/riscv/pic.cc @@ -0,0 +1,25 @@ +/* + * \brief RISC-V PIC initialization + * \author Sebastian Sumpf + * \date 2021-03-05 + */ + +/* + * Copyright (C) 2021 Genode Labs GmbH + * + * This file is part of the Genode OS framework, which is distributed + * under the terms of the GNU Affero General Public License version 3. + */ + + +#include +#include +#include + +Board::Pic::Pic() : + _plic(Genode::Platform::mmio_to_virt(Board::PLIC_BASE)) +{ + /* enable external interrupts */ + enum { SEIE = 0x200 }; + Hw::Riscv_cpu::Sie external_interrupt(SEIE); +} diff --git a/repos/base-hw/src/core/spec/riscv/pic.h b/repos/base-hw/src/core/spec/riscv/pic.h index 58e72ea4a2..f76e5d620c 100644 --- a/repos/base-hw/src/core/spec/riscv/pic.h +++ b/repos/base-hw/src/core/spec/riscv/pic.h @@ -3,11 +3,11 @@ * \author Sebastian Sumpf * \date 2015-06-02 * - * There currently is no interrupt controller defined for the RISC-V platform. + * The platform specific PLIC-register layout can be found in 'plic.h' */ /* - * Copyright (C) 2015-2017 Genode Labs GmbH + * Copyright (C) 2015-2021 Genode Labs GmbH * * This file is part of the Genode OS framework, which is distributed * under the terms of the GNU Affero General Public License version 3. @@ -16,14 +16,23 @@ #ifndef _CORE__SPEC__RISCV__PIC_H_ #define _CORE__SPEC__RISCV__PIC_H_ +#include +#include +#include + namespace Board { class Pic; } /** - * Dummy PIC driver for core + * PIC driver for core for one CPU */ class Board::Pic { + private: + + Plic _plic; + Plic::Id::access_t _last_irq { 0 }; + public: enum { @@ -32,15 +41,45 @@ class Board::Pic * when SMP is an aspect of CPUs only compiled where necessary */ IPI = 0, - NR_OF_IRQ = 15, + NR_OF_IRQ = Plic::NR_OF_IRQ, }; - Pic() { } - bool take_request(unsigned & i) { i = 0; return true; } - void unmask(unsigned, unsigned) { } - void mask(unsigned) { } - void finish_request() { } - void irq_mode(unsigned, unsigned, unsigned) { } + Pic(); + + bool take_request(unsigned & irq) + { + irq = _plic.read(); + if (irq == 0) return false; + _last_irq = irq; + return true; + } + + void finish_request() + { + _plic.write(_last_irq); + } + + void unmask(unsigned irq, unsigned) + { + if (irq > NR_OF_IRQ) return; + _plic.enable(1, irq); + } + + void mask(unsigned irq) + { + if (irq > NR_OF_IRQ) return; + _plic.enable(0, irq); + } + + void irq_mode(unsigned irq, unsigned trigger, unsigned) + { + using namespace Genode; + + if (irq > NR_OF_IRQ || trigger == Irq_session::TRIGGER_UNCHANGED) + return; + + _plic.el(trigger == Irq_session::TRIGGER_EDGE ? 1 : 0, irq); + } }; #endif /* _CORE__SPEC__RISCV__PIC_H_ */ diff --git a/repos/base-hw/src/core/spec/riscv/platform_support.cc b/repos/base-hw/src/core/spec/riscv/platform_support.cc index 4e1d0e9f7a..7199d4e6e2 100644 --- a/repos/base-hw/src/core/spec/riscv/platform_support.cc +++ b/repos/base-hw/src/core/spec/riscv/platform_support.cc @@ -27,7 +27,7 @@ void Platform::_init_io_port_alloc() { } void Platform::_init_additional_platform_info(Genode::Xml_generator&) { } -long Platform::irq(long const /* user_irq */) { return 0; } +long Platform::irq(long const user_irq ) { return user_irq; } bool Platform::get_msi_params(addr_t /* mmconf */, addr_t & /* address */, diff --git a/repos/base-hw/src/core/spec/riscv/timer.cc b/repos/base-hw/src/core/spec/riscv/timer.cc index dd1297b1b7..4538533bfb 100644 --- a/repos/base-hw/src/core/spec/riscv/timer.cc +++ b/repos/base-hw/src/core/spec/riscv/timer.cc @@ -24,7 +24,7 @@ Board::Timer::Timer(unsigned) { /* enable timer interrupt */ enum { STIE = 0x20 }; - asm volatile ("csrs sie, %0" : : "r"(STIE)); + Hw::Riscv_cpu::Sie timer(STIE); } diff --git a/repos/base-hw/src/include/hw/spec/riscv/cpu.h b/repos/base-hw/src/include/hw/spec/riscv/cpu.h index 0965ec220e..49970a1d2f 100644 --- a/repos/base-hw/src/include/hw/spec/riscv/cpu.h +++ b/repos/base-hw/src/include/hw/spec/riscv/cpu.h @@ -43,6 +43,14 @@ struct Hw::Riscv_cpu struct Asid : Bitfield<44,16> { }; struct Mode : Bitfield<60, 4> { }; ); + + struct Sie + { + Sie(Genode::addr_t bits) + { + asm volatile ("csrs sie, %0" : : "r"(bits)); + } + }; }; #endif /* _SRC__LIB__HW__SPEC__RISCV__CPU_H_ */ diff --git a/repos/base-hw/src/include/hw/spec/riscv/qemu_board.h b/repos/base-hw/src/include/hw/spec/riscv/qemu_board.h index 872fa73ff0..8ebdb6b4ed 100644 --- a/repos/base-hw/src/include/hw/spec/riscv/qemu_board.h +++ b/repos/base-hw/src/include/hw/spec/riscv/qemu_board.h @@ -25,6 +25,9 @@ namespace Hw::Riscv_board { RAM_BASE = 0x80020000, RAM_SIZE = 0x7fe0000, TIMER_HZ = 10000000, + + PLIC_BASE = 0xc002000, + PLIC_SIZE = 0x200000, }; enum { UART_BASE, UART_CLOCK };