riscv: Interrupt controller support

- Enable the "platform-level interrupt controller" PLIC on base-hw
- The RISC-V specification offers only a register description, but no
  layout for the register set. This implies the layout is platform
  dependent, and therefore, implemented separately for Qemu

issue #4042
This commit is contained in:
Sebastian Sumpf 2021-03-05 06:28:26 +01:00 committed by Norman Feske
parent bebba3876e
commit 6223ae4413
11 changed files with 135 additions and 16 deletions

View File

@ -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

View File

@ -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()

View File

@ -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<Enable>(value, irq);
}
void el(unsigned, unsigned) { }
};
#endif /* _CORE__SPEC__RISCV_QEMU__PLIC_H_ */

View File

@ -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);

View File

@ -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;
}

View File

@ -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 <board.h>
#include <pic.h>
#include <platform.h>
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);
}

View File

@ -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 <irq_session/irq_session.h>
#include <util/mmio.h>
#include <plic.h>
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<Plic::Id>();
if (irq == 0) return false;
_last_irq = irq;
return true;
}
void finish_request()
{
_plic.write<Plic::Id>(_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_ */

View File

@ -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 */,

View File

@ -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);
}

View File

@ -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_ */

View File

@ -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 };