Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions src/arch/armv8/aarch64/inc/arch/subarch/sysregs.h
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,18 @@ SYSREG_GEN_ACCESSORS(cntvoff_el2)
SYSREG_GEN_ACCESSORS(sctlr_el1)
SYSREG_GEN_ACCESSORS(cntkctl_el1)
SYSREG_GEN_ACCESSORS(cntfrq_el0)
SYSREG_GEN_ACCESSORS(cnthp_ctl_el2)
SYSREG_GEN_ACCESSORS(cnthp_tval_el2)
SYSREG_GEN_ACCESSORS(pmcr_el0)
SYSREG_GEN_ACCESSORS(mdcr_el2)
SYSREG_GEN_ACCESSORS(pmcntenset_el0)
SYSREG_GEN_ACCESSORS(pmcntenclr_el0)
SYSREG_GEN_ACCESSORS(pmselr_el0)
SYSREG_GEN_ACCESSORS(pmxevcntr_el0)
SYSREG_GEN_ACCESSORS(pmxevtyper_el0)
SYSREG_GEN_ACCESSORS(pmintenset_el1)
SYSREG_GEN_ACCESSORS(pmintenclr_el1)
SYSREG_GEN_ACCESSORS(pmovsclr_el0)
SYSREG_GEN_ACCESSORS(par_el1)
SYSREG_GEN_ACCESSORS(tcr_el2)
SYSREG_GEN_ACCESSORS(ttbr0_el2)
Expand Down
198 changes: 198 additions & 0 deletions src/arch/armv8/generic_timer.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,198 @@
/**
* SPDX-License-Identifier: Apache-2.0
* Copyright (c) Bao Project and Contributors. All rights reserved
*/

#include <arch/bao.h>
#include <arch/generic_timer.h>
#include <arch/sysregs.h>
#include <bit.h>
#include <cpu.h>
#include <interrupts.h>
#include <platform.h>
#include <spinlock.h>

#define CNTHP_CTL_EL2_ENABLE 0
#define CNTHP_CTL_EL2_IMASK 1

static irq_handler_t timer_handlers[CPU_MAX];
static irqid_t timer_irq_id = INVALID_IRQID;
static spinlock_t timer_irq_lock = SPINLOCK_INITVAL;

static void timer_arch_interrupt_handler(irqid_t int_id)
{
irq_handler_t handler = timer_handlers[cpu()->id];

if (handler != NULL) {
handler(int_id);
}
}

void timer_arch_define_irq_callback(irq_handler_t handler)
{
irqid_t interrupt_id = platform.arch.generic_timer.interrupt_id;

if ((interrupt_id == INVALID_IRQID) || (interrupt_id == 0U)) {
ERROR("Invalid hypervisor timer interrupt id\n");
}

timer_handlers[cpu()->id] = handler;

spin_lock(&timer_irq_lock);
if (timer_irq_id == INVALID_IRQID) {
timer_irq_id = interrupts_reserve(interrupt_id, timer_arch_interrupt_handler);
if (timer_irq_id == INVALID_IRQID) {
ERROR("Failed to reserve hypervisor timer interrupt id = %u\n", interrupt_id);
}
} else if (timer_irq_id != interrupt_id) {
ERROR("Inconsistent hypervisor timer interrupt id = %u\n", interrupt_id);
}
spin_unlock(&timer_irq_lock);

interrupts_arch_enable(timer_irq_id, true);
}

/**
* @brief Enables the architecture-specific timer.
*/
void timer_arch_enable(void)
{
uint64_t ctl_value;

// Read the current value of the control register CNTHP_CTL_EL2.
ctl_value = sysreg_cnthp_ctl_el2_read();

// CNTHP_CTL_EL2 --> ENABLE, bit [0]
// --> 0b0 - Timer disabled
// --> 0b1 - Timer enabled
ctl_value = bit_set(ctl_value, CNTHP_CTL_EL2_ENABLE);

// CNTHP_CTL_EL2 --> IMASK, bit [1]
// --> 0b0 - Timer interrupt is not masked by the IMASK bit
// --> 0b1 - Timer interrupt is masked by the IMASK bit
ctl_value = bit_clear(ctl_value, CNTHP_CTL_EL2_IMASK);

// Write the updated control value back to the CNTHP_CTL_EL2 register.
sysreg_cnthp_ctl_el2_write(ctl_value);
}

/**
* @brief Disables the architecture-specific timer.
*/
void timer_arch_disable(void)
{
uint64_t ctl_value;

// Read the current value of the control register CNTHP_CTL_EL2.
ctl_value = sysreg_cnthp_ctl_el2_read();

// CNTHP_CTL_EL2 --> ENABLE, bit [0]
// --> 0b0 - Timer disabled
// --> 0b1 - Timer enabled
ctl_value = bit_clear(ctl_value, CNTHP_CTL_EL2_ENABLE);

// Write the updated control value back to the CNTHP_CTL_EL2 register.
sysreg_cnthp_ctl_el2_write(ctl_value);
}

/**
* @brief Gets the system frequency from the architecture-specific timer.
*
* @return The system frequency in Hz.
*/
static inline uint64_t timer_arch_get_system_frequency(void)
{
uint64_t frequency;

// Read the system frequency from the architecture-specific register
// CNTFRQ_EL0.
frequency = sysreg_cntfrq_el0_read();

// Mask the lower 32 bits of the frequency value to get the system frequency
// in Hz.
return frequency & UINT32_MAX;
}

/**
* @brief Sets the architecture-specific timer counter value.
*
* @param count The value to set for the timer counter (lower 32 bits).
*/
static inline void timer_arch_set_counter(uint64_t count)
{
if (count > INT32_MAX) {
ERROR("Hypervisor timer count exceeds TVAL range\n");
}

// Write the new counter value to the architecture-specific register
// CNTHP_TVAL_EL2.
sysreg_cnthp_tval_el2_write(count);
}

/**
* @brief Initializes the architecture-specific timer with the specified period.
*
* @param period The timer period in microseconds.
* @return The calculated counter value to set for the timer.
*/
uint64_t timer_arch_init(uint64_t period)
{
uint64_t frequency;
uint64_t count_value;

// Get the system frequency from the architecture-specific timer.
frequency = timer_arch_get_system_frequency();

// Calculate the count value to set for the timer based on the period and
// system frequency.
count_value = (period * frequency) / 1000000;

// Set the timer counter to the calculated count value.
timer_arch_set_counter(count_value);

// Enable the architecture-specific timer.
timer_arch_enable();

// Return the calculated counter value for the timer.
return count_value;
}

/**
* @brief Reschedules the architecture-specific timer interrupt with the
* specified counter value.
*
* @param count The counter value to set for rescheduling the timer interrupt.
*/
void timer_arch_reschedule_interrupt(uint64_t count)
{
// Set the timer counter to the specified count value for rescheduling the
// interrupt.
timer_arch_set_counter(count);
}

/**
* @brief Reschedules the architecture-specific timer interrupt with the
* specified period in microseconds.
*
* @param period The timer period in microseconds to reschedule the interrupt.
* @return The calculated counter value to set for the timer.
*/
uint64_t timer_arch_reschedule_interrupt_us(uint64_t period)
{
uint64_t frequency;
uint64_t count_value;

// Get the system frequency from the architecture-specific timer.
frequency = timer_arch_get_system_frequency();

// Calculate the count value to set for the timer based on the period and
// system frequency.
count_value = (period * frequency) / 1000000;

// Set the timer counter to the calculated count value for rescheduling
// the interrupt.
timer_arch_set_counter(count_value);

// Return the calculated counter value for the timer.
return count_value;
}
1 change: 1 addition & 0 deletions src/arch/armv8/gic.c
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,7 @@ void gic_handle()
if (res == HANDLED_BY_HYP) {
gicc_dir(ack);
}
interrupts_post_handler();
}
}

Expand Down
105 changes: 105 additions & 0 deletions src/arch/armv8/inc/arch/events.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
/**
* SPDX-License-Identifier: Apache-2.0
* Copyright (c) Bao Project and Contributors. All rights reserved.
*/

#ifndef __ARCH_EVENTS_H__
#define __ARCH_EVENTS_H__

#include <arch/pmu.h>

#define EVENTS_ARCH_CNTR_MAX_NUM PMU_CNTR_MAX_NUM

static inline ssize_t events_arch_cntr_alloc(void)
{
return pmu_cntr_alloc();
}

static inline void events_arch_cntr_free(size_t counter)
{
pmu_cntr_free(counter);
}

static inline void events_arch_configure_counter_partition(size_t mem_throt_reserved)
{
pmu_configure_counter_partition(mem_throt_reserved);
}

/* enable events */
static inline void events_arch_enable(void)
{
pmu_enable();
}

/* disable events */
static inline void events_arch_disable(void)
{
pmu_disable();
}

/* enable events counter */
static inline int events_arch_cntr_enable(size_t counter)
{
return pmu_cntr_enable(counter);
}

/* disable events counter */
static inline void events_arch_cntr_disable(size_t counter)
{
pmu_cntr_disable(counter);
}

/* set event counter value */
static inline void events_arch_cntr_set(size_t counter, unsigned long value)
{
pmu_cntr_set(counter, value);
}

/* get event counter value */
static inline uint64_t events_arch_get_cntr_value(size_t counter)
{
return pmu_cntr_get(counter);
}

/* define event to count */
static inline void events_arch_set_evtyper(size_t counter, size_t event)
{
pmu_set_evtyper(counter, event);
}

/*enable events interrupt*/
static inline void events_arch_interrupt_enable(cpuid_t cpu_id)
{
pmu_interrupt_enable(cpu_id);
}

/*disable events interrupt*/
static inline void events_arch_interrupt_disable(cpuid_t cpu_id)
{
pmu_interrupt_disable(cpu_id);
}

/* enable event counter interrupt */
static inline void events_arch_cntr_irq_enable(size_t counter)
{
pmu_set_cntr_irq_enable(counter);
}

/* disable event counter interrupt */
static inline void events_arch_cntr_irq_disable(size_t counter)
{
pmu_set_cntr_irq_disable(counter);
}

static inline void events_arch_clear_cntr_ovs(size_t counter)
{
pmu_clear_cntr_ovs(counter);
}

/* set event counter interrupt callback */
static inline void events_arch_cntr_set_irq_callback(irq_handler_t handler, size_t counter)
{
pmu_define_event_cntr_irq_callback(handler, counter);
}

#endif /* __ARCH_EVENTS_H__ */
14 changes: 11 additions & 3 deletions src/arch/armv8/inc/arch/generic_timer.h
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,11 @@
* Copyright (c) Bao Project and Contributors. All rights reserved.
*/

#ifndef GENERIC_TIMER_H
#define GENERIC_TIMER_H
#ifndef __ARCH_GENERIC_TIMER_H__
#define __ARCH_GENERIC_TIMER_H__

#include <bao.h>
#include <interrupts.h>

#define GENERIC_TIMER_CNTCTL_CNTCR_EN (0x1)

Expand All @@ -20,4 +21,11 @@ struct generic_timer_cntctrl {
uint32_t CounterID[12];
} __attribute__((packed, aligned(PAGE_SIZE)));

#endif /* GENERIC_TIMER_H */
uint64_t timer_arch_init(uint64_t period);
void timer_arch_enable(void);
void timer_arch_disable(void);
void timer_arch_define_irq_callback(irq_handler_t handler);
void timer_arch_reschedule_interrupt(uint64_t count);
uint64_t timer_arch_reschedule_interrupt_us(uint64_t period);

#endif /* __ARCH_GENERIC_TIMER_H__ */
5 changes: 5 additions & 0 deletions src/arch/armv8/inc/arch/platform.h
Original file line number Diff line number Diff line change
Expand Up @@ -33,8 +33,13 @@ struct arch_platform {
struct {
paddr_t base_addr;
uint32_t fixed_freq;
irqid_t interrupt_id;
} generic_timer;

struct {
irqid_t interrupt_id;
} events;

struct clusters {
size_t num;
size_t* core_num;
Expand Down
Loading
Loading