bootstrap,gic,timer
This commit is contained in:
parent
f7c3993e2d
commit
17db81c514
@ -63,7 +63,7 @@ _free_file(FILE *fh)
|
||||
}
|
||||
|
||||
FILE *
|
||||
fopen(const char *path, const char *mode)
|
||||
fopen(const char *path, const char *mode UNUSED)
|
||||
{
|
||||
uint64_t fd;
|
||||
FILE *fh;
|
||||
@ -93,14 +93,14 @@ fclose(FILE *fh)
|
||||
}
|
||||
|
||||
int
|
||||
feof(FILE *fh)
|
||||
feof(FILE *fh UNUSED)
|
||||
{
|
||||
errno = ENOSYS;
|
||||
return -1;
|
||||
}
|
||||
|
||||
int
|
||||
fflush(FILE *fh)
|
||||
fflush(FILE *fh UNUSED)
|
||||
{
|
||||
errno = ENOSYS;
|
||||
return -1;
|
||||
|
@ -54,7 +54,9 @@ src_arm64 = [
|
||||
"arm64/time.c",
|
||||
"arm64/trap.c",
|
||||
"arm64/trapentry.S",
|
||||
"arm64/gic.c",
|
||||
# Devices
|
||||
"dev/arm64/uart.c",
|
||||
]
|
||||
|
||||
src_common = [
|
||||
|
682
sys/arm64/gic.c
Normal file
682
sys/arm64/gic.c
Normal file
@ -0,0 +1,682 @@
|
||||
#include <machine/gic.h>
|
||||
#include "sys/cdefs.h"
|
||||
#include "errno.h"
|
||||
#include <sys/kassert.h>
|
||||
|
||||
#define DIST_BASE_ADDR (0x2c000000)
|
||||
#define REDIST_BASE_ADDR (0x2c010000)
|
||||
|
||||
struct GICv3_dist_if
|
||||
{
|
||||
volatile uint32_t GICD_CTLR; // +0x0000 - RW - Distributor Control Register
|
||||
const volatile uint32_t GICD_TYPER; // +0x0004 - RO - Interrupt Controller Type Register
|
||||
const volatile uint32_t GICD_IIDR; // +0x0008 - RO - Distributor Implementer Identification Register
|
||||
|
||||
const volatile uint32_t padding0; // +0x000C - RESERVED
|
||||
|
||||
volatile uint32_t GICD_STATUSR; // +0x0010 - RW - Status register
|
||||
|
||||
const volatile uint32_t padding1[3]; // +0x0014 - RESERVED
|
||||
|
||||
volatile uint32_t IMP_DEF[8]; // +0x0020 - RW - Implementation defined registers
|
||||
|
||||
volatile uint32_t GICD_SETSPI_NSR; // +0x0040 - WO - Non-secure Set SPI Pending (Used when SPI is signalled using MSI)
|
||||
const volatile uint32_t padding2; // +0x0044 - RESERVED
|
||||
volatile uint32_t GICD_CLRSPI_NSR; // +0x0048 - WO - Non-secure Clear SPI Pending (Used when SPI is signalled using MSI)
|
||||
const volatile uint32_t padding3; // +0x004C - RESERVED
|
||||
volatile uint32_t GICD_SETSPI_SR; // +0x0050 - WO - Secure Set SPI Pending (Used when SPI is signalled using MSI)
|
||||
const volatile uint32_t padding4; // +0x0054 - RESERVED
|
||||
volatile uint32_t GICD_CLRSPI_SR; // +0x0058 - WO - Secure Clear SPI Pending (Used when SPI is signalled using MSI)
|
||||
|
||||
const volatile uint32_t padding5[3]; // +0x005C - RESERVED
|
||||
|
||||
volatile uint32_t GICD_SEIR; // +0x0068 - WO - System Error Interrupt Register (Note: This was recently removed from the spec)
|
||||
|
||||
const volatile uint32_t padding6[5]; // +0x006C - RESERVED
|
||||
|
||||
volatile uint32_t GICD_IGROUPR[32]; // +0x0080 - RW - Interrupt Group Registers (Note: In GICv3, need to look at IGROUPR and IGRPMODR)
|
||||
|
||||
volatile uint32_t GICD_ISENABLER[32]; // +0x0100 - RW - Interrupt Set-Enable Registers
|
||||
volatile uint32_t GICD_ICENABLER[32]; // +0x0180 - RW - Interrupt Clear-Enable Registers
|
||||
volatile uint32_t GICD_ISPENDR[32]; // +0x0200 - RW - Interrupt Set-Pending Registers
|
||||
volatile uint32_t GICD_ICPENDR[32]; // +0x0280 - RW - Interrupt Clear-Pending Registers
|
||||
volatile uint32_t GICD_ISACTIVER[32]; // +0x0300 - RW - Interrupt Set-Active Register
|
||||
volatile uint32_t GICD_ICACTIVER[32]; // +0x0380 - RW - Interrupt Clear-Active Register
|
||||
|
||||
volatile uint8_t GICD_IPRIORITYR[1024]; // +0x0400 - RW - Interrupt Priority Registers
|
||||
volatile uint32_t GICD_ITARGETSR[256]; // +0x0800 - RW - Interrupt Processor Targets Registers
|
||||
volatile uint32_t GICD_ICFGR[64]; // +0x0C00 - RW - Interrupt Configuration Registers
|
||||
volatile uint32_t GICD_GRPMODR[32]; // +0x0D00 - RW - Interrupt Group Modifier (Note: In GICv3, need to look at IGROUPR and IGRPMODR)
|
||||
const volatile uint32_t padding7[32]; // +0x0D80 - RESERVED
|
||||
volatile uint32_t GICD_NSACR[64]; // +0x0E00 - RW - Non-secure Access Control Register
|
||||
|
||||
volatile uint32_t GICD_SGIR; // +0x0F00 - WO - Software Generated Interrupt Register
|
||||
|
||||
const volatile uint32_t padding8[3]; // +0x0F04 - RESERVED
|
||||
|
||||
volatile uint32_t GICD_CPENDSGIR[4]; // +0x0F10 - RW - Clear pending for SGIs
|
||||
volatile uint32_t GICD_SPENDSGIR[4]; // +0x0F20 - RW - Set pending for SGIs
|
||||
|
||||
const volatile uint32_t padding9[52]; // +0x0F30 - RESERVED
|
||||
|
||||
// GICv3.1 extended SPI range
|
||||
volatile uint32_t GICD_IGROUPRE[128]; // +0x1000 - RW - Interrupt Group Registers (GICv3.1)
|
||||
volatile uint32_t GICD_ISENABLERE[128]; // +0x1200 - RW - Interrupt Set-Enable Registers (GICv3.1)
|
||||
volatile uint32_t GICD_ICENABLERE[128]; // +0x1400 - RW - Interrupt Clear-Enable Registers (GICv3.1)
|
||||
volatile uint32_t GICD_ISPENDRE[128]; // +0x1600 - RW - Interrupt Set-Pending Registers (GICv3.1)
|
||||
volatile uint32_t GICD_ICPENDRE[128]; // +0x1800 - RW - Interrupt Clear-Pending Registers (GICv3.1)
|
||||
volatile uint32_t GICD_ISACTIVERE[128]; // +0x1A00 - RW - Interrupt Set-Active Register (GICv3.1)
|
||||
volatile uint32_t GICD_ICACTIVERE[128]; // +0x1C00 - RW - Interrupt Clear-Active Register (GICv3.1)
|
||||
|
||||
const volatile uint32_t padding10[128]; // +0x1E00 - RESERVED
|
||||
|
||||
volatile uint8_t GICD_IPRIORITYRE[4096]; // +0x2000 - RW - Interrupt Priority Registers (GICv3.1)
|
||||
|
||||
volatile uint32_t GICD_ICFGRE[256]; // +0x3000 - RW - Interrupt Configuration Registers (GICv3.1)
|
||||
volatile uint32_t GICD_IGRPMODRE[128]; // +0x3400 - RW - Interrupt Group Modifier (GICv3.1)
|
||||
volatile uint32_t GICD_NSACRE[256]; // +0x3600 - RW - Non-secure Access Control Register (GICv3.1)
|
||||
|
||||
const volatile uint32_t padding11[2432]; // +0x3A00 - RESERVED
|
||||
|
||||
// GICv3.0
|
||||
volatile uint64_t GICD_ROUTER[1024]; // +0x6000 - RW - Controls SPI routing when ARE=1
|
||||
|
||||
// GICv3.1
|
||||
volatile uint64_t GICD_ROUTERE[1024]; // +0x8000 - RW - Controls SPI routing when ARE=1 (GICv3.1)
|
||||
};
|
||||
|
||||
struct GICv3_rdist_lpis_if
|
||||
{
|
||||
volatile uint32_t GICR_CTLR; // +0x0000 - RW - Redistributor Control Register
|
||||
const volatile uint32_t GICR_IIDR; // +0x0004 - RO - Redistributor Implementer Identification Register
|
||||
const volatile uint64_t GICR_TYPER; // +0x0008 - RO - Redistributor Type Register
|
||||
volatile uint32_t GICR_STATUSR; // +0x0010 - RW - Redistributor Status register
|
||||
volatile uint32_t GICR_WAKER; // +0x0014 - RW - Wake Request Registers
|
||||
const volatile uint32_t GICR_MPAMIDR; // +0x0018 - RO - Reports maximum PARTID and PMG (GICv3.1)
|
||||
volatile uint32_t GICR_PARTID; // +0x001C - RW - Set PARTID and PMG used for Redistributor memory accesses (GICv3.1)
|
||||
const volatile uint32_t padding1[8]; // +0x0020 - RESERVED
|
||||
volatile uint64_t GICR_SETLPIR; // +0x0040 - WO - Set LPI pending (Note: IMP DEF if ITS present)
|
||||
volatile uint64_t GICR_CLRLPIR; // +0x0048 - WO - Set LPI pending (Note: IMP DEF if ITS present)
|
||||
const volatile uint32_t padding2[6]; // +0x0058 - RESERVED
|
||||
volatile uint32_t GICR_SEIR; // +0x0068 - WO - (Note: This was removed from the spec)
|
||||
const volatile uint32_t padding3; // +0x006C - RESERVED
|
||||
volatile uint64_t GICR_PROPBASER; // +0x0070 - RW - Sets location of the LPI configuration table
|
||||
volatile uint64_t GICR_PENDBASER; // +0x0078 - RW - Sets location of the LPI pending table
|
||||
const volatile uint32_t padding4[8]; // +0x0080 - RESERVED
|
||||
volatile uint64_t GICR_INVLPIR; // +0x00A0 - WO - Invalidates cached LPI config (Note: In GICv3.x: IMP DEF if ITS present)
|
||||
const volatile uint32_t padding5[2]; // +0x00A8 - RESERVED
|
||||
volatile uint64_t GICR_INVALLR; // +0x00B0 - WO - Invalidates cached LPI config (Note: In GICv3.x: IMP DEF if ITS present)
|
||||
const volatile uint32_t padding6[2]; // +0x00B8 - RESERVED
|
||||
volatile uint64_t GICR_SYNCR; // +0x00C0 - WO - Redistributor Sync
|
||||
const volatile uint32_t padding7[2]; // +0x00C8 - RESERVED
|
||||
const volatile uint32_t padding8[12]; // +0x00D0 - RESERVED
|
||||
volatile uint64_t GICR_MOVLPIR; // +0x0100 - WO - IMP DEF
|
||||
const volatile uint32_t padding9[2]; // +0x0108 - RESERVED
|
||||
volatile uint64_t GICR_MOVALLR; // +0x0110 - WO - IMP DEF
|
||||
const volatile uint32_t padding10[2]; // +0x0118 - RESERVED
|
||||
};
|
||||
|
||||
struct GICv3_rdist_sgis_if
|
||||
{
|
||||
const volatile uint32_t padding1[32]; // +0x0000 - RESERVED
|
||||
volatile uint32_t GICR_IGROUPR[3]; // +0x0080 - RW - Interrupt Group Registers (Security Registers in GICv1)
|
||||
const volatile uint32_t padding2[29]; // +0x008C - RESERVED
|
||||
volatile uint32_t GICR_ISENABLER[3]; // +0x0100 - RW - Interrupt Set-Enable Registers
|
||||
const volatile uint32_t padding3[29]; // +0x010C - RESERVED
|
||||
volatile uint32_t GICR_ICENABLER[3]; // +0x0180 - RW - Interrupt Clear-Enable Registers
|
||||
const volatile uint32_t padding4[29]; // +0x018C - RESERVED
|
||||
volatile uint32_t GICR_ISPENDR[3]; // +0x0200 - RW - Interrupt Set-Pending Registers
|
||||
const volatile uint32_t padding5[29]; // +0x020C - RESERVED
|
||||
volatile uint32_t GICR_ICPENDR[3]; // +0x0280 - RW - Interrupt Clear-Pending Registers
|
||||
const volatile uint32_t padding6[29]; // +0x028C - RESERVED
|
||||
volatile uint32_t GICR_ISACTIVER[3]; // +0x0300 - RW - Interrupt Set-Active Register
|
||||
const volatile uint32_t padding7[29]; // +0x030C - RESERVED
|
||||
volatile uint32_t GICR_ICACTIVER[3]; // +0x0380 - RW - Interrupt Clear-Active Register
|
||||
const volatile uint32_t padding8[29]; // +0x018C - RESERVED
|
||||
volatile uint8_t GICR_IPRIORITYR[96]; // +0x0400 - RW - Interrupt Priority Registers
|
||||
const volatile uint32_t padding9[488]; // +0x0460 - RESERVED
|
||||
volatile uint32_t GICR_ICFGR[6]; // +0x0C00 - RW - Interrupt Configuration Registers
|
||||
const volatile uint32_t padding10[58]; // +0x0C18 - RESERVED
|
||||
volatile uint32_t GICR_IGRPMODR[3]; // +0x0D00 - RW - Interrupt Group Modifier Register
|
||||
const volatile uint32_t padding11[61]; // +0x0D0C - RESERVED
|
||||
volatile uint32_t GICR_NSACR; // +0x0E00 - RW - Non-secure Access Control Register
|
||||
|
||||
};
|
||||
|
||||
struct GICv3_rdist_vlpis_if
|
||||
{
|
||||
const volatile uint32_t padding1[28]; // +0x0000 - RESERVED
|
||||
volatile uint64_t GICR_VPROPBASER; // +0x0070 - RW - Sets location of the LPI vPE Configuration table
|
||||
volatile uint64_t GICR_VPENDBASER; // +0x0078 - RW - Sets location of the LPI Pending table
|
||||
};
|
||||
|
||||
struct GICv3_rdist_res_if
|
||||
{
|
||||
const volatile uint32_t padding1[32]; // +0x0000 - RESERVED
|
||||
};
|
||||
|
||||
struct GICv3_rdist_if
|
||||
{
|
||||
struct GICv3_rdist_lpis_if lpis __attribute__((aligned (0x10000)));
|
||||
struct GICv3_rdist_sgis_if sgis __attribute__((aligned (0x10000)));
|
||||
|
||||
#ifdef GICV4
|
||||
struct GICv3_rdist_vlpis_if vlpis __attribute__((aligned (0x10000)));
|
||||
struct GICv3_rdist_res_if res __attribute__((aligned (0x10000)));
|
||||
#endif
|
||||
};
|
||||
|
||||
|
||||
// +0 from ITS_BASE
|
||||
struct GICv3_its_ctlr_if
|
||||
{
|
||||
volatile uint32_t GITS_CTLR; // +0x0000 - RW - ITS Control Register
|
||||
const volatile uint32_t GITS_IIDR; // +0x0004 - RO - Implementer Identification Register
|
||||
const volatile uint64_t GITS_TYPER; // +0x0008 - RO - ITS Type register
|
||||
const volatile uint32_t GITS_MPAMIDR; // +0x0010 - RO - Reports maxmimum PARTID and PMG (GICv3.1)
|
||||
volatile uint32_t GITS_PARTIDR; // +0x0004 - RW - Sets the PARTID and PMG used for ITS memory accesses (GICv3.1)
|
||||
const volatile uint32_t GITS_MPIDR; // +0x0018 - RO - ITS affinity, used for shared vPE table
|
||||
const volatile uint32_t padding5; // +0x001C - RESERVED
|
||||
volatile uint32_t GITS_IMPDEF[8]; // +0x0020 - RW - IMP DEF registers
|
||||
const volatile uint32_t padding2[16]; // +0x0040 - RESERVED
|
||||
volatile uint64_t GITS_CBASER; // +0x0080 - RW - Sets base address of ITS command queue
|
||||
volatile uint64_t GITS_CWRITER; // +0x0088 - RW - Points to next enrty to add command
|
||||
volatile uint64_t GITS_CREADR; // +0x0090 - RW - Points to command being processed
|
||||
const volatile uint32_t padding3[2]; // +0x0098 - RESERVED
|
||||
const volatile uint32_t padding4[24]; // +0x00A0 - RESERVED
|
||||
volatile uint64_t GITS_BASER[8]; // +0x0100 - RW - Sets base address of Device and Collection tables
|
||||
};
|
||||
|
||||
// +0x010000 from ITS_BASE
|
||||
struct GICv3_its_int_if
|
||||
{
|
||||
const volatile uint32_t padding1[16]; // +0x0000 - RESERVED
|
||||
volatile uint32_t GITS_TRANSLATER; // +0x0040 - RW - Written by peripherals to generate LPI
|
||||
};
|
||||
|
||||
// +0x020000 from ITS_BASE
|
||||
struct GICv3_its_sgi_if
|
||||
{
|
||||
const volatile uint32_t padding1[8]; // +0x0000 - RESERVED
|
||||
volatile uint64_t GITS_SGIR; // +0x0020 - RW - Written by peripherals to generate vSGI (GICv4.1)
|
||||
};
|
||||
|
||||
|
||||
|
||||
struct gic {
|
||||
struct GICv3_dist_if* gic_dist;
|
||||
struct GICv3_rdist_if* gic_rdist;
|
||||
unsigned int max_rd;
|
||||
};
|
||||
|
||||
static struct gic gic = {
|
||||
.gic_dist = NULL,
|
||||
.gic_rdist = NULL,
|
||||
.max_rd = 0
|
||||
};
|
||||
|
||||
static void
|
||||
gic_addr_init(void)
|
||||
{
|
||||
uint32_t index = 0;
|
||||
|
||||
gic.gic_dist = (void*)DIST_BASE_ADDR;
|
||||
gic.gic_rdist = (void*)REDIST_BASE_ADDR;
|
||||
|
||||
while((gic.gic_rdist[index].lpis.GICR_TYPER & (1<<4)) == 0) // Keep incrementing until GICR_TYPER.Last reports no more RDs in block
|
||||
{
|
||||
index++;
|
||||
}
|
||||
|
||||
gic.max_rd = index;
|
||||
}
|
||||
|
||||
static void
|
||||
gic_enable(void)
|
||||
{
|
||||
// First set the ARE bits
|
||||
gic.gic_dist->GICD_CTLR = (1 << 5) | (1 << 4);
|
||||
|
||||
// The split here is because the register layout is different once ARE==1
|
||||
|
||||
// Now set the rest of the options, only enable group1NS interrupts
|
||||
gic.gic_dist->GICD_CTLR = 0b1110010;
|
||||
// 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"
|
||||
);
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
int
|
||||
gic_get_redist_id(uint32_t affinity, unsigned int *id)
|
||||
{
|
||||
uint32_t index = 0;
|
||||
|
||||
// Check that GIC pointers are valid
|
||||
do {
|
||||
if ((gic.gic_rdist[index].lpis.GICR_TYPER >> 32) == affinity) {
|
||||
*id = index;
|
||||
return 0;
|
||||
}
|
||||
index++;
|
||||
}
|
||||
while(index <= gic.max_rd);
|
||||
|
||||
return EINVAL;
|
||||
}
|
||||
|
||||
static void
|
||||
gic_wakeup_redist(uint32_t rdid)
|
||||
{
|
||||
uint32_t tmp;
|
||||
|
||||
// Tell the Redistributor to wake-up by clearing ProcessorSleep bit
|
||||
tmp = gic.gic_rdist[rdid].lpis.GICR_WAKER;
|
||||
tmp = tmp & ~0x2;
|
||||
gic.gic_rdist[rdid].lpis.GICR_WAKER = tmp;
|
||||
|
||||
// Poll ChildrenAsleep bit until Redistributor wakes
|
||||
do
|
||||
{
|
||||
tmp = gic.gic_rdist[rdid].lpis.GICR_WAKER;
|
||||
} while((tmp & 0x4) != 0);
|
||||
}
|
||||
|
||||
static int
|
||||
gic_is_valid_extspi(uint32_t rd, uint32_t ID)
|
||||
{
|
||||
uint32_t max_spi;
|
||||
// Check Ext SPI implemented
|
||||
if (((gic.gic_dist->GICD_TYPER >> 8) & 0x1) == 0) {
|
||||
return 0; // GICD_TYPER.ESPI==0: Extended SPI range not present
|
||||
} else {
|
||||
max_spi = ((gic.gic_dist->GICD_TYPER >> 27) & 0x1F); // Get field which reports the number ESPIs in blocks of 32, minus 1
|
||||
max_spi = (max_spi + 1) * 32; // Convert into number of ESPIs
|
||||
max_spi = max_spi + 4096; // Range starts at 4096
|
||||
|
||||
if (!(ID < max_spi)) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int
|
||||
gic_is_valid_extppi(uint32_t rd, uint32_t ID)
|
||||
{
|
||||
uint32_t max_ppi;
|
||||
max_ppi = (gic.gic_rdist[rd].lpis.GICR_TYPER >> 27) & 0x1F;
|
||||
if (max_ppi == 0) {
|
||||
return 0;
|
||||
} else if ((max_ppi == 1) && (ID > 1087)) {
|
||||
return 0; // Extended PPI range implemented, but supplied INTID beyond range
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
gic_disable_intr(uint32_t rd, uint32_t intid)
|
||||
{
|
||||
uint32_t bank;
|
||||
|
||||
if (rd > gic.max_rd)
|
||||
return EINVAL;
|
||||
|
||||
if (intid < 31) {
|
||||
// SGI or PPI
|
||||
intid = intid & 0x1f; // ... and which bit within the register
|
||||
intid = 1 << intid; // Move a '1' into the correct bit position
|
||||
|
||||
gic.gic_rdist[rd].sgis.GICR_ICENABLER[0] = 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_ICENABLER[bank] = intid;
|
||||
} else if ((intid > 1055) && (intid < 1120)) {
|
||||
// Extended PPI
|
||||
// Check Ext PPI implemented
|
||||
if (gic_is_valid_extppi(rd, intid) == 0)
|
||||
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[rd].sgis.GICR_ICENABLER[bank] = intid;
|
||||
} else if ((intid > 4095) && (intid < 5120)) {
|
||||
// Extended SPI
|
||||
// Check Ext SPI implemented
|
||||
if (gic_is_valid_extspi(rd, intid) == 0)
|
||||
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_ICENABLERE[bank] = intid;
|
||||
} else {
|
||||
return EINVAL;
|
||||
}
|
||||
|
||||
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)
|
||||
|
||||
static int
|
||||
gic_calc_group_mod(uint32_t intid, uint32_t sec, uint32_t * _group, uint32_t * _mod)
|
||||
{
|
||||
uint32_t group = *_group, mod = *_mod;
|
||||
|
||||
switch (sec) {
|
||||
case GICV3_GROUP0:
|
||||
group = (group & ~intid);
|
||||
mod = (mod & ~intid);
|
||||
break;
|
||||
case GICV3_GROUP1_SECURE:
|
||||
group = (group & ~intid);
|
||||
mod = (mod | intid);
|
||||
break;
|
||||
case GICV3_GROUP1_NON_SECURE:
|
||||
group = (group | intid);
|
||||
mod = (mod & ~intid);
|
||||
break;
|
||||
default:
|
||||
return EINVAL;
|
||||
}
|
||||
|
||||
*_group = group;
|
||||
*_mod = mod;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
gic_set_intr_group(uint32_t rdid, uint32_t intid, uint32_t sec)
|
||||
{
|
||||
uint32_t bank, group, mod;
|
||||
|
||||
if (rdid > gic.max_rd)
|
||||
return EINVAL;
|
||||
|
||||
if (intid < 31) {
|
||||
// SGI or PPI
|
||||
intid = intid & 0x1f; // Find which bit within the register
|
||||
intid = 1 << intid; // Move a '1' into the correct bit position
|
||||
|
||||
// Read current values
|
||||
group = gic.gic_rdist[rdid].sgis.GICR_IGROUPR[0];
|
||||
mod = gic.gic_rdist[rdid].sgis.GICR_IGRPMODR[0];
|
||||
|
||||
// Update required bits
|
||||
gic_calc_group_mod(intid, sec, &group, &mod);
|
||||
|
||||
// Write modified version back
|
||||
gic.gic_rdist[rdid].sgis.GICR_IGROUPR[0] = group;
|
||||
gic.gic_rdist[rdid].sgis.GICR_IGRPMODR[0] = mod;
|
||||
} 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
|
||||
|
||||
group = gic.gic_dist->GICD_IGROUPR[bank];
|
||||
mod = gic.gic_dist->GICD_GRPMODR[bank];
|
||||
|
||||
gic_calc_group_mod(intid, sec, &group, &mod);
|
||||
|
||||
gic.gic_dist->GICD_IGROUPR[bank] = group;
|
||||
gic.gic_dist->GICD_GRPMODR[bank] = mod;
|
||||
} 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
|
||||
|
||||
// Read current values
|
||||
group = gic.gic_rdist[rdid].sgis.GICR_IGROUPR[bank];
|
||||
mod = gic.gic_rdist[rdid].sgis.GICR_IGRPMODR[bank];
|
||||
|
||||
// Update required bits
|
||||
gic_calc_group_mod(intid, sec, &group, &mod);
|
||||
|
||||
// Write modified version back
|
||||
gic.gic_rdist[rdid].sgis.GICR_IGROUPR[bank] = group;
|
||||
gic.gic_rdist[rdid].sgis.GICR_IGRPMODR[bank] = mod;
|
||||
} else if ((intid > 4095) && (intid < 5120)) {
|
||||
// Extended SPI
|
||||
// Check Ext SPI implemented
|
||||
if (gic_is_valid_extspi(rdid, intid) == 0)
|
||||
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
|
||||
|
||||
// Read current values
|
||||
group = gic.gic_dist->GICD_IGROUPRE[bank];
|
||||
mod = gic.gic_dist->GICD_IGRPMODRE[bank];
|
||||
|
||||
// Update required bits
|
||||
gic_calc_group_mod(intid, sec, &group, &mod);
|
||||
|
||||
// Write modified version back
|
||||
gic.gic_dist->GICD_IGROUPRE[bank] = group;
|
||||
gic.gic_dist->GICD_IGRPMODRE[bank] = mod;
|
||||
} else
|
||||
return EINVAL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void
|
||||
gic_send_eoi(int intr)
|
||||
{
|
||||
intr = intr & 0xFFFFFF;
|
||||
__asm__ volatile (
|
||||
"mov x0, %x0;"
|
||||
"msr ICC_EOIR1_EL1, x0;"
|
||||
"dsb sy;"
|
||||
:
|
||||
: "r" (intr)
|
||||
: "x0"
|
||||
);
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
gic_addr_init();
|
||||
gic_enable();
|
||||
|
||||
unsigned int rd;
|
||||
|
||||
// Get the ID of the Redistributor connected to this PE
|
||||
ret = gic_get_redist_id(gic_get_affinity(), &rd);
|
||||
if (ret != 0) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
// 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"
|
||||
);
|
||||
|
||||
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);
|
||||
}
|
29
sys/arm64/include/gic.h
Normal file
29
sys/arm64/include/gic.h
Normal file
@ -0,0 +1,29 @@
|
||||
#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);
|
@ -1,13 +0,0 @@
|
||||
/*
|
||||
* IOAPIC Header
|
||||
*/
|
||||
|
||||
#ifndef __IOAPIC_H__
|
||||
#define __IOAPIC_H__
|
||||
|
||||
void IOAPIC_Init();
|
||||
void IOAPIC_Enable(int irq);
|
||||
void IOAPIC_Disable(int irq);
|
||||
|
||||
#endif /* __IOAPIC_H__ */
|
||||
|
@ -12,7 +12,7 @@
|
||||
#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_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) */
|
||||
@ -32,7 +32,7 @@
|
||||
#define T_CROSSCALL 61 /* Cross Call (IPI) */
|
||||
#define T_DEBUGIPI 62 /* Kernel Debugger Halt (IPI) */
|
||||
|
||||
#define T_UNKNOWN 63 /* Unknown Trap */
|
||||
//#define T_UNKNOWN 63 /* Unknown Trap */
|
||||
|
||||
#define T_MAX 64
|
||||
|
||||
|
@ -3,25 +3,28 @@
|
||||
"elf64-arm64-freebsd")*/
|
||||
|
||||
OUTPUT_ARCH(arm:arm64)
|
||||
ENTRY(_start)
|
||||
ENTRY(_lostart)
|
||||
|
||||
/*
|
||||
PHDRS
|
||||
{
|
||||
headers PT_PHDR PHDRS AT(0x00400040);
|
||||
headers PT_LOAD FILEHDR PHDRS AT(0x00400000);
|
||||
headers PT_PHDR PHDRS AT(0x80400040);
|
||||
headers PT_LOAD FILEHDR PHDRS AT(0x80400000);
|
||||
text PT_LOAD;
|
||||
rodata PT_LOAD;
|
||||
data PT_LOAD;
|
||||
}
|
||||
*/
|
||||
|
||||
SECTIONS
|
||||
{
|
||||
/* Read-only sections, merged into text segment: */
|
||||
PROVIDE (__executable_start = SEGMENT_START("text-segment",
|
||||
0xFFFF800000400000));
|
||||
. = SEGMENT_START("text-segment", 0xFFFF800000400000) + SIZEOF_HEADERS;
|
||||
.text : AT(SEGMENT_START("text-segment", 0xFFFF800000400000) + SIZEOF_HEADERS - 0xFFFF800000000000)
|
||||
. = SEGMENT_START("text-segment", 0xFFFF800080400000);
|
||||
.text : AT(SEGMENT_START("text-segment", 0xFFFF800080400000) - 0xFFFF800000000000)
|
||||
{
|
||||
*(.boot)
|
||||
*(.text .stub .text.* .gnu.linkonce.t.*)
|
||||
*(.text.unlikely .text.*_unlikely .text.unlikely.*)
|
||||
*(.text.exit .text.exit.*)
|
||||
|
@ -7,22 +7,184 @@
|
||||
#define KERNEL_BASE 0xFFFF800000000000
|
||||
#define LOWMEM(_x) (_x - KERNEL_BASE)
|
||||
|
||||
.text
|
||||
#define DIST_BASE_ADDR 0x2c000000
|
||||
|
||||
.section .boot, "ax"
|
||||
|
||||
.balign 4096
|
||||
.space STACK_SIZE, 0
|
||||
_bootstack:
|
||||
|
||||
/**
|
||||
* _start --
|
||||
*
|
||||
* ELF entry point.
|
||||
*/
|
||||
.globl _lostart
|
||||
.equ _lostart, LOWMEM(_start)
|
||||
.globl _start
|
||||
_start:
|
||||
#call MachineBoot_Entry
|
||||
loop:
|
||||
#hlt
|
||||
#jmp loop
|
||||
.extern _evt
|
||||
// setup EVT for all levels (before MMU)
|
||||
ldr x0,=LOWMEM(_evt)
|
||||
msr VBAR_EL1, x0
|
||||
msr VBAR_EL2, x0
|
||||
msr VBAR_EL3, x0
|
||||
|
||||
// Boot stack
|
||||
.p2align 12
|
||||
.globl stack
|
||||
.comm stack, STACK_SIZE
|
||||
// do interrupt stuff in EL3
|
||||
mrs x0, ICC_IGRPEN1_EL3
|
||||
orr w0, w0, #0b11 // enable secure & non secure group 1 interrupts
|
||||
msr ICC_IGRPEN1_EL3, x0
|
||||
|
||||
// enable Disable Secure bit in GIC distributor
|
||||
ldr x0, =DIST_BASE_ADDR + 0x0
|
||||
ldrh w1, [x0]
|
||||
orr w1, w1, #(1 << 6)
|
||||
strh w1, [x0]
|
||||
|
||||
// switch from el3 to el2
|
||||
msr sctlr_el2, xzr
|
||||
msr hcr_el2, xzr
|
||||
|
||||
// Determine the EL2 Execution state
|
||||
mrs X0, SCR_EL3
|
||||
orr X0, X0, #(1<<10) // RW EL2 Execution state is AArch64.
|
||||
orr X0, X0, #(1<<0) // NS EL1 is Non-secure world.
|
||||
and X0, X0, #~(1<<3) // exceptions are not taken to EL3
|
||||
msr SCR_EL3, X0
|
||||
mov X0, #0b01001 // DAIF=0000
|
||||
msr SPSR_EL3, X0 // M[4:0]=01001 EL2h must match SCR_EL3.RW
|
||||
// Determine EL2 entry.
|
||||
ldr X0, =LOWMEM(_el2_entry) // el2_entry points to the first instruction of
|
||||
msr ELR_EL3, X0 // EL2 code.
|
||||
eret // enter el2
|
||||
|
||||
_el2_entry:
|
||||
// Initialize the SCTLR_EL1 register before entering EL1.
|
||||
msr SCTLR_EL1, XZR
|
||||
// Determine the EL1 Execution state.
|
||||
mrs X0, HCR_EL2
|
||||
orr X0, X0, #(1 << 31) // RW=1 EL1 Execution state is AArch64.
|
||||
and X0, X0, #~(1 << 27) // exceptions are not taken to EL2
|
||||
and X0, X0, #~(1 << 3) // FMO, FIQs are not taken to EL2
|
||||
and X0, X0, #~(1 << 4) // IMO, IRQs are not taken to EL2
|
||||
and X0, X0, #~(1 << 5) // AMO, SErrors are not taken to EL2
|
||||
and X0, X0, #~(1 << 48) // GPF, Granule protections are not taken to EL2
|
||||
and X0, X0, #~(1 << 37) // TEA, sync ext aborts are not taken to EL2
|
||||
msr HCR_EL2, X0
|
||||
|
||||
mrs X0, CNTHCTL_EL2
|
||||
orr x0, x0, #0b11 // enable access to el1 physical timer at el1
|
||||
msr CNTHCTL_EL2, x0
|
||||
|
||||
mov X0, #0b00101 // DAIF=0000
|
||||
msr SPSR_EL2, X0 // M[4:0]=00101 EL1h must match HCR_EL2.RW.
|
||||
ldr X0, =LOWMEM(_el1_entry) // el1_entry points to the first instruction of
|
||||
msr ELR_EL2, X0 // EL1 code.
|
||||
eret // enter el1
|
||||
|
||||
_el1_entry:
|
||||
mrs x0, CurrentEL
|
||||
cmp x0, #(1 << 2)
|
||||
cset x0, eq
|
||||
tbz x0, 0, _halt
|
||||
|
||||
// enable SIMD
|
||||
mrs x0, CPACR_EL1
|
||||
orr x0, x0, #(0b11 << 20)
|
||||
msr CPACR_EL1, x0
|
||||
|
||||
// setup boot MMU
|
||||
#define TCR_CONFIG_REGION_48bit (((64 - 48) << 0) | ((64 - 48) << 16))
|
||||
#define TCR_CONFIG_4KB ((0b00 << 14) | (0b10 << 30))
|
||||
ldr x0, =(TCR_CONFIG_REGION_48bit | TCR_CONFIG_4KB);
|
||||
msr tcr_el1, x0
|
||||
#define MAIR_IDX_NORMAL_CACHEABLE (0)
|
||||
#define MAIR_IDX_DEVICE (1)
|
||||
#define MAIR_VAL (0b11111111) | (0b00000000 << 8)
|
||||
// 0 = b11111111 = Normal, Inner/Outer WB/WA/RA
|
||||
// 1 = b00000000 = Device-nGnRnE
|
||||
ldr x0, =(MAIR_VAL)
|
||||
msr mair_el1, x0
|
||||
// write paddr of page table base
|
||||
ldr x0, =LOWMEM(_boot_ptl0lo)
|
||||
msr ttbr0_el1, x0
|
||||
ldr x0, =LOWMEM(_boot_ptl0hi)
|
||||
msr ttbr1_el1, x0
|
||||
// disable TTBR1 (only use ttbr0)
|
||||
|
||||
// setup page tables
|
||||
#define PD_TABLE (0b11)
|
||||
#define PD_BLOCK (0b01)
|
||||
#define PD_ACCESS (1 << 10)
|
||||
#define BOOT_PGD_ATTR (PD_TABLE)
|
||||
#define BOOT_PUD_ATTR (PD_ACCESS | (MAIR_IDX_NORMAL_CACHEABLE << 2) | PD_BLOCK)
|
||||
#define BOOT_PUD_DEV_ATTR (PD_ACCESS | (MAIR_IDX_DEVICE << 2) | PD_BLOCK)
|
||||
// ident map 0x80000000 -> 0x80000000 Size: 1G
|
||||
ldr x0, =LOWMEM(_boot_ptl0lo) + 0x8 * 0 // x0 = L0 entry for vaddr 0x80000000
|
||||
ldr x1, =LOWMEM(_boot_ptl1lo) + BOOT_PGD_ATTR
|
||||
str x1, [x0]
|
||||
|
||||
ldr x0, =LOWMEM(_boot_ptl1lo) + 0x8 * 2 // x0 = L1 entry for vaddr 0x80000000
|
||||
ldr x1, =0x80000000 | BOOT_PUD_ATTR // map to 0x80000000
|
||||
str x1, [x0]
|
||||
|
||||
// ident map 0x00000000 -> 0x00000000 Size: 1G as device memory
|
||||
ldr x0, =LOWMEM(_boot_ptl1lo) + 0x8 * 0 // x0 - L1 entry for vaddr 0x00000000
|
||||
ldr x1, =0x00000000 | BOOT_PUD_DEV_ATTR
|
||||
str x1, [x0]
|
||||
|
||||
// map 0x80000000 -> 0xFFFF800080000000 Size: 1G
|
||||
ldr x0, =LOWMEM(_boot_ptl0hi) + 0x8 * 256 // x0 = L0 entry for vaddr 0xFFFF800080000000
|
||||
ldr x1, =LOWMEM(_boot_ptl1hi) + BOOT_PGD_ATTR
|
||||
str x1, [x0]
|
||||
|
||||
ldr x0, =LOWMEM(_boot_ptl1hi) + 0x8 * 2 // x0 = L1 entry for vaddr 0xFFFF800080000000
|
||||
ldr x1, =0x80000000 | BOOT_PUD_ATTR
|
||||
str x1, [x0]
|
||||
|
||||
// enable MMU
|
||||
mrs x0, sctlr_el1
|
||||
orr x0, x0, #0x1 //enable MMU
|
||||
orr x0, x0, #(0x1 << 12) // enable icache
|
||||
orr x0, x0, #(0x1 << 2) // enable dcache
|
||||
msr sctlr_el1, x0
|
||||
dsb sy
|
||||
isb // barriers
|
||||
|
||||
ldr x0, =_high_addr
|
||||
br x0 // jump to kernel vspace
|
||||
|
||||
_high_addr:
|
||||
// reload stack
|
||||
ldr x0, =_bootstack
|
||||
mov sp, x0
|
||||
|
||||
// re-setup el1 EVT with high addr
|
||||
ldr x0, =_evt
|
||||
msr VBAR_EL1, x0
|
||||
.extern MachineBoot_Entry
|
||||
ldr x0, =MachineBoot_Entry
|
||||
blr x0
|
||||
b _halt
|
||||
|
||||
.global _halt
|
||||
_halt:
|
||||
wfi
|
||||
b _halt
|
||||
|
||||
.balign 4096
|
||||
_boot_ptl0hi:
|
||||
.space 4096,0
|
||||
|
||||
.balign 4096
|
||||
_boot_ptl0lo:
|
||||
.space 4096,0
|
||||
|
||||
.balign 4096
|
||||
_boot_ptl1lo:
|
||||
.space 4096,0
|
||||
|
||||
.balign 4096
|
||||
_boot_ptl1hi:
|
||||
.space 4096,0
|
||||
|
@ -12,6 +12,7 @@
|
||||
#include <machine/trap.h>
|
||||
#include <machine/pmap.h>
|
||||
#include <machine/mp.h>
|
||||
#include <machine/gic.h>
|
||||
|
||||
#include <sys/thread.h>
|
||||
#include <sys/disk.h>
|
||||
@ -76,10 +77,33 @@ Machine_IdleThread(void *test)
|
||||
*/
|
||||
void Machine_Init()
|
||||
{
|
||||
Machine_EarlyInit();
|
||||
/*
|
||||
* Initialize Processor State
|
||||
*/
|
||||
//Trap_Init();
|
||||
|
||||
if (gic_init() != 0) {
|
||||
PANIC("gic initialization failed!\n");
|
||||
}
|
||||
|
||||
kprintf("Initialized GIC.\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) {
|
||||
__asm__ volatile ("wfi");
|
||||
};
|
||||
|
||||
Machine_SyscallInit();
|
||||
|
||||
/*
|
||||
|
@ -16,6 +16,10 @@
|
||||
#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];
|
||||
@ -75,32 +79,29 @@ extern void copystr_unsafe_done(void);
|
||||
extern void copystr_unsafe_fault(void);
|
||||
|
||||
void
|
||||
trap_entry(TrapFrame *tf)
|
||||
trap_entry(void)
|
||||
{
|
||||
// XXX: USE ATOMIC!
|
||||
intStats[tf->vector]++;
|
||||
uint64_t id;
|
||||
__asm__ volatile (
|
||||
"mrs %x0, ICC_IAR1_EL1;"
|
||||
: "=r" (id)
|
||||
:
|
||||
:
|
||||
);
|
||||
|
||||
// Debug NMI
|
||||
kprintf("Unhandled irq: 0x%x\n", id);
|
||||
|
||||
// Kernel
|
||||
// Kernel Debugger
|
||||
|
||||
// User IO
|
||||
|
||||
// Halt on kernel errors
|
||||
|
||||
// User space exceptions
|
||||
|
||||
// IRQs
|
||||
|
||||
// Debug IPI
|
||||
|
||||
// Cross calls
|
||||
|
||||
kprintf("Unhandled Interrupt 0x%x!\n", tf->vector);
|
||||
Trap_Dump(tf);
|
||||
while (1)
|
||||
hlt();
|
||||
if (id == 30) {
|
||||
__asm__ volatile (
|
||||
"mrs x1, CNTFRQ_EL0;"
|
||||
"msr CNTP_TVAL_EL0, x1;"
|
||||
"msr ICC_EOIR1_EL1, %x0;"
|
||||
"dsb sy;"
|
||||
:
|
||||
: "r" (id)
|
||||
: "x1"
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -6,33 +6,93 @@
|
||||
|
||||
.text
|
||||
|
||||
.macro TRAP_NOEC TRAPNUM
|
||||
trap\TRAPNUM:
|
||||
# Push top of the trap frame
|
||||
.endm
|
||||
trap_locore_entry:
|
||||
stp lr, lr, [sp, #-16]!
|
||||
stp x28, x29, [sp, #-16]!
|
||||
stp x26, x27, [sp, #-16]!
|
||||
stp x24, x25, [sp, #-16]!
|
||||
stp x22, x23, [sp, #-16]!
|
||||
stp x20, x21, [sp, #-16]!
|
||||
stp x18, x19, [sp, #-16]!
|
||||
stp x16, x17, [sp, #-16]!
|
||||
stp x14, x15, [sp, #-16]!
|
||||
stp x12, x13, [sp, #-16]!
|
||||
stp x10, x11, [sp, #-16]!
|
||||
stp x8, x9, [sp, #-16]!
|
||||
stp x6, x7, [sp, #-16]!
|
||||
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]!
|
||||
|
||||
.macro TRAP_EC TRAPNUM
|
||||
trap\TRAPNUM:
|
||||
# Push top of the trap frame
|
||||
.endm
|
||||
.extern trap_entry
|
||||
bl trap_entry
|
||||
|
||||
.globl trap_table
|
||||
trap_table:
|
||||
.quad trap0
|
||||
; 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
|
||||
ldp x6, x7, [sp], #16
|
||||
ldp x8, x9, [sp], #16
|
||||
ldp x10, x11, [sp], #16
|
||||
ldp x12, x13, [sp], #16
|
||||
ldp x14, x15, [sp], #16
|
||||
ldp x16, x17, [sp], #16
|
||||
ldp x18, x19, [sp], #16
|
||||
ldp x20, x21, [sp], #16
|
||||
ldp x22, x23, [sp], #16
|
||||
ldp x24, x25, [sp], #16
|
||||
ldp x26, x27, [sp], #16
|
||||
ldp x28, x29, [sp], #16
|
||||
ldp lr, lr, [sp], #16
|
||||
// daif bits are stored in PSTATE and are automatically re-enabled by eret
|
||||
eret
|
||||
|
||||
TRAP_NOEC 0 // DE
|
||||
.global _evt
|
||||
.balign 2048
|
||||
_evt:
|
||||
// same exception level, sp0: sync, irq, fiq, serror
|
||||
b _halt
|
||||
.balign 0x80
|
||||
b _halt
|
||||
.balign 0x80
|
||||
b _halt
|
||||
.balign 0x80
|
||||
b _halt
|
||||
|
||||
trap_common:
|
||||
# Create the rest of the trap frame
|
||||
// same exception level, spX: sync, irq, fiq, serror
|
||||
.balign 0x80
|
||||
b _halt
|
||||
.balign 0x80
|
||||
b trap_locore_entry
|
||||
b _halt
|
||||
.balign 0x80
|
||||
b _halt
|
||||
.balign 0x80
|
||||
b _halt
|
||||
|
||||
# Pass the trap frame as an argument to trap_entry
|
||||
.globl trap_return
|
||||
trap_return:
|
||||
// higher exception level, from aarch64: sync, irq, fiq, serror
|
||||
.balign 0x80
|
||||
b _halt
|
||||
.balign 0x80
|
||||
b _halt
|
||||
.balign 0x80
|
||||
b _halt
|
||||
.balign 0x80
|
||||
b _halt
|
||||
|
||||
# Skip error code and vector number
|
||||
// higher exception level, from aarch32: sync, irq, fiq, serror
|
||||
.balign 0x80
|
||||
b _halt
|
||||
.balign 0x80
|
||||
b _halt
|
||||
.balign 0x80
|
||||
b _halt
|
||||
.balign 0x80
|
||||
b _halt
|
||||
|
||||
# Return to userspace
|
||||
|
||||
.globl Trap_Pop
|
||||
Trap_Pop:
|
||||
|
||||
|
125
sys/dev/arm64/uart.c
Normal file
125
sys/dev/arm64/uart.c
Normal file
@ -0,0 +1,125 @@
|
||||
#include "uart.h"
|
||||
#include "sys/kassert.h"
|
||||
#include <stdint.h>
|
||||
|
||||
#define UART_DR_OFFSET (0x000)
|
||||
#define UART_FR_OFFSET (0x018)
|
||||
#define UART_FR_BUSY (1 << 3)
|
||||
#define UART_IBRD_OFFSET (0x024)
|
||||
#define UART_FBRD_OFFSET (0x028)
|
||||
#define UART_LCR_OFFSET (0x02c)
|
||||
#define UART_LCR_FEN (1 << 4)
|
||||
#define UART_LCR_STP2 (1 << 3)
|
||||
#define UART_CR_OFFSET (0x030)
|
||||
#define UART_CR_UARTEN (1)
|
||||
#define UART_CR_TXEN (1 << 8)
|
||||
#define UART_IMSC_OFFSET (0x038)
|
||||
#define UART_DMACR_OFFSET (0x048)
|
||||
|
||||
struct uart {
|
||||
uintptr_t base;
|
||||
uint64_t clock;
|
||||
uint32_t baud;
|
||||
uint32_t dbits;
|
||||
int two_bit_stop;
|
||||
int initialized;
|
||||
};
|
||||
|
||||
static struct uart g_uart0 = {
|
||||
.base = 0x1c090000,
|
||||
.baud = 115200,
|
||||
.clock = 24000000,
|
||||
.dbits = 8,
|
||||
.two_bit_stop = 1,
|
||||
.initialized = 0
|
||||
};
|
||||
|
||||
static void
|
||||
uart_writereg(const struct uart *dev, uintptr_t offset, uint32_t val)
|
||||
{
|
||||
*(volatile uint32_t *)(dev->base + offset) = val;
|
||||
}
|
||||
|
||||
static uint32_t
|
||||
uart_readreg(const struct uart *dev, uintptr_t offset)
|
||||
{
|
||||
return *(volatile uint32_t *)(dev->base + offset);
|
||||
}
|
||||
|
||||
static void
|
||||
uart_tx_wait(const struct uart *dev)
|
||||
{
|
||||
while(uart_readreg(dev, UART_FR_OFFSET) & UART_FR_BUSY) {
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
uart_init(struct uart *dev)
|
||||
{
|
||||
uint32_t cr = uart_readreg(dev, UART_CR_OFFSET);
|
||||
uint32_t lcr = uart_readreg(dev, UART_LCR_OFFSET);
|
||||
|
||||
// Disable UART
|
||||
uart_writereg(dev, UART_CR_OFFSET, cr & ~UART_CR_UARTEN);
|
||||
|
||||
// Wait for any ongoing transmissions to complete
|
||||
uart_tx_wait(dev);
|
||||
|
||||
// Flush FIFOs, set to 1 byte transfer a time
|
||||
uart_writereg(dev, UART_LCR_OFFSET, lcr & ~UART_LCR_FEN);
|
||||
|
||||
// Set frequency divisors (UARTIBRD and UARTFBRD) to configure the speed
|
||||
const uint32_t div = 4 * dev->clock / dev->baud;
|
||||
uart_writereg(dev, UART_IBRD_OFFSET, (div >> 6) & 0xffff);
|
||||
uart_writereg(dev, UART_FBRD_OFFSET, div & 0x3f);
|
||||
|
||||
// set wlen
|
||||
lcr = ((dev->dbits - 1) & 0b11) << 5;
|
||||
// set stop bits
|
||||
if (dev->two_bit_stop)
|
||||
lcr |= UART_LCR_STP2;
|
||||
// parity disabled, FIFO disabled, stick parity disabled
|
||||
|
||||
// Mask all interrupts by setting corresponding bits to 1
|
||||
uart_writereg(dev, UART_IMSC_OFFSET, 0x7ff);
|
||||
|
||||
// Disable DMA by setting all bits to 0
|
||||
uart_writereg(dev, UART_DMACR_OFFSET, 0x0);
|
||||
|
||||
// enable tx & uart
|
||||
uart_writereg(dev, UART_CR_OFFSET, UART_CR_TXEN | UART_CR_UARTEN);
|
||||
|
||||
dev->initialized = 1;
|
||||
}
|
||||
|
||||
static void
|
||||
uart_send(const struct uart *dev, const char *data, size_t size)
|
||||
{
|
||||
uart_tx_wait(dev);
|
||||
|
||||
for (size_t i = 0; i < size; i++) {
|
||||
if (data[i] == '\n') {
|
||||
// new line is actually CR LF
|
||||
uart_writereg(dev, UART_DR_OFFSET, '\r');
|
||||
uart_tx_wait(dev);
|
||||
}
|
||||
uart_writereg(dev, UART_DR_OFFSET, data[i]);
|
||||
uart_tx_wait(dev);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
Serial_Send(const char *data, size_t size)
|
||||
{
|
||||
if (g_uart0.initialized) {
|
||||
uart_send(&g_uart0, data, size);
|
||||
} else {
|
||||
Halt();
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
Serial_Init(void)
|
||||
{
|
||||
uart_init(&g_uart0);
|
||||
}
|
9
sys/dev/arm64/uart.h
Normal file
9
sys/dev/arm64/uart.h
Normal file
@ -0,0 +1,9 @@
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
void
|
||||
Serial_Init(void);
|
||||
|
||||
void
|
||||
Serial_Send(const char *data, size_t size);
|
@ -5,11 +5,19 @@
|
||||
#include <sys/spinlock.h>
|
||||
#include <sys/kmem.h>
|
||||
#include <sys/thread.h>
|
||||
#include <sys/kassert.h>
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include "console.h"
|
||||
#include "x86/vgacons.h"
|
||||
#include "x86/sercons.h"
|
||||
#include "x86/debugcons.h"
|
||||
|
||||
#if defined (__x86_64__)
|
||||
#include "x86/vgacons.h"
|
||||
#include "x86/sercons.h"
|
||||
#include "x86/debugcons.h"
|
||||
#elif defined(__aarch64__)
|
||||
#include "arm64/uart.h"
|
||||
#endif
|
||||
|
||||
Spinlock consoleLock;
|
||||
Console consoles;
|
||||
@ -25,12 +33,12 @@ Console_Init()
|
||||
VGA_Init();
|
||||
Serial_Init();
|
||||
DebugConsole_Init();
|
||||
#elif defined(__aarch64__)
|
||||
Serial_Init();
|
||||
#endif
|
||||
|
||||
Console_Puts("Castor Operating System\n");
|
||||
|
||||
Spinlock_Init(&consoleLock, "Console Lock", SPINLOCK_TYPE_NORMAL);
|
||||
|
||||
Console_Puts("Castor Operating System\n");
|
||||
Spinlock_Init(&consoles.keyLock, "Console Keyboard Lock", SPINLOCK_TYPE_NORMAL);
|
||||
consoles.nextKey = 0;
|
||||
consoles.lastKey = 0;
|
||||
@ -90,10 +98,12 @@ Console_EnqueueKey(char key)
|
||||
Spinlock_Unlock(&consoles.keyLock);
|
||||
}
|
||||
|
||||
#if !defined(__x86_64__)
|
||||
#if defined(__aarch64__)
|
||||
void
|
||||
Panic(const char *str)
|
||||
{
|
||||
Serial_Send(str, strlen(str));
|
||||
Halt();
|
||||
}
|
||||
#endif
|
||||
|
||||
@ -148,6 +158,8 @@ Console_Putc(char ch)
|
||||
VGA_Putc(ch);
|
||||
Serial_Putc(ch);
|
||||
DebugConsole_Putc(ch);
|
||||
#elif defined(__aarch64__)
|
||||
Serial_Send(&ch, 1);
|
||||
#endif
|
||||
Spinlock_Unlock(&consoleLock);
|
||||
}
|
||||
@ -160,6 +172,8 @@ Console_Puts(const char *str)
|
||||
VGA_Puts(str);
|
||||
Serial_Puts(str);
|
||||
DebugConsole_Puts(str);
|
||||
#elif defined(__aarch64__)
|
||||
Serial_Send(str, strlen(str));
|
||||
#endif
|
||||
Spinlock_Unlock(&consoleLock);
|
||||
}
|
||||
|
@ -19,6 +19,17 @@
|
||||
|
||||
NO_RETURN void Panic(const char *str);
|
||||
|
||||
#if defined(__aarch64__)
|
||||
NO_RETURN extern void
|
||||
_halt(void);
|
||||
|
||||
NO_RETURN static inline void
|
||||
Halt(void)
|
||||
{
|
||||
_halt();
|
||||
}
|
||||
#endif
|
||||
|
||||
int kprintf(const char *fmt, ...);
|
||||
NO_RETURN void Debug_Assert(const char *fmt, ...);
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user