Skip to content

Commit

Permalink
bhyve: Implement a PL031 RTC on arm64
Browse files Browse the repository at this point in the history
Unlike amd64's, this RTC is implemented entirely in userspace. This is
the same RTC as is provided by QEMU's virt machine.

Reviewed by:	jhb
MFC after:	2 weeks
Obtained from:	CheriBSD
  • Loading branch information
jrtc27 authored and markjdb committed Apr 3, 2024
1 parent af0a75b commit 3ae8bca
Show file tree
Hide file tree
Showing 6 changed files with 412 additions and 0 deletions.
1 change: 1 addition & 0 deletions usr.sbin/bhyve/aarch64/Makefile.inc
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
SRCS+= \
fdt.c \
rtc_pl031.c \
uart_pl011.c

.PATH: ${BHYVE_SYSDIR}/sys/arm64/vmm
Expand Down
60 changes: 60 additions & 0 deletions usr.sbin/bhyve/aarch64/bhyverun_machdep.c
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@
#include "mem.h"
#include "pci_emul.h"
#include "pci_irq.h"
#include "rtc_pl031.h"
#include "uart_emul.h"

/* Start of mem + 1M */
Expand All @@ -58,6 +59,9 @@
#define UART_MMIO_BASE 0x10000
#define UART_MMIO_SIZE 0x1000
#define UART_INTR 32
#define RTC_MMIO_BASE 0x11000
#define RTC_MMIO_SIZE 0x1000
#define RTC_INTR 33

#define GIC_DIST_BASE 0x2f000000
#define GIC_DIST_SIZE 0x10000
Expand Down Expand Up @@ -287,6 +291,60 @@ init_mmio_uart(struct vmctx *ctx)
return (true);
}

static void
mmio_rtc_intr_assert(void *arg)
{
struct vmctx *ctx = arg;

vm_assert_irq(ctx, RTC_INTR);
}

static void
mmio_rtc_intr_deassert(void *arg)
{
struct vmctx *ctx = arg;

vm_deassert_irq(ctx, RTC_INTR);
}

static int
mmio_rtc_mem_handler(struct vcpu *vcpu __unused, int dir,
uint64_t addr, int size __unused, uint64_t *val, void *arg1, long arg2)
{
struct rtc_pl031_softc *sc = arg1;
long reg;

reg = addr - arg2;
if (dir == MEM_F_WRITE)
rtc_pl031_write(sc, reg, *val);
else
*val = rtc_pl031_read(sc, reg);

return (0);
}

static void
init_mmio_rtc(struct vmctx *ctx)
{
struct rtc_pl031_softc *sc;
struct mem_range mr;
int error;

sc = rtc_pl031_init(mmio_rtc_intr_assert, mmio_rtc_intr_deassert,
ctx);

bzero(&mr, sizeof(struct mem_range));
mr.name = "rtc";
mr.base = RTC_MMIO_BASE;
mr.size = RTC_MMIO_SIZE;
mr.flags = MEM_F_RW;
mr.handler = mmio_rtc_mem_handler;
mr.arg1 = sc;
mr.arg2 = mr.base;
error = register_mem(&mr);
assert(error == 0);
}

static vm_paddr_t
fdt_gpa(struct vmctx *ctx)
{
Expand Down Expand Up @@ -328,6 +386,8 @@ bhyve_init_platform(struct vmctx *ctx, struct vcpu *bsp)

if (init_mmio_uart(ctx))
fdt_add_uart(UART_MMIO_BASE, UART_MMIO_SIZE, UART_INTR);
init_mmio_rtc(ctx);
fdt_add_rtc(RTC_MMIO_BASE, RTC_MMIO_SIZE, RTC_INTR);
fdt_add_timer();
pci_irq_init(pcie_intrs);
fdt_add_pcie(pcie_intrs);
Expand Down
31 changes: 31 additions & 0 deletions usr.sbin/bhyve/aarch64/fdt.c
Original file line number Diff line number Diff line change
Expand Up @@ -248,6 +248,37 @@ fdt_add_uart(uint64_t uart_base, uint64_t uart_size, int intr)
fdt_end_node(fdt);
}

void
fdt_add_rtc(uint64_t rtc_base, uint64_t rtc_size, int intr)
{
void *fdt, *interrupts, *prop;
char node_name[32];

assert(gic_phandle != 0);
assert(apb_pclk_phandle != 0);
assert(intr >= GIC_FIRST_SPI);

fdt = fdtroot;

snprintf(node_name, sizeof(node_name), "rtc@%lx", rtc_base);
fdt_begin_node(fdt, node_name);
#define RTC_COMPAT "arm,pl031\0arm,primecell"
fdt_property(fdt, "compatible", RTC_COMPAT, sizeof(RTC_COMPAT));
#undef RTC_COMPAT
set_single_reg(fdt, rtc_base, rtc_size);
fdt_property_u32(fdt, "interrupt-parent", gic_phandle);
fdt_property_placeholder(fdt, "interrupts", 3 * sizeof(uint32_t),
&interrupts);
SET_PROP_U32(interrupts, 0, GIC_SPI);
SET_PROP_U32(interrupts, 1, intr - GIC_FIRST_SPI);
SET_PROP_U32(interrupts, 2, IRQ_TYPE_LEVEL_HIGH);
fdt_property_placeholder(fdt, "clocks", sizeof(uint32_t), &prop);
SET_PROP_U32(prop, 0, apb_pclk_phandle);
fdt_property_string(fdt, "clock-names", "apb_pclk");

fdt_end_node(fdt);
}

void
fdt_add_timer(void)
{
Expand Down
1 change: 1 addition & 0 deletions usr.sbin/bhyve/aarch64/fdt.h
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ void fdt_add_gic(uint64_t dist_base, uint64_t dist_size,
void fdt_add_timer(void);
void fdt_add_pcie(int intrs[static 4]);
void fdt_add_uart(uint64_t uart_base, uint64_t uart_size, int intr);
void fdt_add_rtc(uint64_t rtc_base, uint64_t rtc_size, int intr);
void fdt_finalize(void);

#endif /* _FDT_H_ */
Loading

0 comments on commit 3ae8bca

Please sign in to comment.