bootstrap,gic,timer

This commit is contained in:
quackerd 2023-12-01 05:28:53 +08:00
parent f7c3993e2d
commit 17db81c514
15 changed files with 1194 additions and 85 deletions

View File

@ -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;

View File

@ -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
View 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
View 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);

View File

@ -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__ */

View File

@ -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

View File

@ -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.*)

View File

@ -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

View File

@ -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();
/*

View File

@ -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

View File

@ -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
View 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
View File

@ -0,0 +1,9 @@
#pragma once
#include <stdint.h>
void
Serial_Init(void);
void
Serial_Send(const char *data, size_t size);

View File

@ -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);
}

View File

@ -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, ...);