interrupt and timer
This commit is contained in:
parent
6b34443bee
commit
1eed961317
@ -55,7 +55,7 @@ env.Append(CFLAGS = [ "-Wshadow", "-Wno-typedef-redefinition" ])
|
||||
if env["ARCH"] == "amd64":
|
||||
env.Append(CPPFLAGS = [ "-target", "x86_64-freebsd-freebsd-elf" ])
|
||||
elif env["ARCH"] == "arm64":
|
||||
env.Append(CPPFLAGS = [ "-target", "arm64-freebsd-freebsd-elf" ])
|
||||
env.Append(CPPFLAGS = [ "-target", "arm64-freebsd-freebsd-elf", "-ffixed-x18" ,"-march=armv8-a+lse"])
|
||||
env.Append(LINKFLAGS = [ "-fuse-ld=lld", "-Wl,-maarch64elf" ])
|
||||
else:
|
||||
print("Unsupported architecture: " + env["ARCH"])
|
||||
|
255
include/stdatomic.h
Normal file
255
include/stdatomic.h
Normal file
@ -0,0 +1,255 @@
|
||||
/* Copyright (C) 2013-2024 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GCC.
|
||||
|
||||
GCC is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 3, or (at your option)
|
||||
any later version.
|
||||
|
||||
GCC is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
Under Section 7 of GPL version 3, you are granted additional
|
||||
permissions described in the GCC Runtime Library Exception, version
|
||||
3.1, as published by the Free Software Foundation.
|
||||
|
||||
You should have received a copy of the GNU General Public License and
|
||||
a copy of the GCC Runtime Library Exception along with this program;
|
||||
see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
|
||||
<http://www.gnu.org/licenses/>. */
|
||||
|
||||
/* ISO C11 Standard: 7.17 Atomics <stdatomic.h>. */
|
||||
|
||||
#ifndef _STDATOMIC_H
|
||||
#define _STDATOMIC_H
|
||||
|
||||
typedef enum
|
||||
{
|
||||
memory_order_relaxed = __ATOMIC_RELAXED,
|
||||
memory_order_consume = __ATOMIC_CONSUME,
|
||||
memory_order_acquire = __ATOMIC_ACQUIRE,
|
||||
memory_order_release = __ATOMIC_RELEASE,
|
||||
memory_order_acq_rel = __ATOMIC_ACQ_REL,
|
||||
memory_order_seq_cst = __ATOMIC_SEQ_CST
|
||||
} memory_order;
|
||||
|
||||
|
||||
typedef _Atomic _Bool atomic_bool;
|
||||
typedef _Atomic char atomic_char;
|
||||
typedef _Atomic signed char atomic_schar;
|
||||
typedef _Atomic unsigned char atomic_uchar;
|
||||
typedef _Atomic short atomic_short;
|
||||
typedef _Atomic unsigned short atomic_ushort;
|
||||
typedef _Atomic int atomic_int;
|
||||
typedef _Atomic unsigned int atomic_uint;
|
||||
typedef _Atomic long atomic_long;
|
||||
typedef _Atomic unsigned long atomic_ulong;
|
||||
typedef _Atomic long long atomic_llong;
|
||||
typedef _Atomic unsigned long long atomic_ullong;
|
||||
#ifdef __CHAR8_TYPE__
|
||||
typedef _Atomic __CHAR8_TYPE__ atomic_char8_t;
|
||||
#endif
|
||||
typedef _Atomic __CHAR16_TYPE__ atomic_char16_t;
|
||||
typedef _Atomic __CHAR32_TYPE__ atomic_char32_t;
|
||||
typedef _Atomic __WCHAR_TYPE__ atomic_wchar_t;
|
||||
typedef _Atomic __INT_LEAST8_TYPE__ atomic_int_least8_t;
|
||||
typedef _Atomic __UINT_LEAST8_TYPE__ atomic_uint_least8_t;
|
||||
typedef _Atomic __INT_LEAST16_TYPE__ atomic_int_least16_t;
|
||||
typedef _Atomic __UINT_LEAST16_TYPE__ atomic_uint_least16_t;
|
||||
typedef _Atomic __INT_LEAST32_TYPE__ atomic_int_least32_t;
|
||||
typedef _Atomic __UINT_LEAST32_TYPE__ atomic_uint_least32_t;
|
||||
typedef _Atomic __INT_LEAST64_TYPE__ atomic_int_least64_t;
|
||||
typedef _Atomic __UINT_LEAST64_TYPE__ atomic_uint_least64_t;
|
||||
typedef _Atomic __INT_FAST8_TYPE__ atomic_int_fast8_t;
|
||||
typedef _Atomic __UINT_FAST8_TYPE__ atomic_uint_fast8_t;
|
||||
typedef _Atomic __INT_FAST16_TYPE__ atomic_int_fast16_t;
|
||||
typedef _Atomic __UINT_FAST16_TYPE__ atomic_uint_fast16_t;
|
||||
typedef _Atomic __INT_FAST32_TYPE__ atomic_int_fast32_t;
|
||||
typedef _Atomic __UINT_FAST32_TYPE__ atomic_uint_fast32_t;
|
||||
typedef _Atomic __INT_FAST64_TYPE__ atomic_int_fast64_t;
|
||||
typedef _Atomic __UINT_FAST64_TYPE__ atomic_uint_fast64_t;
|
||||
typedef _Atomic __INTPTR_TYPE__ atomic_intptr_t;
|
||||
typedef _Atomic __UINTPTR_TYPE__ atomic_uintptr_t;
|
||||
typedef _Atomic __SIZE_TYPE__ atomic_size_t;
|
||||
typedef _Atomic __PTRDIFF_TYPE__ atomic_ptrdiff_t;
|
||||
typedef _Atomic __INTMAX_TYPE__ atomic_intmax_t;
|
||||
typedef _Atomic __UINTMAX_TYPE__ atomic_uintmax_t;
|
||||
|
||||
|
||||
#if !(defined __STDC_VERSION__ && __STDC_VERSION__ > 201710L)
|
||||
#define ATOMIC_VAR_INIT(VALUE) (VALUE)
|
||||
#endif
|
||||
|
||||
/* Initialize an atomic object pointed to by PTR with VAL. */
|
||||
#define atomic_init(PTR, VAL) \
|
||||
atomic_store_explicit (PTR, VAL, __ATOMIC_RELAXED)
|
||||
|
||||
#define kill_dependency(Y) \
|
||||
__extension__ \
|
||||
({ \
|
||||
__auto_type __kill_dependency_tmp = (Y); \
|
||||
__kill_dependency_tmp; \
|
||||
})
|
||||
|
||||
extern void atomic_thread_fence (memory_order);
|
||||
#define atomic_thread_fence(MO) __atomic_thread_fence (MO)
|
||||
extern void atomic_signal_fence (memory_order);
|
||||
#define atomic_signal_fence(MO) __atomic_signal_fence (MO)
|
||||
#define atomic_is_lock_free(OBJ) __atomic_is_lock_free (sizeof (*(OBJ)), (OBJ))
|
||||
|
||||
#define ATOMIC_BOOL_LOCK_FREE __GCC_ATOMIC_BOOL_LOCK_FREE
|
||||
#define ATOMIC_CHAR_LOCK_FREE __GCC_ATOMIC_CHAR_LOCK_FREE
|
||||
#ifdef __GCC_ATOMIC_CHAR8_T_LOCK_FREE
|
||||
#define ATOMIC_CHAR8_T_LOCK_FREE __GCC_ATOMIC_CHAR8_T_LOCK_FREE
|
||||
#endif
|
||||
#define ATOMIC_CHAR16_T_LOCK_FREE __GCC_ATOMIC_CHAR16_T_LOCK_FREE
|
||||
#define ATOMIC_CHAR32_T_LOCK_FREE __GCC_ATOMIC_CHAR32_T_LOCK_FREE
|
||||
#define ATOMIC_WCHAR_T_LOCK_FREE __GCC_ATOMIC_WCHAR_T_LOCK_FREE
|
||||
#define ATOMIC_SHORT_LOCK_FREE __GCC_ATOMIC_SHORT_LOCK_FREE
|
||||
#define ATOMIC_INT_LOCK_FREE __GCC_ATOMIC_INT_LOCK_FREE
|
||||
#define ATOMIC_LONG_LOCK_FREE __GCC_ATOMIC_LONG_LOCK_FREE
|
||||
#define ATOMIC_LLONG_LOCK_FREE __GCC_ATOMIC_LLONG_LOCK_FREE
|
||||
#define ATOMIC_POINTER_LOCK_FREE __GCC_ATOMIC_POINTER_LOCK_FREE
|
||||
|
||||
|
||||
/* Note that these macros require __auto_type to remove
|
||||
_Atomic qualifiers (and const qualifiers, if those are valid on
|
||||
macro operands).
|
||||
|
||||
Also note that the header file uses the generic form of __atomic
|
||||
builtins, which requires the address to be taken of the value
|
||||
parameter, and then we pass that value on. This allows the macros
|
||||
to work for any type, and the compiler is smart enough to convert
|
||||
these to lock-free _N variants if possible, and throw away the
|
||||
temps. */
|
||||
|
||||
#define atomic_store_explicit(PTR, VAL, MO) \
|
||||
__extension__ \
|
||||
({ \
|
||||
__auto_type __atomic_store_ptr = (PTR); \
|
||||
__typeof__ ((void)0, *__atomic_store_ptr) __atomic_store_tmp = (VAL); \
|
||||
__atomic_store (__atomic_store_ptr, &__atomic_store_tmp, (MO)); \
|
||||
})
|
||||
|
||||
#define atomic_store(PTR, VAL) \
|
||||
atomic_store_explicit (PTR, VAL, __ATOMIC_SEQ_CST)
|
||||
|
||||
|
||||
#define atomic_load_explicit(PTR, MO) \
|
||||
__extension__ \
|
||||
({ \
|
||||
__auto_type __atomic_load_ptr = (PTR); \
|
||||
__typeof__ ((void)0, *__atomic_load_ptr) __atomic_load_tmp; \
|
||||
__atomic_load (__atomic_load_ptr, &__atomic_load_tmp, (MO)); \
|
||||
__atomic_load_tmp; \
|
||||
})
|
||||
|
||||
#define atomic_load(PTR) atomic_load_explicit (PTR, __ATOMIC_SEQ_CST)
|
||||
|
||||
|
||||
#define atomic_exchange_explicit(PTR, VAL, MO) \
|
||||
__extension__ \
|
||||
({ \
|
||||
__auto_type __atomic_exchange_ptr = (PTR); \
|
||||
__typeof__ ((void)0, *__atomic_exchange_ptr) __atomic_exchange_val = (VAL); \
|
||||
__typeof__ ((void)0, *__atomic_exchange_ptr) __atomic_exchange_tmp; \
|
||||
__atomic_exchange (__atomic_exchange_ptr, &__atomic_exchange_val, \
|
||||
&__atomic_exchange_tmp, (MO)); \
|
||||
__atomic_exchange_tmp; \
|
||||
})
|
||||
|
||||
#define atomic_exchange(PTR, VAL) \
|
||||
atomic_exchange_explicit (PTR, VAL, __ATOMIC_SEQ_CST)
|
||||
|
||||
|
||||
#define atomic_compare_exchange_strong_explicit(PTR, VAL, DES, SUC, FAIL) \
|
||||
__extension__ \
|
||||
({ \
|
||||
__auto_type __atomic_compare_exchange_ptr = (PTR); \
|
||||
__typeof__ ((void)0, *__atomic_compare_exchange_ptr) __atomic_compare_exchange_tmp \
|
||||
= (DES); \
|
||||
__atomic_compare_exchange (__atomic_compare_exchange_ptr, (VAL), \
|
||||
&__atomic_compare_exchange_tmp, 0, \
|
||||
(SUC), (FAIL)); \
|
||||
})
|
||||
|
||||
#define atomic_compare_exchange_strong(PTR, VAL, DES) \
|
||||
atomic_compare_exchange_strong_explicit (PTR, VAL, DES, __ATOMIC_SEQ_CST, \
|
||||
__ATOMIC_SEQ_CST)
|
||||
|
||||
#define atomic_compare_exchange_weak_explicit(PTR, VAL, DES, SUC, FAIL) \
|
||||
__extension__ \
|
||||
({ \
|
||||
__auto_type __atomic_compare_exchange_ptr = (PTR); \
|
||||
__typeof__ ((void)0, *__atomic_compare_exchange_ptr) __atomic_compare_exchange_tmp \
|
||||
= (DES); \
|
||||
__atomic_compare_exchange (__atomic_compare_exchange_ptr, (VAL), \
|
||||
&__atomic_compare_exchange_tmp, 1, \
|
||||
(SUC), (FAIL)); \
|
||||
})
|
||||
|
||||
#define atomic_compare_exchange_weak(PTR, VAL, DES) \
|
||||
atomic_compare_exchange_weak_explicit (PTR, VAL, DES, __ATOMIC_SEQ_CST, \
|
||||
__ATOMIC_SEQ_CST)
|
||||
|
||||
|
||||
|
||||
#define atomic_fetch_add(PTR, VAL) __atomic_fetch_add ((PTR), (VAL), \
|
||||
__ATOMIC_SEQ_CST)
|
||||
#define atomic_fetch_add_explicit(PTR, VAL, MO) \
|
||||
__atomic_fetch_add ((PTR), (VAL), (MO))
|
||||
|
||||
#define atomic_fetch_sub(PTR, VAL) __atomic_fetch_sub ((PTR), (VAL), \
|
||||
__ATOMIC_SEQ_CST)
|
||||
#define atomic_fetch_sub_explicit(PTR, VAL, MO) \
|
||||
__atomic_fetch_sub ((PTR), (VAL), (MO))
|
||||
|
||||
#define atomic_fetch_or(PTR, VAL) __atomic_fetch_or ((PTR), (VAL), \
|
||||
__ATOMIC_SEQ_CST)
|
||||
#define atomic_fetch_or_explicit(PTR, VAL, MO) \
|
||||
__atomic_fetch_or ((PTR), (VAL), (MO))
|
||||
|
||||
#define atomic_fetch_xor(PTR, VAL) __atomic_fetch_xor ((PTR), (VAL), \
|
||||
__ATOMIC_SEQ_CST)
|
||||
#define atomic_fetch_xor_explicit(PTR, VAL, MO) \
|
||||
__atomic_fetch_xor ((PTR), (VAL), (MO))
|
||||
|
||||
#define atomic_fetch_and(PTR, VAL) __atomic_fetch_and ((PTR), (VAL), \
|
||||
__ATOMIC_SEQ_CST)
|
||||
#define atomic_fetch_and_explicit(PTR, VAL, MO) \
|
||||
__atomic_fetch_and ((PTR), (VAL), (MO))
|
||||
|
||||
|
||||
typedef _Atomic struct
|
||||
{
|
||||
#if __GCC_ATOMIC_TEST_AND_SET_TRUEVAL == 1
|
||||
_Bool __val;
|
||||
#else
|
||||
unsigned char __val;
|
||||
#endif
|
||||
} atomic_flag;
|
||||
|
||||
#define ATOMIC_FLAG_INIT { 0 }
|
||||
|
||||
|
||||
extern _Bool atomic_flag_test_and_set (volatile atomic_flag *);
|
||||
#define atomic_flag_test_and_set(PTR) \
|
||||
__atomic_test_and_set ((PTR), __ATOMIC_SEQ_CST)
|
||||
extern _Bool atomic_flag_test_and_set_explicit (volatile atomic_flag *,
|
||||
memory_order);
|
||||
#define atomic_flag_test_and_set_explicit(PTR, MO) \
|
||||
__atomic_test_and_set ((PTR), (MO))
|
||||
|
||||
extern void atomic_flag_clear (volatile atomic_flag *);
|
||||
#define atomic_flag_clear(PTR) __atomic_clear ((PTR), __ATOMIC_SEQ_CST)
|
||||
extern void atomic_flag_clear_explicit (volatile atomic_flag *, memory_order);
|
||||
#define atomic_flag_clear_explicit(PTR, MO) __atomic_clear ((PTR), (MO))
|
||||
|
||||
#if defined __STDC_VERSION__ && __STDC_VERSION__ > 201710L
|
||||
#define __STDC_VERSION_STDATOMIC_H__ 202311L
|
||||
#endif
|
||||
|
||||
#endif /* _STDATOMIC_H */
|
@ -43,7 +43,7 @@ src_arm64 = [
|
||||
# ARM64
|
||||
"arm64/debug.c",
|
||||
"arm64/disasm.c",
|
||||
"arm64/irq.c",
|
||||
"arm64/trap.c",
|
||||
"arm64/machine.c",
|
||||
"arm64/mp.c",
|
||||
"arm64/pci.c",
|
||||
@ -51,13 +51,12 @@ src_arm64 = [
|
||||
"arm64/support.S",
|
||||
"arm64/switch.S",
|
||||
"arm64/thread.c",
|
||||
"arm64/time.c",
|
||||
"arm64/trap.c",
|
||||
"arm64/timer.c",
|
||||
"arm64/trapentry.S",
|
||||
"arm64/pdcache.c",
|
||||
"arm64/gic.c",
|
||||
# Devices
|
||||
"dev/arm64/uart.c",
|
||||
"dev/arm64/gic.c",
|
||||
# Metal
|
||||
"arm64/metal.c",
|
||||
"arm64/paging.c",
|
||||
|
@ -69,6 +69,7 @@ Debug_Breakpoint(TrapFrame *tf)
|
||||
frames[CPU()] = tf;
|
||||
|
||||
// Should probably force all cores into the debugger
|
||||
|
||||
while(atomic_swap_uint64(&debugLock, 1) == 1) {
|
||||
// Wait to acquire debugger lock
|
||||
}
|
||||
|
@ -57,7 +57,7 @@ PMap_Init()
|
||||
systemAS.tables = PAGETABLE_ENTRIES / 2 + 1;
|
||||
systemAS.mappings = 0;
|
||||
if (!systemAS.root)
|
||||
PANIC("Cannot allocate system page table");
|
||||
Panic("Cannot allocate system page table");
|
||||
|
||||
for (i = 0; i < PAGETABLE_ENTRIES / 2; i++)
|
||||
systemAS.root->entries[i] = 0;
|
||||
@ -66,7 +66,7 @@ PMap_Init()
|
||||
PageTable *pgtbl = PAlloc_AllocPage();
|
||||
PageEntry pte = DMVA2PA((uint64_t)pgtbl) | PTE_W | PTE_P;
|
||||
if (!pgtbl)
|
||||
PANIC("Not enough memory!");
|
||||
Panic("Not enough memory!");
|
||||
|
||||
systemAS.root->entries[i] = pte;
|
||||
|
||||
|
@ -1,6 +1,7 @@
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <stdatomic.h>
|
||||
|
||||
#include <sys/kassert.h>
|
||||
#include <sys/kconfig.h>
|
||||
@ -9,7 +10,6 @@
|
||||
|
||||
#include <machine/cpu.h>
|
||||
#include <machine/cpuop.h>
|
||||
#include <machine/atomic.h>
|
||||
#include <machine/trap.h>
|
||||
#include <machine/mp.h>
|
||||
|
||||
@ -49,8 +49,8 @@ Debug_ResumeCPUs()
|
||||
void
|
||||
Debug_HaltIPI(TrapFrame *tf)
|
||||
{
|
||||
MP_SetState(CPUSTATE_HALTED);
|
||||
__sync_fetch_and_add(&debugHalted, 1);
|
||||
MP_GetCPUState()->state = CPUSTATE_HALTED;
|
||||
atomic_fetch_add(&debugHalted, 1);
|
||||
|
||||
frames[CPU()] = tf;
|
||||
|
||||
@ -58,8 +58,8 @@ Debug_HaltIPI(TrapFrame *tf)
|
||||
pause();
|
||||
}
|
||||
|
||||
__sync_fetch_and_sub(&debugHalted, 1);
|
||||
MP_SetState(CPUSTATE_BOOTED);
|
||||
atomic_fetch_sub(&debugHalted, 1);
|
||||
MP_GetCPUState()->state = CPUSTATE_BOOTED;
|
||||
}
|
||||
|
||||
void
|
||||
@ -68,7 +68,7 @@ Debug_Breakpoint(TrapFrame *tf)
|
||||
frames[CPU()] = tf;
|
||||
|
||||
// Should probably force all cores into the debugger
|
||||
while(atomic_swap_uint64(&debugLock, 1) == 1) {
|
||||
while(atomic_exchange(&debugLock, 1) == 1) {
|
||||
// Wait to acquire debugger lock
|
||||
}
|
||||
|
||||
@ -80,7 +80,7 @@ Debug_Breakpoint(TrapFrame *tf)
|
||||
|
||||
// Resume all processors
|
||||
Debug_ResumeCPUs();
|
||||
atomic_set_uint64(&debugLock, 0);
|
||||
atomic_store(&debugLock, 0);
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -1,9 +1,11 @@
|
||||
#include <machine/pmap.h>
|
||||
#include <machine/cpuop.h>
|
||||
#include <machine/mp.h>
|
||||
#include <machine/bootinfo.h>
|
||||
#include <sys/cdefs.h>
|
||||
#include <errno.h>
|
||||
#include <sys/kassert.h>
|
||||
#include "gic.h"
|
||||
#include <machine/gic.h>
|
||||
|
||||
#include <sys/contrib/libfdt/libfdt.h>
|
||||
|
||||
@ -217,14 +219,14 @@ static struct gic gic = {
|
||||
.max_rd = 0
|
||||
};
|
||||
|
||||
static bool
|
||||
static int
|
||||
gic_discover(void)
|
||||
{
|
||||
const void * dtb = kbootinfo.dtb_addr;
|
||||
const int offset = fdt_node_offset_by_compatible(dtb, -1, "arm,gic-v3");
|
||||
|
||||
if (offset < 0) {
|
||||
return false;
|
||||
return ENOENT;
|
||||
}
|
||||
|
||||
int lenp;
|
||||
@ -232,7 +234,7 @@ gic_discover(void)
|
||||
|
||||
if (prop == NULL || lenp != 8 * sizeof(uint32_t)) {
|
||||
// invalid gicv3 dtb spec
|
||||
return false;
|
||||
return EINVAL;
|
||||
}
|
||||
|
||||
const uint32_t * ptr = (const uint32_t *)prop->data;
|
||||
@ -252,7 +254,7 @@ gic_discover(void)
|
||||
|
||||
gic.max_rd = index;
|
||||
|
||||
return true;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
@ -268,32 +270,18 @@ gic_enable(void)
|
||||
// enable all interrupt groups and routing, disable security
|
||||
|
||||
// set SRE bits to enable system registers
|
||||
__asm__ volatile (
|
||||
"mrs x0, ICC_SRE_EL1;"
|
||||
"orr x0, x0, #0x1;"
|
||||
"msr ICC_SRE_EL1, x0;"
|
||||
:
|
||||
:
|
||||
: "x0"
|
||||
);
|
||||
}
|
||||
uint64_t sre = SYSREG_GET(ICC_SRE_EL1);
|
||||
sre |= 1;
|
||||
SYSREG_SET(ICC_SRE_EL1, sre);
|
||||
|
||||
uint32_t
|
||||
gic_get_affinity(void)
|
||||
{
|
||||
uint64_t aff;
|
||||
|
||||
__asm__ volatile (
|
||||
"MRS x0, MPIDR_EL1;"
|
||||
"UBFX x1, x0, #32, #8;"
|
||||
"BFI w0, w1, #24, #8;"
|
||||
"MOV %0, x0;"
|
||||
: "=r" (aff)
|
||||
:
|
||||
: "x0", "x1"
|
||||
);
|
||||
|
||||
return aff;
|
||||
// __asm__ volatile (
|
||||
// "mrs x0, ICC_SRE_EL1;"
|
||||
// "orr x0, x0, #0x1;"
|
||||
// "msr ICC_SRE_EL1, x0;"
|
||||
// :
|
||||
// :
|
||||
// : "x0"
|
||||
// );
|
||||
}
|
||||
|
||||
int
|
||||
@ -366,9 +354,10 @@ gic_is_valid_extppi(uint32_t rd, uint32_t ID)
|
||||
|
||||
|
||||
int
|
||||
gic_disable_intr(uint32_t rd, uint32_t intid)
|
||||
gic_disable_intr(uint32_t intid)
|
||||
{
|
||||
uint32_t bank;
|
||||
const uint32_t rd = MP_GetCPUState()->gic_redist_id;
|
||||
|
||||
if (rd > gic.max_rd)
|
||||
return EINVAL;
|
||||
@ -417,102 +406,6 @@ gic_disable_intr(uint32_t rd, uint32_t intid)
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
gic_enable_intr(uint32_t rdid, uint32_t intid)
|
||||
{
|
||||
uint32_t bank;
|
||||
|
||||
if (rdid > gic.max_rd) {
|
||||
return EINVAL;
|
||||
}
|
||||
|
||||
if (intid < 31) {
|
||||
// SGI or PPI
|
||||
gic.gic_rdist[rdid].sgis.GICR_ISENABLER[0] = (1 << intid);
|
||||
} else if (intid < 1020) {
|
||||
// SPI
|
||||
bank = intid/32; // There are 32 IDs per register, need to work out which register to access
|
||||
intid = intid & 0x1f; // ... and which bit within the register
|
||||
intid = 1 << intid; // Move a '1' into the correct bit position
|
||||
gic.gic_dist->GICD_ISENABLER[bank] = intid;
|
||||
} else if ((intid > 1055) && (intid < 1120)) {
|
||||
// Extended PPI
|
||||
// Check Ext PPI implemented
|
||||
if (!gic_is_valid_extppi(rdid, intid))
|
||||
return EINVAL;
|
||||
|
||||
intid = intid - 1024;
|
||||
bank = intid / 32; // There are 32 IDs per register, need to work out which register to access
|
||||
intid = intid & 0x1F; // ... and which bit within the register
|
||||
intid = 1 << intid; // Move a '1' into the correct bit position
|
||||
|
||||
gic.gic_rdist[rdid].sgis.GICR_ISENABLER[bank] = intid;
|
||||
} else if ((intid > 4095) && (intid < 5120)) {
|
||||
// Extended SPI
|
||||
// Check Ext SPI implemented
|
||||
if (!gic_is_valid_extspi(rdid, intid))
|
||||
return EINVAL;
|
||||
|
||||
intid = intid - 4096;
|
||||
bank = intid / 32; // There are 32 IDs per register, need to work out which register to access
|
||||
intid = intid & 0x1F; // ... and which bit within the register
|
||||
intid = 1 << intid; // Move a '1' into the correct bit position
|
||||
gic.gic_dist->GICD_ISENABLERE[bank] = intid;
|
||||
} else {
|
||||
return EINVAL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void
|
||||
gic_set_prio_mask(unsigned int mask)
|
||||
{
|
||||
uint64_t _mask = mask & 0xFF;
|
||||
__asm__ volatile (
|
||||
"mov x0, %0;"
|
||||
"msr icc_pmr_el1, x0;"
|
||||
"dsb sy;"
|
||||
:
|
||||
: "r" (_mask)
|
||||
: "x0"
|
||||
);
|
||||
}
|
||||
|
||||
int
|
||||
gic_set_intr_prio(uint32_t rdid, uint32_t intid, uint8_t prio)
|
||||
{
|
||||
if (rdid > gic.max_rd) {
|
||||
return EINVAL;
|
||||
}
|
||||
|
||||
if (intid < 31) {
|
||||
// SGI or PPI
|
||||
gic.gic_rdist[rdid].sgis.GICR_IPRIORITYR[intid] = prio;
|
||||
} else if (intid < 1020) {
|
||||
// SPI
|
||||
gic.gic_dist->GICD_IPRIORITYR[intid] = prio;
|
||||
} else if ((intid > 1055) && (intid < 1120)) {
|
||||
// Extended PPI
|
||||
// Check Ext PPI implemented
|
||||
if (!gic_is_valid_extppi(rdid, intid))
|
||||
return EINVAL;
|
||||
|
||||
intid = intid - 1024;
|
||||
gic.gic_rdist[rdid].sgis.GICR_IPRIORITYR[intid] = prio;
|
||||
} else if ((intid > 4095) && (intid < 5120)) {
|
||||
// Extended SPI
|
||||
// Check Ext SPI implemented
|
||||
if (!gic_is_valid_extspi(rdid, intid))
|
||||
return EINVAL;
|
||||
gic.gic_dist->GICD_IPRIORITYRE[(intid-4096)] = prio;
|
||||
} else {
|
||||
return EINVAL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#define GICV3_GROUP0 (0)
|
||||
#define GICV3_GROUP1_SECURE (1)
|
||||
#define GICV3_GROUP1_NON_SECURE (2)
|
||||
@ -545,10 +438,10 @@ gic_calc_group_mod(uint32_t intid, uint32_t sec, uint32_t * _group, uint32_t * _
|
||||
}
|
||||
|
||||
static int
|
||||
gic_set_intr_group(uint32_t rdid, uint32_t intid, uint32_t sec)
|
||||
gic_set_intr_group(uint32_t intid, uint32_t sec)
|
||||
{
|
||||
uint32_t bank, group, mod;
|
||||
|
||||
const uint32_t rdid = MP_GetCPUState()->gic_redist_id;
|
||||
if (rdid > gic.max_rd)
|
||||
return EINVAL;
|
||||
|
||||
@ -629,81 +522,177 @@ gic_set_intr_group(uint32_t rdid, uint32_t intid, uint32_t sec)
|
||||
return 0;
|
||||
}
|
||||
|
||||
void
|
||||
gic_send_eoi(int intr)
|
||||
int
|
||||
gic_enable_intr(uint32_t intid)
|
||||
{
|
||||
intr = intr & 0xFFFFFF;
|
||||
__asm__ volatile (
|
||||
"mov x0, %x0;"
|
||||
"msr ICC_EOIR1_EL1, x0;"
|
||||
"dsb sy;"
|
||||
:
|
||||
: "r" (intr)
|
||||
: "x0"
|
||||
);
|
||||
}
|
||||
uint32_t bank;
|
||||
const uint32_t rdid = MP_GetCPUState()->gic_redist_id;
|
||||
|
||||
unsigned int
|
||||
gic_ack_intr(void)
|
||||
{
|
||||
unsigned int ret;
|
||||
__asm__ volatile (
|
||||
"mrs x0, ICC_IAR1_EL1;"
|
||||
"mov %x0, x0;"
|
||||
: "=r" (ret)
|
||||
:
|
||||
: "x0"
|
||||
);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int
|
||||
gic_init(void)
|
||||
{
|
||||
int ret;
|
||||
|
||||
if (!gic_discover()) {
|
||||
return ENOENT;
|
||||
if (rdid > gic.max_rd) {
|
||||
return EINVAL;
|
||||
}
|
||||
|
||||
gic_enable();
|
||||
|
||||
unsigned int rd;
|
||||
|
||||
// Get the ID of the Redistributor connected to this PE
|
||||
ret = gic_get_redist_id(gic_get_affinity(), &rd);
|
||||
int ret = gic_set_intr_prio(intid, 0);
|
||||
if (ret != 0) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = gic_set_intr_group(intid, GICV3_GROUP1_NON_SECURE);
|
||||
if (ret != 0) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (intid < 31) {
|
||||
// SGI or PPI
|
||||
gic.gic_rdist[rdid].sgis.GICR_ISENABLER[0] = (1 << intid);
|
||||
} else if (intid < 1020) {
|
||||
// SPI
|
||||
bank = intid/32; // There are 32 IDs per register, need to work out which register to access
|
||||
intid = intid & 0x1f; // ... and which bit within the register
|
||||
intid = 1 << intid; // Move a '1' into the correct bit position
|
||||
gic.gic_dist->GICD_ISENABLER[bank] = intid;
|
||||
} else if ((intid > 1055) && (intid < 1120)) {
|
||||
// Extended PPI
|
||||
// Check Ext PPI implemented
|
||||
if (!gic_is_valid_extppi(rdid, intid))
|
||||
return EINVAL;
|
||||
|
||||
intid = intid - 1024;
|
||||
bank = intid / 32; // There are 32 IDs per register, need to work out which register to access
|
||||
intid = intid & 0x1F; // ... and which bit within the register
|
||||
intid = 1 << intid; // Move a '1' into the correct bit position
|
||||
|
||||
gic.gic_rdist[rdid].sgis.GICR_ISENABLER[bank] = intid;
|
||||
} else if ((intid > 4095) && (intid < 5120)) {
|
||||
// Extended SPI
|
||||
// Check Ext SPI implemented
|
||||
if (!gic_is_valid_extspi(rdid, intid))
|
||||
return EINVAL;
|
||||
|
||||
intid = intid - 4096;
|
||||
bank = intid / 32; // There are 32 IDs per register, need to work out which register to access
|
||||
intid = intid & 0x1F; // ... and which bit within the register
|
||||
intid = 1 << intid; // Move a '1' into the correct bit position
|
||||
gic.gic_dist->GICD_ISENABLERE[bank] = intid;
|
||||
} else {
|
||||
return EINVAL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void
|
||||
gic_set_prio_mask(unsigned int mask)
|
||||
{
|
||||
uint64_t _mask = mask & 0xFF;
|
||||
|
||||
SYSREG_SET(ICC_PMR_EL1, _mask);
|
||||
data_barrier();
|
||||
|
||||
// __asm__ volatile (
|
||||
// "mov x0, %0;"
|
||||
// "msr icc_pmr_el1, x0;"
|
||||
// "dsb sy;"
|
||||
// :
|
||||
// : "r" (_mask)
|
||||
// : "x0"
|
||||
// );
|
||||
}
|
||||
|
||||
int
|
||||
gic_set_intr_prio(uint32_t intid, uint8_t prio)
|
||||
{
|
||||
const uint32_t rdid = MP_GetCPUState()->gic_redist_id;
|
||||
|
||||
if (rdid > gic.max_rd) {
|
||||
return EINVAL;
|
||||
}
|
||||
|
||||
if (intid < 31) {
|
||||
// SGI or PPI
|
||||
gic.gic_rdist[rdid].sgis.GICR_IPRIORITYR[intid] = prio;
|
||||
} else if (intid < 1020) {
|
||||
// SPI
|
||||
gic.gic_dist->GICD_IPRIORITYR[intid] = prio;
|
||||
} else if ((intid > 1055) && (intid < 1120)) {
|
||||
// Extended PPI
|
||||
// Check Ext PPI implemented
|
||||
if (!gic_is_valid_extppi(rdid, intid))
|
||||
return EINVAL;
|
||||
|
||||
intid = intid - 1024;
|
||||
gic.gic_rdist[rdid].sgis.GICR_IPRIORITYR[intid] = prio;
|
||||
} else if ((intid > 4095) && (intid < 5120)) {
|
||||
// Extended SPI
|
||||
// Check Ext SPI implemented
|
||||
if (!gic_is_valid_extspi(rdid, intid))
|
||||
return EINVAL;
|
||||
gic.gic_dist->GICD_IPRIORITYRE[(intid-4096)] = prio;
|
||||
} else {
|
||||
return EINVAL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void
|
||||
gic_send_eoi(int intr)
|
||||
{
|
||||
uint64_t _intr = intr & 0xFFFFFF;
|
||||
SYSREG_SET(ICC_EOIR1_EL1, _intr);
|
||||
data_barrier();
|
||||
}
|
||||
|
||||
int
|
||||
gic_init(void)
|
||||
{
|
||||
int ret;
|
||||
if ((ret = gic_discover()) != 0) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
gic_enable();
|
||||
return gic_redist_init();
|
||||
}
|
||||
|
||||
int
|
||||
gic_redist_init(void)
|
||||
{
|
||||
int ret;
|
||||
unsigned int rd;
|
||||
struct CPUState * cpustate = MP_GetCPUState();
|
||||
|
||||
// Get the ID of the Redistributor connected to this PE
|
||||
ret = gic_get_redist_id(cpustate->mpid, &rd);
|
||||
if (ret != 0) {
|
||||
return ret;
|
||||
}
|
||||
cpustate->gic_redist_id = rd;
|
||||
kprintf("GIC: CPU %d, MPID 0x%lx, Redist ID 0x%lx.\n", cpustate->id, cpustate->mpid, cpustate->gic_redist_id);
|
||||
|
||||
// Mark this core as being active
|
||||
gic_wakeup_redist(rd);
|
||||
|
||||
// Configure the CPU interface
|
||||
// This assumes that the SRE bits are already set
|
||||
// enable group 1 interrupts
|
||||
__asm__ volatile (
|
||||
"MRS x0, ICC_IGRPEN1_EL1;"
|
||||
"ORR w0, w0, #1;"
|
||||
"MSR ICC_IGRPEN1_EL1, x0;"
|
||||
"ISB"
|
||||
:
|
||||
:
|
||||
: "x0"
|
||||
);
|
||||
uint64_t igrpen1 = SYSREG_GET(ICC_IGRPEN1_EL1);
|
||||
igrpen1 |= 1;
|
||||
SYSREG_SET(ICC_IGRPEN1_EL1, igrpen1);
|
||||
inst_barrier();
|
||||
|
||||
// __asm__ volatile (
|
||||
// "MRS x0, ICC_IGRPEN1_EL1;"
|
||||
// "ORR w0, w0, #1;"
|
||||
// "MSR ICC_IGRPEN1_EL1, x0;"
|
||||
// "ISB"
|
||||
// :
|
||||
// :
|
||||
// : "x0"
|
||||
// );
|
||||
|
||||
// unmask all interrupt priorities
|
||||
gic_set_prio_mask(0xff);
|
||||
|
||||
// Non-secure EL1 Physical Timer (INTID 30)
|
||||
ret = gic_set_intr_prio(rd, 30, 0);
|
||||
if (ret != 0) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = gic_set_intr_group(rd, 30, GICV3_GROUP1_NON_SECURE);
|
||||
if (ret != 0) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
return gic_enable_intr(rd, 30);
|
||||
return 0;
|
||||
}
|
@ -1,38 +0,0 @@
|
||||
|
||||
#ifndef __ATOMIC_H__
|
||||
#define __ATOMIC_H__
|
||||
|
||||
static INLINE uint64_t
|
||||
atomic_swap_uint32(volatile uint32_t *dst, uint32_t newval)
|
||||
{
|
||||
uint32_t retval;
|
||||
|
||||
__asm__ volatile(".arch_extension lse; swp %w2, %w0, [%w1]; .arch_extension nolse;"
|
||||
: "=r" (retval)
|
||||
: "r" (dst), "r" (newval)
|
||||
: "memory");
|
||||
|
||||
return newval;
|
||||
}
|
||||
|
||||
static INLINE uint64_t
|
||||
atomic_swap_uint64(volatile uint64_t *dst, uint64_t newval)
|
||||
{
|
||||
uint64_t retval;
|
||||
|
||||
__asm__ volatile(".arch_extension lse; swp %2, %0, [%1]; .arch_extension nolse;"
|
||||
: "=r" (retval)
|
||||
: "r" (dst), "r" (newval)
|
||||
: "memory");
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
static inline void
|
||||
atomic_set_uint64(volatile uint64_t *dst, uint64_t newval)
|
||||
{
|
||||
*dst = newval;
|
||||
}
|
||||
|
||||
#endif /* __ATOMIC_H__ */
|
||||
|
@ -11,12 +11,12 @@
|
||||
|
||||
static ALWAYS_INLINE INLINE void enable_interrupts()
|
||||
{
|
||||
__asm__ volatile("msr daifclr, #(0x0002)\n");
|
||||
__asm__ volatile("msr daifclr, #0b1111");
|
||||
}
|
||||
|
||||
static ALWAYS_INLINE INLINE void disable_interrupts()
|
||||
{
|
||||
__asm__ volatile("msr daifset, #(0x0002)\n");
|
||||
__asm__ volatile("msr daifset, #0b1111");
|
||||
}
|
||||
|
||||
static ALWAYS_INLINE INLINE void hlt()
|
||||
@ -26,15 +26,7 @@ static ALWAYS_INLINE INLINE void hlt()
|
||||
|
||||
static ALWAYS_INLINE INLINE void flushtlb()
|
||||
{
|
||||
uint64_t zero = 0;
|
||||
__asm__ volatile (
|
||||
"msr ttbr0_el1, %x0;"
|
||||
"msr ttbr1_el1, %x0;"
|
||||
"TLBI VMALLE1;"
|
||||
:
|
||||
: "r" (zero)
|
||||
:
|
||||
);
|
||||
__asm__ volatile("TLBI VMALLE1");
|
||||
}
|
||||
|
||||
static ALWAYS_INLINE INLINE void pause()
|
||||
@ -47,5 +39,37 @@ static ALWAYS_INLINE INLINE void breakpoint()
|
||||
__asm__ volatile("brk #0");
|
||||
}
|
||||
|
||||
static ALWAYS_INLINE INLINE void inst_barrier()
|
||||
{
|
||||
__asm__ volatile("isb");
|
||||
}
|
||||
|
||||
static ALWAYS_INLINE INLINE void data_barrier()
|
||||
{
|
||||
__asm__ volatile("dsb sy");
|
||||
}
|
||||
|
||||
#define SYSREG_GET(name) \
|
||||
({ \
|
||||
uint64_t _tmp; \
|
||||
__asm__ volatile ( \
|
||||
"mrs %0, " #name \
|
||||
: "=r" (_tmp) \
|
||||
: \
|
||||
: \
|
||||
); \
|
||||
_tmp; \
|
||||
})
|
||||
|
||||
#define SYSREG_SET(name, var) \
|
||||
({ \
|
||||
__asm__ volatile ( \
|
||||
"msr " #name ", %0" \
|
||||
: \
|
||||
: "r" (var) \
|
||||
: \
|
||||
); \
|
||||
})
|
||||
|
||||
#endif /* __ARM64OP_H__ */
|
||||
|
||||
|
32
sys/arm64/include/gic.h
Normal file
32
sys/arm64/include/gic.h
Normal file
@ -0,0 +1,32 @@
|
||||
#pragma once
|
||||
#include <stdint.h>
|
||||
|
||||
uint32_t
|
||||
gic_get_affinity(void);
|
||||
|
||||
void
|
||||
gic_set_prio_mask(unsigned int mask);
|
||||
|
||||
int
|
||||
gic_set_intr_prio(uint32_t intid, uint8_t prio);
|
||||
|
||||
void
|
||||
gic_send_eoi(int intr);
|
||||
|
||||
// initialize global GIC
|
||||
int
|
||||
gic_init(void);
|
||||
|
||||
// per core GIC redist init
|
||||
int
|
||||
gic_redist_init(void);
|
||||
|
||||
int
|
||||
gic_enable_intr(uint32_t intid);
|
||||
|
||||
int
|
||||
gic_disable_intr(uint32_t intid);
|
||||
|
||||
int
|
||||
gic_get_redist_id(uint32_t affinity, unsigned int *id);
|
||||
|
280
sys/arm64/include/metalasm.h
Normal file
280
sys/arm64/include/metalasm.h
Normal file
@ -0,0 +1,280 @@
|
||||
#pragma once
|
||||
#define AARCH_REG_X0 (0)
|
||||
#define AARCH_REG_X1 (1)
|
||||
#define AARCH_REG_X2 (2)
|
||||
#define AARCH_REG_X3 (3)
|
||||
#define AARCH_REG_X4 (4)
|
||||
#define AARCH_REG_X5 (5)
|
||||
#define AARCH_REG_X6 (6)
|
||||
#define AARCH_REG_X7 (7)
|
||||
#define AARCH_REG_X8 (8)
|
||||
#define AARCH_REG_X9 (9)
|
||||
#define AARCH_REG_X10 (10)
|
||||
#define AARCH_REG_X11 (11)
|
||||
#define AARCH_REG_X12 (12)
|
||||
#define AARCH_REG_X13 (13)
|
||||
#define AARCH_REG_X14 (14)
|
||||
#define AARCH_REG_X15 (15)
|
||||
#define AARCH_REG_X16 (16)
|
||||
#define AARCH_REG_X17 (17)
|
||||
#define AARCH_REG_X18 (18)
|
||||
#define AARCH_REG_X19 (19)
|
||||
#define AARCH_REG_X20 (20)
|
||||
#define AARCH_REG_X21 (21)
|
||||
#define AARCH_REG_X22 (22)
|
||||
#define AARCH_REG_X23 (23)
|
||||
#define AARCH_REG_X24 (24)
|
||||
#define AARCH_REG_X25 (25)
|
||||
#define AARCH_REG_X26 (26)
|
||||
#define AARCH_REG_X27 (27)
|
||||
#define AARCH_REG_X28 (28)
|
||||
#define AARCH_REG_X29 (29)
|
||||
#define AARCH_REG_X30 (30)
|
||||
#define AARCH_REG_X31 (31)
|
||||
|
||||
#define METAL_REG_MO0 (0)
|
||||
#define METAL_REG_MO1 (1)
|
||||
#define METAL_REG_MO2 (2)
|
||||
#define METAL_REG_MO3 (3)
|
||||
#define METAL_REG_MO4 (4)
|
||||
#define METAL_REG_MO5 (5)
|
||||
#define METAL_REG_MR0 (6)
|
||||
#define METAL_REG_MR1 (7)
|
||||
#define METAL_REG_MR2 (8)
|
||||
#define METAL_REG_MR3 (9)
|
||||
#define METAL_REG_MI0 (10)
|
||||
#define METAL_REG_MI1 (11)
|
||||
#define METAL_REG_MI2 (12)
|
||||
#define METAL_REG_MI3 (13)
|
||||
#define METAL_REG_MI4 (14)
|
||||
#define METAL_REG_MI5 (15)
|
||||
#define METAL_REG_MLR (METAL_REG_MI5)
|
||||
#define METAL_REG_MIR0 (METAL_REG_MI0)
|
||||
#define METAL_REG_MIR1 (METAL_REG_MI1)
|
||||
#define METAL_REG_MIR2 (METAL_REG_MI2)
|
||||
#define METAL_REG_MER0 (METAL_REG_MI0)
|
||||
#define METAL_REG_MER1 (METAL_REG_MI1)
|
||||
#define METAL_REG_MER2 (METAL_REG_MI2)
|
||||
#define METAL_REG_MSPSR (METAL_REG_MI3)
|
||||
#define METAL_REG_MSR (16)
|
||||
#define METAL_REG_MBR (17)
|
||||
#define METAL_REG_MIB (18)
|
||||
#define METAL_REG_MEB (19)
|
||||
#define METAL_REG_MTP (20)
|
||||
#define METAL_REG_MG5 (21)
|
||||
#define METAL_REG_MG6 (22)
|
||||
#define METAL_REG_MG7 (23)
|
||||
#define METAL_REG_MG8 (24)
|
||||
#define METAL_REG_MG9 (25)
|
||||
#define METAL_REG_MG10 (26)
|
||||
#define METAL_REG_MG11 (27)
|
||||
#define METAL_REG_MG12 (28)
|
||||
#define METAL_REG_MG13 (29)
|
||||
#define METAL_REG_MG14 (30)
|
||||
#define METAL_REG_MG15 (31)
|
||||
|
||||
#define _METAL_STR(x) #x
|
||||
#define METAL_STR(x) _METAL_STR(x)
|
||||
#define _METAL_GAS_ENCODE(x) ".word " METAL_STR(x) ";"
|
||||
#define METAL_GAS_ENCODE(x) _METAL_GAS_ENCODE(x)
|
||||
|
||||
// metal insts defs
|
||||
#define METAL_WMR_ENCODING(mreg, greg) (0xd61f2C00 | ((mreg) << 5) | ((greg) << 0))
|
||||
#define METAL_WMR_GAS(mreg, greg) METAL_GAS_ENCODE(METAL_WMR_ENCODING(mreg, greg))
|
||||
#define MASM_WMR(mreg, greg) .word METAL_WMR_ENCODING(mreg, greg)
|
||||
#define METAL_WMR(reg, var) do { __asm__ volatile (\
|
||||
"mov x0, %x0;" \
|
||||
METAL_WMR_GAS(reg, AARCH_REG_X0)\
|
||||
: \
|
||||
: "r" (var)\
|
||||
: "x0" \
|
||||
); } while(0)
|
||||
|
||||
#define METAL_RMR_ENCODING(mreg, greg) (0xd61f2800 | ((mreg) << 5) | ((greg) << 0))
|
||||
#define METAL_RMR_GAS(mreg, greg) METAL_GAS_ENCODE(METAL_RMR_ENCODING(mreg,greg))
|
||||
#define MASM_RMR(mreg, greg) .word METAL_RMR_ENCODING(mreg, greg)
|
||||
#define METAL_RMR(reg, var) do { \
|
||||
__asm__ volatile ( \
|
||||
METAL_RMR_GAS(reg, AARCH_REG_X0) \
|
||||
"mov %x0, x0;"\
|
||||
: "+r" (var) \
|
||||
: \
|
||||
: "x0" \
|
||||
); } while(0)
|
||||
|
||||
//
|
||||
// we need to preserve the stack pointer between mroutine calls
|
||||
// mroutines never return values using stacks
|
||||
// and since "mexit"s always occur before "return"s
|
||||
// the function epilogue is not run before returning
|
||||
// which may destroy the stack if local variables are defined
|
||||
//
|
||||
// we do this using the mroutine stub function to wrap mroutine calls
|
||||
//
|
||||
#define METAL_MENTER_ENCODING(mroutine) (0xd61f2000 | ((mroutine) << 0))
|
||||
#define METAL_MENTER_GAS(mroutine) METAL_GAS_ENCODE(METAL_MENTER_ENCODING(mroutine))
|
||||
#define METAL_MENTER(mroutine) do { \
|
||||
__asm__ volatile ( \
|
||||
METAL_MENTER_GAS(mroutine) \
|
||||
: \
|
||||
: \
|
||||
: \
|
||||
); \
|
||||
} while(0)
|
||||
|
||||
#define METAL_MEXIT_ENCODING(mreg) (0xd61f2400 | ((mreg) << 0))
|
||||
#define METAL_MEXIT_GAS(mreg) METAL_GAS_ENCODE(METAL_MEXIT_ENCODING(mreg))
|
||||
#define METAL_MEXIT(mreg) do { \
|
||||
__asm__ volatile ( \
|
||||
METAL_MEXIT_GAS(mreg) \
|
||||
: \
|
||||
: \
|
||||
: \
|
||||
); } while(0)
|
||||
|
||||
#define MEXIT_FLAG_IIM (1 << 2) // this mexit masks instruction intercept for the first instruction after mexit
|
||||
#define MEXIT_FLAG_RFI (1 << 1) // this mexit is a return from intercept (also restores CPSR from MSPSR)
|
||||
#define MEXIT_FLAG_ID (1 << 0) // this mexit masks interrupts for the first instruction after mexit
|
||||
#define MEXIT_FLAG_EIM (1 << 3) // this mexit masks exception intercept for the first instruction after mexit
|
||||
|
||||
// do not provide C version of RAR/WAR for the current bank
|
||||
// can't decide which GP register to use as temp
|
||||
#define METAL_RAR_ENCODING(idxmreg, dstmreg) (0xd61f3000 | ((idxmreg) << 5) | ((dstmreg) << 0))
|
||||
#define METAL_RAR_GAS(idxmreg, dstmreg) METAL_GAS_ENCODE(METAL_RAR_ENCODING(idxmreg, dstmreg))
|
||||
|
||||
#define METAL_WAR_ENCODING(idxmreg, srcmreg) (0xd61f3400 | ((idxmreg) << 5) | ((srcmreg) << 0))
|
||||
#define METAL_WAR_GAS(idxmreg, dstmreg) METAL_GAS_ENCODE(METAL_WAR_ENCODING(idxmreg, dstmreg))
|
||||
|
||||
#define METAL_RPR_ENCODING(idxmreg, dstmreg) (0xd61f4000 | ((idxmreg) << 5) | ((dstmreg) << 0))
|
||||
#define METAL_RPR_GAS(idxmreg, dstmreg) METAL_GAS_ENCODE(METAL_RPR_ENCODING(idxmreg, dstmreg))
|
||||
#define METAL_RPR(idxvar, var) do { __asm__ volatile (\
|
||||
METAL_RMR_GAS(METAL_REG_MR0, AARCH_REG_X1) \
|
||||
METAL_RMR_GAS(METAL_REG_MR1, AARCH_REG_X2) \
|
||||
\
|
||||
"mov x0, %x1;" \
|
||||
METAL_WMR_GAS(METAL_REG_MR0, AARCH_REG_X0) \
|
||||
METAL_RPR_GAS(METAL_REG_MR0, METAL_REG_MR1) \
|
||||
METAL_RMR_GAS(METAL_REG_MR1, AARCH_REG_X0) \
|
||||
"mov %x0, x0;" \
|
||||
\
|
||||
METAL_WMR_GAS(METAL_REG_MR0, AARCH_REG_X1) \
|
||||
METAL_WMR_GAS(METAL_REG_MR1, AARCH_REG_X2) \
|
||||
: "+r" (var) \
|
||||
: "r" (idxvar)\
|
||||
: "x0", "x1", "x2" \
|
||||
); } while(0)
|
||||
|
||||
#define METAL_WPR_ENCODING(idxmreg, srcmreg) (0xd61f4400 | ((idxmreg) << 5) | ((srcmreg) << 0))
|
||||
#define METAL_WPR_GAS(idxmreg, srcmreg) METAL_GAS_ENCODE(METAL_WPR_ENCODING(idxmreg, srcmreg))
|
||||
#define METAL_WPR(idxvar, var) do { __asm__ volatile (\
|
||||
METAL_RMR_GAS(METAL_REG_MR0, AARCH_REG_X1) \
|
||||
METAL_RMR_GAS(METAL_REG_MR1, AARCH_REG_X2) \
|
||||
\
|
||||
"mov x0, %x0;" \
|
||||
METAL_WMR_GAS(METAL_REG_MR0, AARCH_REG_X0) \
|
||||
"mov x0, %x1;" \
|
||||
METAL_WMR_GAS(METAL_REG_MR1, AARCH_REG_X0) \
|
||||
\
|
||||
METAL_WPR_GAS(METAL_REG_MR0, METAL_REG_MR1) \
|
||||
\
|
||||
METAL_WMR_GAS(METAL_REG_MR0, AARCH_REG_X1) \
|
||||
METAL_WMR_GAS(METAL_REG_MR1, AARCH_REG_X2) \
|
||||
: \
|
||||
: "r" (idxvar), "r" (var) \
|
||||
: "x0", "x1", "x2" \
|
||||
); } while(0)
|
||||
|
||||
#define METAL_MCLI_ENCODING (0xd61f3800)
|
||||
#define METAL_MCLI_GAS METAL_GAS_ENCODE(METAL_MCLI_ENCODING)
|
||||
#define METAL_MCLI do { \
|
||||
__asm__ volatile ( \
|
||||
METAL_MCLI_GAS \
|
||||
: \
|
||||
: \
|
||||
: \
|
||||
); } while(0)
|
||||
|
||||
#define METAL_MSTI_ENCODING (0xd61f3C00)
|
||||
#define METAL_MSTI_GAS METAL_GAS_ENCODE(METAL_MSTI_ENCODING)
|
||||
#define METAL_MSTI do { \
|
||||
__asm__ volatile ( \
|
||||
METAL_MSTI_GAS \
|
||||
: \
|
||||
: \
|
||||
: \
|
||||
); } while(0)
|
||||
|
||||
#define _METAL_WTLB_SHIFT_RM (0)
|
||||
#define _METAL_WTLB_SHIFT_RN (5)
|
||||
#define _METAL_WTLB_SHIFT_RL (10)
|
||||
#define _METAL_WTLB_ENCODING(rl, rn, rm) ".word " METAL_STR(0xd63f8000 | (rl << _METAL_WTLB_SHIFT_RL) | (rn << _METAL_WTLB_SHIFT_RN) | (rm << _METAL_WTLB_SHIFT_RM))
|
||||
#define METAL_WTLB(descreg, inforeg, vaddrreg) do { __asm__ volatile (\
|
||||
_METAL_WTLB_ENCODING(descreg, vaddrreg, inforeg)); \
|
||||
} while (0)
|
||||
|
||||
#define _METAL_RTLB_SHIFT_RM (0)
|
||||
#define _METAL_RTLB_SHIFT_RN (5)
|
||||
#define _METAL_RTLB_SHIFT_RL (10)
|
||||
#define _METAL_RTLB_ENCODING(rl, rn, rm) ".word " METAL_STR(0xd61f8000 | (rl << _METAL_RTLB_SHIFT_RL) | (rn << _METAL_RTLB_SHIFT_RN) | (rm << _METAL_RTLB_SHIFT_RM))
|
||||
#define METAL_RTLB(descreg, inforeg, vaddrreg) do { __asm__ volatile (\
|
||||
_METAL_RTLB_ENCODING(descreg, vaddrreg, inforeg)); \
|
||||
} while (0)
|
||||
|
||||
|
||||
#define METAL_PMEMOP_MODE_NORMAL (0)
|
||||
#define METAL_PMEMOP_MODE_PRE (1)
|
||||
#define METAL_PMEMOP_MODE_POST (2)
|
||||
|
||||
// PSTR
|
||||
#define _METAL_PSTR_TEMPLATE(var, paddr, cmd) do { __asm__ volatile (\
|
||||
"mov x0, %x0;" \
|
||||
"mov x1, %x1;" \
|
||||
"mov x2, #0;" \
|
||||
cmd \
|
||||
: \
|
||||
: "r" (var), "r" (paddr) \
|
||||
: "x0", "x1", "x2" \
|
||||
); } while (0)
|
||||
|
||||
#define METAL_PSTRR8_ENCODING(dReg, bReg, oReg) (0x8c400000 | ((dReg) << 0) | ((bReg) << 5) | ((oReg) << 10))
|
||||
#define METAL_PSTRR8_GAS(dReg, bReg, oReg) METAL_GAS_ENCODE(METAL_PSTRR8_ENCODING(dReg, bReg, oReg))
|
||||
#define METAL_PSTR8(var, paddr) _METAL_PSTR_TEMPLATE(var, paddr, METAL_PSTRR8_GAS(AARCH_REG_X0, AARCH_REG_X1, AARCH_REG_X2))
|
||||
|
||||
#define METAL_PSTRR16_ENCODING(dReg, bReg, oReg) (0x8cc00000 | ((dReg) << 0) | ((bReg) << 5) | ((oReg) << 10))
|
||||
#define METAL_PSTRR16_GAS(dReg, bReg, oReg) METAL_GAS_ENCODE(METAL_PSTRR16_ENCODING(dReg, bReg, oReg))
|
||||
#define METAL_PSTR16(var, paddr) _METAL_PSTR_TEMPLATE(var, paddr, METAL_PSTRR16_GAS(AARCH_REG_X0, AARCH_REG_X1, AARCH_REG_X2))
|
||||
|
||||
#define METAL_PSTRR32_ENCODING(dReg, bReg, oReg) (0x8d400000 | ((dReg) << 0) | ((bReg) << 5) | ((oReg) << 10))
|
||||
#define METAL_PSTRR32_GAS(dReg, bReg, oReg) METAL_GAS_ENCODE(METAL_PSTRR32_ENCODING(dReg, bReg, oReg))
|
||||
#define METAL_PSTR32(var, paddr) _METAL_PSTR_TEMPLATE(var, paddr, METAL_PSTRR32_GAS(AARCH_REG_X0, AARCH_REG_X1, AARCH_REG_X2))
|
||||
|
||||
#define METAL_PSTRR64_ENCODING(dReg, bReg, oReg) (0x8dc00000 | ((dReg) << 0) | ((bReg) << 5) | ((oReg) << 10))
|
||||
#define METAL_PSTRR64_GAS(dReg, bReg, oReg) METAL_GAS_ENCODE(METAL_PSTRR64_ENCODING(dReg, bReg, oReg))
|
||||
#define METAL_PSTR64(var, paddr) _METAL_PSTR_TEMPLATE(var, paddr, METAL_PSTRR64_GAS(AARCH_REG_X0, AARCH_REG_X1, AARCH_REG_X2))
|
||||
|
||||
// PLDR
|
||||
#define _METAL_PLDR_TEMPLATE(var, paddr, cmd) do { __asm__ volatile (\
|
||||
"mov x1, %x1;" \
|
||||
"mov x2, #0;" \
|
||||
cmd \
|
||||
"mov %x0, x0;" \
|
||||
: "+r" (var) \
|
||||
: "r" (paddr) \
|
||||
: "x0", "x1", "x2" \
|
||||
); } while (0)
|
||||
|
||||
#define METAL_PLDRR8_ENCODING(dReg, bReg, oReg) (0x8c000000 | ((dReg) << 0) | ((bReg) << 5) | ((oReg) << 10))
|
||||
#define METAL_PLDRR8_GAS(dReg, bReg, oReg) METAL_GAS_ENCODE(METAL_PLDRR8_ENCODING(dReg, bReg, oReg))
|
||||
#define METAL_PLDR8(var, paddr) _METAL_PLDR_TEMPLATE(var, paddr, METAL_PLDRR8_GAS(AARCH_REG_X0, AARCH_REG_X1, AARCH_REG_X2))
|
||||
|
||||
#define METAL_PLDRR16_ENCODING(dReg, bReg, oReg) (0x8c800000 | ((dReg) << 0) | ((bReg) << 5) | ((oReg) << 10))
|
||||
#define METAL_PLDRR16_GAS(dReg, bReg, oReg) METAL_GAS_ENCODE(METAL_PLDRR16_ENCODING(dReg, bReg, oReg))
|
||||
#define METAL_PLDR16(var, paddr) _METAL_PLDR_TEMPLATE(var, paddr, METAL_PLDRR16_GAS(AARCH_REG_X0, AARCH_REG_X1, AARCH_REG_X2))
|
||||
|
||||
#define METAL_PLDRR32_ENCODING(dReg, bReg, oReg) (0x8d000000 | ((dReg) << 0) | ((bReg) << 5) | ((oReg) << 10))
|
||||
#define METAL_PLDRR32_GAS(dReg, bReg, oReg) METAL_GAS_ENCODE(METAL_PLDRR32_ENCODING(dReg, bReg, oReg))
|
||||
#define METAL_PLDR32(var, paddr) _METAL_PLDR_TEMPLATE(var, paddr, METAL_PLDRR32_GAS(AARCH_REG_X0, AARCH_REG_X1, AARCH_REG_X2))
|
||||
|
||||
#define METAL_PLDRR64_ENCODING(dReg, bReg, oReg) (0x8d800000 | ((dReg) << 0) | ((bReg) << 5) | ((oReg) << 10))
|
||||
#define METAL_PLDRR64_GAS(dReg, bReg, oReg) METAL_GAS_ENCODE(METAL_PLDRR64_ENCODING(dReg, bReg, oReg))
|
||||
#define METAL_PLDR64(var, paddr) _METAL_PLDR_TEMPLATE(var, paddr, METAL_PLDRR64_GAS(AARCH_REG_X0, AARCH_REG_X1, AARCH_REG_X2))
|
@ -6,284 +6,7 @@ extern "C" {
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
|
||||
#define AARCH_REG_X0 (0)
|
||||
#define AARCH_REG_X1 (1)
|
||||
#define AARCH_REG_X2 (2)
|
||||
#define AARCH_REG_X3 (3)
|
||||
#define AARCH_REG_X4 (4)
|
||||
#define AARCH_REG_X5 (5)
|
||||
#define AARCH_REG_X6 (6)
|
||||
#define AARCH_REG_X7 (7)
|
||||
#define AARCH_REG_X8 (8)
|
||||
#define AARCH_REG_X9 (9)
|
||||
#define AARCH_REG_X10 (10)
|
||||
#define AARCH_REG_X11 (11)
|
||||
#define AARCH_REG_X12 (12)
|
||||
#define AARCH_REG_X13 (13)
|
||||
#define AARCH_REG_X14 (14)
|
||||
#define AARCH_REG_X15 (15)
|
||||
#define AARCH_REG_X16 (16)
|
||||
#define AARCH_REG_X17 (17)
|
||||
#define AARCH_REG_X18 (18)
|
||||
#define AARCH_REG_X19 (19)
|
||||
#define AARCH_REG_X20 (20)
|
||||
#define AARCH_REG_X21 (21)
|
||||
#define AARCH_REG_X22 (22)
|
||||
#define AARCH_REG_X23 (23)
|
||||
#define AARCH_REG_X24 (24)
|
||||
#define AARCH_REG_X25 (25)
|
||||
#define AARCH_REG_X26 (26)
|
||||
#define AARCH_REG_X27 (27)
|
||||
#define AARCH_REG_X28 (28)
|
||||
#define AARCH_REG_X29 (29)
|
||||
#define AARCH_REG_X30 (30)
|
||||
#define AARCH_REG_X31 (31)
|
||||
|
||||
#define METAL_REG_MO0 (0)
|
||||
#define METAL_REG_MO1 (1)
|
||||
#define METAL_REG_MO2 (2)
|
||||
#define METAL_REG_MO3 (3)
|
||||
#define METAL_REG_MO4 (4)
|
||||
#define METAL_REG_MO5 (5)
|
||||
#define METAL_REG_MR0 (6)
|
||||
#define METAL_REG_MR1 (7)
|
||||
#define METAL_REG_MR2 (8)
|
||||
#define METAL_REG_MR3 (9)
|
||||
#define METAL_REG_MI0 (10)
|
||||
#define METAL_REG_MI1 (11)
|
||||
#define METAL_REG_MI2 (12)
|
||||
#define METAL_REG_MI3 (13)
|
||||
#define METAL_REG_MI4 (14)
|
||||
#define METAL_REG_MI5 (15)
|
||||
#define METAL_REG_MLR (METAL_REG_MI5)
|
||||
#define METAL_REG_MIR0 (METAL_REG_MI0)
|
||||
#define METAL_REG_MIR1 (METAL_REG_MI1)
|
||||
#define METAL_REG_MIR2 (METAL_REG_MI2)
|
||||
#define METAL_REG_MER0 (METAL_REG_MI0)
|
||||
#define METAL_REG_MER1 (METAL_REG_MI1)
|
||||
#define METAL_REG_MER2 (METAL_REG_MI2)
|
||||
#define METAL_REG_MSPSR (METAL_REG_MI3)
|
||||
#define METAL_REG_MSR (16)
|
||||
#define METAL_REG_MBR (17)
|
||||
#define METAL_REG_MIB (18)
|
||||
#define METAL_REG_MEB (19)
|
||||
#define METAL_REG_MTP (20)
|
||||
#define METAL_REG_MG5 (21)
|
||||
#define METAL_REG_MG6 (22)
|
||||
#define METAL_REG_MG7 (23)
|
||||
#define METAL_REG_MG8 (24)
|
||||
#define METAL_REG_MG9 (25)
|
||||
#define METAL_REG_MG10 (26)
|
||||
#define METAL_REG_MG11 (27)
|
||||
#define METAL_REG_MG12 (28)
|
||||
#define METAL_REG_MG13 (29)
|
||||
#define METAL_REG_MG14 (30)
|
||||
#define METAL_REG_MG15 (31)
|
||||
|
||||
#define _METAL_STR(x) #x
|
||||
#define METAL_STR(x) _METAL_STR(x)
|
||||
#define _METAL_GAS_ENCODE(x) ".word " METAL_STR(x) ";"
|
||||
#define METAL_GAS_ENCODE(x) _METAL_GAS_ENCODE(x)
|
||||
|
||||
// metal insts defs
|
||||
#define METAL_WMR_ENCODING(mreg, greg) (0xd61f2C00 | ((mreg) << 5) | ((greg) << 0))
|
||||
#define METAL_WMR_GAS(mreg, greg) METAL_GAS_ENCODE(METAL_WMR_ENCODING(mreg, greg))
|
||||
#define METAL_WMR(reg, var) do { __asm__ volatile (\
|
||||
"mov x0, %x0;" \
|
||||
METAL_WMR_GAS(reg, AARCH_REG_X0)\
|
||||
: \
|
||||
: "r" (var)\
|
||||
: "x0" \
|
||||
); } while(0)
|
||||
|
||||
#define METAL_RMR_ENCODING(mreg, greg) (0xd61f2800 | ((mreg) << 5) | ((greg) << 0))
|
||||
#define METAL_RMR_GAS(mreg, greg) METAL_GAS_ENCODE(METAL_RMR_ENCODING(mreg,greg))
|
||||
#define METAL_RMR(reg, var) do { \
|
||||
__asm__ volatile ( \
|
||||
METAL_RMR_GAS(reg, AARCH_REG_X0) \
|
||||
"mov %x0, x0;"\
|
||||
: "+r" (var) \
|
||||
: \
|
||||
: "x0" \
|
||||
); } while(0)
|
||||
|
||||
//
|
||||
// we need to preserve the stack pointer between mroutine calls
|
||||
// mroutines never return values using stacks
|
||||
// and since "mexit"s always occur before "return"s
|
||||
// the function epilogue is not run before returning
|
||||
// which may destroy the stack if local variables are defined
|
||||
//
|
||||
// we do this using the mroutine stub function to wrap mroutine calls
|
||||
//
|
||||
#define METAL_MENTER_ENCODING(mroutine) (0xd61f2000 | ((mroutine) << 0))
|
||||
#define METAL_MENTER_GAS(mroutine) METAL_GAS_ENCODE(METAL_MENTER_ENCODING(mroutine))
|
||||
#define METAL_MENTER(mroutine) do { \
|
||||
__asm__ volatile ( \
|
||||
METAL_MENTER_GAS(mroutine) \
|
||||
: \
|
||||
: \
|
||||
: \
|
||||
); \
|
||||
} while(0)
|
||||
|
||||
#define METAL_MEXIT_ENCODING(mreg) (0xd61f2400 | ((mreg) << 0))
|
||||
#define METAL_MEXIT_GAS(mreg) METAL_GAS_ENCODE(METAL_MEXIT_ENCODING(mreg))
|
||||
#define METAL_MEXIT(mreg) do { \
|
||||
__asm__ volatile ( \
|
||||
METAL_MEXIT_GAS(mreg) \
|
||||
: \
|
||||
: \
|
||||
: \
|
||||
); } while(0)
|
||||
|
||||
#define MEXIT_FLAG_IIM (1 << 2) // this mexit masks instruction intercept for the first instruction after mexit
|
||||
#define MEXIT_FLAG_RFI (1 << 1) // this mexit is a return from intercept (also restores CPSR from MSPSR)
|
||||
#define MEXIT_FLAG_ID (1 << 0) // this mexit masks interrupts for the first instruction after mexit
|
||||
#define MEXIT_FLAG_EIM (1 << 3) // this mexit masks exception intercept for the first instruction after mexit
|
||||
|
||||
// do not provide C version of RAR/WAR for the current bank
|
||||
// can't decide which GP register to use as temp
|
||||
#define METAL_RAR_ENCODING(idxmreg, dstmreg) (0xd61f3000 | ((idxmreg) << 5) | ((dstmreg) << 0))
|
||||
#define METAL_RAR_GAS(idxmreg, dstmreg) METAL_GAS_ENCODE(METAL_RAR_ENCODING(idxmreg, dstmreg))
|
||||
|
||||
#define METAL_WAR_ENCODING(idxmreg, srcmreg) (0xd61f3400 | ((idxmreg) << 5) | ((srcmreg) << 0))
|
||||
#define METAL_WAR_GAS(idxmreg, dstmreg) METAL_GAS_ENCODE(METAL_WAR_ENCODING(idxmreg, dstmreg))
|
||||
|
||||
#define METAL_RPR_ENCODING(idxmreg, dstmreg) (0xd61f4000 | ((idxmreg) << 5) | ((dstmreg) << 0))
|
||||
#define METAL_RPR_GAS(idxmreg, dstmreg) METAL_GAS_ENCODE(METAL_RPR_ENCODING(idxmreg, dstmreg))
|
||||
#define METAL_RPR(idxvar, var) do { __asm__ volatile (\
|
||||
METAL_RMR_GAS(METAL_REG_MR0, AARCH_REG_X1) \
|
||||
METAL_RMR_GAS(METAL_REG_MR1, AARCH_REG_X2) \
|
||||
\
|
||||
"mov x0, %x1;" \
|
||||
METAL_WMR_GAS(METAL_REG_MR0, AARCH_REG_X0) \
|
||||
METAL_RPR_GAS(METAL_REG_MR0, METAL_REG_MR1) \
|
||||
METAL_RMR_GAS(METAL_REG_MR1, AARCH_REG_X0) \
|
||||
"mov %x0, x0;" \
|
||||
\
|
||||
METAL_WMR_GAS(METAL_REG_MR0, AARCH_REG_X1) \
|
||||
METAL_WMR_GAS(METAL_REG_MR1, AARCH_REG_X2) \
|
||||
: "+r" (var) \
|
||||
: "r" (idxvar)\
|
||||
: "x0", "x1", "x2" \
|
||||
); } while(0)
|
||||
|
||||
#define METAL_WPR_ENCODING(idxmreg, srcmreg) (0xd61f4400 | ((idxmreg) << 5) | ((srcmreg) << 0))
|
||||
#define METAL_WPR_GAS(idxmreg, srcmreg) METAL_GAS_ENCODE(METAL_WPR_ENCODING(idxmreg, srcmreg))
|
||||
#define METAL_WPR(idxvar, var) do { __asm__ volatile (\
|
||||
METAL_RMR_GAS(METAL_REG_MR0, AARCH_REG_X1) \
|
||||
METAL_RMR_GAS(METAL_REG_MR1, AARCH_REG_X2) \
|
||||
\
|
||||
"mov x0, %x0;" \
|
||||
METAL_WMR_GAS(METAL_REG_MR0, AARCH_REG_X0) \
|
||||
"mov x0, %x1;" \
|
||||
METAL_WMR_GAS(METAL_REG_MR1, AARCH_REG_X0) \
|
||||
\
|
||||
METAL_WPR_GAS(METAL_REG_MR0, METAL_REG_MR1) \
|
||||
\
|
||||
METAL_WMR_GAS(METAL_REG_MR0, AARCH_REG_X1) \
|
||||
METAL_WMR_GAS(METAL_REG_MR1, AARCH_REG_X2) \
|
||||
: \
|
||||
: "r" (idxvar), "r" (var) \
|
||||
: "x0", "x1", "x2" \
|
||||
); } while(0)
|
||||
|
||||
#define METAL_MCLI_ENCODING (0xd61f3800)
|
||||
#define METAL_MCLI_GAS METAL_GAS_ENCODE(METAL_MCLI_ENCODING)
|
||||
#define METAL_MCLI do { \
|
||||
__asm__ volatile ( \
|
||||
METAL_MCLI_GAS \
|
||||
: \
|
||||
: \
|
||||
: \
|
||||
); } while(0)
|
||||
|
||||
#define METAL_MSTI_ENCODING (0xd61f3C00)
|
||||
#define METAL_MSTI_GAS METAL_GAS_ENCODE(METAL_MSTI_ENCODING)
|
||||
#define METAL_MSTI do { \
|
||||
__asm__ volatile ( \
|
||||
METAL_MSTI_GAS \
|
||||
: \
|
||||
: \
|
||||
: \
|
||||
); } while(0)
|
||||
|
||||
#define _METAL_WTLB_SHIFT_RM (0)
|
||||
#define _METAL_WTLB_SHIFT_RN (5)
|
||||
#define _METAL_WTLB_SHIFT_RL (10)
|
||||
#define _METAL_WTLB_ENCODING(rl, rn, rm) ".word " METAL_STR(0xd63f8000 | (rl << _METAL_WTLB_SHIFT_RL) | (rn << _METAL_WTLB_SHIFT_RN) | (rm << _METAL_WTLB_SHIFT_RM))
|
||||
#define METAL_WTLB(descreg, inforeg, vaddrreg) do { __asm__ volatile (\
|
||||
_METAL_WTLB_ENCODING(descreg, vaddrreg, inforeg)); \
|
||||
} while (0)
|
||||
|
||||
#define _METAL_RTLB_SHIFT_RM (0)
|
||||
#define _METAL_RTLB_SHIFT_RN (5)
|
||||
#define _METAL_RTLB_SHIFT_RL (10)
|
||||
#define _METAL_RTLB_ENCODING(rl, rn, rm) ".word " METAL_STR(0xd61f8000 | (rl << _METAL_RTLB_SHIFT_RL) | (rn << _METAL_RTLB_SHIFT_RN) | (rm << _METAL_RTLB_SHIFT_RM))
|
||||
#define METAL_RTLB(descreg, inforeg, vaddrreg) do { __asm__ volatile (\
|
||||
_METAL_RTLB_ENCODING(descreg, vaddrreg, inforeg)); \
|
||||
} while (0)
|
||||
|
||||
|
||||
#define METAL_PMEMOP_MODE_NORMAL (0)
|
||||
#define METAL_PMEMOP_MODE_PRE (1)
|
||||
#define METAL_PMEMOP_MODE_POST (2)
|
||||
|
||||
// PSTR
|
||||
#define _METAL_PSTR_TEMPLATE(var, paddr, cmd) do { __asm__ volatile (\
|
||||
"mov x0, %x0;" \
|
||||
"mov x1, %x1;" \
|
||||
"mov x2, #0;" \
|
||||
cmd \
|
||||
: \
|
||||
: "r" (var), "r" (paddr) \
|
||||
: "x0", "x1", "x2" \
|
||||
); } while (0)
|
||||
|
||||
#define METAL_PSTRR8_ENCODING(dReg, bReg, oReg) (0x8c400000 | ((dReg) << 0) | ((bReg) << 5) | ((oReg) << 10))
|
||||
#define METAL_PSTRR8_GAS(dReg, bReg, oReg) METAL_GAS_ENCODE(METAL_PSTRR8_ENCODING(dReg, bReg, oReg))
|
||||
#define METAL_PSTR8(var, paddr) _METAL_PSTR_TEMPLATE(var, paddr, METAL_PSTRR8_GAS(AARCH_REG_X0, AARCH_REG_X1, AARCH_REG_X2))
|
||||
|
||||
#define METAL_PSTRR16_ENCODING(dReg, bReg, oReg) (0x8cc00000 | ((dReg) << 0) | ((bReg) << 5) | ((oReg) << 10))
|
||||
#define METAL_PSTRR16_GAS(dReg, bReg, oReg) METAL_GAS_ENCODE(METAL_PSTRR16_ENCODING(dReg, bReg, oReg))
|
||||
#define METAL_PSTR16(var, paddr) _METAL_PSTR_TEMPLATE(var, paddr, METAL_PSTRR16_GAS(AARCH_REG_X0, AARCH_REG_X1, AARCH_REG_X2))
|
||||
|
||||
#define METAL_PSTRR32_ENCODING(dReg, bReg, oReg) (0x8d400000 | ((dReg) << 0) | ((bReg) << 5) | ((oReg) << 10))
|
||||
#define METAL_PSTRR32_GAS(dReg, bReg, oReg) METAL_GAS_ENCODE(METAL_PSTRR32_ENCODING(dReg, bReg, oReg))
|
||||
#define METAL_PSTR32(var, paddr) _METAL_PSTR_TEMPLATE(var, paddr, METAL_PSTRR32_GAS(AARCH_REG_X0, AARCH_REG_X1, AARCH_REG_X2))
|
||||
|
||||
#define METAL_PSTRR64_ENCODING(dReg, bReg, oReg) (0x8dc00000 | ((dReg) << 0) | ((bReg) << 5) | ((oReg) << 10))
|
||||
#define METAL_PSTRR64_GAS(dReg, bReg, oReg) METAL_GAS_ENCODE(METAL_PSTRR64_ENCODING(dReg, bReg, oReg))
|
||||
#define METAL_PSTR64(var, paddr) _METAL_PSTR_TEMPLATE(var, paddr, METAL_PSTRR64_GAS(AARCH_REG_X0, AARCH_REG_X1, AARCH_REG_X2))
|
||||
|
||||
// PLDR
|
||||
#define _METAL_PLDR_TEMPLATE(var, paddr, cmd) do { __asm__ volatile (\
|
||||
"mov x1, %x1;" \
|
||||
"mov x2, #0;" \
|
||||
cmd \
|
||||
"mov %x0, x0;" \
|
||||
: "+r" (var) \
|
||||
: "r" (paddr) \
|
||||
: "x0", "x1", "x2" \
|
||||
); } while (0)
|
||||
|
||||
#define METAL_PLDRR8_ENCODING(dReg, bReg, oReg) (0x8c000000 | ((dReg) << 0) | ((bReg) << 5) | ((oReg) << 10))
|
||||
#define METAL_PLDRR8_GAS(dReg, bReg, oReg) METAL_GAS_ENCODE(METAL_PLDRR8_ENCODING(dReg, bReg, oReg))
|
||||
#define METAL_PLDR8(var, paddr) _METAL_PLDR_TEMPLATE(var, paddr, METAL_PLDRR8_GAS(AARCH_REG_X0, AARCH_REG_X1, AARCH_REG_X2))
|
||||
|
||||
#define METAL_PLDRR16_ENCODING(dReg, bReg, oReg) (0x8c800000 | ((dReg) << 0) | ((bReg) << 5) | ((oReg) << 10))
|
||||
#define METAL_PLDRR16_GAS(dReg, bReg, oReg) METAL_GAS_ENCODE(METAL_PLDRR16_ENCODING(dReg, bReg, oReg))
|
||||
#define METAL_PLDR16(var, paddr) _METAL_PLDR_TEMPLATE(var, paddr, METAL_PLDRR16_GAS(AARCH_REG_X0, AARCH_REG_X1, AARCH_REG_X2))
|
||||
|
||||
#define METAL_PLDRR32_ENCODING(dReg, bReg, oReg) (0x8d000000 | ((dReg) << 0) | ((bReg) << 5) | ((oReg) << 10))
|
||||
#define METAL_PLDRR32_GAS(dReg, bReg, oReg) METAL_GAS_ENCODE(METAL_PLDRR32_ENCODING(dReg, bReg, oReg))
|
||||
#define METAL_PLDR32(var, paddr) _METAL_PLDR_TEMPLATE(var, paddr, METAL_PLDRR32_GAS(AARCH_REG_X0, AARCH_REG_X1, AARCH_REG_X2))
|
||||
|
||||
#define METAL_PLDRR64_ENCODING(dReg, bReg, oReg) (0x8d800000 | ((dReg) << 0) | ((bReg) << 5) | ((oReg) << 10))
|
||||
#define METAL_PLDRR64_GAS(dReg, bReg, oReg) METAL_GAS_ENCODE(METAL_PLDRR64_ENCODING(dReg, bReg, oReg))
|
||||
#define METAL_PLDR64(var, paddr) _METAL_PLDR_TEMPLATE(var, paddr, METAL_PLDRR64_GAS(AARCH_REG_X0, AARCH_REG_X1, AARCH_REG_X2))
|
||||
#include <machine/metalasm.h>
|
||||
|
||||
// Mroutine helpers
|
||||
|
||||
|
@ -2,22 +2,38 @@
|
||||
#ifndef __MACHINE_MP_H__
|
||||
#define __MACHINE_MP_H__
|
||||
|
||||
#include <sys/kconfig.h>
|
||||
#include <stdint.h>
|
||||
#include <sys/kassert.h>
|
||||
|
||||
#define CPUSTATE_NOT_PRESENT 0
|
||||
#define CPUSTATE_BOOTED 1
|
||||
#define CPUSTATE_HALTED 2
|
||||
#define CPUSTATE_MAX 2
|
||||
|
||||
void MP_Init();
|
||||
void MP_InitAP();
|
||||
void MP_SetState(int state);
|
||||
int MP_GetCPUs();
|
||||
|
||||
/* Cross Calls */
|
||||
typedef int (*CrossCallCB)(void *);
|
||||
void MP_CrossCallTrap();
|
||||
int MP_CrossCall(CrossCallCB cb, void *arg);
|
||||
|
||||
uint32_t LAPIC_CPU();
|
||||
struct CPUState {
|
||||
unsigned int id;
|
||||
uint32_t mpid;
|
||||
uint32_t gic_redist_id;
|
||||
volatile int state;
|
||||
};
|
||||
|
||||
register uint64_t _cpu __asm__("x18");
|
||||
static inline unsigned int CPU(void)
|
||||
{
|
||||
return _cpu;
|
||||
}
|
||||
|
||||
void MP_InitCore(void);
|
||||
void MP_BootAPs(void);
|
||||
unsigned int MP_GetCPUs(void);
|
||||
struct CPUState * MP_GetCPUState(void);
|
||||
|
||||
|
||||
#endif /* __MACHINE_MP__ */
|
||||
|
||||
|
19
sys/arm64/include/timer.h
Normal file
19
sys/arm64/include/timer.h
Normal file
@ -0,0 +1,19 @@
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
#include <machine/cpuop.h>
|
||||
|
||||
static inline uint64_t
|
||||
Time_GetTSC()
|
||||
{
|
||||
return SYSREG_GET(CNTPCT_EL0);
|
||||
}
|
||||
|
||||
static inline uint64_t
|
||||
Time_GetTSCFreq()
|
||||
{
|
||||
return SYSREG_GET(CNTFRQ_EL0);
|
||||
}
|
||||
|
||||
void
|
||||
PTimer_Init();
|
@ -2,79 +2,101 @@
|
||||
#ifndef __TRAP_H__
|
||||
#define __TRAP_H__
|
||||
|
||||
#define T_UNKNOWN 0x00 /* Unknown */
|
||||
#define T_WFIWFE 0x01 /* WFI/WFE */
|
||||
#define T_SIMDFP 0x07
|
||||
#define T_ILLSTATE 0x0e /* Illegal Execution State */
|
||||
#define T_SYSINST 0x18 /* System Instruction */
|
||||
#define T_INSTABRT_L 0x20 /* Instruction Abort (EL0) */
|
||||
#define T_INSTABRT 0x21 /* Instruction Abort */
|
||||
#define T_PCAC 0x22 /* PC Alignment Check */
|
||||
#define T_SPAC 0x26 /* SP Alignment Check */
|
||||
#define T_DATAABRT_L 0x24 /* Data Abort (EL0) */
|
||||
#include <sys/queue.h>
|
||||
#include <stdint.h>
|
||||
|
||||
// #define T_UNKNOWN 0x00 /* Unknown */
|
||||
// #define T_WFIWFE 0x01 /* WFI/WFE */
|
||||
// #define T_SIMDFP 0x07
|
||||
// #define T_ILLSTATE 0x0e /* Illegal Execution State */
|
||||
// #define T_SYSINST 0x18 /* System Instruction */
|
||||
// #define T_INSTABRT_L 0x20 /* Instruction Abort (EL0) */
|
||||
// #define T_INSTABRT 0x21 /* Instruction Abort */
|
||||
// #define T_PCAC 0x22 /* PC Alignment Check */
|
||||
// #define T_SPAC 0x26 /* SP Alignment Check */
|
||||
// #define T_DATAABRT_L 0x24 /* Data Abort (EL0) */
|
||||
//#define T_DATAABRT_L 0x25 /* Data Abort (EL0) */
|
||||
#define T_SERROR 0x2f /* SError */
|
||||
#define T_DBGBRK_EL0 0x32 /* Breakpoint (EL0) */
|
||||
#define T_DBGBRK_EL1 0x33 /* Breakpoint (EL1) */
|
||||
#define T_DBGSTP_EL0 0x32 /* Step (EL0) */
|
||||
#define T_DBGSTP_EL1 0x33 /* Step (EL1) */
|
||||
#define T_DBGWP_EL0 0x34 /* Watchpoint (EL0) */
|
||||
#define T_DBGWP_EL1 0x35 /* Watchpoint (EL1) */
|
||||
#define T_BRK 0x3c /* Breakpoint */
|
||||
// #define T_SERROR 0x2f /* SError */
|
||||
// #define T_DBGBRK_EL0 0x32 /* Breakpoint (EL0) */
|
||||
// #define T_DBGBRK_EL1 0x33 /* Breakpoint (EL1) */
|
||||
// #define T_DBGSTP_EL0 0x32 /* Step (EL0) */
|
||||
// #define T_DBGSTP_EL1 0x33 /* Step (EL1) */
|
||||
// #define T_DBGWP_EL0 0x34 /* Watchpoint (EL0) */
|
||||
// #define T_DBGWP_EL1 0x35 /* Watchpoint (EL1) */
|
||||
// #define T_BRK 0x3c /* Breakpoint */
|
||||
|
||||
#define T_CPU_LAST T_BRK
|
||||
// #define T_CPU_LAST T_BRK
|
||||
|
||||
// IRQs
|
||||
#define T_IRQ_BASE 32
|
||||
#define T_IRQ_LEN 24
|
||||
#define T_IRQ_MAX (T_IRQ_BASE + T_IRQ_LEN - 1)
|
||||
|
||||
#define T_CROSSCALL 61 /* Cross Call (IPI) */
|
||||
#define T_DEBUGIPI 62 /* Kernel Debugger Halt (IPI) */
|
||||
// #define T_CROSSCALL 61 /* Cross Call (IPI) */
|
||||
// #define T_DEBUGIPI 62 /* Kernel Debugger Halt (IPI) */
|
||||
|
||||
//#define T_UNKNOWN 63 /* Unknown Trap */
|
||||
|
||||
#define T_MAX 64
|
||||
|
||||
// IRQs
|
||||
#define T_IRQ_MAX (8192)
|
||||
#define T_TYPE_IRQ (1)
|
||||
#define T_TYPE_EXC (0)
|
||||
typedef struct TrapFrame
|
||||
{
|
||||
uint64_t r15;
|
||||
uint64_t r14;
|
||||
uint64_t r13;
|
||||
uint64_t r12;
|
||||
uint64_t r11;
|
||||
uint64_t r10;
|
||||
uint64_t r9;
|
||||
uint64_t type;
|
||||
uint64_t intid;
|
||||
|
||||
uint64_t esr;
|
||||
uint64_t far;
|
||||
|
||||
uint64_t elr;
|
||||
uint64_t spsr;
|
||||
|
||||
uint64_t mi0;
|
||||
uint64_t mi1;
|
||||
uint64_t mi2;
|
||||
uint64_t mi3;
|
||||
uint64_t mi4;
|
||||
uint64_t mi5;
|
||||
uint64_t mr0;
|
||||
uint64_t mr1;
|
||||
uint64_t mr2;
|
||||
uint64_t mr3;
|
||||
uint64_t mo0;
|
||||
uint64_t mo1;
|
||||
uint64_t mo2;
|
||||
uint64_t mo3;
|
||||
uint64_t mo4;
|
||||
uint64_t mo5;
|
||||
|
||||
uint64_t r0;
|
||||
uint64_t r1;
|
||||
uint64_t r2;
|
||||
uint64_t r3;
|
||||
uint64_t r4;
|
||||
uint64_t r5;
|
||||
uint64_t r6;
|
||||
uint64_t r7;
|
||||
uint64_t r8;
|
||||
uint64_t rbp;
|
||||
uint64_t rdi;
|
||||
uint64_t rsi;
|
||||
uint64_t rdx;
|
||||
uint64_t rcx;
|
||||
uint64_t rbx;
|
||||
uint64_t ds;
|
||||
uint64_t rax;
|
||||
|
||||
uint64_t vector;
|
||||
uint32_t errcode;
|
||||
uint32_t _unused0;
|
||||
uint64_t rip;
|
||||
uint16_t cs;
|
||||
uint16_t _unused1;
|
||||
uint16_t _unused2;
|
||||
uint16_t _unused3;
|
||||
uint64_t rflags;
|
||||
uint64_t rsp;
|
||||
uint16_t ss;
|
||||
uint16_t _unused4;
|
||||
uint16_t _unused5;
|
||||
uint16_t _unused6;
|
||||
uint64_t r9;
|
||||
uint64_t r10;
|
||||
uint64_t r11;
|
||||
uint64_t r12;
|
||||
uint64_t r13;
|
||||
uint64_t r14;
|
||||
uint64_t r15;
|
||||
uint64_t r16;
|
||||
uint64_t r17;
|
||||
uint64_t r18;
|
||||
uint64_t r19;
|
||||
uint64_t r20;
|
||||
uint64_t r21;
|
||||
uint64_t r22;
|
||||
uint64_t r23;
|
||||
uint64_t r24;
|
||||
uint64_t r25;
|
||||
uint64_t r26;
|
||||
uint64_t r27;
|
||||
uint64_t r28;
|
||||
uint64_t r29;
|
||||
uint64_t r30;
|
||||
uint64_t r31;
|
||||
} TrapFrame;
|
||||
|
||||
void Trap_Init();
|
||||
void Trap_InitAP();
|
||||
void Trap_Dump(TrapFrame *tf);
|
||||
void Trap_Pop(TrapFrame *tf);
|
||||
|
||||
#endif /* __TRAP_H__ */
|
||||
|
||||
|
@ -1,53 +0,0 @@
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include <sys/kassert.h>
|
||||
#include <sys/irq.h>
|
||||
|
||||
#include <machine/trap.h>
|
||||
// #include <machine/ioapic.h>
|
||||
|
||||
LIST_HEAD(IRQHandlerList, IRQHandler);
|
||||
struct IRQHandlerList handlers[T_IRQ_LEN];
|
||||
|
||||
void
|
||||
IRQ_Init()
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < T_IRQ_LEN; i++)
|
||||
{
|
||||
LIST_INIT(&handlers[i]);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
IRQ_Handler(int irq)
|
||||
{
|
||||
struct IRQHandler *h;
|
||||
LIST_FOREACH(h, &handlers[irq], link)
|
||||
{
|
||||
h->cb(h->arg);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
IRQ_Register(int irq, struct IRQHandler *h)
|
||||
{
|
||||
ASSERT(irq < T_IRQ_LEN);
|
||||
|
||||
LIST_INSERT_HEAD(&handlers[irq], h, link);
|
||||
|
||||
//IOAPIC_Enable(irq);
|
||||
}
|
||||
|
||||
void
|
||||
IRQ_Unregister(int irq, struct IRQHandler *h)
|
||||
{
|
||||
LIST_REMOVE(h, link);
|
||||
|
||||
if (LIST_EMPTY(&handlers[irq])) {
|
||||
//IOAPIC_Disable(irq);
|
||||
}
|
||||
}
|
||||
|
@ -19,16 +19,15 @@
|
||||
#include <sys/vfs.h>
|
||||
#include <sys/elf64.h>
|
||||
|
||||
#include "../dev/arm64/gic.h"
|
||||
#include "../dev/console.h"
|
||||
#include <machine/cpuop.h>
|
||||
#include <machine/metal.h>
|
||||
#include <machine/mrt.h>
|
||||
#include <machine/pdcache.h>
|
||||
#include <machine/timer.h>
|
||||
|
||||
extern void KTime_Init();
|
||||
extern void KTimer_Init();
|
||||
extern void RTC_Init();
|
||||
extern void PCI_Init();
|
||||
extern void MachineBoot_AddMem();
|
||||
extern void Loader_LoadInit();
|
||||
@ -58,12 +57,14 @@ Machine_SyscallInit()
|
||||
void
|
||||
Machine_EarlyInit()
|
||||
{
|
||||
MP_InitCore();
|
||||
Spinlock_EarlyInit();
|
||||
Critical_Init();
|
||||
Critical_Enter();
|
||||
WaitChannel_EarlyInit();
|
||||
Console_Init();
|
||||
PAlloc_Init();
|
||||
kprintf("Boot CPU: id = %d, mpid = 0x%x.\n", CPU(), MP_GetCPUState()->mpid);
|
||||
}
|
||||
|
||||
static void
|
||||
@ -95,44 +96,30 @@ void Machine_Init()
|
||||
PAlloc_LateInit();
|
||||
MachineBoot_AddMem();
|
||||
|
||||
// initialize GIC
|
||||
kprintf("Initializing GIC ...\n");
|
||||
if (gic_init() != 0) {
|
||||
PANIC("GIC initialization failed!\n");
|
||||
}
|
||||
kprintf("GIC Initialized!\n");
|
||||
|
||||
//enable hardware timer
|
||||
// __asm__ volatile (
|
||||
// "mrs x1, CNTFRQ_EL0;"
|
||||
// "msr CNTP_TVAL_EL0, x1;"
|
||||
// "mov x0, #1;"
|
||||
// "msr CNTP_CTL_EL0, x0;"
|
||||
// "msr DAIFClr, #0b1111;"
|
||||
// :
|
||||
// :
|
||||
// : "x0", "x1"
|
||||
// );
|
||||
|
||||
while(1){
|
||||
hlt();
|
||||
}
|
||||
/*
|
||||
* Initialize Interrupts
|
||||
*/
|
||||
IRQ_Init();
|
||||
|
||||
/*
|
||||
* Initialize Time Keeping
|
||||
*/
|
||||
KTime_Init();
|
||||
//RTC_Init(); // Finishes initializing KTime
|
||||
|
||||
/*
|
||||
* Initialize Interrupts
|
||||
*/
|
||||
IRQ_Init();
|
||||
// XXX: disable interrupts here to avoid the timer interrupt firing before KTimer is initialized
|
||||
// alternatively, break the dependency or use an "initialized" flag in KTimer_Process
|
||||
disable_interrupts();
|
||||
PTimer_Init();
|
||||
KTimer_Init();
|
||||
enable_interrupts();
|
||||
|
||||
while(1){
|
||||
hlt();
|
||||
}
|
||||
|
||||
// GICv3
|
||||
Thread_Init();
|
||||
|
||||
KTimer_Init(); // Depends on RTC and KTime
|
||||
|
||||
/*
|
||||
* Initialize Additional Processors
|
||||
*/
|
||||
@ -181,14 +168,12 @@ void Machine_InitAP()
|
||||
Critical_Enter();
|
||||
|
||||
// Setup CPU state
|
||||
Trap_InitAP();
|
||||
//Trap_InitAP();
|
||||
PMap_InitAP();
|
||||
Machine_SyscallInit();
|
||||
|
||||
// Setup LAPIC
|
||||
|
||||
// Boot processor
|
||||
MP_InitAP();
|
||||
MP_InitCore();
|
||||
Thread_InitAP();
|
||||
Critical_Exit();
|
||||
|
||||
|
194
sys/arm64/mp.c
194
sys/arm64/mp.c
@ -2,13 +2,13 @@
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
#include <stdatomic.h>
|
||||
|
||||
#include <sys/kassert.h>
|
||||
#include <sys/kconfig.h>
|
||||
#include <sys/kdebug.h>
|
||||
#include <sys/kmem.h>
|
||||
#include <sys/ktime.h>
|
||||
#include <sys/mp.h>
|
||||
|
||||
#include <machine/cpu.h>
|
||||
#include <machine/cpuop.h>
|
||||
@ -19,9 +19,7 @@
|
||||
extern uint8_t mpstart_begin[];
|
||||
extern uint8_t mpstart_end[];
|
||||
|
||||
extern AS systemAS;
|
||||
|
||||
#define MP_WAITTIME 250000000ULL
|
||||
// #define MP_WAITTIME 250000000ULL
|
||||
|
||||
typedef struct CrossCallFrame {
|
||||
CrossCallCB cb;
|
||||
@ -31,163 +29,143 @@ typedef struct CrossCallFrame {
|
||||
volatile int status[MAX_CPUS];
|
||||
} CrossCallFrame;
|
||||
|
||||
const char *CPUStateToString[] = {
|
||||
static const char *CPUStateToString[] = {
|
||||
"NOT PRESENT",
|
||||
"BOOTED",
|
||||
"HALTED",
|
||||
};
|
||||
|
||||
typedef struct CPUState {
|
||||
int state;
|
||||
UnixEpochNS heartbeat;
|
||||
CrossCallFrame *frame;
|
||||
} CPUState;
|
||||
static struct CPUState cpu_states[MAX_CPUS] = {0};
|
||||
static unsigned int cpu_count = 0;
|
||||
|
||||
volatile static bool booted;
|
||||
volatile static int lastCPU;
|
||||
volatile static CPUState cpus[MAX_CPUS];
|
||||
struct CPUState * MP_GetCPUState(void)
|
||||
{
|
||||
ASSERT(CPU() < cpu_count);
|
||||
return &cpu_states[CPU()];
|
||||
}
|
||||
|
||||
void
|
||||
MP_Init()
|
||||
MP_BootAPs(void)
|
||||
{
|
||||
int i;
|
||||
kprintf("Booting on CPU %u\n", CPU());
|
||||
// Boot APs
|
||||
NOT_IMPLEMENTED();
|
||||
}
|
||||
|
||||
cpus[CPU()].state = CPUSTATE_BOOTED;
|
||||
cpus[CPU()].frame = NULL;
|
||||
|
||||
for (i = 1; i < MAX_CPUS; i++) {
|
||||
cpus[i].state = CPUSTATE_NOT_PRESENT;
|
||||
cpus[i].frame = NULL;
|
||||
void
|
||||
MP_InitCore(void)
|
||||
{
|
||||
int cpuid = atomic_fetch_add(&cpu_count, 1);
|
||||
// make sure CPU() macro works
|
||||
if (cpuid >= MAX_CPUS) {
|
||||
Panic("Too many CPUs.");
|
||||
}
|
||||
|
||||
/*
|
||||
* XXX: We really should read from the MP Table, but this appears to be
|
||||
* reliable for now.
|
||||
*/
|
||||
lastCPU = 0;
|
||||
/*
|
||||
for (i = 1; i < MAX_CPUS; i++) {
|
||||
if (MPBootAP(i) < 0)
|
||||
break;
|
||||
cpu_states[cpuid].state = CPUSTATE_BOOTED;
|
||||
cpu_states[cpuid].id = cpuid;
|
||||
const uint64_t mpidr = SYSREG_GET(mpidr_el1);
|
||||
const uint32_t mpid = (mpidr & 0xFFFFFF) | ((mpidr >> 8) & 0xFF000000);
|
||||
cpu_states[cpuid].mpid = mpid;
|
||||
|
||||
lastCPU = i;
|
||||
}
|
||||
*/
|
||||
lastCPU++;
|
||||
// set x18 properly on this cpu
|
||||
_cpu = cpuid;
|
||||
// back up to this core's software id register
|
||||
SYSREG_SET(tpidr_el1, (uint64_t)cpuid);
|
||||
}
|
||||
|
||||
void
|
||||
MP_InitAP()
|
||||
{
|
||||
kprintf("AP %d booted!\n", CPU());
|
||||
cpus[CPU()].state = CPUSTATE_BOOTED;
|
||||
booted = 1;
|
||||
}
|
||||
|
||||
void
|
||||
MP_SetState(int state)
|
||||
{
|
||||
ASSERT(state > 0 && state <= CPUSTATE_MAX);
|
||||
cpus[CPU()].state = state;
|
||||
}
|
||||
|
||||
int
|
||||
MP_GetCPUs()
|
||||
{
|
||||
return lastCPU;
|
||||
}
|
||||
|
||||
void
|
||||
MP_CrossCallTrap()
|
||||
{
|
||||
int c;
|
||||
// int c;
|
||||
|
||||
Critical_Enter();
|
||||
// Critical_Enter();
|
||||
|
||||
for (c = 0; c <= lastCPU; c++) {
|
||||
CrossCallFrame *frame = cpus[c].frame;
|
||||
if (frame == NULL)
|
||||
continue;
|
||||
// for (c = 0; c <= lastCPU; c++) {
|
||||
// volatile CrossCallFrame *frame = cpu_states[c].frame;
|
||||
// if (frame == NULL)
|
||||
// continue;
|
||||
|
||||
if (frame->done[CPU()] == 1)
|
||||
continue;
|
||||
// if (frame->done[CPU()] == 1)
|
||||
// continue;
|
||||
|
||||
frame->status[CPU()] = (frame->cb)(frame->arg);
|
||||
frame->done[CPU()] = 1;
|
||||
// frame->status[CPU()] = (frame->cb)(frame->arg);
|
||||
// frame->done[CPU()] = 1;
|
||||
|
||||
// Increment
|
||||
__sync_add_and_fetch(&frame->count, 1);
|
||||
}
|
||||
// // Increment
|
||||
// __sync_add_and_fetch(&frame->count, 1);
|
||||
// }
|
||||
|
||||
Critical_Exit();
|
||||
// Critical_Exit();
|
||||
NOT_IMPLEMENTED();
|
||||
}
|
||||
|
||||
// XXX: The thread should not be migrated in the middle of this call.
|
||||
int
|
||||
MP_CrossCall(CrossCallCB cb, void *arg)
|
||||
{
|
||||
volatile CrossCallFrame frame;
|
||||
// volatile CrossCallFrame frame;
|
||||
|
||||
// Setup frame
|
||||
memset((void *)&frame, 0, sizeof(frame));
|
||||
frame.cb = cb;
|
||||
frame.arg = arg;
|
||||
frame.count = 1;
|
||||
// // Setup frame
|
||||
// memset((void *)&frame, 0, sizeof(frame));
|
||||
// frame.cb = cb;
|
||||
// frame.arg = arg;
|
||||
// frame.count = 1;
|
||||
|
||||
Critical_Enter();
|
||||
// Critical_Enter();
|
||||
|
||||
cpus[CPU()].frame = (CrossCallFrame *)&frame;
|
||||
// cpu_states[CPU()].frame = (volatile CrossCallFrame *)&frame;
|
||||
|
||||
/*
|
||||
if (LAPIC_Broadcast(T_CROSSCALL) < 0)
|
||||
return -1;
|
||||
*/
|
||||
// /*
|
||||
// if (LAPIC_Broadcast(T_CROSSCALL) < 0)
|
||||
// return -1;
|
||||
// */
|
||||
|
||||
// Run on the local CPU
|
||||
frame.status[CPU()] = cb(arg);
|
||||
frame.done[CPU()] = 1;
|
||||
// // Run on the local CPU
|
||||
// frame.status[CPU()] = cb(arg);
|
||||
// frame.done[CPU()] = 1;
|
||||
|
||||
// Wait for all to respond
|
||||
while (frame.count < lastCPU) {
|
||||
// Check for timeout
|
||||
// // Wait for all to respond
|
||||
// while (frame.count < lastCPU) {
|
||||
// // Check for timeout
|
||||
|
||||
// XXX: Should dump the crosscall frame
|
||||
}
|
||||
cpus[CPU()].frame = NULL;
|
||||
|
||||
Critical_Exit();
|
||||
// // XXX: Should dump the crosscall frame
|
||||
// }
|
||||
// cpu_states[CPU()].frame = NULL;
|
||||
|
||||
// Critical_Exit();
|
||||
NOT_IMPLEMENTED();
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
static int UNUSED
|
||||
MPPing(UNUSED void *arg)
|
||||
{
|
||||
//kprintf("CPU %d Ack\n", CPU());
|
||||
NOT_IMPLEMENTED();
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
static void UNUSED
|
||||
Debug_CrossCall(UNUSED int argc, UNUSED const char *argv[])
|
||||
{
|
||||
int i;
|
||||
UnixEpochNS startTS, stopTS;
|
||||
// int i;
|
||||
// UnixEpochNS startTS, stopTS;
|
||||
|
||||
startTS = KTime_GetEpochNS();
|
||||
for (i = 0; i < 32; i++) {
|
||||
MP_CrossCall(&MPPing, NULL);
|
||||
}
|
||||
stopTS = KTime_GetEpochNS();
|
||||
// startTS = KTime_GetEpochNS();
|
||||
// for (i = 0; i < 32; i++) {
|
||||
// MP_CrossCall(&MPPing, NULL);
|
||||
// }
|
||||
// stopTS = KTime_GetEpochNS();
|
||||
|
||||
// XXX: Print min and max
|
||||
kprintf("Average CrossCall Latency: %llu ns\n",
|
||||
(stopTS - startTS) / 32ULL);
|
||||
// // XXX: Print min and max
|
||||
// kprintf("Average CrossCall Latency: %llu ns\n",
|
||||
// (stopTS - startTS) / 32ULL);
|
||||
|
||||
return;
|
||||
// return;
|
||||
NOT_IMPLEMENTED();
|
||||
}
|
||||
|
||||
REGISTER_DBGCMD(crosscall, "Ping crosscall", Debug_CrossCall);
|
||||
//REGISTER_DBGCMD(crosscall, "Ping crosscall", Debug_CrossCall);
|
||||
|
||||
static void
|
||||
Debug_CPUS(UNUSED int argc, UNUSED const char *argv[])
|
||||
@ -195,8 +173,8 @@ Debug_CPUS(UNUSED int argc, UNUSED const char *argv[])
|
||||
int c;
|
||||
|
||||
for (c = 0; c < MAX_CPUS; c++) {
|
||||
if (cpus[c].state != CPUSTATE_NOT_PRESENT) {
|
||||
kprintf("CPU %d: %s\n", c, CPUStateToString[cpus[c].state]);
|
||||
if (cpu_states[c].state != CPUSTATE_NOT_PRESENT) {
|
||||
kprintf("CPU %d: %s\n", c, CPUStateToString[cpu_states[c].state]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -70,7 +70,9 @@ void vm_early_paging_init()
|
||||
// :
|
||||
// : "x0"
|
||||
// );
|
||||
|
||||
uint64_t zero = 0;
|
||||
SYSREG_SET(ttbr0_el1, zero);
|
||||
SYSREG_SET(ttbr1_el1, zero);
|
||||
|
||||
// reset page tables
|
||||
flushtlb();
|
||||
|
@ -75,20 +75,20 @@ PMap_Init()
|
||||
systemAS.xmem_tbl = PMapAllocPageTable();
|
||||
|
||||
if (!systemAS.dmap_tbl)
|
||||
PANIC("Cannot allocate dmap page table");
|
||||
Panic("Cannot allocate dmap page table");
|
||||
if (!systemAS.xmem_tbl)
|
||||
PANIC("Cannot allocate xmem page table");
|
||||
Panic("Cannot allocate xmem page table");
|
||||
|
||||
// Setup system mappings
|
||||
if(!PMap_SystemLMap(0x0, MEM_DIRECTMAP_BASE,
|
||||
512, PROT_ALL)) // 128GB RWX
|
||||
{
|
||||
PANIC("Cannot setup direct map");
|
||||
Panic("Cannot setup direct map");
|
||||
}
|
||||
if(!PMap_SystemLMap(0x0, MEM_DIRECTMAP_DEV_BASE,
|
||||
512, PROT_ALL | MAP_NOCACHE)) // 128GB Device
|
||||
{
|
||||
PANIC("Cannot setup device map");
|
||||
Panic("Cannot setup device map");
|
||||
}
|
||||
|
||||
PMap_LoadAS(&systemAS);
|
||||
@ -176,7 +176,7 @@ PMap_LoadAS(AS *space)
|
||||
METAL_MENTER(MRT_SET_MPTB_IDX);
|
||||
METAL_MROUTINE_GETRET(MRT_SET_MPTB_RET_STATUS, ret);
|
||||
if (ret != 0)
|
||||
PANIC("Failed to load DMAP page table.");
|
||||
Panic("Failed to load DMAP page table.");
|
||||
|
||||
// set xmem region
|
||||
idx = MRT_SET_MPTB_XMEM;
|
||||
@ -186,7 +186,7 @@ PMap_LoadAS(AS *space)
|
||||
METAL_MENTER(MRT_SET_MPTB_IDX);
|
||||
METAL_MROUTINE_GETRET(MRT_SET_MPTB_RET_STATUS, ret);
|
||||
if (ret != 0)
|
||||
PANIC("Failed to load XMEM page table.");
|
||||
Panic("Failed to load XMEM page table.");
|
||||
|
||||
// set userspace
|
||||
idx = MRT_SET_MPTB_USER;
|
||||
@ -196,7 +196,7 @@ PMap_LoadAS(AS *space)
|
||||
METAL_MENTER(MRT_SET_MPTB_IDX);
|
||||
METAL_MROUTINE_GETRET(MRT_SET_MPTB_RET_STATUS, ret);
|
||||
if (ret != 0)
|
||||
PANIC("Failed to load USER page table.");
|
||||
Panic("Failed to load USER page table.");
|
||||
|
||||
flushtlb();
|
||||
}
|
||||
@ -211,7 +211,7 @@ PMap_MapPage(uint64_t phys, uint64_t virt, uint64_t pages, uint32_t pgshift, str
|
||||
if (pd == NULL) {
|
||||
// XXX: if this fails and not the first page to be mapped
|
||||
// the this function inflicts side effects
|
||||
PANIC("Out of pdcache nodes.\n");
|
||||
Panic("Out of pdcache nodes.\n");
|
||||
}
|
||||
|
||||
pd->vaddr = (virt & ~((1ull << pgshift) - 1)) + i * (1ull << pgshift);
|
||||
|
@ -1,35 +0,0 @@
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include <sys/kassert.h>
|
||||
#include <sys/kdebug.h>
|
||||
#include <sys/ktime.h>
|
||||
|
||||
#include <machine/cpu.h>
|
||||
#include <machine/cpuop.h>
|
||||
|
||||
uint64_t
|
||||
Time_GetTSC()
|
||||
{
|
||||
uint64_t ui;
|
||||
__asm__ volatile("mrs %0, CNTVCT_EL0" : "=&r" (ui));
|
||||
return ui;
|
||||
}
|
||||
|
||||
uint64_t
|
||||
Time_GetTSCFreq()
|
||||
{
|
||||
uint64_t ui;
|
||||
__asm__ volatile("mrs %0, CNTFRQ_EL0" : "=&r" (ui));
|
||||
return ui;
|
||||
}
|
||||
|
||||
static void
|
||||
Debug_ReadTSC(UNUSED int argc, UNUSED const char *argv[])
|
||||
{
|
||||
kprintf("RDTSC: %lld\n", Time_GetTSC());
|
||||
}
|
||||
|
||||
REGISTER_DBGCMD(readtsc, "Print current timestamp", Debug_ReadTSC);
|
||||
|
72
sys/arm64/timer.c
Normal file
72
sys/arm64/timer.c
Normal file
@ -0,0 +1,72 @@
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include <sys/kassert.h>
|
||||
#include <sys/kdebug.h>
|
||||
#include <sys/ktime.h>
|
||||
#include <sys/irq.h>
|
||||
#include <sys/ktimer.h>
|
||||
|
||||
#include <machine/gic.h>
|
||||
#include <machine/cpu.h>
|
||||
#include <machine/cpuop.h>
|
||||
#include <machine/timer.h>
|
||||
|
||||
#define KTIMER_HZ (1)
|
||||
#define KTIMER_IRQ (30)
|
||||
// hardcode to 2024/03/14 12:34:56 AM EST
|
||||
#define KTIMER_EPOCH (1710390896ull)
|
||||
|
||||
static struct IRQHandler _irqh;
|
||||
|
||||
static inline void
|
||||
PTimer_Reschedule()
|
||||
{
|
||||
const uint64_t next_tsc = Time_GetTSCFreq() / KTIMER_HZ + SYSREG_GET(CNTP_CVAL_EL0);
|
||||
SYSREG_SET(CNTP_CVAL_EL0, next_tsc);
|
||||
}
|
||||
|
||||
static void
|
||||
PTimer_Tick(UNUSED void * arg)
|
||||
{
|
||||
PTimer_Reschedule();
|
||||
gic_send_eoi(KTIMER_IRQ);
|
||||
|
||||
KTimer_Process();
|
||||
|
||||
kprintf("Hardware timer tick, epoch = %llu, tsc = %llu, CVAL = %llu.\n", KTime_GetEpoch(), Time_GetTSC(), SYSREG_GET(CNTP_CVAL_EL0));
|
||||
}
|
||||
|
||||
void
|
||||
PTimer_Init()
|
||||
{
|
||||
const uint64_t tsc_freq = Time_GetTSCFreq();
|
||||
_irqh.irq = KTIMER_IRQ;
|
||||
_irqh.arg = NULL,
|
||||
_irqh.cb = PTimer_Tick;
|
||||
IRQ_Register(KTIMER_IRQ, &_irqh);
|
||||
|
||||
// read the tsc and populate counter with the current value
|
||||
const uint64_t tsc = Time_GetTSC();
|
||||
SYSREG_SET(CNTP_CVAL_EL0, tsc);
|
||||
|
||||
// reschedule the next tick
|
||||
PTimer_Reschedule();
|
||||
|
||||
// enable timer
|
||||
const uint64_t cntp_ctl_el0 = 1;
|
||||
SYSREG_SET(CNTP_CTL_EL0, cntp_ctl_el0);
|
||||
|
||||
KTime_SetTime(KTIMER_EPOCH, tsc, tsc_freq);
|
||||
kprintf("Hardware timer: epoch = %llu, tsc = %llu, tsc freq = %llu.\n", KTIMER_EPOCH, tsc, tsc_freq);
|
||||
}
|
||||
|
||||
static void
|
||||
Debug_ReadTSC(UNUSED int argc, UNUSED const char *argv[])
|
||||
{
|
||||
kprintf("RDTSC: %lld\n", Time_GetTSC());
|
||||
}
|
||||
|
||||
REGISTER_DBGCMD(readtsc, "Print current timestamp", Debug_ReadTSC);
|
||||
|
133
sys/arm64/trap.c
133
sys/arm64/trap.c
@ -1,73 +1,94 @@
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include <sys/kconfig.h>
|
||||
#include <sys/kassert.h>
|
||||
#include <sys/kdebug.h>
|
||||
#include <sys/kmem.h>
|
||||
#include <sys/ktime.h>
|
||||
#include <sys/spinlock.h>
|
||||
#include <sys/irq.h>
|
||||
#include <sys/syscall.h>
|
||||
#include <sys/mp.h>
|
||||
#include <sys/kdebug.h>
|
||||
|
||||
#include <machine/cpu.h>
|
||||
#include <machine/cpuop.h>
|
||||
#include <machine/gic.h>
|
||||
#include <machine/trap.h>
|
||||
#include <machine/mp.h>
|
||||
|
||||
#if defined(_aarch64_)
|
||||
#include <dev/arm64/uart.h>
|
||||
#endif
|
||||
|
||||
#include <sys/thread.h>
|
||||
|
||||
extern uint64_t trap_table[T_MAX];
|
||||
extern void trap_pop(TrapFrame *tf);
|
||||
extern void Debug_Breakpoint(TrapFrame *tf);
|
||||
extern void Debug_HaltIPI(TrapFrame *tf);
|
||||
extern void KTimer_Process();
|
||||
|
||||
LIST_HEAD(IRQHandlerList, IRQHandler);
|
||||
static struct IRQHandlerList handlers[T_IRQ_MAX];
|
||||
static uint64_t intStats[256];
|
||||
|
||||
void
|
||||
Trap_Init()
|
||||
IRQ_Init()
|
||||
{
|
||||
kprintf("Initializing IRQ ...\n");
|
||||
|
||||
if (gic_init() != 0) {
|
||||
Panic("GIC initialization failed!\n");
|
||||
}
|
||||
|
||||
int i;
|
||||
|
||||
kprintf("Initializing IDT... ");
|
||||
|
||||
for (i = 0; i < 256; i++) {
|
||||
intStats[i] = 0;
|
||||
for (i = 0; i < T_IRQ_MAX; i++)
|
||||
{
|
||||
intStats[i] = 0;
|
||||
LIST_INIT(&handlers[i]);
|
||||
}
|
||||
|
||||
kprintf("Done!\n");
|
||||
|
||||
enable_interrupts();
|
||||
kprintf("Initialized IRQ!\n");
|
||||
}
|
||||
|
||||
void
|
||||
Trap_InitAP()
|
||||
IRQ_Handler(int irq)
|
||||
{
|
||||
struct IRQHandler *h;
|
||||
LIST_FOREACH(h, &handlers[irq], link)
|
||||
{
|
||||
h->cb(h->arg);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
Trap_Dump(TrapFrame *tf)
|
||||
IRQ_Register(int irq, struct IRQHandler *h)
|
||||
{
|
||||
ASSERT(irq < T_IRQ_MAX);
|
||||
|
||||
LIST_INSERT_HEAD(&handlers[irq], h, link);
|
||||
|
||||
if (gic_enable_intr(irq) != 0) {
|
||||
Panic("Failed to enable interrupt.\n");
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
IRQ_Unregister(int irq, struct IRQHandler *h)
|
||||
{
|
||||
LIST_REMOVE(h, link);
|
||||
|
||||
if (LIST_EMPTY(&handlers[irq])) {
|
||||
if (gic_disable_intr(irq) != 0) {
|
||||
Panic("Failed to disable interrupt.\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
Trap_Dump(UNUSED TrapFrame *tf)
|
||||
{
|
||||
kprintf("CPU %d\n", CPU());
|
||||
kprintf("Interrupt %d Error Code: %016llx\n",
|
||||
tf->vector, tf->errcode);
|
||||
// kprintf("Interrupt %d Error Code: %016llx\n",
|
||||
// tf->vector, tf->errcode);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
Trap_StackDump(TrapFrame *tf)
|
||||
Trap_StackDump(UNUSED TrapFrame *tf)
|
||||
{
|
||||
uint64_t rsp;
|
||||
uint64_t *data;
|
||||
// uint64_t rsp;
|
||||
// uint64_t *data;
|
||||
|
||||
// XXX: This should use safe copy
|
||||
for (rsp = tf->rsp; (rsp & 0xFFF) != 0; rsp += 8) {
|
||||
data = (uint64_t *)rsp;
|
||||
kprintf("%016llx: %016llx\n", rsp, *data);
|
||||
}
|
||||
// for (rsp = tf->rsp; (rsp & 0xFFF) != 0; rsp += 8) {
|
||||
// data = (uint64_t *)rsp;
|
||||
// kprintf("%016llx: %016llx\n", rsp, *data);
|
||||
// }
|
||||
}
|
||||
|
||||
extern int copy_unsafe(void *to, void *from, uintptr_t len);
|
||||
@ -79,28 +100,14 @@ extern void copystr_unsafe_done(void);
|
||||
extern void copystr_unsafe_fault(void);
|
||||
|
||||
void
|
||||
trap_entry(void)
|
||||
trap_entry(TrapFrame * tf)
|
||||
{
|
||||
uint64_t id;
|
||||
__asm__ volatile (
|
||||
"mrs %x0, ICC_IAR1_EL1;"
|
||||
: "=r" (id)
|
||||
:
|
||||
:
|
||||
);
|
||||
|
||||
kprintf("Unhandled irq: 0x%x\n", id);
|
||||
|
||||
if (id == 30) {
|
||||
__asm__ volatile (
|
||||
"mrs x1, CNTFRQ_EL0;"
|
||||
"msr CNTP_TVAL_EL0, x1;"
|
||||
"msr ICC_EOIR1_EL1, %x0;"
|
||||
"dsb sy;"
|
||||
:
|
||||
: "r" (id)
|
||||
: "x1"
|
||||
);
|
||||
if (tf->type == T_TYPE_EXC) {
|
||||
Panic("Unexpected exception: Type = 0x%llx, IntID = 0x%llx, ESR = 0x%llx, FAR = 0x%llx, ELR = 0x%llx, SPSR = 0x%llx.\n", tf->type, tf->intid, tf->esr, tf->far, tf->elr, tf->spsr);
|
||||
} else {
|
||||
kprintf("IRQ: Type = 0x%llx, IntID = 0x%llx, ESR = 0x%llx, FAR = 0x%llx, ELR = 0x%llx, SPSR = 0x%llx.\n", tf->type, tf->intid, tf->esr, tf->far, tf->elr, tf->spsr);
|
||||
// irq
|
||||
IRQ_Handler(tf->intid);
|
||||
}
|
||||
}
|
||||
|
||||
@ -110,11 +117,11 @@ Debug_Traps(UNUSED int argc, UNUSED const char *argv[])
|
||||
int i;
|
||||
|
||||
kprintf("Trap Interrupts Trap Interrupts\n");
|
||||
for (i = 0; i < T_MAX / 2; i++)
|
||||
for (i = 0; i < T_IRQ_MAX / 2; i++)
|
||||
{
|
||||
kprintf("%-4d %-12d %-4d %-12d\n",
|
||||
i, intStats[i],
|
||||
T_MAX / 2 + i, intStats[T_MAX / 2 + i]);
|
||||
T_IRQ_MAX / 2 + i, intStats[T_IRQ_MAX / 2 + i]);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,13 +1,9 @@
|
||||
#include <machine/metalasm.h>
|
||||
/*
|
||||
* Trap Handlers
|
||||
*/
|
||||
|
||||
.extern trap_entry
|
||||
|
||||
.text
|
||||
|
||||
trap_locore_entry:
|
||||
stp lr, lr, [sp, #-16]!
|
||||
.macro trapframe_save_common type
|
||||
stp x30, x31, [sp, #-16]!
|
||||
stp x28, x29, [sp, #-16]!
|
||||
stp x26, x27, [sp, #-16]!
|
||||
stp x24, x25, [sp, #-16]!
|
||||
@ -23,16 +19,95 @@ trap_locore_entry:
|
||||
stp x4, x5, [sp, #-16]!
|
||||
stp x2, x3, [sp, #-16]!
|
||||
stp x0, x1, [sp, #-16]!
|
||||
; mrs x0, spsr_el1
|
||||
; mrs x1, elr_el1
|
||||
; stp x0, x1, [sp, #-16]!
|
||||
|
||||
.extern trap_entry
|
||||
bl trap_entry
|
||||
// Metal Registers
|
||||
MASM_RMR(METAL_REG_MO4, AARCH_REG_X0)
|
||||
MASM_RMR(METAL_REG_MO5, AARCH_REG_X1)
|
||||
stp x0, x1, [sp, #-16]!
|
||||
|
||||
MASM_RMR(METAL_REG_MO2, AARCH_REG_X0)
|
||||
MASM_RMR(METAL_REG_MO3, AARCH_REG_X1)
|
||||
stp x0, x1, [sp, #-16]!
|
||||
|
||||
MASM_RMR(METAL_REG_MO0, AARCH_REG_X0)
|
||||
MASM_RMR(METAL_REG_MO1, AARCH_REG_X1)
|
||||
stp x0, x1, [sp, #-16]!
|
||||
|
||||
MASM_RMR(METAL_REG_MR2, AARCH_REG_X0)
|
||||
MASM_RMR(METAL_REG_MR3, AARCH_REG_X1)
|
||||
stp x0, x1, [sp, #-16]!
|
||||
|
||||
MASM_RMR(METAL_REG_MR0, AARCH_REG_X0)
|
||||
MASM_RMR(METAL_REG_MR1, AARCH_REG_X1)
|
||||
stp x0, x1, [sp, #-16]!
|
||||
|
||||
MASM_RMR(METAL_REG_MI4, AARCH_REG_X0)
|
||||
MASM_RMR(METAL_REG_MI5, AARCH_REG_X1)
|
||||
stp x0, x1, [sp, #-16]!
|
||||
|
||||
MASM_RMR(METAL_REG_MI2, AARCH_REG_X0)
|
||||
MASM_RMR(METAL_REG_MI3, AARCH_REG_X1)
|
||||
stp x0, x1, [sp, #-16]!
|
||||
|
||||
MASM_RMR(METAL_REG_MI0, AARCH_REG_X0)
|
||||
MASM_RMR(METAL_REG_MI1, AARCH_REG_X1)
|
||||
stp x0, x1, [sp, #-16]!
|
||||
|
||||
// ELR and SPSR
|
||||
mrs x0, elr_el1
|
||||
mrs x1, spsr_el1
|
||||
stp x0, x1, [sp, #-16]!
|
||||
|
||||
// FAR and ESR
|
||||
mrs x0, esr_el1
|
||||
mrs x1, far_el1
|
||||
stp x0, x1, [sp, #-16]!
|
||||
|
||||
// IAR and type
|
||||
mov x0, #\type
|
||||
mrs x1, ICC_IAR1_EL1
|
||||
stp x0, x1, [sp, #-16]!
|
||||
.endm
|
||||
|
||||
.macro trapframe_restore_common
|
||||
add sp, sp, #32 // skip status, IAR, FAR and ESR
|
||||
|
||||
ldp x0, x1, [sp], #16
|
||||
msr elr_el1, x0
|
||||
msr spsr_el1, x1
|
||||
|
||||
ldp x0, x1, [sp], #16
|
||||
MASM_WMR(METAL_REG_MI0, AARCH_REG_X0)
|
||||
MASM_WMR(METAL_REG_MI1, AARCH_REG_X1)
|
||||
|
||||
ldp x0, x1, [sp], #16
|
||||
MASM_WMR(METAL_REG_MI2, AARCH_REG_X0)
|
||||
MASM_WMR(METAL_REG_MI3, AARCH_REG_X1)
|
||||
|
||||
ldp x0, x1, [sp], #16
|
||||
MASM_WMR(METAL_REG_MI4, AARCH_REG_X0)
|
||||
MASM_WMR(METAL_REG_MI5, AARCH_REG_X1)
|
||||
|
||||
ldp x0, x1, [sp], #16
|
||||
MASM_WMR(METAL_REG_MR0, AARCH_REG_X0)
|
||||
MASM_WMR(METAL_REG_MR1, AARCH_REG_X1)
|
||||
|
||||
ldp x0, x1, [sp], #16
|
||||
MASM_WMR(METAL_REG_MR2, AARCH_REG_X0)
|
||||
MASM_WMR(METAL_REG_MR3, AARCH_REG_X1)
|
||||
|
||||
ldp x0, x1, [sp], #16
|
||||
MASM_WMR(METAL_REG_MO0, AARCH_REG_X0)
|
||||
MASM_WMR(METAL_REG_MO1, AARCH_REG_X1)
|
||||
|
||||
ldp x0, x1, [sp], #16
|
||||
MASM_WMR(METAL_REG_MO2, AARCH_REG_X0)
|
||||
MASM_WMR(METAL_REG_MO3, AARCH_REG_X1)
|
||||
|
||||
ldp x0, x1, [sp], #16
|
||||
MASM_WMR(METAL_REG_MO4, AARCH_REG_X0)
|
||||
MASM_WMR(METAL_REG_MO5, AARCH_REG_X1)
|
||||
|
||||
; ldp x0, x1, [sp], #16
|
||||
; msr spsr_el1, x0
|
||||
; msr elr_el1, x1
|
||||
ldp x0, x1, [sp], #16
|
||||
ldp x2, x3, [sp], #16
|
||||
ldp x4, x5, [sp], #16
|
||||
@ -48,8 +123,25 @@ trap_locore_entry:
|
||||
ldp x24, x25, [sp], #16
|
||||
ldp x26, x27, [sp], #16
|
||||
ldp x28, x29, [sp], #16
|
||||
ldp lr, lr, [sp], #16
|
||||
ldp x30, x31, [sp], #16
|
||||
// daif bits are stored in PSTATE and are automatically re-enabled by eret
|
||||
.endm
|
||||
|
||||
.extern trap_entry
|
||||
.text
|
||||
|
||||
interrupt_locore_entry:
|
||||
trapframe_save_common 1
|
||||
mov x0, sp
|
||||
bl trap_entry
|
||||
trapframe_restore_common
|
||||
eret
|
||||
|
||||
exception_locore_entry:
|
||||
trapframe_save_common 0
|
||||
mov x0, sp
|
||||
bl trap_entry
|
||||
trapframe_restore_common
|
||||
eret
|
||||
|
||||
.global _evt
|
||||
@ -66,9 +158,10 @@ b _halt
|
||||
|
||||
// same exception level, spX: sync, irq, fiq, serror
|
||||
.balign 0x80
|
||||
b exception_locore_entry
|
||||
b _halt
|
||||
.balign 0x80
|
||||
b trap_locore_entry
|
||||
b interrupt_locore_entry
|
||||
b _halt
|
||||
.balign 0x80
|
||||
b _halt
|
||||
|
@ -1,29 +0,0 @@
|
||||
#pragma once
|
||||
#include <stdint.h>
|
||||
|
||||
uint32_t
|
||||
gic_get_affinity(void);
|
||||
|
||||
void
|
||||
gic_set_prio_mask(unsigned int mask);
|
||||
|
||||
int
|
||||
gic_set_intr_prio(uint32_t rdid, uint32_t intid, uint8_t prio);
|
||||
|
||||
void
|
||||
gic_send_eoi(int intr);
|
||||
|
||||
unsigned int
|
||||
gic_ack_intr(void);
|
||||
|
||||
int
|
||||
gic_init(void);
|
||||
|
||||
int
|
||||
gic_enable_intr(uint32_t rdid, uint32_t intid);
|
||||
|
||||
int
|
||||
gic_disable_intr(uint32_t rd, uint32_t intid);
|
||||
|
||||
int
|
||||
gic_get_redist_id(uint32_t affinity, unsigned int *id);
|
@ -90,7 +90,7 @@ static void
|
||||
uart_init(struct uart *dev)
|
||||
{
|
||||
if (!uart_discover(dev)) {
|
||||
PANIC("Failed to discover uart");
|
||||
Panic("Failed to discover uart");
|
||||
}
|
||||
|
||||
uint32_t cr = uart_readreg(dev, UART_CR_OFFSET);
|
||||
@ -157,4 +157,5 @@ void
|
||||
Serial_Init(void)
|
||||
{
|
||||
uart_init(&g_uart0);
|
||||
kprintf("Initialized PL011 UART, base = 0x%llx.\n", g_uart0.base);
|
||||
}
|
@ -100,10 +100,16 @@ Console_EnqueueKey(char key)
|
||||
|
||||
#if defined(__aarch64__)
|
||||
void
|
||||
Panic(const char *str)
|
||||
Panic(const char *str, ...)
|
||||
{
|
||||
Serial_Send(str, strlen(str));
|
||||
Halt();
|
||||
va_list args;
|
||||
va_start(args, str);
|
||||
kvprintf(str, args);
|
||||
va_end(args);
|
||||
// Serial_Send(str, strlen(str));
|
||||
while (true) {
|
||||
Halt();
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
|
@ -14,6 +14,7 @@
|
||||
|
||||
#define NO_RETURN __attribute__((noreturn))
|
||||
#define UNREACHABLE __builtin_unreachable
|
||||
#define PRINTF_LIKE __attribute__((format(printf, 1, 2)))
|
||||
|
||||
#define UNUSED __attribute__((unused))
|
||||
|
||||
|
@ -4,6 +4,7 @@
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
#include <sys/sysctl.h>
|
||||
#include <stdarg.h>
|
||||
|
||||
#define ASSERT(_x) \
|
||||
if (!(_x)) { \
|
||||
@ -15,9 +16,8 @@
|
||||
Debug_Assert("NOT_IMPLEMENTED(): %s %s:%d\n", \
|
||||
__FUNCTION__, __FILE__, __LINE__); \
|
||||
}
|
||||
#define PANIC Panic
|
||||
|
||||
NO_RETURN void Panic(const char *str);
|
||||
NO_RETURN void Panic(const char *str, ...);
|
||||
|
||||
#if defined(__aarch64__)
|
||||
NO_RETURN extern void
|
||||
@ -31,6 +31,7 @@ Halt(void)
|
||||
#endif
|
||||
|
||||
int kprintf(const char *fmt, ...);
|
||||
int kvprintf(const char *fmt, va_list ap);
|
||||
NO_RETURN void Debug_Assert(const char *fmt, ...);
|
||||
|
||||
#define static_assert _Static_assert
|
||||
|
@ -2,7 +2,9 @@
|
||||
#ifndef __SYS_KTIME_H__
|
||||
#define __SYS_KTIME_H__
|
||||
|
||||
uint64_t Time_GetTSC();
|
||||
//XXX: breaks x86
|
||||
#include <machine/timer.h>
|
||||
#include <stdint.h>
|
||||
|
||||
typedef struct KTime {
|
||||
int sec;
|
||||
|
@ -7,11 +7,7 @@ uint32_t LAPIC_CPU();
|
||||
|
||||
#define CPU LAPIC_CPU
|
||||
#elif defined(__aarch64__)
|
||||
static inline unsigned int ARM_CPU()
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
#define CPU ARM_CPU
|
||||
#include <machine/mp.h>
|
||||
#endif
|
||||
|
||||
#endif /* __MP_H__ */
|
||||
|
@ -2,6 +2,7 @@
|
||||
#include <stddef.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <stdatomic.h>
|
||||
|
||||
#include <sys/kassert.h>
|
||||
#include <sys/queue.h>
|
||||
@ -61,14 +62,14 @@ void
|
||||
KTimer_Retain(KTimerEvent *evt)
|
||||
{
|
||||
ASSERT(evt->refCount != 0);
|
||||
__sync_fetch_and_add(&evt->refCount, 1);
|
||||
atomic_fetch_add(&evt->refCount, 1);
|
||||
}
|
||||
|
||||
void
|
||||
KTimer_Release(KTimerEvent *evt)
|
||||
{
|
||||
ASSERT(evt->refCount != 0);
|
||||
if (__sync_fetch_and_sub(&evt->refCount, 1) == 1) {
|
||||
if (atomic_fetch_sub(&evt->refCount, 1) == 1) {
|
||||
KTimerEvent_Free(evt);
|
||||
}
|
||||
}
|
||||
@ -90,7 +91,7 @@ KTimer_Process()
|
||||
uint64_t now;
|
||||
|
||||
if (CPU() != 0) {
|
||||
return;
|
||||
return;
|
||||
}
|
||||
|
||||
now = KTime_GetEpoch();
|
||||
|
@ -75,7 +75,8 @@ static void printnum(void (*func)(int, void*),void *handle,
|
||||
}
|
||||
}
|
||||
|
||||
int kvprintf(char const *fmt, void (*func)(int,void *), void *handle, va_list ap)
|
||||
static int
|
||||
_kvprintf(char const *fmt, void (*func)(int,void *), void *handle, va_list ap)
|
||||
{
|
||||
const char *p;
|
||||
int ch;
|
||||
@ -199,7 +200,8 @@ again:
|
||||
return 0;
|
||||
}
|
||||
|
||||
void consoleputc(int c,void* handle)
|
||||
static void
|
||||
consoleputc(int c,void* handle)
|
||||
{
|
||||
if (c == '\n') {
|
||||
Console_Putc('\r');
|
||||
@ -207,13 +209,20 @@ void consoleputc(int c,void* handle)
|
||||
Console_Putc(c);
|
||||
}
|
||||
|
||||
int kprintf(const char *fmt, ...)
|
||||
int
|
||||
kvprintf(const char *fmt, va_list ap)
|
||||
{
|
||||
return _kvprintf(fmt, consoleputc, 0, ap);
|
||||
}
|
||||
|
||||
int
|
||||
kprintf(const char *fmt, ...)
|
||||
{
|
||||
int ret;
|
||||
va_list ap;
|
||||
|
||||
va_start(ap, fmt);
|
||||
ret = kvprintf(fmt, consoleputc, 0, ap);
|
||||
ret = kvprintf(fmt, ap);
|
||||
va_end(ap);
|
||||
|
||||
return ret;
|
||||
@ -224,7 +233,7 @@ void Debug_Assert(const char *fmt, ...)
|
||||
va_list ap;
|
||||
|
||||
va_start(ap, fmt);
|
||||
kvprintf(fmt, consoleputc, 0, ap);
|
||||
kvprintf(fmt, ap);
|
||||
va_end(ap);
|
||||
|
||||
#if 0
|
||||
|
@ -6,6 +6,7 @@
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
#include <stdatomic.h>
|
||||
|
||||
#include <errno.h>
|
||||
#include <sys/syscall.h>
|
||||
@ -171,7 +172,7 @@ void
|
||||
Process_Retain(Process *proc)
|
||||
{
|
||||
ASSERT(proc->refCount != 0);
|
||||
__sync_fetch_and_add(&proc->refCount, 1);
|
||||
atomic_fetch_add(&proc->refCount, 1);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -185,7 +186,7 @@ void
|
||||
Process_Release(Process *proc)
|
||||
{
|
||||
ASSERT(proc->refCount != 0);
|
||||
if (__sync_fetch_and_sub(&proc->refCount, 1) == 1) {
|
||||
if (atomic_fetch_sub(&proc->refCount, 1) == 1) {
|
||||
Process_Destroy(proc);
|
||||
}
|
||||
}
|
||||
|
@ -7,6 +7,7 @@
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
#include <stdatomic.h>
|
||||
|
||||
#include <sys/kassert.h>
|
||||
#include <sys/kconfig.h>
|
||||
@ -15,7 +16,6 @@
|
||||
#include <sys/mp.h>
|
||||
#include <sys/spinlock.h>
|
||||
|
||||
#include <machine/atomic.h>
|
||||
#include <machine/cpu.h>
|
||||
#include <machine/metal.h>
|
||||
#include <machine/cpuop.h>
|
||||
@ -82,7 +82,7 @@ Spinlock_Lock(Spinlock *lock) __NO_LOCK_ANALYSIS
|
||||
Critical_Enter();
|
||||
|
||||
startTSC = Time_GetTSC();
|
||||
while (atomic_swap_uint64(&lock->lock, 1) == 1)
|
||||
while (atomic_exchange(&lock->lock, 1) == 1)
|
||||
{
|
||||
if (lock->type == SPINLOCK_TYPE_RECURSIVE && lock->cpu == CPU()) {
|
||||
break;
|
||||
@ -120,7 +120,7 @@ Spinlock_Unlock(Spinlock *lock) __NO_LOCK_ANALYSIS
|
||||
if (lock->rCount == 0) {
|
||||
lock->cpu = 0;
|
||||
lock->lockTime += Time_GetTSC() - lock->lockedTSC;
|
||||
atomic_set_uint64(&lock->lock, 0);
|
||||
atomic_store(&lock->lock, 0);
|
||||
}
|
||||
|
||||
Critical_Exit();
|
||||
|
@ -6,6 +6,7 @@
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
#include <stdatomic.h>
|
||||
|
||||
#include <errno.h>
|
||||
#include <sys/syscall.h>
|
||||
@ -254,7 +255,7 @@ void
|
||||
Thread_Retain(Thread *thr)
|
||||
{
|
||||
ASSERT(thr->refCount != 0);
|
||||
__sync_fetch_and_add(&thr->refCount, 1);
|
||||
atomic_fetch_add(&thr->refCount, 1);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -266,7 +267,7 @@ void
|
||||
Thread_Release(Thread *thr)
|
||||
{
|
||||
ASSERT(thr->refCount != 0);
|
||||
if (__sync_fetch_and_sub(&thr->refCount, 1) == 1) {
|
||||
if (atomic_fetch_sub(&thr->refCount, 1) == 1) {
|
||||
Thread_Destroy(thr);
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user