1
0
Fork 0
mirror of https://github.com/hermitcore/libhermit.git synced 2025-03-16 00:00:06 +01:00
libhermit/arch/aarch64/include/asm/processor.h
2018-07-02 20:05:49 +00:00

464 lines
12 KiB
C

/*
* Copyright (c) 2017, Stefan Lankes, RWTH Aachen University
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/**
* @author Stefan Lankes
* @file arch/arm64/include/asm/processor.h
* @brief CPU-specific functions
*
* This file contains structures and functions related to CPU-specific assembler commands.
*/
#ifndef __ARCH_PROCESSOR_H__
#define __ARCH_PROCESSOR_H__
#include <hermit/stddef.h>
#include <asm/irqflags.h>
#include <asm/atomic.h>
#ifdef __cplusplus
extern "C" {
#endif
#define ARMV8_PMCR_E (1 << 0) /* Enable all counters */
#define ARMV8_PMCR_P (1 << 1) /* Reset all counters */
#define ARMV8_PMCR_C (1 << 2) /* Cycle counter reset */
#define ARMV8_PMUSERENR_EN (1 << 0) /* EL0 access enable */
#define ARMV8_PMUSERENR_CR (1 << 2) /* Cycle counter read enable */
#define ARMV8_PMUSERENR_ER (1 << 3) /* Event counter read enable */
#define ARMV8_PMCNTENSET_EL0_EN (1 << 31) /* Performance Monitors Count Enable Set register */
/* interrupts */
#define INT_PPI_VMAINT (16+9)
#define INT_PPI_HYP_TIMER (16+10)
#define INT_PPI_VIRT_TIMER (16+11)
#define INT_PPI_SPHYS_TIMER (16+13)
#define INT_PPI_NSPHYS_TIMER (16+14)
// determine the cpu features
int cpu_detection(void);
inline static int has_hbmem(void) {
return 0;
}
inline static size_t get_hbmem_base(void) {
return 0;
}
inline static size_t get_hbmem_size(void) {
return 0;
}
static inline uint32_t get_isr(void)
{
uint32_t status;
asm volatile("mrs %0, isr_el1" : "=r"(status));
return status;
}
static inline uint32_t get_sctlr(void)
{
uint32_t status;
asm volatile("mrs %0, sctlr_el1" : "=r"(status));
return status;
}
static inline uint64_t get_elr(void)
{
uint64_t ret;
asm volatile("mrs %0, elr_el1" : "=r"(ret));
return ret;
}
/** @brief get the current exception level
*
* Helper function to get the current exception level
*
*/
static inline uint32_t get_current_el(void)
{
uint32_t curr;
asm volatile("mrs %0, CurrentEL" : "=r"(curr));
return (curr>>2) & 0x3;
}
/** @brief Get thread id register */
static inline size_t get_tpidr(void) {
uint64_t addr;
asm volatile("mrs %0, tpidr_el0" : "=r"(addr));
return addr;
}
/** @brief Set thread id register */
static inline void set_tpidr(size_t addr) {
asm volatile("msr tpidr_el0, %0" :: "r"(addr));
}
/** @brief Read id_aa64mmfr0_el1 register
* @return id_aa64mmfr0_el1's value
*/
static inline size_t read_id_aa64mmfr0(void) {
size_t val;
asm volatile("mrs %0, id_aa64mmfr0_el1" : "=r"(val) :: "memory");
return val;
}
/** @brief Read sctlr_el1 register
* @return sctlr_el1's value
*/
static inline size_t read_sctlr(void) {
size_t val;
asm volatile("mrs %0, sctlr_el1" : "=r"(val) :: "memory");
return val;
}
/** @brief Write a value into sctlr_el1 register
* @param val The value you want to write into sctlr_el1
*/
static inline void write_sctlr(size_t val) {
asm volatile("msr sctlr_el1, %0" :: "r"(val) : "memory");
}
/** @brief Read tcr_el1 register
* @return tcr_el1's value
*/
static inline size_t read_tcr(void) {
size_t val;
asm volatile("mrs %0, tcr_el1" : "=r"(val) :: "memory");
return val;
}
/** @brief Write a value into tcr_el1 register
* @param val The value you want to write into tcr_el1
*/
static inline void write_tcr(size_t val) {
asm volatile("msr tcr_el1, %0" :: "r"(val) : "memory");
}
/** @brief Read mair_el1 register
* @return mair_el1's value
*/
static inline size_t read_mair(void) {
size_t val;
asm volatile("mrs %0, mair_el1" : "=r"(val) :: "memory");
return val;
}
/** @brief Write a value into mair_el1 register
* @param val The value you want to write into mair_el1
*/
static inline void write_mair(size_t val) {
asm volatile("msr mair_el1, %0" :: "r"(val) : "memory");
}
/** @brief Read ttbr0_el1 register
* @return ttbr0_el1's value
*/
static inline size_t get_ttbr0(void) {
size_t val;
asm volatile("mrs %0, ttbr0_el1" : "=r"(val) :: "memory");
return val;
}
/** @brief Write a value into ttbr0_el1 register
* @param val The value you want to write into ttbr0_el1
*/
static inline void set_ttbr0(size_t val) {
asm volatile("msr ttbr0_el1, %0" :: "r"(val) : "memory");
}
/** @brief Read ttbr1_el1 register
* @return ttbr1_el1's value
*/
static inline size_t get_ttbr1(void) {
size_t val;
asm volatile("mrs %0, ttbr1_el1" : "=r"(val) :: "memory");
return val;
}
/** @brief Write a value into ttbr1_el1 register
* @param val The value you want to write into ttbr1_el1
*/
static inline void set_ttbr1(size_t val) {
asm volatile("msr ttbr1_el1, %0" :: "r"(val) : "memory");
}
/** @brief Read far_el1 register
* @return faulting virtual address
*/
static inline size_t read_far(void) {
size_t val = 0;
asm volatile("mrs %0, far_el1" : "=r"(val) :: "memory");
return val;
}
/** @brief Read esr_el1 register
* @return esr_el1's (Exception Syndrome Register) value
*/
static inline size_t read_esr(void) {
size_t val;
asm volatile("mrs %0, esr_el1" : "=r"(val) :: "memory");
return val;
}
static inline uint64_t get_cntpct(void)
{
uint64_t value;
asm volatile("mrs %0, cntpct_el0" : "=r" (value) :: "memory");
return value;
}
static inline uint64_t get_mpidr(void)
{
uint64_t value;
asm volatile("mrs %0, mpidr_el1" : "=r"(value) :: "memory");
return value;
}
static inline uint64_t get_cpuactlr(void)
{
uint64_t value;
asm volatile("mrs %0, s3_1_c15_c2_0" : "=r"(value) :: "memory");
return value;
}
static inline uint64_t get_cpuectlr(void)
{
uint64_t value;
asm volatile("mrs %0, s3_1_c15_c2_1" : "=r"(value) :: "memory");
return value;
}
inline static uint64_t get_rdtsc(void) { return get_cntpct(); }
/// A one-instruction-do-nothing
#define NOP asm volatile ("nop")
/// The PAUSE instruction provides a hint to the processor that the code sequence is a spin-wait loop.
#define PAUSE asm volatile ("yield")
/// The HALT instruction stops the processor until the next interrupt arrives
#define HALT asm volatile ("wfi")
/// Force strict CPU ordering, serializes load and store operations.
static inline void mb(void) { asm volatile ("dmb ish" : : : "memory"); }
/// Force strict CPU ordering, serializes load operations.
static inline void rmb(void) { asm volatile ("dmb ishld" : : : "memory"); }
/// Force strict CPU ordering, serializes store operations.
static inline void wmb(void) { asm volatile ("dmb ishst" : : : "memory"); }
/** @brief search the first most significant bit
*
* @param i source operand
* @return
* - first bit, which is set in the source operand
* - invalid value, if not bit ist set
*/
static inline size_t msb(size_t i) {
size_t ret, tmp = 63;
if (!i)
return (sizeof(size_t)*8);
asm volatile (
"clz %0, %1\n\t"
"sub %0, %2, %0"
: "=r"(ret)
: "r"(i), "r"(tmp)
: "cc");
return ret;
}
static inline uint32_t get_cntfrq(void)
{
uint32_t val;
asm volatile("mrs %0, cntfrq_el0" : "=r" (val) :: "memory");
return val;
}
static inline void set_cntfrq(uint32_t value)
{
asm volatile("msr cntfrq_el0, %0" :: "r"(value) : "memory");
}
static inline uint32_t get_cntkctl(void)
{
uint32_t value;
asm volatile("mrs %0, cntkctl_el1" : "=r" (value) :: "memory");
return value;
}
static inline void set_cntkctl(uint32_t value)
{
asm volatile("msr cntkctl_el1, %0" :: "r" (value) : "memory");
}
static inline void set_cntp_cval(uint64_t value)
{
asm volatile("msr cntp_cval_el0, %0" :: "r"(value) : "memory");
}
static inline uint64_t get_cntp_cval(void)
{
uint64_t value;
asm volatile("mrs %0, cntp_cval_el0" : "=r" (value) :: "memory");
return value;
}
static inline void set_cntp_tval(uint64_t value)
{
asm volatile("msr cntp_tval_el0, %0" :: "r"(value) : "memory");
}
static inline uint64_t get_cntp_tval(void)
{
uint64_t value;
asm volatile("mrs %0, cntp_tval_el0" : "=r" (value) :: "memory");
return value;
}
static inline void set_cntp_ctl(uint32_t value)
{
asm volatile("msr cntp_ctl_el0, %0" :: "r"(value) : "memory");
}
static inline uint32_t get_cntp_ctl(void)
{
uint32_t value;
asm volatile("mrs %0, cntp_ctl_el0" : "=r" (value) :: "memory");
return value;
}
static inline uint64_t get_cntvct(void)
{
uint64_t value;
asm volatile("mrs %0, cntvct_el0" : "=r" (value) :: "memory");
return value;
}
static inline void set_cntv_cval(uint64_t value)
{
asm volatile("msr cntv_cval_el0, %0" :: "r"(value) : "memory");
}
static inline uint64_t get_cntv_cval(void)
{
uint64_t value;
asm volatile("mrs %0, cntv_cval_el0" : "=r" (value) :: "memory");
return value;
}
static inline void set_cntv_tval(uint64_t value)
{
asm volatile("msr cntv_tval_el0, %0" :: "r"(value) : "memory");
}
static inline uint64_t get_cntv_tval(void)
{
uint64_t value;
asm volatile("mrs %0, cntv_tval_el0" : "=r" (value) :: "memory");
return value;
}
static inline void set_cntv_ctl(uint32_t value)
{
asm volatile("msr cntv_ctl_el0, %0" :: "r"(value) : "memory");
}
static inline uint32_t get_cntv_ctl(void)
{
uint32_t value;
asm volatile("mrs %0, cntv_ctl_el0" : "=r" (value) :: "memory");
return value;
}
/** @brief Init several subsystems
*
* This function calls the initialization procedures for:
* - GDT
* - APIC
* - PCI [if configured]
*
* @return 0 in any case
*/
inline static int system_init(void)
{
cpu_detection();
return 0;
}
/** @brief Detect and read out CPU frequency
*
* @return The CPU frequency in MHz
*/
uint32_t detect_cpu_frequency(void);
/** @brief Read out CPU frequency if detected before
*
* If you did not issue the detect_cpu_frequency() function before,
* this function will call it implicitly.
*
* @return The CPU frequency in MHz
*/
uint32_t get_cpu_frequency(void);
/** @brief Busywait an microseconds interval of time
* @param usecs The time to wait in microseconds
*/
void udelay(uint32_t usecs);
/// Finalize the GIC initialization
int irq_post_init(void);
/// Sets up the system clock
int timer_calibration(void);
extern atomic_int32_t cpu_online;
/** @brief System calibration
*
* This procedure will detect the CPU frequency and calibrate the APIC timer.
*
* @return 0 in any case.
*/
static inline int system_calibration(void)
{
irq_post_init();
timer_calibration();
atomic_int32_inc(&cpu_online);
irq_enable();
return 0;
}
#ifdef __cplusplus
}
#endif
#endif