Support armv8.(TODO: fix clock)

This commit is contained in:
TXuian
2024-05-28 10:54:21 +08:00
parent 71cf0c667c
commit 6114b4618f
32 changed files with 148 additions and 464 deletions
@@ -1,3 +1,3 @@
SRC_FILES := gicv3.c gicv3_distributer.c
SRC_FILES := gicv3.c
include $(KERNEL_ROOT)/compiler.mk
@@ -1,3 +1,14 @@
/*
* Copyright (c) 2020 AIIT XUOS Lab
* XiUOS is licensed under Mulan PSL v2.
* You can use this software according to the terms and conditions of the Mulan PSL v2.
* You may obtain a copy of Mulan PSL v2 at:
* http://license.coscl.org.cn/MulanPSL2
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
* See the Mulan PSL v2 for more details.
*/
/**
* @file gicv3.c
* @brief gicv3 operation
@@ -25,47 +36,30 @@ static struct {
char* rdist_addrs[NR_CPU];
} gicv3;
static inline uint32_t
icc_igrpen1_el1()
static inline uint32_t icc_igrpen1_el1()
{
uint32_t x;
__asm__ volatile("mrs %0, S3_0_C12_C12_7" : "=r"(x));
return x;
}
static inline void
w_icc_igrpen1_el1(uint32_t x)
static inline void w_icc_igrpen1_el1(uint32_t x)
{
__asm__ volatile("msr S3_0_C12_C12_7, %0" : : "r"(x));
}
static inline uint32_t
icc_pmr_el1()
static inline uint32_t icc_pmr_el1()
{
uint32_t x;
__asm__ volatile("mrs %0, S3_0_C4_C6_0" : "=r"(x));
return x;
}
static inline void
w_icc_pmr_el1(uint32_t x)
static inline void w_icc_pmr_el1(uint32_t x)
{
__asm__ volatile("msr S3_0_C4_C6_0, %0" : : "r"(x));
}
// static inline uint32_t
// icc_iar1_el1()
// {
// uint32_t x;
// __asm__ volatile("mrs %0, S3_0_C12_C12_0" : "=r"(x));
// return x;
// }
// static inline void
// w_icc_eoir1_el1(uint32_t x)
// {
// __asm__ volatile("msr S3_0_C12_C12_1, %0" : : "r"(x));
// }
inline uint32_t gic_read_irq_ack()
{
uint32_t x;
@@ -79,53 +73,45 @@ gic_write_end_of_irq(uint32_t x)
__asm__ volatile("msr S3_0_C12_C12_1, %0" : : "r"(x));
}
static inline uint32_t
icc_sre_el1()
static inline uint32_t icc_sre_el1()
{
uint32_t x;
__asm__ volatile("mrs %0, S3_0_C12_C12_5" : "=r"(x));
return x;
}
static inline void
w_icc_sre_el1(uint32_t x)
static inline void w_icc_sre_el1(uint32_t x)
{
__asm__ volatile("msr S3_0_C12_C12_5, %0" : : "r"(x));
}
static void
gicd_write(uint32_t off, uint32_t val)
static void gicd_write(uint32_t off, uint32_t val)
{
*(volatile uint32_t*)(gicv3.gicd + off) = val;
}
static uint32_t
gicd_read(uint32_t off)
static uint32_t gicd_read(uint32_t off)
{
return *(volatile uint32_t*)(gicv3.gicd + off);
}
static void
gicr_write(uint32_t cpuid, uint32_t off, uint32_t val)
static void gicr_write(uint32_t cpuid, uint32_t off, uint32_t val)
{
*(volatile uint32_t*)(gicv3.rdist_addrs[cpuid] + off) = val;
}
static uint32_t
gicr_read(uint32_t cpuid, uint32_t off)
static uint32_t gicr_read(uint32_t cpuid, uint32_t off)
{
return *(volatile uint32_t*)(gicv3.rdist_addrs[cpuid] + off);
}
static void
giccinit()
static void giccinit()
{
w_icc_igrpen1_el1(0);
w_icc_pmr_el1(0xff);
}
static void
gicdinit()
static void gicdinit()
{
gicd_write(D_CTLR, 0);
@@ -136,8 +122,7 @@ gicdinit()
gicd_write(D_IGROUPR(i), ~0);
}
static void
gicrinit(uint32_t cpuid)
static void gicrinit(uint32_t cpuid)
{
gicr_write(cpuid, R_CTLR, 0);
@@ -32,59 +32,6 @@ Modification:
#include <mmio_access.h>
//! @addtogroup gic
//! @{
////////////////////////////////////////////////////////////////////////////////
// Definitions
////////////////////////////////////////////////////////////////////////////////
//! @brief Options for sending a software generated interrupt.
//!
//! These options are used for the @a filter_list parameter of the gic_send_sgi()
//! function. They control how to select which CPUs that the interrupt is
//! sent to.
enum _gicd_sgi_filter {
//! Forward the interrupt to the CPU interfaces specified in the @a target_list parameter.
kGicSgiFilter_UseTargetList = 0,
//! Forward the interrupt to all CPU interfaces except that of the processor that requested
//! the interrupt.
kGicSgiFilter_AllOtherCPUs = 1,
//! Forward the interrupt only to the CPU interface of the processor that requested the
//! interrupt.
kGicSgiFilter_OnlyThisCPU = 2
};
////////////////////////////////////////////////////////////////////////////////
// API
////////////////////////////////////////////////////////////////////////////////
#if defined(__cplusplus)
extern "C" {
#endif
__attribute__((__always_inline__)) static inline uint32_t get_arm_private_peripheral_base()
{
return MMIO_P2V(0x00A00000);
}
__attribute__((__always_inline__)) static inline uint32_t irq_get_register_offset(uint32_t irqID)
{
return irqID / 32;
}
__attribute__((__always_inline__)) static inline uint32_t irq_get_bit_offset(uint32_t irqID)
{
return irqID & 0x1f;
}
__attribute__((__always_inline__)) static inline uint32_t irq_get_bit_mask(uint32_t irqID)
{
return 1 << irq_get_bit_offset(irqID);
}
//! @name Initialization
//@{
//! @brief Init interrupt handling.
@@ -98,13 +45,6 @@ __attribute__((__always_inline__)) static inline uint32_t irq_get_bit_mask(uint3
//! that were pending are cleared, and all interrupts are made secure (group 0).
void gic_init(void);
//! @brief Init the current CPU's GIC interface.
//!
//! @post Enables the CPU interface and sets the priority mask to 255. Interrupt preemption
//! is disabled by setting the Binary Point to a value of 7.
void gic_init_cpu(void);
//@}
//! @name GIC Interrupt Distributor Functions
//@{
//! @brief Enable or disable the GIC Distributor.
@@ -192,10 +132,6 @@ uint32_t gic_read_irq_ack(void);
void gic_write_end_of_irq(uint32_t irq_id);
//@}
#if defined(__cplusplus)
}
#endif
//! @}
////////////////////////////////////////////////////////////////////////////////
@@ -1,77 +0,0 @@
/**
* @file gicv3_distributer.c
* @brief gicv3_distributer
* @version 1.0
* @author AIIT XUOS Lab
* @date 2024.05.10
*/
/*************************************************
File name: gicv3_distributer.c
Description: gicv3_distributer operation
Others:
History:
Author: AIIT XUOS Lab
Modification:
*************************************************/
#include "string.h"
#include "gicv3_common_opa.h"
#include "gicv3_registers.h"
static inline gicd_t* gic_get_gicd(void)
{
uint64_t base = get_arm_private_peripheral_base() + kGICDBaseOffset;
return (gicd_t*)base;
}
void gic_set_cpu_target(uint32_t irqID, unsigned cpuNumber, bool enableIt)
{
// Make sure the CPU number is valid.
gicd_t* gicd = gic_get_gicd();
uint8_t cpuMask = 1 << cpuNumber;
if (enableIt) {
gicd->ITARGETSRn[irqID] |= (cpuMask & 0xff);
} else {
gicd->ITARGETSRn[irqID] &= ~(cpuMask & 0xff);
}
}
void gic_set_irq_security(uint32_t irqID, bool isSecure)
{
gicd_t* gicd = gic_get_gicd();
uint32_t reg = irq_get_register_offset(irqID);
uint32_t mask = irq_get_bit_mask(irqID);
uint32_t value = gicd->IGROUPRn[reg];
if (!isSecure) {
value &= ~mask;
} else {
value |= mask;
}
gicd->IGROUPRn[reg] = value;
}
void gic_enable_irq(uint32_t irqID, bool isEnabled)
{
gicd_t* gicd = gic_get_gicd();
uint32_t reg = irq_get_register_offset(irqID);
uint32_t mask = irq_get_bit_mask(irqID);
// Select set-enable or clear-enable register based on enable flag.
if (isEnabled) {
gicd->ISENABLERn[reg] = mask;
} else {
gicd->ICENABLERn[reg] = mask;
}
}
void gic_set_irq_priority(uint32_t ID, uint32_t priority)
{
gicd_t* gicd = gic_get_gicd();
gicd->IPRIORITYRn[ID] = priority & 0xff;
}
@@ -24,15 +24,14 @@ Modification:
1. Rename the file
*************************************************/
#ifndef __LINUX_IRQCHIP_ARM_GIC_H
#define __LINUX_IRQCHIP_ARM_GIC_H
#pragma once
#include "memlayout.h"
// clang-format off
// interrupt controller GICv3
#define GICV3 (DEV_VRTMEM_BASE + 0x08000000L)
#define GICV3_REDIST (DEV_VRTMEM_BASE + 0x080a0000L)
#define GICV3 MMIO_P2V_WO(0x08000000ULL)
#define GICV3_REDIST MMIO_P2V_WO(0x080a0000ULL)
#define D_CTLR 0x0
#define D_TYPER 0x4
@@ -57,65 +56,4 @@ Modification:
#define R_ICFGR0 (SGI_BASE + 0xc00)
#define R_ICFGR1 (SGI_BASE + 0xc04)
#define R_IGRPMODR0 (SGI_BASE + 0xd00)
// clang-format on
#endif
#include <stdint.h>
enum _gic_base_offsets {
kGICDBaseOffset = 0x10000, //!< GIC distributor offset.
kGICCBaseOffset = 0x100 //!< GIC CPU interface offset.
};
//! @brief GIC distributor registers.
//!
//! Uses the GICv2 register names, but does not include GICv2 registers.
//!
//! The IPRIORITYRn and ITARGETSRn registers are byte accessible, so their types are uint8_t
//! instead of uint32_t to reflect this. These members are indexed directly with the interrupt
//! number.
struct _gicd_registers {
uint32_t CTLR; //!< Distributor Control Register.
uint32_t TYPER; //!< Interrupt Controller Type Register.
uint32_t IIDR; //!< Distributor Implementer Identification Register.
uint32_t _reserved0[29];
uint32_t IGROUPRn[8]; //!< Interrupt Group Registers.
uint32_t _reserved1[24];
uint32_t ISENABLERn[32]; //!< Interrupt Set-Enable Registers.
uint32_t ICENABLERn[32]; //!< Interrupt Clear-Enable Registers.
uint32_t ISPENDRn[32]; //!< Interrupt Set-Pending Registers.
uint32_t ICPENDRn[32]; //!< Interrupt Clear-Pending Registers.
uint32_t ICDABRn[32]; //!< Active Bit Registers.
uint32_t _reserved2[32];
uint8_t IPRIORITYRn[255 * sizeof(uint32_t)]; //!< Interrupt Priority Registers. (Byte accessible)
uint32_t _reserved3;
uint8_t ITARGETSRn[255 * sizeof(uint32_t)]; //!< Interrupt Processor Targets Registers. (Byte accessible)
uint32_t _reserved4;
uint32_t ICFGRn[64]; //!< Interrupt Configuration Registers.
uint32_t _reserved5[128];
uint32_t SGIR; //!< Software Generated Interrupt Register
};
//! @brief Bitfields constants for the GICD_CTLR register.
enum _gicd_ctlr_fields {
kBM_GICD_CTLR_EnableGrp1 = (1 << 1),
kBM_GICD_CTLR_EnableGrp0 = (1 << 0)
};
enum _gicd_sgir_fields {
kBP_GICD_SGIR_TargetListFilter = 24,
kBM_GICD_SGIR_TargetListFilter = (0x3 << kBP_GICD_SGIR_TargetListFilter),
kBP_GICD_SGIR_CPUTargetList = 16,
kBM_GICD_SGIR_CPUTargetList = (0xff << kBP_GICD_SGIR_CPUTargetList),
kBP_GICD_SGIR_NSATT = 15,
kBM_GICD_SGIR_NSATT = (1 << kBP_GICD_SGIR_NSATT),
kBP_GICD_SGIR_SGIINTID = 0,
kBM_GICD_SGIR_SGIINTID = 0xf
};
typedef volatile struct _gicd_registers gicd_t;
@@ -1,3 +1,14 @@
/*
* Copyright (c) 2020 AIIT XUOS Lab
* XiUOS is licensed under Mulan PSL v2.
* You can use this software according to the terms and conditions of the Mulan PSL v2.
* You may obtain a copy of Mulan PSL v2 at:
* http://license.coscl.org.cn/MulanPSL2
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
* See the Mulan PSL v2 for more details.
*/
/**
* @file exception_registers.h
* @brief exception registers
@@ -41,18 +41,20 @@ extern void iabort_handler(struct trapframe* r);
void kernel_abort_handler(struct trapframe* tf)
{
uint64_t esr = r_esr_el1();
switch ((esr >> 26) & 0x3F) {
switch ((esr >> 0x1A) & 0x3F) {
case 0b100100:
case 0b100101:
dabort_handler(tf);
break;
case 0b100000:
case 0b100001:
iabort_handler(tf);
break;
default:
uint64_t ec = (esr >> 26) & 0x3f;
uint64_t iss = esr & 0x1ffffff;
ERROR("esr %p %p %p\n", esr, ec, iss);
ERROR("elr = %p far = %p\n", r_elr_el1(), r_far_el1());
ERROR("esr: %016lx %016lx %016lx\n", esr, ec, iss);
ERROR("elr = %016lx far = %016lx\n", r_elr_el1(), r_far_el1());
ERROR("Current Task: %s.\n", cur_cpu()->task->name);
panic("Unimplemented Error Occured.\n");
}
@@ -67,11 +69,30 @@ void kernel_intr_handler(struct trapframe* tf)
extern void context_switch(struct context**, struct context*);
void syscall_arch_handler(struct trapframe* tf)
{
uint64_t ec = (r_esr_el1() >> 0x1A) & 0x3F;
if (ec == 0b010101) {
w_esr_el1(0);
uint64_t esr = r_esr_el1();
uint64_t ec = (esr >> 0x1A) & 0x3F;
w_esr_el1(0);
switch (ec) {
case 0B010101:
software_irq_dispatch(tf);
} else {
kernel_abort_handler(tf);
break;
case 0b100100:
case 0b100101:
dabort_handler(tf);
break;
case 0b100000:
case 0b100001:
iabort_handler(tf);
break;
default:
printf("USYSCALL: unexpected ec: %016lx", esr);
printf(" elr = %016lx far = %016lx\n", r_elr_el1(), r_far_el1());
// kill error task
xizi_enter_kernel();
assert(cur_cpu()->task != NULL);
sys_exit(cur_cpu()->task);
context_switch(&cur_cpu()->task->thread_context.context, cur_cpu()->scheduler);
panic("dabort end should never be reashed.\n");
}
}
@@ -37,13 +37,6 @@ Modification:
#include "log.h"
#include "multicores.h"
extern void init_stack(uint64_t, uint64_t);
extern void user_trap_swi_enter(void);
extern void trap_iabort(void);
extern void trap_dabort(void);
extern void trap_irq_enter(void);
extern void trap_undefined_instruction(void);
static struct XiziTrapDriver xizi_trap_driver;
void panic(char* s)
@@ -53,13 +46,6 @@ void panic(char* s)
;
}
/* stack for different mode*/
static char mode_stack_pages[NR_CPU][NR_MODE_STACKS][MODE_STACK_SIZE];
extern uint64_t _vector_jumper;
extern uint64_t _vector_start;
extern uint64_t _vector_end;
extern void alltraps();
static void _sys_irq_init(int cpu_id)
{
@@ -84,7 +70,7 @@ static void _cpu_irq_disable(void)
static void _single_irq_enable(int irq, int cpu, int prio)
{
gic_setup_spi(cpu, irq);
gic_setup_spi((uint32_t)cpu, (uint32_t)irq);
}
static void _single_irq_disable(int irq, int cpu)
@@ -33,7 +33,6 @@ Modification:
#include "core.h"
.macro savereg
msr daifset, #0xf
// make room to save registers.
sub sp, sp, #272
@@ -183,6 +182,7 @@ alltraps:
b .
el1sync:
msr daifset, #0xf
savereg
mov x0, sp
@@ -190,12 +190,16 @@ el1sync:
b .
el1irq:
savereg
msr daifset, #0xf
usavereg
mov x0, sp
# this should never happen by design
bl kernel_intr_handler
b .
bl intr_irq_dispatch
urestorereg
msr daifclr, #0xf
eret
el0sync:
msr daifset, #0xf