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/interface.cc
SRC_CC += spec/riscv/kernel/pd.cc SRC_CC += spec/riscv/kernel/pd.cc
SRC_CC += spec/riscv/cpu.cc SRC_CC += spec/riscv/cpu.cc
SRC_CC += spec/riscv/pic.cc
SRC_CC += spec/riscv/platform_support.cc SRC_CC += spec/riscv/platform_support.cc
SRC_CC += spec/riscv/timer.cc SRC_CC += spec/riscv/timer.cc
SRC_CC += spec/64bit/memory_map.cc SRC_CC += spec/64bit/memory_map.cc

View File

@ -20,7 +20,7 @@ using namespace Board;
Bootstrap::Platform::Board::Board() Bootstrap::Platform::Board::Board()
: :
early_ram_regions(Memory_region { RAM_BASE, RAM_SIZE } ), early_ram_regions(Memory_region { RAM_BASE, RAM_SIZE } ),
core_mmio() core_mmio(Memory_region { PLIC_BASE, PLIC_SIZE })
{ } { }
unsigned Bootstrap::Platform::enable_mmu() 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 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 polarity =
(Genode::Irq_session::Polarity) (user_arg_3() & 0b11); (Genode::Irq_session::Polarity) (user_arg_3() & 0b11);

View File

@ -28,8 +28,13 @@ void Thread::exception(Cpu & cpu)
using Stval = Genode::Cpu::Stval; using Stval = Genode::Cpu::Stval;
if (regs->is_irq()) { if (regs->is_irq()) {
/* there are only cpu-local timer interrupts right now */ /* cpu-local timer interrupt */
cpu.interrupt(cpu.timer().interrupt_id()); if (regs->irq() == cpu.timer().interrupt_id()) {
cpu.interrupt(cpu.timer().interrupt_id());
} else {
/* interrupt controller */
_interrupt(0);
}
return; 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 * \author Sebastian Sumpf
* \date 2015-06-02 * \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 * This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU Affero General Public License version 3. * under the terms of the GNU Affero General Public License version 3.
@ -16,14 +16,23 @@
#ifndef _CORE__SPEC__RISCV__PIC_H_ #ifndef _CORE__SPEC__RISCV__PIC_H_
#define _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; } namespace Board { class Pic; }
/** /**
* Dummy PIC driver for core * PIC driver for core for one CPU
*/ */
class Board::Pic class Board::Pic
{ {
private:
Plic _plic;
Plic::Id::access_t _last_irq { 0 };
public: public:
enum { enum {
@ -32,15 +41,45 @@ class Board::Pic
* when SMP is an aspect of CPUs only compiled where necessary * when SMP is an aspect of CPUs only compiled where necessary
*/ */
IPI = 0, IPI = 0,
NR_OF_IRQ = 15, NR_OF_IRQ = Plic::NR_OF_IRQ,
}; };
Pic() { } Pic();
bool take_request(unsigned & i) { i = 0; return true; }
void unmask(unsigned, unsigned) { } bool take_request(unsigned & irq)
void mask(unsigned) { } {
void finish_request() { } irq = _plic.read<Plic::Id>();
void irq_mode(unsigned, unsigned, unsigned) { } 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_ */ #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&) { } 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 */, bool Platform::get_msi_params(addr_t /* mmconf */, addr_t & /* address */,

View File

@ -24,7 +24,7 @@ Board::Timer::Timer(unsigned)
{ {
/* enable timer interrupt */ /* enable timer interrupt */
enum { STIE = 0x20 }; 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 Asid : Bitfield<44,16> { };
struct Mode : Bitfield<60, 4> { }; 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_ */ #endif /* _SRC__LIB__HW__SPEC__RISCV__CPU_H_ */

View File

@ -25,6 +25,9 @@ namespace Hw::Riscv_board {
RAM_BASE = 0x80020000, RAM_BASE = 0x80020000,
RAM_SIZE = 0x7fe0000, RAM_SIZE = 0x7fe0000,
TIMER_HZ = 10000000, TIMER_HZ = 10000000,
PLIC_BASE = 0xc002000,
PLIC_SIZE = 0x200000,
}; };
enum { UART_BASE, UART_CLOCK }; enum { UART_BASE, UART_CLOCK };