From 4ffba85108b79ac9e5e577a504b11137b843e365 Mon Sep 17 00:00:00 2001 From: Nick Chan Date: Sun, 25 Aug 2024 15:34:59 +0800 Subject: [PATCH 01/19] soc: Added UART bases for A7-A11, T2 SoCs. Add UART bases for A7-A11, T2 SoCs. Signed-off-by: Nick Chan --- config.h | 2 ++ src/soc.h | 25 +++++++++++++++++++++++++ src/uart.c | 15 +++++++++++---- 3 files changed, 38 insertions(+), 4 deletions(-) diff --git a/config.h b/config.h index 31c893879..9a2882246 100644 --- a/config.h +++ b/config.h @@ -20,6 +20,8 @@ // Target for device-specific debug builds //#define TARGET T8103 +// Some devices like Apple TV HD use other uarts for debug console +//#define TARGET_BOARD 0x34 #ifdef RELEASE # define FB_SILENT_MODE diff --git a/src/soc.h b/src/soc.h index eb375edac..b6632ad2d 100644 --- a/src/soc.h +++ b/src/soc.h @@ -5,6 +5,17 @@ #include "../config.h" +#define S5L8960X 0x8960 +#define T7000 0x7000 +#define T7001 0x7001 +#define S8000 0x8000 +#define S8001 0x8001 +#define S8003 0x8003 +#define T8010 0x8010 +#define T8011 0x8011 +#define T8012 0x8012 +#define T8015 0x8015 + #define T8103 0x8103 #define T8112 0x8112 #define T8122 0x8122 @@ -28,6 +39,20 @@ #define EARLY_UART_BASE 0x235200000 #elif TARGET == T6034 || TARGET == T6031 #define EARLY_UART_BASE 0x391200000 +#elif TARGET == T8015 +#define EARLY_UART_BASE 0x22e600000 +#elif TARGET == T7000 || TARGET == T7001 || TARGET == S8000 || TARGET == S8001 || \ + TARGET == S8003 || TARGET == T8010 || TARGET == T8011 +#if TARGET == T7000 && defined(TARGET_BOARD) && TARGET_BOARD == 0x34 // Apple TV HD +#define EARLY_UART_BASE 0x20a0d8000 +#else +#define EARLY_UART_BASE 0x20a0c0000 +#endif + +#elif TARGET == T8012 +#define EARLY_UART_BASE 0x20a600000 +#elif TARGET == S5L8960X +#define EARLY_UART_BASE 0x20a0a0000 #endif #endif diff --git a/src/uart.c b/src/uart.c index 67aa0e3ac..6bd2dab61 100644 --- a/src/uart.c +++ b/src/uart.c @@ -17,13 +17,20 @@ static u64 uart_base = 0; int uart_init(void) { int path[8]; - int node = adt_path_offset_trace(adt, "/arm-io/uart0", path); - - if (node < 0) { - printf("!!! UART node not found!\n"); + const char *uart_path; + + if (adt_path_offset_trace(adt, "/arm-io/uart6/debug-console", NULL) > 0) { + uart_path = "/arm-io/uart6"; + /* T2 ADT does not have /arm-io/uart0/debug-console, but it is the correct UART */ + } else if (adt_path_offset_trace(adt, "/arm-io/uart0", NULL) > 0) { + uart_path = "/arm-io/uart0"; + } else { + printf("!!!Debug UART node not found!\n"); return -1; } + adt_path_offset_trace(adt, uart_path, path); + if (adt_get_reg(adt, path, "reg", 0, &uart_base, NULL)) { printf("!!! Failed to get UART reg property!\n"); return -1; From 66d99cac1ed38890205bd5a15226591f7a4118c5 Mon Sep 17 00:00:00 2001 From: Nick Chan Date: Mon, 23 Sep 2024 23:20:27 +0800 Subject: [PATCH 02/19] utils: Add more functions to detect CPU features These functions will be used to skip over parts not supported by A7-A11 SoCs. Signed-off-by: Nick Chan --- src/cpu_regs.h | 10 ++++++++++ src/main.c | 13 +++++++++++-- src/string.c | 24 ++++++++++++++++++++++++ src/utils.c | 18 ++++++++++++++++++ src/utils.h | 4 ++++ sysinc/string.h | 1 + 6 files changed, 68 insertions(+), 2 deletions(-) diff --git a/src/cpu_regs.h b/src/cpu_regs.h index 920abf8ee..40cd37966 100644 --- a/src/cpu_regs.h +++ b/src/cpu_regs.h @@ -625,3 +625,13 @@ /* Lockdown registers */ #define SYS_IMP_APL_SPR_LOCKDOWN_EL2 sys_reg(3, 4, 15, 0, 5) #define SYS_IMP_APL_SPR_LOCKDOWN_EL1 sys_reg(3, 4, 15, 0, 6) + +/* Feature ID registers */ +#define AIDR_EL1_MUL53 BIT(0) +#define AIDR_EL1_WKDM BIT(1) +#define AIDR_EL1_ARCH_RETENTION BIT(2) +#define AIDR_EL1_AMX BIT(4) +#define AIDR_EL1_TSO BIT(9) +#define AIDR_EL1_GXF BIT(16) +#define AIDR_EL1_APFLG BIT(19) +#define AIDR_EL1_PSRV BIT(20) diff --git a/src/main.c b/src/main.c index 66c05ba9f..d922cb182 100644 --- a/src/main.c +++ b/src/main.c @@ -39,9 +39,18 @@ u32 board_id = ~0, chip_id = ~0; void get_device_info(void) { + const char *model = (const char *)adt_getprop(adt, 0, "model", NULL); + const char *target = (const char *)adt_getprop(adt, 0, "target-type", NULL); + printf("Device info:\n"); - printf(" Model: %s\n", (const char *)adt_getprop(adt, 0, "model", NULL)); - printf(" Target: %s\n", (const char *)adt_getprop(adt, 0, "target-type", NULL)); + + if (model) + printf(" Model: %s\n", model); + + if (target) + printf(" Target: %s\n", target); + + is_mac = !!strstr(model, "Mac"); int chosen = adt_path_offset(adt, "/chosen"); if (chosen > 0) { diff --git a/src/string.c b/src/string.c index 318d0fcb9..8681be334 100644 --- a/src/string.c +++ b/src/string.c @@ -188,6 +188,30 @@ char *strrchr(const char *s, int c) return NULL; } +char *strstr(const char *s1, const char *s2) +{ + const char *p1 = s1; + const char *p2; + + while (*s1) { + p2 = s2; + + while (*p2 && (*p1 == *p2)) { + ++p1; + ++p2; + } + + if (!*p2) { + return (char *)s1; + } + + ++s1; + p1 = s1; + } + + return NULL; +} + /* Very naive, no attempt to check for errors */ long atol(const char *s) { diff --git a/src/utils.c b/src/utils.c index ff8dd84ba..3ed569fe7 100644 --- a/src/utils.c +++ b/src/utils.c @@ -4,12 +4,15 @@ #include #include "utils.h" +#include "cpu_regs.h" #include "iodev.h" #include "smp.h" #include "types.h" #include "vsprintf.h" #include "xnuboot.h" +bool is_mac = false; + static char ascii(char s) { if (s < 0x20) @@ -181,6 +184,21 @@ bool is_heap(void *addr) return p > top_of_kernel_data && p < top_of_ram; } +bool supports_arch_retention(void) +{ + return mrs(AIDR_EL1) & AIDR_EL1_ARCH_RETENTION; +} + +bool supports_gxf(void) +{ + return mrs(AIDR_EL1) & AIDR_EL1_GXF; +} + +bool supports_pan(void) +{ + return (mrs(ID_AA64MMFR1_EL1) >> 20) & 0xf; +} + // TODO: update mapping? u64 top_of_memory_alloc(size_t size) { diff --git a/src/utils.h b/src/utils.h index f4646a53a..fe3eb1b37 100644 --- a/src/utils.h +++ b/src/utils.h @@ -429,6 +429,7 @@ struct vector_args { }; extern u32 board_id, chip_id; +extern bool is_mac; extern bool cpufeat_actlr_el2; extern struct vector_args next_stage; @@ -437,6 +438,9 @@ void cpu_sleep(bool deep) __attribute__((noreturn)); void deep_wfi(void); bool is_heap(void *addr); +bool supports_arch_retention(void); +bool supports_gxf(void); +bool supports_pan(void); u64 top_of_memory_alloc(size_t size); #endif diff --git a/sysinc/string.h b/sysinc/string.h index 1aa9e267d..def429c19 100644 --- a/sysinc/string.h +++ b/sysinc/string.h @@ -18,6 +18,7 @@ size_t strlen(const char *s); size_t strnlen(const char *s, size_t n); char *strchr(const char *s, int c); char *strrchr(const char *s, int c); +char *strstr(const char *s1, const char *s2); long atol(const char *s); static inline int tolower(int c) From f465515de028625d2fc78c80a2ae983e9da6f97f Mon Sep 17 00:00:00 2001 From: Nick Chan Date: Sun, 25 Aug 2024 15:15:17 +0800 Subject: [PATCH 03/19] chickens: Add A7-A11 chickens Cyclone and Typhoon are similar enough to share a file. Hurricane and Zephyr are the physical cores on A10 backing the Hurricane-Zephyr logical core. Signed-off-by: Nick Chan --- Makefile | 4 + src/chickens.c | 141 ++++++++++++++++++++++++-------- src/chickens_cyclone_typhoon.c | 43 ++++++++++ src/chickens_hurricane_zephyr.c | 39 +++++++++ src/chickens_monsoon_mistral.c | 27 ++++++ src/chickens_twister.c | 33 ++++++++ src/cpu_regs.h | 81 +++++++++++++----- src/utils.h | 10 ++- 8 files changed, 323 insertions(+), 55 deletions(-) create mode 100644 src/chickens_cyclone_typhoon.c create mode 100644 src/chickens_hurricane_zephyr.c create mode 100644 src/chickens_monsoon_mistral.c create mode 100644 src/chickens_twister.c diff --git a/Makefile b/Makefile index 01a1e249b..1b7795460 100644 --- a/Makefile +++ b/Makefile @@ -101,10 +101,14 @@ OBJECTS := \ chickens.o \ chickens_avalanche.o \ chickens_blizzard.o \ + chickens_cyclone_typhoon.o \ chickens_everest.o \ chickens_firestorm.o \ + chickens_hurricane_zephyr.o \ + chickens_monsoon_mistral.o \ chickens_icestorm.o \ chickens_sawtooth.o \ + chickens_twister.o \ clk.o \ cpufreq.o \ dapf.o \ diff --git a/src/chickens.c b/src/chickens.c index 04ebe40ad..673b8a5d0 100644 --- a/src/chickens.c +++ b/src/chickens.c @@ -6,29 +6,56 @@ #include "utils.h" /* Part IDs in MIDR_EL1 */ -#define MIDR_PART_T8181_ICESTORM 0x20 -#define MIDR_PART_T8181_FIRESTORM 0x21 -#define MIDR_PART_T8103_ICESTORM 0x22 -#define MIDR_PART_T8103_FIRESTORM 0x23 -#define MIDR_PART_T6000_ICESTORM 0x24 -#define MIDR_PART_T6000_FIRESTORM 0x25 -#define MIDR_PART_T6001_ICESTORM 0x28 -#define MIDR_PART_T6001_FIRESTORM 0x29 -#define MIDR_PART_T8110_BLIZZARD 0x30 -#define MIDR_PART_T8110_AVALANCHE 0x31 -#define MIDR_PART_T8112_BLIZZARD 0x32 -#define MIDR_PART_T8112_AVALANCHE 0x33 -#define MIDR_PART_T6020_BLIZZARD 0x34 -#define MIDR_PART_T6020_AVALANCHE 0x35 -#define MIDR_PART_T6021_BLIZZARD 0x38 -#define MIDR_PART_T6021_AVALANCHE 0x39 -#define MIDR_PART_T6031_EVEREST 0x49 -#define MIDR_PART_T6031_SAWTOOTH 0x48 +#define MIDR_PART_S5L8960X_CYCLONE 0x1 +#define MIDR_PART_T7000_TYPHOON 0x2 +#define MIDR_PART_T7001_TYPHOON 0x3 +#define MIDR_PART_S8000_TWISTER 0x4 +#define MIDR_PART_S8001_3_TWISTER 0x5 +#define MIDR_PART_T8010_2_HURRICANE 0x6 +#define MIDR_PART_T8011_HURRICANE 0x7 +#define MIDR_PART_T8015_MONSOON 0x8 +#define MIDR_PART_T8015_MISTRAL 0x9 +#define MIDR_PART_T8020_VORTEX 0xb +#define MIDR_PART_T8020_TEMPSET 0xc +#define MIDR_PART_T8006_TEMPSET 0xf +#define MIDR_PART_T8027_VORTEX 0x10 +#define MIDR_PART_T8027_TEMPSET 0x11 +#define MIDR_PART_T8030_LIGHTNING 0x12 +#define MIDR_PART_T8030_THUNDER 0x13 +#define MIDR_PART_T8101_ICESTORM 0x20 +#define MIDR_PART_T8101_FIRESTORM 0x21 +#define MIDR_PART_T8103_ICESTORM 0x22 +#define MIDR_PART_T8103_FIRESTORM 0x23 +#define MIDR_PART_T6000_ICESTORM 0x24 +#define MIDR_PART_T6000_FIRESTORM 0x25 +#define MIDR_PART_T8301_THUNDER 0x26 +#define MIDR_PART_T6001_ICESTORM 0x28 +#define MIDR_PART_T6001_FIRESTORM 0x29 +#define MIDR_PART_T8110_BLIZZARD 0x30 +#define MIDR_PART_T8110_AVALANCHE 0x31 +#define MIDR_PART_T8112_BLIZZARD 0x32 +#define MIDR_PART_T8112_AVALANCHE 0x33 +#define MIDR_PART_T6020_BLIZZARD 0x34 +#define MIDR_PART_T6020_AVALANCHE 0x35 +#define MIDR_PART_T6021_BLIZZARD 0x38 +#define MIDR_PART_T6021_AVALANCHE 0x39 +#define MIDR_PART_T6031_EVEREST 0x49 +#define MIDR_PART_T6031_SAWTOOTH 0x48 #define MIDR_REV_LOW GENMASK(3, 0) #define MIDR_PART GENMASK(15, 4) #define MIDR_REV_HIGH GENMASK(23, 20) +void init_s5l8960x_cyclone(void); +void init_t7000_typhoon(void); +void init_t7001_typhoon(void); +void init_samsung_twister(int rev); +void init_tsmc_twister(void); +void init_t8010_2_hurricane_zephyr(void); +void init_t8011_hurricane_zephyr(void); +void init_t8015_monsoon(void); +void init_t8015_mistral(void); +void init_t8015_monsoon(void); void init_m1_icestorm(void); void init_t8103_firestorm(int rev); void init_t6000_firestorm(int rev); @@ -56,19 +83,66 @@ const char *init_cpu(void) else reg_set(SYS_IMP_APL_HID4, HID4_DISABLE_DC_MVA | HID4_DISABLE_DC_SW_L2_OPS); - /* Enable NEX powergating, the reset cycles might be overriden by chickens */ - if (!is_ecore()) { - reg_mask(SYS_IMP_APL_HID13, HID13_RESET_CYCLES_MASK, HID13_RESET_CYCLES(12)); - reg_set(SYS_IMP_APL_HID14, HID14_ENABLE_NEX_POWER_GATING); - } - uint64_t midr = mrs(MIDR_EL1); int part = FIELD_GET(MIDR_PART, midr); int rev = (FIELD_GET(MIDR_REV_HIGH, midr) << 4) | FIELD_GET(MIDR_REV_LOW, midr); printf(" CPU part: 0x%x rev: 0x%x\n", part, rev); + if (part >= MIDR_PART_T8015_MONSOON) { + /* Enable NEX powergating, the reset cycles might be overriden by chickens */ + if (!is_ecore()) { + reg_mask(SYS_IMP_APL_HID13, HID13_RESET_CYCLES_MASK, HID13_RESET_CYCLES(12)); + reg_set(SYS_IMP_APL_HID14, HID14_ENABLE_NEX_POWER_GATING); + } + } + switch (part) { + case MIDR_PART_S5L8960X_CYCLONE: + cpu = "A7 Cyclone"; + init_s5l8960x_cyclone(); + break; + + case MIDR_PART_T7000_TYPHOON: + cpu = "A8 Typhoon"; + init_t7000_typhoon(); + break; + + case MIDR_PART_T7001_TYPHOON: + cpu = "A8X Typhoon"; + init_t7001_typhoon(); + break; + + case MIDR_PART_S8000_TWISTER: + cpu = "A9 Twister (Samsung)"; + init_samsung_twister(rev); + break; + + case MIDR_PART_S8001_3_TWISTER: + cpu = "A9(X) Twister (TSMC)"; + init_tsmc_twister(); + break; + + case MIDR_PART_T8010_2_HURRICANE: + cpu = "A10/T2 Hurricane-Zephyr"; + init_t8010_2_hurricane_zephyr(); + break; + + case MIDR_PART_T8011_HURRICANE: + cpu = "A10X Hurricane-Zephyr"; + init_t8011_hurricane_zephyr(); + break; + + case MIDR_PART_T8015_MONSOON: + cpu = "A11 Monsoon"; + init_t8015_monsoon(); + break; + + case MIDR_PART_T8015_MISTRAL: + cpu = "A11 Mistral"; + init_t8015_mistral(); + break; + case MIDR_PART_T8103_FIRESTORM: cpu = "M1 Firestorm"; init_t8103_firestorm(rev); @@ -147,23 +221,26 @@ const char *init_cpu(void) if (part >= MIDR_PART_T8110_BLIZZARD) cpufeat_actlr_el2 = true; - int core = mrs(MPIDR_EL1) & 0xff; + if (part >= MIDR_PART_T8101_ICESTORM && part != MIDR_PART_T8301_THUNDER) { + int core = mrs(MPIDR_EL1) & 0xff; - msr(SYS_IMP_APL_AMX_CTX_EL1, core); - msr(SYS_IMP_APL_AMX_CTL_EL1, 0x100); + // Enable IRQs (at least necessary on t600x) + // XXX 0 causes pathological behavior in EL1, 2 works. + msr(SYS_IMP_APL_SIQ_CFG_EL1, 2); + sysop("isb"); - // Enable IRQs (at least necessary on t600x) - // XXX 0 causes pathological behavior in EL1, 2 works. - msr(SYS_IMP_APL_SIQ_CFG_EL1, 2); + msr(SYS_IMP_APL_AMX_CTX_EL1, core); + } - sysop("isb"); + if (part >= MIDR_PART_T8030_LIGHTNING) + msr(SYS_IMP_APL_AMX_CTL_EL1, 0x100); /* Unmask external IRQs, set WFI mode to up (2) */ reg_mask(SYS_IMP_APL_CYC_OVRD, CYC_OVRD_FIQ_MODE_MASK | CYC_OVRD_IRQ_MODE_MASK | CYC_OVRD_WFI_MODE_MASK, CYC_OVRD_FIQ_MODE(0) | CYC_OVRD_IRQ_MODE(0) | CYC_OVRD_WFI_MODE(2)); - /* Enable branch prediction state retention across ACC sleep */ + // Enable branch prediction state retention across ACC sleep reg_mask(SYS_IMP_APL_ACC_CFG, ACC_CFG_BP_SLEEP_MASK, ACC_CFG_BP_SLEEP(3)); return cpu; diff --git a/src/chickens_cyclone_typhoon.c b/src/chickens_cyclone_typhoon.c new file mode 100644 index 000000000..d079a339d --- /dev/null +++ b/src/chickens_cyclone_typhoon.c @@ -0,0 +1,43 @@ +/* SPDX-License-Identifier: MIT */ + +#include "cpu_regs.h" +#include "utils.h" + +// This file includes chickens for both cyclone and typhoon chips +// due to their similarity. + +static void init_common_cyclone_typhoon(void) +{ + /* "Disable LSP flush with context switch to work around bug in LSP + that can cause Cyclone to wedge when CONTEXTIDR is written." */ + reg_set(SYS_IMP_APL_HID0, HID0_LOOP_BUFFER_DISABLE); + + /* Not sure on what's happening here... did the meaning of this bit + change at some point? Original name: ARM64_REG_HID1_rccDisStallInactiveIexCtl */ + reg_set(SYS_IMP_APL_HID1, HID1_DIS_SPEC_MDSB_INVL_ROB_FLUSH); + reg_set(SYS_IMP_APL_HID3, HID3_DIS_XMON_SNP_EVICT_TRIGGER_L2_STARAVTION_MODE); + + reg_clr(SYS_IMP_APL_HID5, HID5_DIS_HWP_LD | HID5_DIS_HWP_ST); + + // Change memcache data ID from 0 to 15 + reg_set(SYS_IMP_APL_HID8, HID8_DATA_SET_ID0_VALUE(0xf) | HID8_DATA_SET_ID1_VALUE(0xf)); +} + +void init_t7000_typhoon(void) +{ + init_common_cyclone_typhoon(); +} + +void init_t7001_typhoon(void) +{ + init_common_cyclone_typhoon(); + + // Change memcache data ID from 0 to 15 + reg_set(SYS_IMP_APL_HID8, HID8_DATA_SET_ID2_VALUE(0xf)); +} + +void init_s5l8960x_cyclone(void) +{ + init_common_cyclone_typhoon(); + reg_set(SYS_IMP_APL_HID1, HID1_DIS_LSP_FLUSH_WITH_CONTEXT_SWITCH); +} diff --git a/src/chickens_hurricane_zephyr.c b/src/chickens_hurricane_zephyr.c new file mode 100644 index 000000000..126336e9a --- /dev/null +++ b/src/chickens_hurricane_zephyr.c @@ -0,0 +1,39 @@ +/* SPDX-License-Identifier: MIT */ + +#include "cpu_regs.h" +#include "utils.h" + +// This file name has both the codenames of E-core and P-core because to software +// it is one core that switches modes based on frequency + +static void init_common_hurricane_zephyr(void) +{ + /* "Increase Snoop reservation in EDB to reduce starvation risk + Needs to be done before MMU is enabled" */ + reg_mask(SYS_IMP_APL_HID5, HID5_SNOOP_EDB_RESV_MASK, HID5_SNOOP_EDB_RESV_VALUE(2)); + + // "IC prefetch configuration" + reg_mask(SYS_IMP_APL_HID0, HID0_IC_PREFETCH_DEPTH_MASK, HID0_IC_PREFETCH_DEPTH_VALUE(1)); + reg_set(SYS_IMP_APL_HID0, HID0_IC_PREFETCH_LIMIT_ONE_BRN); + + // "disable reporting of TLB-multi-hit-error" + reg_clr(SYS_IMP_APL_LSU_ERR_CTL, LSU_ERR_CTL_DISABLE_TLB_MULTI_HIT_ERROR_REPORTING); + + // "disable crypto fusion across decode groups" + /* Not sure on what's happening here... did the meaning of this bit + change at some point? Original Name: ARM64_REG_HID1_disAESFuseAcrossGrp */ + reg_set(SYS_IMP_APL_HID1, HID1_CONSERVATIVE_SIQ); +} + +void init_t8010_2_hurricane_zephyr(void) +{ + init_common_hurricane_zephyr(); +} + +void init_t8011_hurricane_zephyr(void) +{ + init_common_hurricane_zephyr(); + + reg_clr(SYS_IMP_APL_HID3, HID3_DISABLE_DC_ZVA_CMD_ONLY); + reg_clr(SYS_IMP_APL_EHID3, EHID3_DISABLE_DC_ZVA_CMD_ONLY); +} diff --git a/src/chickens_monsoon_mistral.c b/src/chickens_monsoon_mistral.c new file mode 100644 index 000000000..c08af3ca2 --- /dev/null +++ b/src/chickens_monsoon_mistral.c @@ -0,0 +1,27 @@ +/* SPDX-License-Identifier: MIT */ + +#include "cpu_regs.h" +#include "utils.h" + +static void init_t8015_common(void) +{ + // "Disable refcount syncing between E and P" + reg_mask(SYS_IMP_APL_CYC_OVRD, CYC_OVRD_DSBL_SNOOP_TIME_MASK, + CYC_OVRD_DSBL_SNOOP_TIME_VALUE(2)); + + // "WKdm write ack lost when bif_wke_colorWrAck_XXaH asserts concurrently for both colors" + reg_set(SYS_IMP_APL_HID8, WKE_FORCE_STRICT_ORDER); +} + +void init_t8015_mistral(void) +{ + init_t8015_common(); + + // "Atomic launch eligibility is erroneously taken away when a store at SMB gets invalidated" + reg_clr(SYS_IMP_APL_EHID11, EHID11_SMB_DRAIN_THRESH_MASK); +} + +void init_t8015_monsoon(void) +{ + init_t8015_common(); +} diff --git a/src/chickens_twister.c b/src/chickens_twister.c new file mode 100644 index 000000000..929cd1455 --- /dev/null +++ b/src/chickens_twister.c @@ -0,0 +1,33 @@ +/* SPDX-License-Identifier: MIT */ + +#include "cpu_regs.h" +#include "utils.h" + +static void init_twister_common(void) +{ + reg_clr(SYS_IMP_APL_HID11_LEGACY, HID11_DISABLE_FILL_C1_BUB_OPT); + + // Change memcache data ID from 0 to 15 + reg_set(SYS_IMP_APL_HID8, HID8_DATA_SET_ID0_VALUE(0xf) | HID8_DATA_SET_ID1_VALUE(0xf) | + HID8_DATA_SET_ID2_VALUE(0xf) | HID8_DATA_SET_ID3_VALUE(0xf)); + + reg_set(SYS_IMP_APL_HID7, HID7_HID11_DISABLE_NEX_FAST_FMUL); + + // "disable reporting of TLB-multi-hit-error" + reg_clr(SYS_IMP_APL_LSU_ERR_STS, LSU_ERR_STS_DISABLE_TLB_MULTI_HIT_ERROR_REPORTING); +} + +void init_samsung_twister(int rev) +{ + if (rev == 0x20) { // s8000 ONLY + /* "Set CYC_CFG:skipInit to pull in isAlive by one DCLK + to work around potential hang. Must only be applied to Maui C0." "*/ + reg_set(SYS_IMP_APL_ACC_CFG, ACC_CFG_SKIP_INIT); + } + init_twister_common(); +} + +void init_tsmc_twister(void) +{ + init_twister_common(); +} diff --git a/src/cpu_regs.h b/src/cpu_regs.h index 40cd37966..e63923075 100644 --- a/src/cpu_regs.h +++ b/src/cpu_regs.h @@ -21,9 +21,13 @@ /* HID registers */ #define SYS_IMP_APL_HID0 sys_reg(3, 0, 15, 0, 0) +#define HID0_LOOP_BUFFER_DISABLE BIT(20) +#define HID0_IC_PREFETCH_LIMIT_ONE_BRN BIT(25) #define HID0_FETCH_WIDTH_DISABLE BIT(28) #define HID0_CACHE_FUSION_DISABLE BIT(36) #define HID0_SAME_PG_POWER_OPTIMIZATION BIT(45) +#define HID0_IC_PREFETCH_DEPTH_MASK GENMASK(62, 60) +#define HID0_IC_PREFETCH_DEPTH_VALUE(x) (ULONG(x) << 60) #define SYS_IMP_APL_EHID0 sys_reg(3, 0, 15, 0, 1) #define EHID0_BLI_UNK32 BIT(32) @@ -145,11 +149,13 @@ #define EHID1_EN_LFSR_STALL_RS6 BIT(62) #define EHID1_EN_LFSR BIT(63) -#define SYS_IMP_APL_HID3 sys_reg(3, 0, 15, 3, 0) -#define HID3_DISABLE_ARBITER_FIX_BIF_CRD BIT(44) -#define HID3_DEV_PCIE_THROTTLE_LIMIT_MASK GENMASK(62, 57) -#define HID3_DEV_PCIE_THROTTLE_LIMIT(x) ((ULONG(x)) << 57) -#define HID3_DEV_PCIE_THROTTLE_ENABLE BIT(63) +#define SYS_IMP_APL_HID3 sys_reg(3, 0, 15, 3, 0) +#define HID3_DISABLE_DC_ZVA_CMD_ONLY BIT(25) +#define HID3_DISABLE_ARBITER_FIX_BIF_CRD BIT(44) +#define HID3_DIS_XMON_SNP_EVICT_TRIGGER_L2_STARAVTION_MODE BIT(50) +#define HID3_DEV_PCIE_THROTTLE_LIMIT_MASK GENMASK(62, 57) +#define HID3_DEV_PCIE_THROTTLE_LIMIT(x) ((ULONG(x)) << 57) +#define HID3_DEV_PCIE_THROTTLE_ENABLE BIT(63) #define SYS_IMP_APL_HID4 sys_reg(3, 0, 15, 4, 0) #define HID4_INV_CORE_CLK_OBS_TO_SOC BIT(0) @@ -208,6 +214,8 @@ #define HID4_ENABLE_LFSR BIT(63) #define SYS_IMP_APL_EHID4 sys_reg(3, 0, 15, 4, 1) +#define SYS_IMP_APL_EHID3 sys_reg(3, 0, 15, 3, 1) +#define EHID3_DISABLE_DC_ZVA_CMD_ONLY BIT(25) #define EHID4_DISABLE_HW_PREF_LD BIT(0) #define EHID4_DISABLE_HW_PREF_ST BIT(1) #define EHID4_DISABLE_SW_PRELOAD BIT(2) @@ -263,22 +271,38 @@ #define EHID4_LFSR_SEED_MASK GENMASK(62, 56) #define EHID4_ENABLE_LFSR BIT(63) -#define SYS_IMP_APL_HID5 sys_reg(3, 0, 15, 5, 0) -#define HID5_BLZ_UNK_19_18_MASK GENMASK(19, 18) -#define HID5_BLZ_UNK18 BIT(18) -#define HID5_BLZ_UNK19 BIT(19) -#define HID5_DISABLE_FILL_2C_MERGE BIT(61) +#define SYS_IMP_APL_HID5 sys_reg(3, 0, 15, 5, 0) +#define HID5_SNOOP_EDB_RESV_MASK GENMASK(15, 14) +#define HID5_SNOOP_EDB_RESV_VALUE(x) ((ULONG(x)) << 14) +#define HID5_BLZ_UNK_19_18_MASK GENMASK(19, 18) +#define HID5_BLZ_UNK18 BIT(18) +#define HID5_BLZ_UNK19 BIT(19) +#define HID5_DIS_HWP_LD BIT(44) +#define HID5_DIS_HWP_ST BIT(45) +#define HID5_DISABLE_FILL_2C_MERGE BIT(61) #define SYS_IMP_APL_HID6 sys_reg(3, 0, 15, 6, 0) #define HID6_UP_CRD_TKN_INIT_C2(x) ((ULONG(x)) << 5) #define HID6_UP_CRD_TKN_INIT_C2_MASK (0x1FUL << 5) #define SYS_IMP_APL_HID7 sys_reg(3, 0, 15, 7, 0) +#define HID7_HID11_DISABLE_NEX_FAST_FMUL BIT(10) #define HID7_FORCE_NONSPEC_IF_SPEC_FLUSH_POINTER_INVALID_AND_MP_VALID BIT(16) #define HID7_FORCE_NONSPEC_IF_STEPPING BIT(20) #define HID7_FORCE_NONSPEC_TARGET_TIMER_SEL(x) ((ULONG(x)) << 24) #define HID7_FORCE_NONSPEC_TARGET_TIMER_SEL_MASK (3UL << 24) +#define SYS_IMP_APL_HID8 sys_reg(3, 0, 15, 8, 0) +#define HID8_DATA_SET_ID0_VALUE(x) ((ULONG(x)) << 4) +#define HID8_DATA_SET_ID0_VALUE_MASK GENMASK(7, 4) +#define HID8_DATA_SET_ID1_VALUE(x) ((ULONG(x)) << 8) +#define HID8_DATA_SET_ID1_VALUE_MASK GENMASK(11, 8) +#define WKE_FORCE_STRICT_ORDER BIT(35) +#define HID8_DATA_SET_ID2_VALUE(x) ((ULONG(x)) << 56) +#define HID8_DATA_SET_ID2_VALUE_MASK GENMASK(59, 56) +#define HID8_DATA_SET_ID3_VALUE(x) ((ULONG(x)) << 60) +#define HID8_DATA_SET_ID3_VALUE_MASK GENMASK(63, 60) + #define SYS_IMP_APL_HID9 sys_reg(3, 0, 15, 9, 0) #define HID9_AVL_UNK17 BIT(17) #define HID9_TSO_ALLOW_DC_ZVA_WC BIT(26) @@ -296,9 +320,14 @@ #define HID10_FORCE_WAIT_STATE_DRAIN_UC BIT(32) #define HID10_DISABLE_ZVA_TEMPORAL_TSO BIT(49) -#define SYS_IMP_APL_HID11 sys_reg(3, 0, 15, 11, 0) -#define HID11_ENABLE_FIX_UC_55719865 BIT(15) -#define HID11_DISABLE_LD_NT_WIDGET BIT(59) +#define SYS_IMP_APL_HID11 sys_reg(3, 0, 15, 11, 0) +#define SYS_IMP_APL_HID11_LEGACY sys_reg(3, 0, 15, 13, 0) /* A7-A9 */ +#define HID11_DISABLE_FILL_C1_BUB_OPT BIT(7) +#define HID11_ENABLE_FIX_UC_55719865 BIT(15) +#define HID11_DISABLE_LD_NT_WIDGET BIT(59) + +#define SYS_IMP_APL_EHID11 sys_reg(3, 0, 15, 11, 1) +#define EHID11_SMB_DRAIN_THRESH_MASK GENMASK(41, 40) #define SYS_IMP_APL_HID12 sys_reg(3, 0, 15, 12, 0) @@ -455,8 +484,12 @@ #define SYS_IMP_APL_PMC9 sys_reg(3, 2, 15, 10, 0) #define SYS_IMP_APL_LSU_ERR_STS sys_reg(3, 3, 15, 0, 0) +#define SYS_IMP_APL_LSU_ERR_CTL sys_reg(3, 3, 15, 1, 0) #define SYS_IMP_APL_E_LSU_ERR_STS sys_reg(3, 3, 15, 2, 0) +#define LSU_ERR_STS_DISABLE_TLB_MULTI_HIT_ERROR_REPORTING BIT(54) +#define LSU_ERR_CTL_DISABLE_TLB_MULTI_HIT_ERROR_REPORTING BIT(3) + #define SYS_IMP_APL_L2C_ERR_STS sys_reg(3, 3, 15, 8, 0) #define L2C_ERR_STS_RECURSIVE_FAULT BIT(1) @@ -478,15 +511,19 @@ #define SYS_IMP_APL_ACC_CFG sys_reg(3, 5, 15, 4, 0) #define ACC_CFG_BP_SLEEP(x) ((ULONG(x)) << 2) #define ACC_CFG_BP_SLEEP_MASK (3UL << 2) - -#define SYS_IMP_APL_CYC_OVRD sys_reg(3, 5, 15, 5, 0) -#define CYC_OVRD_FIQ_MODE(x) ((ULONG(x)) << 20) -#define CYC_OVRD_FIQ_MODE_MASK (3UL << 20) -#define CYC_OVRD_IRQ_MODE(x) ((ULONG(x)) << 22) -#define CYC_OVRD_IRQ_MODE_MASK (3UL << 22) -#define CYC_OVRD_WFI_MODE(x) ((ULONG(x)) << 24) -#define CYC_OVRD_WFI_MODE_MASK (3UL << 24) -#define CYC_OVRD_DISABLE_WFI_RET BIT(0) +#define ACC_CFG_DEEP_SLEEP BIT(24) +#define ACC_CFG_SKIP_INIT BIT(30) + +#define SYS_IMP_APL_CYC_OVRD sys_reg(3, 5, 15, 5, 0) +#define CYC_OVRD_FIQ_MODE(x) ((ULONG(x)) << 20) +#define CYC_OVRD_FIQ_MODE_MASK (3UL << 20) +#define CYC_OVRD_IRQ_MODE(x) ((ULONG(x)) << 22) +#define CYC_OVRD_IRQ_MODE_MASK (3UL << 22) +#define CYC_OVRD_WFI_MODE(x) ((ULONG(x)) << 24) +#define CYC_OVRD_WFI_MODE_MASK (3UL << 24) +#define CYC_OVRD_DISABLE_WFI_RET BIT(0) +#define CYC_OVRD_DSBL_SNOOP_TIME_MASK GENMASK(31, 30) +#define CYC_OVRD_DSBL_SNOOP_TIME_VALUE(x) (ULONG(x) << 30) #define SYS_IMP_APL_ACC_OVRD sys_reg(3, 5, 15, 6, 0) diff --git a/src/utils.h b/src/utils.h index fe3eb1b37..c35487845 100644 --- a/src/utils.h +++ b/src/utils.h @@ -3,6 +3,7 @@ #ifndef UTILS_H #define UTILS_H +#include "soc.h" #include "types.h" #define printf(...) debug_printf(__VA_ARGS__) @@ -324,9 +325,16 @@ static inline void write64_lo_hi(u64 addr, u64 val) #define dma_rmb() sysop("dmb oshld") #define dma_wmb() sysop("dmb oshst") +extern u32 board_id, chip_id; +static inline bool has_ecores(void) +{ + return !(chip_id == S5L8960X || chip_id == T7000 || chip_id == T7001 || chip_id == S8000 || + chip_id == S8001 || chip_id == S8003); +} + static inline int is_ecore(void) { - return !(mrs(MPIDR_EL1) & (1 << 16)); + return has_ecores() && !(mrs(MPIDR_EL1) & (1 << 16)); } static inline int in_el2(void) From 99719696d04c62c6660a753bdb2876cf288dcd85 Mon Sep 17 00:00:00 2001 From: Nick Chan Date: Sun, 25 Aug 2024 15:27:56 +0800 Subject: [PATCH 04/19] Add support for handling EL3. A7-A9X has an EL3. Handle it (without SMP support). Signed-off-by: Nick Chan --- m1n1-raw.ld | 7 +++++++ m1n1.ld | 5 +++++ src/chickens.c | 2 +- src/exception.c | 48 +++++++++++++++++++++++++++++++++++++----------- src/start.S | 32 ++++++++++++++++++++++++++++++++ src/startup.c | 4 ++++ src/utils.h | 12 +++++++++++- 7 files changed, 97 insertions(+), 13 deletions(-) diff --git a/m1n1-raw.ld b/m1n1-raw.ld index 56ebfe497..7f88b608d 100644 --- a/m1n1-raw.ld +++ b/m1n1-raw.ld @@ -1,6 +1,7 @@ ENTRY(_start) _stack_size = 0x20000; +_stack_size_el3 = 0x8000; /* We are actually relocatable */ . = 0; @@ -71,6 +72,12 @@ SECTIONS { *(COMMON) _bss_end = .; } : data + .stack_el3 : ALIGN(0x4000) { + PROVIDE(_stack_top_el3 = .); + . += _stack_size_el3 - 8; + QUAD(0x5176694b43415453); + PROVIDE(_stack_bot_el3 = .); + } .stack : ALIGN(0x4000) { PROVIDE(_stack_top = .); . += _stack_size - 8; diff --git a/m1n1.ld b/m1n1.ld index 6ac86d7ac..5d6d95e8e 100644 --- a/m1n1.ld +++ b/m1n1.ld @@ -4,6 +4,7 @@ ENTRY(_start) _va_base = 0xFFFFFE0007004000; _stack_size = 0x20000; +_stack_size_el3 = 0x8000; _max_payload_size = 64*1024*1024; @@ -176,6 +177,10 @@ SECTIONS { *(COMMON) . = ALIGN(0x4000); _bss_end = .; + PROVIDE(_stack_top_el3 = .); + . += _stack_size_el3; + PROVIDE(_stack_bot_el3 = .); + . = ALIGN(0x4000); PROVIDE(_stack_top = .); . += _stack_size; PROVIDE(_stack_bot = .); diff --git a/src/chickens.c b/src/chickens.c index 673b8a5d0..02329ef63 100644 --- a/src/chickens.c +++ b/src/chickens.c @@ -69,7 +69,7 @@ void init_t6021_avalanche(int rev); void init_t6031_sawtooth(void); void init_t6031_everest(int rev); -bool cpufeat_actlr_el2; +bool cpufeat_actlr_el2, cpufeat_fast_ipi; const char *init_cpu(void) { diff --git a/src/exception.c b/src/exception.c index d1f606d3f..9b2b37532 100644 --- a/src/exception.c +++ b/src/exception.c @@ -30,6 +30,8 @@ static char *m_table[0x10] = { [0x05] = "EL1h", // [0x08] = "EL2t", // [0x09] = "EL2h", // + [0x0c] = "EL3t", // + [0x0d] = "EL3h", // }; static char *gl_m_table[0x10] = { @@ -114,6 +116,8 @@ static const char *get_exception_level(void) return "EL1"; else if (lvl == 0x08) return "EL2"; + else if (lvl == 0x0c) + return "EL3"; } return "?"; @@ -121,7 +125,10 @@ static const char *get_exception_level(void) void exception_initialize(void) { - msr(VBAR_EL1, _vectors_start); + if (in_el3()) + msr(VBAR_EL3, _vectors_start); + else + msr(VBAR_EL1, _vectors_start); // Clear FIQ sources msr(CNTP_CTL_EL0, 7L); @@ -130,9 +137,12 @@ void exception_initialize(void) msr(CNTP_CTL_EL02, 7L); msr(CNTV_CTL_EL02, 7L); } - reg_clr(SYS_IMP_APL_PMCR0, PMCR0_IACT | PMCR0_IMODE_MASK); - reg_clr(SYS_IMP_APL_UPMCR0, UPMCR0_IMODE_MASK); - msr(SYS_IMP_APL_IPI_SR_EL1, IPI_SR_PENDING); + + if (cpufeat_fast_ipi) { + reg_clr(SYS_IMP_APL_PMCR0, PMCR0_IACT | PMCR0_IMODE_MASK); + reg_clr(SYS_IMP_APL_UPMCR0, UPMCR0_IMODE_MASK); + msr(SYS_IMP_APL_IPI_SR_EL1, IPI_SR_PENDING); + } if (is_boot_cpu()) msr(DAIF, 0 << 6); // Enable SError, IRQ and FIQ @@ -168,8 +178,10 @@ void print_regs(u64 *regs, int el12) u64 sp = ((u64)(regs)) + 256; in_gl = in_gl12(); + bool el3 = in_el3(); - u64 spsr = in_gl ? mrs(SYS_IMP_APL_SPSR_GL1) : (el12 ? mrs(SPSR_EL12) : mrs(SPSR_EL1)); + u64 spsr = in_gl ? mrs(SYS_IMP_APL_SPSR_GL1) + : (el12 ? mrs(SPSR_EL12) : (el3 ? mrs(SPSR_EL3) : mrs(SPSR_EL1))); printf("Exception taken from %s\n", get_exception_source(spsr)); printf("Running in %s\n", get_exception_level()); @@ -184,9 +196,12 @@ void print_regs(u64 *regs, int el12) printf("x24-x27: %016lx %016lx %016lx %016lx\n", regs[24], regs[25], regs[26], regs[27]); printf("x28-x30: %016lx %016lx %016lx\n", regs[28], regs[29], regs[30]); - u64 elr = in_gl ? mrs(SYS_IMP_APL_ELR_GL1) : (el12 ? mrs(ELR_EL12) : mrs(ELR_EL1)); - u64 esr = in_gl ? mrs(SYS_IMP_APL_ESR_GL1) : (el12 ? mrs(ESR_EL12) : mrs(ESR_EL1)); - u64 far = in_gl ? mrs(SYS_IMP_APL_FAR_GL1) : (el12 ? mrs(FAR_EL12) : mrs(FAR_EL1)); + u64 elr = in_gl ? mrs(SYS_IMP_APL_ELR_GL1) + : (el12 ? mrs(ELR_EL12) : (el3 ? mrs(ELR_EL3) : mrs(ELR_EL1))); + u64 esr = in_gl ? mrs(SYS_IMP_APL_ESR_GL1) + : (el12 ? mrs(ESR_EL12) : (el3 ? mrs(ESR_EL3) : mrs(ESR_EL1))); + u64 far = in_gl ? mrs(SYS_IMP_APL_FAR_GL1) + : (el12 ? mrs(FAR_EL12) : (el3 ? mrs(FAR_EL3) : mrs(FAR_EL1))); printf("PC: 0x%lx (rel: 0x%lx)\n", elr, elr - (u64)_base); printf("SP: 0x%lx\n", sp); @@ -221,10 +236,11 @@ void exc_sync(u64 *regs) u32 insn; int el12 = 0; bool in_gl = in_gl12(); + bool el3 = in_el3(); - u64 spsr = in_gl ? mrs(SYS_IMP_APL_SPSR_GL1) : mrs(SPSR_EL1); - u64 esr = in_gl ? mrs(SYS_IMP_APL_ESR_GL1) : mrs(ESR_EL1); - u64 elr = in_gl ? mrs(SYS_IMP_APL_ELR_GL1) : mrs(ELR_EL1); + u64 spsr = in_gl ? mrs(SYS_IMP_APL_SPSR_GL1) : (el3 ? mrs(SPSR_EL3) : mrs(SPSR_EL1)); + u64 esr = in_gl ? mrs(SYS_IMP_APL_ESR_GL1) : (el3 ? mrs(ESR_EL3) : mrs(ESR_EL1)); + u64 elr = in_gl ? mrs(SYS_IMP_APL_ELR_GL1) : (el3 ? mrs(ELR_EL3) : mrs(ELR_EL1)); if ((spsr & 0xf) == 0 && ((esr >> 26) & 0x3f) == 0x3c) { // On clean EL0 return, let the normal exception return @@ -256,6 +272,14 @@ void exc_sync(u64 *regs) printf("Unknown HVC: 0x%x\n", imm); break; } + } else if (in_el3() && ((esr >> 26) & 0x3f) == 0x17) { + // Monitor call + u32 imm = mrs(ESR_EL3) & 0xffff; + switch (imm) { + default: + printf("Unknown SMC: 0x%x\n", imm); + break; + } } else { if (!(exc_guard & GUARD_SILENT)) printf("Exception: SYNC\n"); @@ -297,6 +321,8 @@ void exc_sync(u64 *regs) printf("Recovering from exception (ELR=0x%lx)\n", elr); if (in_gl) msr(SYS_IMP_APL_ELR_GL1, elr); + if (el3) + msr(ELR_EL3, elr); else msr(ELR_EL1, elr); diff --git a/src/start.S b/src/start.S index b0051e6f3..fcefb9612 100644 --- a/src/start.S +++ b/src/start.S @@ -96,11 +96,27 @@ _start: mov w0, '\n' bl debug_putc + mrs x8, CurrentEL + cmp x8, #0xc + beq start_el3 + mov x0, x19 mov x1, x20 bl _start_c b . +.globl exception_initialize +start_el3: + bl exception_initialize + adrp x8, _stack_bot_el3 + mov sp, x8 + mov x0, x19 + mov x1, x20 + msr tpidr_el3, xzr + adrp x6, _stack_bot + adr x7, _start_c + b el3_eret_to_el1 + .globl exc_unk .type exc_unk, @function exc_unk: @@ -148,6 +164,22 @@ cpu_reset: bl _cpu_reset_c b . +el3_eret_to_el1: + adr x8, _vectors_start + msr sctlr_el1, xzr + + mrs x8, scr_el3 + orr x8, x8, #(1<<10) // EL1 execution state is AArch64 + orr x8, x8, #(1<<0) // EL1 is non-secure + msr scr_el3, x8 + msr elr_el3, x7 // Set EL1 entry point + mov x8, #0x5 // EL1h + msr spsr_el3, x8 + + msr sp_el1, x6 // Set EL1 stack pointer + + eret + .globl debug_putc .type debug_putc, @function debug_putc: diff --git a/src/startup.c b/src/startup.c index 5473f3707..a883bea30 100644 --- a/src/startup.c +++ b/src/startup.c @@ -115,9 +115,13 @@ void _cpu_reset_c(void *stack) printf(" MPIDR: 0x%lx\n", mrs(MPIDR_EL1)); const char *type = init_cpu(); printf(" CPU: %s\n", type); + printf(" Running in EL%lu\n\n", mrs(CurrentEL) >> 2); exception_initialize(); + if (in_el3()) + return; + if (!is_boot_cpu()) smp_secondary_entry(); else diff --git a/src/utils.h b/src/utils.h index c35487845..7e8232945 100644 --- a/src/utils.h +++ b/src/utils.h @@ -342,6 +342,16 @@ static inline int in_el2(void) return (mrs(CurrentEL) >> 2) == 2; } +static inline int in_el3(void) +{ + return (mrs(CurrentEL) >> 2) == 3; +} + +static inline int has_el3(void) +{ + return !!(mrs(ID_AA64PFR0_EL1) & 0xf000); +} + extern int boot_cpu_idx; extern u64 boot_cpu_mpidr; static inline int is_boot_cpu(void) @@ -438,7 +448,7 @@ struct vector_args { extern u32 board_id, chip_id; extern bool is_mac; -extern bool cpufeat_actlr_el2; +extern bool cpufeat_actlr_el2, cpufeat_fast_ipi; extern struct vector_args next_stage; From 1dd3e98a4f34206643a937bc6dcdbafb42ebbd5b Mon Sep 17 00:00:00 2001 From: Nick Chan Date: Sun, 25 Aug 2024 15:22:56 +0800 Subject: [PATCH 05/19] Skip over features unsupported in A7-A11 SoCs. This includes - GXF - SPRR - PAN (A7-A9) - Atomics (A7-A10) - FIPI (A7-A10) - DCP SPRR on T8030 seems to be quite different from M1 (at least according to qemu-t8030), so keep it disabled for those CPU parts. Signed-off-by: Nick Chan --- src/chickens.c | 8 +++++++- src/display.c | 12 +++++++++--- src/exception.c | 27 ++++++++++++++++----------- src/gxf.c | 3 +++ src/main.c | 12 +++++++----- src/memory.c | 12 ++++++++---- src/start.S | 5 ++++- src/startup.c | 15 +++++++++++++++ src/utils.c | 7 +++++-- src/utils.h | 5 +++-- 10 files changed, 77 insertions(+), 29 deletions(-) diff --git a/src/chickens.c b/src/chickens.c index 02329ef63..086777442 100644 --- a/src/chickens.c +++ b/src/chickens.c @@ -69,7 +69,7 @@ void init_t6021_avalanche(int rev); void init_t6031_sawtooth(void); void init_t6031_everest(int rev); -bool cpufeat_actlr_el2, cpufeat_fast_ipi; +bool cpufeat_actlr_el2, cpufeat_fast_ipi, cpufeat_mmu_sprr; const char *init_cpu(void) { @@ -230,11 +230,17 @@ const char *init_cpu(void) sysop("isb"); msr(SYS_IMP_APL_AMX_CTX_EL1, core); + + /* T8030 SPRR is different */ + cpufeat_mmu_sprr = true; } if (part >= MIDR_PART_T8030_LIGHTNING) msr(SYS_IMP_APL_AMX_CTL_EL1, 0x100); + if (part >= MIDR_PART_T8015_MONSOON) + cpufeat_fast_ipi = true; + /* Unmask external IRQs, set WFI mode to up (2) */ reg_mask(SYS_IMP_APL_CYC_OVRD, CYC_OVRD_FIQ_MODE_MASK | CYC_OVRD_IRQ_MODE_MASK | CYC_OVRD_WFI_MODE_MASK, diff --git a/src/display.c b/src/display.c index 395099b1d..1bb28ae26 100644 --- a/src/display.c +++ b/src/display.c @@ -264,6 +264,11 @@ int display_start_dcp(void) return 0; #endif + if (!has_dcp) { + printf("display: DCP not present\n"); + return -1; + } + const display_config_t *disp_cfg = display_get_config(); display_is_dptx = !!disp_cfg->dptx_phy[0]; @@ -622,13 +627,14 @@ int display_init(void) else printf("display: Display is internal\n"); - if (cur_boot_args.video.width == 640 && cur_boot_args.video.height == 1136) { + if ((cur_boot_args.video.width == 640 && cur_boot_args.video.height == 1136) && + chip_id != S5L8960X) { printf("display: Dummy framebuffer found, initializing display\n"); return display_configure(NULL); - } else if (display_is_external) { + } else if (display_is_external && is_mac) { printf("display: External display found, reconfiguring\n"); return display_configure(NULL); - } else if (!(cur_boot_args.video.depth & FB_DEPTH_FLAG_RETINA)) { + } else if ((!(cur_boot_args.video.depth & FB_DEPTH_FLAG_RETINA)) && is_mac) { printf("display: Internal display with non-retina flag, assuming Sonoma bug and " "reconfiguring\n"); fb_clear_direct(); // Old m1n1 stage1 ends up with an ugly logo situation, clear it. diff --git a/src/exception.c b/src/exception.c index 9b2b37532..8588aeb9f 100644 --- a/src/exception.c +++ b/src/exception.c @@ -137,7 +137,6 @@ void exception_initialize(void) msr(CNTP_CTL_EL02, 7L); msr(CNTV_CTL_EL02, 7L); } - if (cpufeat_fast_ipi) { reg_clr(SYS_IMP_APL_PMCR0, PMCR0_IACT | PMCR0_IMODE_MASK); reg_clr(SYS_IMP_APL_UPMCR0, UPMCR0_IMODE_MASK); @@ -223,11 +222,13 @@ void print_regs(u64 *regs, int el12) if (is_ecore()) { printf("E_LSU_ERR_STS: 0x%lx\n", mrs(SYS_IMP_APL_E_LSU_ERR_STS)); printf("E_FED_ERR_STS: 0x%lx\n", mrs(SYS_IMP_APL_E_FED_ERR_STS)); - printf("E_MMU_ERR_STS: 0x%lx\n", mrs(SYS_IMP_APL_E_MMU_ERR_STS)); + if (cpufeat_fast_ipi) + printf("E_MMU_ERR_STS: 0x%lx\n", mrs(SYS_IMP_APL_E_MMU_ERR_STS)); } else { printf("LSU_ERR_STS: 0x%lx\n", mrs(SYS_IMP_APL_LSU_ERR_STS)); printf("FED_ERR_STS: 0x%lx\n", mrs(SYS_IMP_APL_FED_ERR_STS)); - printf("MMU_ERR_STS: 0x%lx\n", mrs(SYS_IMP_APL_MMU_ERR_STS)); + if (cpufeat_fast_ipi) + printf("MMU_ERR_STS: 0x%lx\n", mrs(SYS_IMP_APL_MMU_ERR_STS)); } } @@ -383,15 +384,19 @@ void exc_fiq(u64 *regs) printf(" PMC IRQ, masking\n"); reg_clr(SYS_IMP_APL_PMCR0, PMCR0_IACT | PMCR0_IMODE_MASK); } - reg = mrs(SYS_IMP_APL_UPMCR0); - if ((reg & UPMCR0_IMODE_MASK) == UPMCR0_IMODE_FIQ && (mrs(SYS_IMP_APL_UPMSR) & UPMSR_IACT)) { - printf(" UPMC IRQ, masking\n"); - reg_clr(SYS_IMP_APL_UPMCR0, UPMCR0_IMODE_MASK); - } - if (mrs(SYS_IMP_APL_IPI_SR_EL1) & IPI_SR_PENDING) { - printf(" Fast IPI IRQ, clearing\n"); - msr(SYS_IMP_APL_IPI_SR_EL1, IPI_SR_PENDING); + if (cpufeat_fast_ipi) { + reg = mrs(SYS_IMP_APL_UPMCR0); + if ((reg & UPMCR0_IMODE_MASK) == UPMCR0_IMODE_FIQ && + (mrs(SYS_IMP_APL_UPMSR) & UPMSR_IACT)) { + printf(" UPMC IRQ, masking\n"); + reg_clr(SYS_IMP_APL_UPMCR0, UPMCR0_IMODE_MASK); + } + + if (mrs(SYS_IMP_APL_IPI_SR_EL1) & IPI_SR_PENDING) { + printf(" Fast IPI IRQ, clearing\n"); + msr(SYS_IMP_APL_IPI_SR_EL1, IPI_SR_PENDING); + } } UNUSED(regs); diff --git a/src/gxf.c b/src/gxf.c index 7b751c5f9..2b1e52a9f 100644 --- a/src/gxf.c +++ b/src/gxf.c @@ -30,6 +30,9 @@ void gxf_init(void) bool gxf_enabled(void) { + if (!supports_gxf()) + return false; + if (!(mrs(SYS_IMP_APL_SPRR_CONFIG_EL1) & SPRR_CONFIG_EN)) return false; diff --git a/src/main.c b/src/main.c index d922cb182..2f1a7cc9f 100644 --- a/src/main.c +++ b/src/main.c @@ -51,6 +51,7 @@ void get_device_info(void) printf(" Target: %s\n", target); is_mac = !!strstr(model, "Mac"); + has_dcp = adt_path_offset(adt, "/arm-io/dcp") > 0; int chosen = adt_path_offset(adt, "/chosen"); if (chosen > 0) { @@ -146,13 +147,13 @@ void m1n1_main(void) printf("Running in EL%lu\n\n", mrs(CurrentEL) >> 2); - get_device_info(); firmware_init(); heapblock_init(); #ifndef BRINGUP - gxf_init(); + if (supports_gxf()) + gxf_init(); mcc_init(); mmu_init(); aic_init(); @@ -160,13 +161,14 @@ void m1n1_main(void) wdt_disable(); #ifndef BRINGUP pmgr_init(); - #ifdef USE_FB display_init(); // Kick DCP to sleep, so dodgy monitors which cause reconnect cycles don't cause us to lose the // framebuffer. - display_shutdown(DCP_SLEEP_IF_EXTERNAL); - fb_init(false); + if (has_dcp) + display_shutdown(DCP_SLEEP_IF_EXTERNAL); + // On idevice we need to always clear, because otherwise it looks scuffed on white devices + fb_init(!is_mac); fb_display_logo(); #ifdef FB_SILENT_MODE fb_set_active(!cur_boot_args.video.display); diff --git a/src/memory.c b/src/memory.c index b4abecf9c..733cbafa8 100644 --- a/src/memory.c +++ b/src/memory.c @@ -503,10 +503,12 @@ void mmu_init(void) mmu_init_pagetables(); mmu_add_default_mappings(); mmu_configure(); - mmu_init_sprr(); + if (cpufeat_mmu_sprr) + mmu_init_sprr(); // Enable EL0 memory access by EL1 - msr(PAN, 0); + if (supports_pan()) + msr(PAN, 0); // RES1 bits u64 sctlr = SCTLR_LSMAOE | SCTLR_nTLSMD | SCTLR_TSCXT | SCTLR_ITD; @@ -521,10 +523,12 @@ void mmu_init(void) static void mmu_secondary_setup(void) { mmu_configure(); - mmu_init_sprr(); + if (cpufeat_mmu_sprr) + mmu_init_sprr(); // Enable EL0 memory access by EL1 - msr(PAN, 0); + if (supports_pan()) + msr(PAN, 0); // RES1 bits u64 sctlr = SCTLR_LSMAOE | SCTLR_nTLSMD | SCTLR_TSCXT | SCTLR_ITD; diff --git a/src/start.S b/src/start.S index fcefb9612..befef9975 100644 --- a/src/start.S +++ b/src/start.S @@ -95,6 +95,7 @@ _start: bl debug_putc mov w0, '\n' bl debug_putc + bl pan_fixup mrs x8, CurrentEL cmp x8, #0xc @@ -105,7 +106,6 @@ _start: bl _start_c b . -.globl exception_initialize start_el3: bl exception_initialize adrp x8, _stack_bot_el3 @@ -197,6 +197,9 @@ debug_putc: .globl reboot .type reboot, @function reboot: + mrs x8, id_aa64pfr0_el1 + tst w8, 0xf00 + beq 1f mrs x0, CurrentEL cmp x0, #8 beq 1f diff --git a/src/startup.c b/src/startup.c index a883bea30..b76705432 100644 --- a/src/startup.c +++ b/src/startup.c @@ -44,6 +44,21 @@ void apply_rela(uint64_t base, struct rela_entry *rela_start, struct rela_entry } } +extern uint32_t _v_sp0_sync[], _v_sp0_irq[], _v_sp0_fiq[], _v_sp0_serr[]; +void pan_fixup(void) +{ + if (supports_pan()) + return; + + /* Patch msr pan, #0 to nop */ + _v_sp0_sync[0] = 0xd503201f; + _v_sp0_irq[0] = 0xd503201f; + _v_sp0_fiq[0] = 0xd503201f; + _v_sp0_serr[0] = 0xd503201f; + + sysop("isb"); +} + void dump_boot_args(struct boot_args *ba) { printf(" revision: %d\n", ba->revision); diff --git a/src/utils.c b/src/utils.c index 3ed569fe7..8a4b8d0f7 100644 --- a/src/utils.c +++ b/src/utils.c @@ -8,10 +8,11 @@ #include "iodev.h" #include "smp.h" #include "types.h" +#include "utils.h" #include "vsprintf.h" #include "xnuboot.h" -bool is_mac = false; +bool is_mac, has_dcp; static char ascii(char s) { @@ -149,7 +150,7 @@ void spin_lock(spinlock_t *lock) __asm__ volatile("1:\n" "mov\t%0, -1\n" "2:\n" - "\tcasa\t%0, %2, %1\n" + "\tldaxr\t%0, %1\n" "\tcmn\t%0, 1\n" "\tbeq\t3f\n" "\tldxr\t%0, %1\n" @@ -158,6 +159,8 @@ void spin_lock(spinlock_t *lock) "\twfe\n" "\tb\t1b\n" "3:" + "\tstxr\t%w0, %2, %1\n" + "\tcbnz\t%w0, 2b\n" : "=&r"(tmp), "+m"(lock->lock) : "r"(me) : "cc", "memory"); diff --git a/src/utils.h b/src/utils.h index 7e8232945..b055f29f5 100644 --- a/src/utils.h +++ b/src/utils.h @@ -447,8 +447,9 @@ struct vector_args { }; extern u32 board_id, chip_id; -extern bool is_mac; -extern bool cpufeat_actlr_el2, cpufeat_fast_ipi; + +extern bool is_mac, has_dcp; +extern bool cpufeat_actlr_el2, cpufeat_fast_ipi, cpufeat_mmu_sprr; extern struct vector_args next_stage; From ad7012075cf896e11ea1071f67bf1450474a9d42 Mon Sep 17 00:00:00 2001 From: Nick Chan Date: Sun, 25 Aug 2024 15:30:10 +0800 Subject: [PATCH 06/19] Add support for different boot-args revisions. Boot-args version 1 (iOS 12), and version 3 (iOS 18, macOS 15). Signed-off-by: Nick Chan --- src/firmware.c | 36 ++++++++++++++++------------ src/firmware.h | 4 ++++ src/memory.c | 2 +- src/startup.c | 65 +++++++++++++++++++++++++++++++++++++++++++++++--- src/utils.h | 1 + src/xnuboot.h | 24 +++++++++++++++---- 6 files changed, 109 insertions(+), 23 deletions(-) diff --git a/src/firmware.c b/src/firmware.c index cf14bd34e..eeaf85975 100644 --- a/src/firmware.c +++ b/src/firmware.c @@ -58,7 +58,7 @@ int firmware_set_fdt(void *fdt, int node, const char *prop, const struct fw_vers return 0; } -static void parse_version(const char *s, u32 *out) +void firmware_parse_version(const char *s, u32 *out) { memset(out, 0, sizeof(*out) * IBOOT_VER_COMP); @@ -86,21 +86,9 @@ static void detect_firmware(struct fw_version_info *info, const char *ver) info->iboot = ver; } -// Note: semi-open range -bool firmware_sfw_in_range(enum fw_version lower_bound, enum fw_version upper_bound) +bool firmware_iboot_in_range(u32 min[IBOOT_VER_COMP], u32 max[IBOOT_VER_COMP], + u32 this[IBOOT_VER_COMP]) { - u32 min[IBOOT_VER_COMP] = {0}; - u32 max[IBOOT_VER_COMP] = {UINT32_MAX}; - u32 this[IBOOT_VER_COMP] = {0}; - - if (lower_bound > V_UNKNOWN && lower_bound < NUM_FW_VERSIONS) - parse_version(fw_versions[lower_bound].iboot, min); - - if (upper_bound > V_UNKNOWN && upper_bound < NUM_FW_VERSIONS) - parse_version(fw_versions[upper_bound].iboot, max); - - parse_version(system_firmware.iboot, this); - int i; for (i = 0; i < IBOOT_VER_COMP; i++) if (this[i] != min[i]) @@ -116,6 +104,24 @@ bool firmware_sfw_in_range(enum fw_version lower_bound, enum fw_version upper_bo return this[i] < max[i]; } +// Note: semi-open range +bool firmware_sfw_in_range(enum fw_version lower_bound, enum fw_version upper_bound) +{ + u32 min[IBOOT_VER_COMP] = {0}; + u32 max[IBOOT_VER_COMP] = {UINT32_MAX}; + u32 this[IBOOT_VER_COMP] = {0}; + + if (lower_bound > V_UNKNOWN && lower_bound < NUM_FW_VERSIONS) + firmware_parse_version(fw_versions[lower_bound].iboot, min); + + if (upper_bound > V_UNKNOWN && upper_bound < NUM_FW_VERSIONS) + firmware_parse_version(fw_versions[upper_bound].iboot, max); + + firmware_parse_version(system_firmware.iboot, this); + + return firmware_iboot_in_range(min, max, this); +} + int firmware_init(void) { int node = adt_path_offset(adt, "/chosen"); diff --git a/src/firmware.h b/src/firmware.h index dbc4f7aab..610da5645 100644 --- a/src/firmware.h +++ b/src/firmware.h @@ -5,6 +5,7 @@ #include "types.h" +/* macOS */ enum fw_version { V_UNKNOWN = 0, V12_1, @@ -48,6 +49,9 @@ extern const struct fw_version_info fw_versions[NUM_FW_VERSIONS]; int firmware_init(void); int firmware_set_fdt(void *fdt, int node, const char *prop, const struct fw_version_info *ver); +bool firmware_iboot_in_range(u32 min[IBOOT_VER_COMP], u32 max[IBOOT_VER_COMP], + u32 this[IBOOT_VER_COMP]); bool firmware_sfw_in_range(enum fw_version lower_bound, enum fw_version upper_bound); +void firmware_parse_version(const char *s, u32 *out); #endif diff --git a/src/memory.c b/src/memory.c index 733cbafa8..afccc8de5 100644 --- a/src/memory.c +++ b/src/memory.c @@ -411,7 +411,7 @@ static void mmu_add_default_mappings(void) * With SPRR enabled, this becomes RW. * This range includes all real RAM, including carveouts */ - mmu_add_mapping(ram_base, ram_base, cur_boot_args.mem_size_actual, MAIR_IDX_NORMAL, PERM_RWX); + mmu_add_mapping(ram_base, ram_base, mem_size_actual, MAIR_IDX_NORMAL, PERM_RWX); /* Unmap carveout regions */ mcc_unmap_carveouts(); diff --git a/src/startup.c b/src/startup.c index b76705432..70bf25896 100644 --- a/src/startup.c +++ b/src/startup.c @@ -1,7 +1,9 @@ /* SPDX-License-Identifier: MIT */ +#include "adt.h" #include "chickens.h" #include "exception.h" +#include "firmware.h" #include "smp.h" #include "string.h" #include "types.h" @@ -59,8 +61,13 @@ void pan_fixup(void) sysop("isb"); } +u64 boot_flags, mem_size_actual; void dump_boot_args(struct boot_args *ba) { + if (ba->revision > 3) { + printf("Unsupported boot_args revision %hu\n!", ba->revision); + } + printf(" revision: %d\n", ba->revision); printf(" version: %d\n", ba->version); printf(" virt_base: 0x%lx\n", ba->virt_base); @@ -78,11 +85,61 @@ void dump_boot_args(struct boot_args *ba) printf(" machine_type: %d\n", ba->machine_type); printf(" devtree: %p\n", ba->devtree); printf(" devtree_size: 0x%x\n", ba->devtree_size); - printf(" cmdline: %s\n", ba->cmdline); - printf(" boot_flags: 0x%lx\n", ba->boot_flags); - printf(" mem_size_act: 0x%lx\n", ba->mem_size_actual); + int node = adt_path_offset(adt, "/chosen"); + + if (node < 0) { + printf("ADT: no /chosen found\n"); + return; + } + + /* This is called very early - before firmware information is initialized */ + u32 len; + const char *p = adt_getprop(adt, node, "firmware-version", &len); + if (!p) { + printf("ADT: failed to find firmware-version\n"); + return; + } + + uint16_t version = ba->revision; + u32 iboot_min[IBOOT_VER_COMP] = {0}; + u32 iboot_version[IBOOT_VER_COMP] = {0}; + u32 iboot_ba_v1_max[IBOOT_VER_COMP] = {5539}; /* iOS 13 = 5540 */ + + firmware_parse_version(p, iboot_version); + if (firmware_iboot_in_range(iboot_min, iboot_ba_v1_max, iboot_version)) + version = 1; + + switch (version) { + case 1: + printf(" cmdline: %s\n", ba->rv1.cmdline); + printf(" boot_flags: 0x%lx\n", ba->rv1.boot_flags); + printf(" mem_size_act: 0x%lx\n", ba->rv1.mem_size_actual); + boot_flags = ba->rv1.boot_flags; + mem_size_actual = ba->rv1.mem_size_actual; + break; + case 2: + printf(" cmdline: %s\n", ba->rv2.cmdline); + printf(" boot_flags: 0x%lx\n", ba->rv2.boot_flags); + printf(" mem_size_act: 0x%lx\n", ba->rv2.mem_size_actual); + boot_flags = ba->rv2.boot_flags; + mem_size_actual = ba->rv2.mem_size_actual; + break; + case 3: + default: + printf(" cmdline: %s\n", ba->rv3.cmdline); + printf(" boot_flags: 0x%lx\n", ba->rv3.boot_flags); + printf(" mem_size_act: 0x%lx\n", ba->rv3.mem_size_actual); + boot_flags = ba->rv3.boot_flags; + mem_size_actual = ba->rv3.mem_size_actual; + break; + } + if (!mem_size_actual) { + mem_size_actual = ALIGN_UP(ba->phys_base + ba->mem_size - 0x800000000, BIT(30)); + printf("Correcting mem_size_actual to 0x%lx\n", mem_size_actual); + } } +extern void get_device_info(void); void _start_c(void *boot_args, void *base) { UNUSED(base); @@ -105,6 +162,8 @@ void _start_c(void *boot_args, void *base) } uart_puts("Initializing"); + get_device_info(); + printf("CPU init (MIDR: 0x%lx)...\n", mrs(MIDR_EL1)); const char *type = init_cpu(); printf(" CPU: %s\n\n", type); diff --git a/src/utils.h b/src/utils.h index b055f29f5..4060641d1 100644 --- a/src/utils.h +++ b/src/utils.h @@ -452,6 +452,7 @@ extern bool is_mac, has_dcp; extern bool cpufeat_actlr_el2, cpufeat_fast_ipi, cpufeat_mmu_sprr; extern struct vector_args next_stage; +extern u64 boot_flags, mem_size_actual; void cpu_sleep(bool deep) __attribute__((noreturn)); void deep_wfi(void); diff --git a/src/xnuboot.h b/src/xnuboot.h index 32623b3e3..f713f0319 100644 --- a/src/xnuboot.h +++ b/src/xnuboot.h @@ -3,7 +3,9 @@ #ifndef XNUBOOT_H #define XNUBOOT_H -#define CMDLINE_LENGTH 608 +#define CMDLINE_LENGTH_RV1 256 +#define CMDLINE_LENGTH_RV2 608 +#define CMDLINE_LENGTH_RV3 1024 struct boot_video { u64 base; @@ -25,9 +27,23 @@ struct boot_args { u32 machine_type; void *devtree; u32 devtree_size; - char cmdline[CMDLINE_LENGTH]; - u64 boot_flags; - u64 mem_size_actual; + union { + struct { + char cmdline[CMDLINE_LENGTH_RV1]; + u64 boot_flags; + u64 mem_size_actual; + } rv1; + struct { + char cmdline[CMDLINE_LENGTH_RV2]; + u64 boot_flags; + u64 mem_size_actual; + } rv2; + struct { + char cmdline[CMDLINE_LENGTH_RV3]; + u64 boot_flags; + u64 mem_size_actual; + } rv3; + }; }; extern u64 boot_args_addr; From 8777b72c419d9733f3eb23cb9d03043dca026ac3 Mon Sep 17 00:00:00 2001 From: Nick Chan Date: Sun, 25 Aug 2024 15:46:27 +0800 Subject: [PATCH 07/19] memory: Add support for 4K translation Add support for 4K page sizes, supported by A7-A8X. Co-developed-by: fenfenS <104295404+fenfenS@users.noreply.github.com> Signed-off-by: fenfenS <104295404+fenfenS@users.noreply.github.com> Signed-off-by: Nick Chan --- src/arm_cpu_regs.h | 2 ++ src/dlmalloc/malloc_config.h | 2 +- src/memory.c | 64 +++++++++++++++++++++++++----------- src/utils.h | 10 ++++++ 4 files changed, 57 insertions(+), 21 deletions(-) diff --git a/src/arm_cpu_regs.h b/src/arm_cpu_regs.h index 1c8732b72..5789fef7e 100644 --- a/src/arm_cpu_regs.h +++ b/src/arm_cpu_regs.h @@ -309,6 +309,7 @@ #define TCR_IPS_16TB 0b100UL #define TCR_TG1 GENMASK(31, 30) #define TCR_TG1_16K 0b01UL +#define TCR_TG1_4K 0b10UL #define TCR_SH1 GENMASK(29, 28) #define TCR_SH1_IS 0b11UL #define TCR_ORGN1 GENMASK(27, 26) @@ -321,6 +322,7 @@ #define TCR_T1SZ_48BIT 16UL #define TCR_TG0 GENMASK(15, 14) #define TCR_TG0_16K 0b10UL +#define TCR_TG0_4K 0b0UL #define TCR_SH0 GENMASK(13, 12) #define TCR_SH0_IS 0b11UL #define TCR_ORGN0 GENMASK(11, 10) diff --git a/src/dlmalloc/malloc_config.h b/src/dlmalloc/malloc_config.h index 7616baf4e..7ddddda1a 100644 --- a/src/dlmalloc/malloc_config.h +++ b/src/dlmalloc/malloc_config.h @@ -15,7 +15,7 @@ #define ABORT panic("dlmalloc: internal error\n") #define NO_MALLINFO 1 #define NO_MALLOC_STATS 1 -#define malloc_getpagesize 16384 +#define malloc_getpagesize get_page_size() #define LACKS_FCNTL_H 1 #define LACKS_SYS_MMAN_H 1 #define LACKS_SYS_PARAM_H 1 diff --git a/src/memory.c b/src/memory.c index afccc8de5..7835060a8 100644 --- a/src/memory.c +++ b/src/memory.c @@ -13,7 +13,7 @@ #include "utils.h" #include "xnuboot.h" -#define PAGE_SIZE 0x4000 +#define PAGE_SIZE get_page_size() #define CACHE_LINE_SIZE 64 #define CACHE_RANGE_OP(func, op) \ @@ -50,22 +50,27 @@ static inline void write_sctlr(u64 val) sysop("isb"); } -#define VADDR_L3_INDEX_BITS 11 -#define VADDR_L2_INDEX_BITS 11 -// We treat two concatenated L1 page tables as one -#define VADDR_L1_INDEX_BITS 12 +#define VADDR_L3_INDEX_BITS (is_16k() ? 11 : 9) +#define VADDR_L2_INDEX_BITS (is_16k() ? 11 : 9) +// We treat two concatenated L1 page tables as one on 16K +// And all the L1 page tables together on 4K... +#define VADDR_L1_INDEX_BITS (is_16k() ? 12 : 18) +#define VADDR_L1_INDEX_BITS_ACTUAL (is_16k() ? 11 : 9) +#define VADDR_L0_INDEX_BITS (is_16k() ? 1 : 9) -#define VADDR_L3_OFFSET_BITS 14 -#define VADDR_L2_OFFSET_BITS 25 -#define VADDR_L1_OFFSET_BITS 36 +#define VADDR_L3_OFFSET_BITS (is_16k() ? 14 : 12) +#define VADDR_L2_OFFSET_BITS (is_16k() ? 25 : 21) +#define VADDR_L1_OFFSET_BITS (is_16k() ? 36 : 30) #define VADDR_L1_ALIGN_MASK GENMASK(VADDR_L1_OFFSET_BITS - 1, VADDR_L2_OFFSET_BITS) #define VADDR_L2_ALIGN_MASK GENMASK(VADDR_L2_OFFSET_BITS - 1, VADDR_L3_OFFSET_BITS) #define PTE_TARGET_MASK GENMASK(49, VADDR_L3_OFFSET_BITS) -#define ENTRIES_PER_L1_TABLE BIT(VADDR_L1_INDEX_BITS) -#define ENTRIES_PER_L2_TABLE BIT(VADDR_L2_INDEX_BITS) -#define ENTRIES_PER_L3_TABLE BIT(VADDR_L3_INDEX_BITS) +#define ENTRIES_PER_L0_TABLE BIT(VADDR_L0_INDEX_BITS) +#define ENTRIES_PER_L1_TABLE BIT(VADDR_L1_INDEX_BITS) +#define ENTRIES_PER_L1_TABLE_ACTUAL BIT(VADDR_L1_INDEX_BITS_ACTUAL) +#define ENTRIES_PER_L2_TABLE BIT(VADDR_L2_INDEX_BITS) +#define ENTRIES_PER_L3_TABLE BIT(VADDR_L3_INDEX_BITS) #define IS_PTE(pte) ((pte) && pte & PTE_VALID) @@ -91,6 +96,22 @@ static inline void write_sctlr(u64 val) * point to the two halves in the single L0 table and then create L2/L3 tables on demand. */ +/* + * On 4K devices, the following virtual address space results: + * + * [L0 index] [L1 index] [L2 index] [L3 index] [page offset] + * 9 bit 9 bits 9 bits 9 bits 11 bits + * + * To simplify things we treat the L1 page table as a concatenated table, + * which results in the following layout: + * + * [L1 index] [L2 index] [L3 index] [page offset] + * 18 bits 9 bits 9 bits 11 bits + * + * We initialize one giant L1 table which covers the entire virtual memory space, + * point to the parts in a single L0 table and then create L2/L3 tables on demand. + */ + /* * SPRR mappings interpret these bits as a 4-bit index as follows * [AP1][AP0][PXN][UXN] @@ -301,14 +322,16 @@ static u64 mmu_make_table_pte(u64 *addr) static void mmu_init_pagetables(void) { - mmu_pt_L0 = memalign(PAGE_SIZE, sizeof(u64) * 2); + mmu_pt_L0 = memalign(PAGE_SIZE, sizeof(u64) * ENTRIES_PER_L0_TABLE); mmu_pt_L1 = memalign(PAGE_SIZE, sizeof(u64) * ENTRIES_PER_L1_TABLE); - memset64(mmu_pt_L0, 0, sizeof(u64) * 2); + memset64(mmu_pt_L0, 0, sizeof(u64) * ENTRIES_PER_L0_TABLE); memset64(mmu_pt_L1, 0, sizeof(u64) * ENTRIES_PER_L1_TABLE); - mmu_pt_L0[0] = mmu_make_table_pte(&mmu_pt_L1[0]); - mmu_pt_L0[1] = mmu_make_table_pte(&mmu_pt_L1[ENTRIES_PER_L1_TABLE >> 1]); + for (size_t i = 0; i < ENTRIES_PER_L0_TABLE; i++) { + mmu_pt_L0[i] = mmu_make_table_pte(&mmu_pt_L1[i * ENTRIES_PER_L1_TABLE_ACTUAL]); + } + return; } void mmu_add_mapping(u64 from, u64 to, size_t size, u8 attribute_index, u64 perms) @@ -399,7 +422,7 @@ static void mmu_add_default_mappings(void) { ram_base = ALIGN_DOWN(cur_boot_args.phys_base, BIT(32)); uint64_t ram_size = cur_boot_args.mem_size + cur_boot_args.phys_base - ram_base; - ram_size = ALIGN_DOWN(ram_size, 0x4000); + ram_size = ALIGN_DOWN(ram_size, PAGE_SIZE); printf("MMU: RAM base: 0x%lx\n", ram_base); printf("MMU: Top of normal RAM: 0x%lx\n", ram_base + ram_size); @@ -466,12 +489,13 @@ static void mmu_configure(void) (MAIR_ATTR_DEVICE_nGnRnE << MAIR_SHIFT_DEVICE_nGnRnE) | (MAIR_ATTR_DEVICE_nGnRE << MAIR_SHIFT_DEVICE_nGnRE) | (MAIR_ATTR_NORMAL_NC << MAIR_SHIFT_NORMAL_NC)); - msr(TCR_EL1, FIELD_PREP(TCR_IPS, TCR_IPS_4TB) | FIELD_PREP(TCR_TG1, TCR_TG1_16K) | + msr(TCR_EL1, FIELD_PREP(TCR_IPS, TCR_IPS_4TB) | + FIELD_PREP(TCR_TG1, is_16k() ? TCR_TG1_16K : TCR_TG1_4K) | FIELD_PREP(TCR_SH1, TCR_SH1_IS) | FIELD_PREP(TCR_ORGN1, TCR_ORGN1_WBWA) | FIELD_PREP(TCR_IRGN1, TCR_IRGN1_WBWA) | FIELD_PREP(TCR_T1SZ, TCR_T1SZ_48BIT) | - FIELD_PREP(TCR_TG0, TCR_TG0_16K) | FIELD_PREP(TCR_SH0, TCR_SH0_IS) | - FIELD_PREP(TCR_ORGN0, TCR_ORGN0_WBWA) | FIELD_PREP(TCR_IRGN0, TCR_IRGN0_WBWA) | - FIELD_PREP(TCR_T0SZ, TCR_T0SZ_48BIT)); + FIELD_PREP(TCR_TG0, is_16k() ? TCR_TG0_16K : TCR_TG0_4K) | + FIELD_PREP(TCR_SH0, TCR_SH0_IS) | FIELD_PREP(TCR_ORGN0, TCR_ORGN0_WBWA) | + FIELD_PREP(TCR_IRGN0, TCR_IRGN0_WBWA) | FIELD_PREP(TCR_T0SZ, TCR_T0SZ_48BIT)); msr(TTBR0_EL1, (uintptr_t)mmu_pt_L0); msr(TTBR1_EL1, (uintptr_t)mmu_pt_L0); diff --git a/src/utils.h b/src/utils.h index 4060641d1..250de40b0 100644 --- a/src/utils.h +++ b/src/utils.h @@ -352,6 +352,11 @@ static inline int has_el3(void) return !!(mrs(ID_AA64PFR0_EL1) & 0xf000); } +static inline bool is_16k(void) +{ + return ((mrs(ID_AA64MMFR0_EL1) >> 20) & 0xf) == 0x1; +} + extern int boot_cpu_idx; extern u64 boot_cpu_mpidr; static inline int is_boot_cpu(void) @@ -359,6 +364,11 @@ static inline int is_boot_cpu(void) return boot_cpu_idx == -1 || boot_cpu_mpidr == mrs(MPIDR_EL1); } +static inline size_t get_page_size(void) +{ + return is_16k() ? 16384 : 4096; +} + extern char _base[]; extern char _rodata_end[]; extern char _end[]; From 6a1e952ee74562ff08581ba8af96ada5596aa89a Mon Sep 17 00:00:00 2001 From: Nick Chan Date: Sun, 25 Aug 2024 15:32:28 +0800 Subject: [PATCH 08/19] smp: Added A7-A11 start support This includes: - EL3 handling - "Slow" IPI support - New start offsets Signed-off-by: Nick Chan --- src/aic.c | 5 ++++ src/aic.h | 1 + src/smp.c | 66 +++++++++++++++++++++++++++++++++++++++++++++-------- src/smp.h | 4 +++- src/start.S | 13 +++++++++++ 5 files changed, 79 insertions(+), 10 deletions(-) diff --git a/src/aic.c b/src/aic.c index 9ef900acd..22cbf0e77 100644 --- a/src/aic.c +++ b/src/aic.c @@ -147,6 +147,11 @@ void aic_set_sw(int irq, bool active) MASK_BIT(irq)); } +void aic_write(u32 reg, u32 val) +{ + write32(aic->base + reg, val); +} + uint32_t aic_ack(void) { return read32(aic->base + aic->regs.event); diff --git a/src/aic.h b/src/aic.h index 1f401b1c3..70b529ac1 100644 --- a/src/aic.h +++ b/src/aic.h @@ -35,6 +35,7 @@ extern struct aic *aic; void aic_init(void); void aic_set_sw(int irq, bool active); +void aic_write(u32 reg, u32 val); uint32_t aic_ack(void); #endif diff --git a/src/smp.c b/src/smp.c index fe5b08a36..0a8197fb6 100644 --- a/src/smp.c +++ b/src/smp.c @@ -2,6 +2,8 @@ #include "smp.h" #include "adt.h" +#include "aic.h" +#include "aic_regs.h" #include "cpu_regs.h" #include "malloc.h" #include "pmgr.h" @@ -10,10 +12,12 @@ #include "types.h" #include "utils.h" -#define CPU_START_OFF_T8103 0x54000 -#define CPU_START_OFF_T8112 0x34000 -#define CPU_START_OFF_T6020 0x28000 -#define CPU_START_OFF_T6031 0x88000 +#define CPU_START_OFF_S5L8960X 0x30000 +#define CPU_START_OFF_S8000 0xd4000 +#define CPU_START_OFF_T8103 0x54000 +#define CPU_START_OFF_T8112 0x34000 +#define CPU_START_OFF_T6020 0x28000 +#define CPU_START_OFF_T6031 0x88000 #define CPU_REG_CORE GENMASK(7, 0) #define CPU_REG_CLUSTER GENMASK(10, 8) @@ -28,11 +32,14 @@ struct spin_table { }; void *_reset_stack; +void *_reset_stack_el1; #define DUMMY_STACK_SIZE 0x1000 -u8 dummy_stack[DUMMY_STACK_SIZE]; +u8 dummy_stack[DUMMY_STACK_SIZE]; // Highest EL +u8 dummy_stack_el1[DUMMY_STACK_SIZE]; // EL1 stack if EL3 exists u8 *secondary_stacks[MAX_CPUS] = {dummy_stack}; +u8 *secondary_stacks_el3[MAX_EL3_CPUS]; static bool wfe_mode = false; @@ -63,14 +70,28 @@ void smp_secondary_entry(void) me->flag = 1; sysop("dmb sy"); u64 target; + if (!cpufeat_fast_ipi) + aic_write(AIC_IPI_MASK_SET, AIC_IPI_SELF); // we only use the "other" IPI while (1) { while (!(target = me->target)) { if (wfe_mode) { sysop("wfe"); } else { - deep_wfi(); - msr(SYS_IMP_APL_IPI_SR_EL1, 1); + if (!supports_arch_retention()) { + // A7 - A11 does not support state retention across deep WFI + // i.e. CPU always ends up at rvbar after deep WFI + sysop("wfi"); + } else { + deep_wfi(); + } + if (cpufeat_fast_ipi) { + msr(SYS_IMP_APL_IPI_SR_EL1, 1); + } else { + aic_ack(); // Actually read IPI reason + aic_write(AIC_IPI_ACK, AIC_IPI_OTHER); + aic_write(AIC_IPI_MASK_CLR, AIC_IPI_OTHER); + } } sysop("isb"); } @@ -92,6 +113,9 @@ static void smp_start_cpu(int index, int die, int cluster, int core, u64 impl, u if (index >= MAX_CPUS) return; + if (has_el3() && index >= MAX_EL3_CPUS) + return; + if (spin_table[index].flag) return; @@ -101,7 +125,12 @@ static void smp_start_cpu(int index, int die, int cluster, int core, u64 impl, u target_cpu = index; secondary_stacks[index] = memalign(0x4000, SECONDARY_STACK_SIZE); - _reset_stack = secondary_stacks[index] + SECONDARY_STACK_SIZE; + if (has_el3()) { + secondary_stacks_el3[index] = memalign(0x4000, SECONDARY_STACK_SIZE); + _reset_stack = secondary_stacks_el3[index] + SECONDARY_STACK_SIZE; // EL3 + _reset_stack_el1 = secondary_stacks[index] + SECONDARY_STACK_SIZE; // EL1 + } else + _reset_stack = secondary_stacks[index] + SECONDARY_STACK_SIZE; sysop("dmb sy"); @@ -129,6 +158,7 @@ static void smp_start_cpu(int index, int die, int cluster, int core, u64 impl, u printf(" Started.\n"); _reset_stack = dummy_stack + DUMMY_STACK_SIZE; + _reset_stack_el1 = dummy_stack_el1 + DUMMY_STACK_SIZE; } static void smp_stop_cpu(int index, int die, int cluster, int core, u64 impl, u64 cpu_start_base, @@ -202,6 +232,20 @@ void smp_start_secondaries(void) memset(cpu_nodes, 0, sizeof(cpu_nodes)); switch (chip_id) { + case S5L8960X: + case T7000: + case T7001: + cpu_start_off = CPU_START_OFF_S5L8960X; + break; + case S8000: + case S8001: + case S8003: + case T8010: + case T8011: + case T8012: + case T8015: + cpu_start_off = CPU_START_OFF_S8000; + break; case T8103: case T6000: case T6001: @@ -324,7 +368,11 @@ void smp_send_ipi(int cpu) return; u64 mpidr = spin_table[cpu].mpidr; - msr(SYS_IMP_APL_IPI_RR_GLOBAL_EL1, (mpidr & 0xff) | ((mpidr & 0xff00) << 8)); + if (cpufeat_fast_ipi) { + msr(SYS_IMP_APL_IPI_RR_GLOBAL_EL1, (mpidr & 0xff) | ((mpidr & 0xff00) << 8)); + } else { + aic_write(AIC_IPI_SEND, AIC_IPI_SEND_CPU(cpu)); + } } void smp_call4(int cpu, void *func, u64 arg0, u64 arg1, u64 arg2, u64 arg3) diff --git a/src/smp.h b/src/smp.h index 691caec1a..223d2a311 100644 --- a/src/smp.h +++ b/src/smp.h @@ -6,10 +6,12 @@ #include "types.h" #include "utils.h" -#define MAX_CPUS 24 +#define MAX_CPUS 24 +#define MAX_EL3_CPUS 4 #define SECONDARY_STACK_SIZE 0x10000 extern u8 *secondary_stacks[MAX_CPUS]; +extern u8 *secondary_stacks_el3[MAX_EL3_CPUS]; void smp_secondary_entry(void); diff --git a/src/start.S b/src/start.S index befef9975..aa11e18ba 100644 --- a/src/start.S +++ b/src/start.S @@ -161,9 +161,22 @@ cpu_reset: bl debug_putc mov x0, sp + + mrs x8, CurrentEL + cmp x8, #0xc + beq cpu_reset_el3 + bl _cpu_reset_c b . +cpu_reset_el3: + bl _cpu_reset_c + adrp x6, _reset_stack_el1 + add x6, x6, :lo12:_reset_stack_el1 + ldr x6, [x6] + mov x0, x6 + adr x7, _cpu_reset_c + el3_eret_to_el1: adr x8, _vectors_start msr sctlr_el1, xzr From 6520e979ea68e8a4be43bf1c1a2171a8e12d09e1 Mon Sep 17 00:00:00 2001 From: Nick Chan Date: Sun, 25 Aug 2024 15:33:03 +0800 Subject: [PATCH 09/19] smp: Add support for ADT from old FW Old ADT does not have /cpus/cpu/cpu-impl-reg, and the value is in /arm-io/pmgr/reg[2*n+2]. Signed-off-by: Nick Chan --- src/smp.c | 39 ++++++++++++++++++++++++++++++++++----- 1 file changed, 34 insertions(+), 5 deletions(-) diff --git a/src/smp.c b/src/smp.c index 0a8197fb6..5a622a193 100644 --- a/src/smp.c +++ b/src/smp.c @@ -223,6 +223,12 @@ void smp_start_secondaries(void) return; } + int arm_io_node; + if ((arm_io_node = adt_path_offset(adt, "/arm-io")) < 0) { + printf("Error getting /arm-io node\n"); + return; + } + int node = adt_path_offset(adt, "/cpus"); if (node < 0) { printf("Error getting /cpus node\n"); @@ -275,7 +281,9 @@ void smp_start_secondaries(void) u32 cpu_id; if (ADT_GETPROP(adt, node, "cpu-id", &cpu_id) < 0) - continue; + if (ADT_GETPROP(adt, node, "reg", &cpu_id) < 0) + continue; + if (cpu_id >= MAX_CPUS) { printf("cpu-id %d exceeds max CPU count %d: increase MAX_CPUS\n", cpu_id, MAX_CPUS); continue; @@ -323,8 +331,16 @@ void smp_start_secondaries(void) u64 cpu_impl_reg[2]; if (ADT_GETPROP(adt, cpu_node, "reg", ®) < 0) continue; - if (ADT_GETPROP_ARRAY(adt, cpu_node, "cpu-impl-reg", cpu_impl_reg) < 0) - continue; + if (ADT_GETPROP_ARRAY(adt, cpu_node, "cpu-impl-reg", cpu_impl_reg) < 0) { + u32 reg_len; + const u64 *regs = adt_getprop(adt, arm_io_node, "reg", ®_len); + if (!regs) + continue; + u32 index = 2 * i + 2; + if (reg_len < index) + continue; + memcpy(cpu_impl_reg, ®s[index], 16); + } u8 core = FIELD_GET(CPU_REG_CORE, reg); u8 cluster = FIELD_GET(CPU_REG_CLUSTER, reg); @@ -339,6 +355,11 @@ void smp_start_secondaries(void) void smp_stop_secondaries(bool deep_sleep) { printf("Stopping secondary CPUs...\n"); + int arm_io_node; + if ((arm_io_node = adt_path_offset(adt, "/arm-io")) < 0) { + printf("Error getting /arm-io node\n"); + return; + } smp_set_wfe_mode(true); for (int i = 0; i < MAX_CPUS; i++) { @@ -351,8 +372,16 @@ void smp_stop_secondaries(bool deep_sleep) u64 cpu_impl_reg[2]; if (ADT_GETPROP(adt, node, "reg", ®) < 0) continue; - if (ADT_GETPROP_ARRAY(adt, node, "cpu-impl-reg", cpu_impl_reg) < 0) - continue; + if (ADT_GETPROP_ARRAY(adt, node, "cpu-impl-reg", cpu_impl_reg) < 0) { + u32 reg_len; + const u64 *regs = adt_getprop(adt, arm_io_node, "reg", ®_len); + if (!regs) + continue; + u32 index = 2 * i + 2; + if (reg_len < index) + continue; + memcpy(cpu_impl_reg, ®s[index], 16); + } u8 core = FIELD_GET(CPU_REG_CORE, reg); u8 cluster = FIELD_GET(CPU_REG_CLUSTER, reg); From e792b5c1cddb0c560d1f2fb79d5e47172a681630 Mon Sep 17 00:00:00 2001 From: Nick Chan Date: Thu, 29 Aug 2024 02:13:24 +0800 Subject: [PATCH 10/19] smp: Write _vectors_start into boot CPU rvbar where possible On A7-A11 we have a ROM exploit and we can keep CPU0 RVBAR unlocked. Signed-off-by: Nick Chan --- src/smp.c | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/src/smp.c b/src/smp.c index 5a622a193..74ed2ecc0 100644 --- a/src/smp.c +++ b/src/smp.c @@ -319,9 +319,6 @@ void smp_start_secondaries(void) } for (int i = 0; i < MAX_CPUS; i++) { - - if (i == boot_cpu_idx) - continue; int cpu_node = cpu_nodes[i]; if (!cpu_node) @@ -342,6 +339,18 @@ void smp_start_secondaries(void) memcpy(cpu_impl_reg, ®s[index], 16); } + if (i == boot_cpu_idx) { + // Check if already locked + if (read64(cpu_impl_reg[0]) & 1) + continue; + + // Unlocked, write _vectors_start into boot CPU's rvbar + write64(cpu_impl_reg[0], (u64)_vectors_start); + sysop("dmb sy"); + + continue; + } + u8 core = FIELD_GET(CPU_REG_CORE, reg); u8 cluster = FIELD_GET(CPU_REG_CLUSTER, reg); u8 die = FIELD_GET(CPU_REG_DIE, reg); From f40293c10e3c40103411712f57d36b26c023c67c Mon Sep 17 00:00:00 2001 From: Nick Chan Date: Mon, 7 Oct 2024 19:14:54 +0800 Subject: [PATCH 11/19] smp: Add support for deep sleep on A7-A9X Signed-off-by: Nick Chan --- src/chickens.c | 7 +++++++ src/smp.c | 3 ++- src/utils.h | 1 + src/utils_asm.S | 18 +++++++++++++++--- 4 files changed, 25 insertions(+), 4 deletions(-) diff --git a/src/chickens.c b/src/chickens.c index 086777442..2f7bcd8a5 100644 --- a/src/chickens.c +++ b/src/chickens.c @@ -70,6 +70,7 @@ void init_t6031_sawtooth(void); void init_t6031_everest(int rev); bool cpufeat_actlr_el2, cpufeat_fast_ipi, cpufeat_mmu_sprr; +bool cpufeat_global_sleep; const char *init_cpu(void) { @@ -241,6 +242,12 @@ const char *init_cpu(void) if (part >= MIDR_PART_T8015_MONSOON) cpufeat_fast_ipi = true; + if (part >= MIDR_PART_T8010_2_HURRICANE) + cpufeat_global_sleep = true; + else + /* Disable deep sleep */ + reg_clr(SYS_IMP_APL_ACC_CFG, ACC_CFG_DEEP_SLEEP); + /* Unmask external IRQs, set WFI mode to up (2) */ reg_mask(SYS_IMP_APL_CYC_OVRD, CYC_OVRD_FIQ_MODE_MASK | CYC_OVRD_IRQ_MODE_MASK | CYC_OVRD_WFI_MODE_MASK, diff --git a/src/smp.c b/src/smp.c index 74ed2ecc0..efbde3b66 100644 --- a/src/smp.c +++ b/src/smp.c @@ -179,8 +179,9 @@ static void smp_stop_cpu(int index, int die, int cluster, int core, u64 impl, u6 // Request CPU stop write32(cpu_start_base + 0x0, 1 << (4 * cluster + core)); + u64 dsleep = deep_sleep; // Put the CPU to sleep - smp_call1(index, cpu_sleep, deep_sleep); + smp_call2(index, cpu_sleep, dsleep, cpufeat_global_sleep); // If going into deep sleep, powering off the last core in a cluster kills our register // access, so just wait a bit. diff --git a/src/utils.h b/src/utils.h index 250de40b0..256ed5aa6 100644 --- a/src/utils.h +++ b/src/utils.h @@ -460,6 +460,7 @@ extern u32 board_id, chip_id; extern bool is_mac, has_dcp; extern bool cpufeat_actlr_el2, cpufeat_fast_ipi, cpufeat_mmu_sprr; +extern bool cpufeat_global_sleep; extern struct vector_args next_stage; extern u64 boot_flags, mem_size_actual; diff --git a/src/utils_asm.S b/src/utils_asm.S index 0deee5a7c..2b901d3a4 100644 --- a/src/utils_asm.S +++ b/src/utils_asm.S @@ -185,6 +185,8 @@ cpu_sleep: cmp x0, #0 bne 1f + mov x4, x1 + mrs x1, SYS_IMP_APL_CYC_OVRD and x1, x1, #~CYC_OVRD_IRQ_MODE_MASK orr x1, x1, #CYC_OVRD_IRQ_MODE(2) @@ -192,8 +194,10 @@ cpu_sleep: orr x1, x1, #CYC_OVRD_FIQ_MODE(2) msr SYS_IMP_APL_CYC_OVRD, x1 1: - cmp x0, #0 + beq 3f + + cmp x4, #0 beq 2f mrs x1, SYS_IMP_APL_ACC_OVRD @@ -205,14 +209,22 @@ cpu_sleep: orr x1, x1, #ACC_OVRD_DISABLE_PIO_ON_WFI_CPU orr x1, x1, #ACC_OVRD_DEEP_SLEEP msr SYS_IMP_APL_ACC_OVRD, x1 + + cmp x4, #0 + bne 3f + 2: + mrs x1, SYS_IMP_APL_ACC_CFG + orr x1, x1, #ACC_CFG_DEEP_SLEEP + msr SYS_IMP_APL_ACC_CFG, x1 +3: mrs x1, SYS_IMP_APL_CYC_OVRD orr x1, x1, #CYC_OVRD_WFI_MODE(3) orr x1, x1, #CYC_OVRD_DISABLE_WFI_RET msr SYS_IMP_APL_CYC_OVRD, x1 -3: +4: isb wfi - b 3b + b 4b From 2acf509dcf82efccd4e613636fbce4989922a46c Mon Sep 17 00:00:00 2001 From: Nick Chan Date: Tue, 8 Oct 2024 11:51:12 +0800 Subject: [PATCH 12/19] smp: Add A7-A9X cache errata workaround Signed-off-by: Nick Chan --- src/chickens.c | 6 ++++-- src/memory.c | 8 ++++++++ src/smp.c | 7 ++++++- src/utils.h | 3 ++- 4 files changed, 20 insertions(+), 4 deletions(-) diff --git a/src/chickens.c b/src/chickens.c index 2f7bcd8a5..da132b7fc 100644 --- a/src/chickens.c +++ b/src/chickens.c @@ -70,7 +70,7 @@ void init_t6031_sawtooth(void); void init_t6031_everest(int rev); bool cpufeat_actlr_el2, cpufeat_fast_ipi, cpufeat_mmu_sprr; -bool cpufeat_global_sleep; +bool cpufeat_global_sleep, cpufeat_workaround_cyclone_cache; const char *init_cpu(void) { @@ -244,9 +244,11 @@ const char *init_cpu(void) if (part >= MIDR_PART_T8010_2_HURRICANE) cpufeat_global_sleep = true; - else + else { /* Disable deep sleep */ reg_clr(SYS_IMP_APL_ACC_CFG, ACC_CFG_DEEP_SLEEP); + cpufeat_workaround_cyclone_cache = true; + } /* Unmask external IRQs, set WFI mode to up (2) */ reg_mask(SYS_IMP_APL_CYC_OVRD, diff --git a/src/memory.c b/src/memory.c index 7835060a8..c88086e70 100644 --- a/src/memory.c +++ b/src/memory.c @@ -19,12 +19,20 @@ #define CACHE_RANGE_OP(func, op) \ void func(void *addr, size_t length) \ { \ + if (func == dc_civac_range && cpufeat_workaround_cyclone_cache) { \ + reg_clr(SYS_IMP_APL_HID4, HID4_DISABLE_DC_MVA); \ + sysop("isb"); \ + } \ u64 p = (u64)addr; \ u64 end = p + length; \ while (p < end) { \ cacheop(op, p); \ p += CACHE_LINE_SIZE; \ } \ + if (func == dc_civac_range && cpufeat_workaround_cyclone_cache) { \ + reg_set(SYS_IMP_APL_HID4, HID4_DISABLE_DC_MVA); \ + sysop("isb"); \ + } \ } CACHE_RANGE_OP(ic_ivau_range, "ic ivau") diff --git a/src/smp.c b/src/smp.c index efbde3b66..0367e2e83 100644 --- a/src/smp.c +++ b/src/smp.c @@ -6,6 +6,7 @@ #include "aic_regs.h" #include "cpu_regs.h" #include "malloc.h" +#include "memory.h" #include "pmgr.h" #include "soc.h" #include "string.h" @@ -129,10 +130,14 @@ static void smp_start_cpu(int index, int die, int cluster, int core, u64 impl, u secondary_stacks_el3[index] = memalign(0x4000, SECONDARY_STACK_SIZE); _reset_stack = secondary_stacks_el3[index] + SECONDARY_STACK_SIZE; // EL3 _reset_stack_el1 = secondary_stacks[index] + SECONDARY_STACK_SIZE; // EL1 + + dc_civac_range(&_reset_stack_el1, sizeof(void *)); } else _reset_stack = secondary_stacks[index] + SECONDARY_STACK_SIZE; - sysop("dmb sy"); + dc_civac_range(&_reset_stack, sizeof(void *)); + + sysop("dsb sy"); write64(impl, (u64)_vectors_start); diff --git a/src/utils.h b/src/utils.h index 256ed5aa6..6ce9e0428 100644 --- a/src/utils.h +++ b/src/utils.h @@ -3,6 +3,7 @@ #ifndef UTILS_H #define UTILS_H +#include "cpu_regs.h" #include "soc.h" #include "types.h" @@ -460,7 +461,7 @@ extern u32 board_id, chip_id; extern bool is_mac, has_dcp; extern bool cpufeat_actlr_el2, cpufeat_fast_ipi, cpufeat_mmu_sprr; -extern bool cpufeat_global_sleep; +extern bool cpufeat_global_sleep, cpufeat_workaround_cyclone_cache; extern struct vector_args next_stage; extern u64 boot_flags, mem_size_actual; From 2d75ecf525fabe72dbca6b80c29889b60a28d69f Mon Sep 17 00:00:00 2001 From: Nick Chan Date: Sun, 25 Aug 2024 15:34:07 +0800 Subject: [PATCH 13/19] fb: Add A7-A11 device support This includes: - Do not treat iPhone 5 buffer as dummy on 5s - Added support for 24-bit framebuffer - When we have a vertical display, use whole fb as console Signed-off-by: Nick Chan --- src/fb.c | 49 ++++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 42 insertions(+), 7 deletions(-) diff --git a/src/fb.c b/src/fb.c index 1a0e4e771..8a3c317be 100644 --- a/src/fb.c +++ b/src/fb.c @@ -104,14 +104,42 @@ static inline rgb_t pixel2rgb_30(u32 c) return (rgb_t){(c >> 22) & 0xff, (c >> 12) & 0xff, c >> 2}; } +static inline u32 rgb2pixel_24(rgb_t c) +{ + return c.b | (c.g << 8) | (c.r << 16); +} + +static inline rgb_t pixel2rgb_24(u32 c) +{ + return (rgb_t){(c >> 16) & 0xff, (c >> 8) & 0xff, c}; +} + +static inline u32 rgb2pixel(rgb_t c) +{ + if ((cur_boot_args.video.depth & 0xff) == 32) { + return rgb2pixel_24(c); + } else { + return rgb2pixel_30(c); + } +} + +static inline rgb_t pixel2rgb(u32 c) +{ + if ((cur_boot_args.video.depth & 0xff) == 32) { + return pixel2rgb_24(c); + } else { + return pixel2rgb_30(c); + } +} + static inline void fb_set_pixel(u32 x, u32 y, rgb_t c) { - fb.ptr[x + y * fb.stride] = rgb2pixel_30(c); + fb.ptr[x + y * fb.stride] = rgb2pixel(c); } static inline rgb_t fb_get_pixel(u32 x, u32 y) { - return pixel2rgb_30(fb.ptr[x + y * fb.stride]); + return pixel2rgb(fb.ptr[x + y * fb.stride]); } void fb_blit(u32 x, u32 y, u32 w, u32 h, void *data, u32 stride, pix_fmt_t pix_fmt) @@ -163,7 +191,7 @@ void fb_fill(u32 x, u32 y, u32 w, u32 h, rgb_t color) if (!console.initialized) return; - u32 c = rgb2pixel_30(color); + u32 c = rgb2pixel(color); for (u32 i = 0; i < h; i++) memset32(&fb.ptr[x + (y + i) * fb.stride], c, w * 4); fb_update(); @@ -174,7 +202,7 @@ void fb_clear(rgb_t color) if (!console.initialized) return; - u32 c = rgb2pixel_30(color); + u32 c = rgb2pixel(color); memset32(fb.ptr, c, fb.stride * fb.height * 4); fb_update(); } @@ -412,9 +440,16 @@ void fb_init(bool clear) console.cursor.col = 0; console.cursor.row = 0; - console.cursor.max_row = (fb.height / console.font.height) - 2 * console.margin.rows; - console.cursor.max_col = - ((fb.width - logo->width) / 2) / console.font.width - 2 * console.margin.cols; + if (fb.height < fb.width) { + console.cursor.max_row = (fb.height / console.font.height) - 2 * console.margin.rows; + console.cursor.max_col = + ((fb.width - logo->width) / 2) / console.font.width - 2 * console.margin.cols; + } else { // there aren't much screen real estate for us to waste here + console.cursor.max_row = (fb.height / console.font.height); + console.cursor.max_col = (fb.width / console.font.width); + console.margin.rows = 0; + console.margin.cols = 0; + } console.initialized = true; console.active = false; From fe82437c7c42045643dda41b341a652e21ebb7fb Mon Sep 17 00:00:00 2001 From: Nick Chan Date: Sun, 25 Aug 2024 15:40:07 +0800 Subject: [PATCH 14/19] kboot: Add workarounds for ADT for A7-A11 SoCs. Account for the differences between the iOS ADT and macOS ADT, and also some physical differences between Apple Silicon Macs and A7-A11 devoces, reflected in the ADT. Signed-off-by: Nick Chan --- src/firmware.c | 2 ++ src/kboot.c | 61 +++++++++++++++++++++++++++++++++++++------------- 2 files changed, 47 insertions(+), 16 deletions(-) diff --git a/src/firmware.c b/src/firmware.c index eeaf85975..b7a200e1e 100644 --- a/src/firmware.c +++ b/src/firmware.c @@ -147,6 +147,8 @@ int firmware_init(void) printf("System FW version: %s (%s)\n", system_firmware.string, system_firmware.iboot); } else { printf("ADT: failed to find system-firmware-version\n"); + system_firmware.string = "unknown"; + system_firmware.iboot = "unknown"; return -1; } diff --git a/src/kboot.c b/src/kboot.c index 34e3bbfd6..5e499ffff 100644 --- a/src/kboot.c +++ b/src/kboot.c @@ -75,13 +75,22 @@ void get_notchless_fb(u64 *fb_base, u64 *fb_height) u32 val; - if (ADT_GETPROP(adt, node, "partially-occluded-display", &val) < 0 || !val) { + if ((ADT_GETPROP(adt, node, "partially-occluded-display", &val) < 0 || !val) && + chip_id != T8015) { + printf("FDT: No notch detected\n"); + return; + } + + // iPhone X + if (chip_id != T8015 || (board_id != 0x6 && board_id != 0xe)) { printf("FDT: No notch detected\n"); return; } u64 hfrac = cur_boot_args.video.height * 16 / cur_boot_args.video.width; u64 new_height = cur_boot_args.video.width * hfrac / 16; + if (chip_id == T8015 && (board_id == 0x6 || board_id == 0xe)) + new_height = 2346; if (new_height == cur_boot_args.video.height) { printf("FDT: Notch detected, but display aspect is already 16:%lu?\n", hfrac); @@ -269,13 +278,15 @@ static int dt_set_chosen(void) if (node < 0) bail("FDT: /chosen node not found in devtree\n"); - if (fdt_setprop(dt, node, "asahi,iboot1-version", system_firmware.iboot, - strlen(system_firmware.iboot) + 1)) - bail("FDT: couldn't set asahi,iboot1-version\n"); + if (is_mac) { + if (fdt_setprop(dt, node, "asahi,iboot1-version", system_firmware.iboot, + strlen(system_firmware.iboot) + 1)) + bail("FDT: couldn't set asahi,iboot1-version\n"); - if (fdt_setprop(dt, node, "asahi,system-fw-version", system_firmware.string, - strlen(system_firmware.string) + 1)) - bail("FDT: couldn't set asahi,system-fw-version\n"); + if (fdt_setprop(dt, node, "asahi,system-fw-version", system_firmware.string, + strlen(system_firmware.string) + 1)) + bail("FDT: couldn't set asahi,system-fw-version\n"); + } if (fdt_setprop(dt, node, "asahi,iboot2-version", os_firmware.iboot, strlen(os_firmware.iboot) + 1)) @@ -301,12 +312,18 @@ static int dt_set_memory(void) if (anode < 0) bail("ADT: /chosen not found\n"); - u64 dram_base, dram_size; + u64 dram_base = 0, dram_size = 0; + + // iOS 12 and below seems to be missing a bunch of stuff... + if (ADT_GETPROP(adt, anode, "dram-base", &dram_base) < 0) { + printf("ADT: Failed to get dram-base\n"); + dram_base = 0x800000000; + } - if (ADT_GETPROP(adt, anode, "dram-base", &dram_base) < 0) - bail("ADT: Failed to get dram-base\n"); - if (ADT_GETPROP(adt, anode, "dram-size", &dram_size) < 0) - bail("ADT: Failed to get dram-size\n"); + if (ADT_GETPROP(adt, anode, "dram-size", &dram_size) < 0) { + printf("ADT: Failed to get dram-size\n"); + dram_size = mem_size_actual; + } // Tell the kernel our usable memory range. We cannot declare all of DRAM, and just reserve the // bottom and top, because the kernel would still map it (and just not use it), which breaks @@ -627,8 +644,14 @@ static int dt_set_bluetooth(void) int ret; int anode = adt_path_offset(adt, "/arm-io/bluetooth"); - if (anode < 0) - bail("ADT: /arm-io/bluetooth not found\n"); + if (anode < 0) { + /* + * t8012-based system does not have bluetooth, and on + * some other devices bluetooth is connected with UART. + */ + printf("ADT: /arm-io/bluetooth not found\n"); + return 0; + } const char *path = fdt_get_alias(dt, "bluetooth0"); if (path == NULL) @@ -785,8 +808,14 @@ static int dt_set_wifi(void) { int anode = adt_path_offset(adt, "/arm-io/wlan"); - if (anode < 0) - bail("ADT: /arm-io/wlan not found\n"); + if (anode < 0) { + /* + * t8012-based system does not have wifi, and on some other + * devices WIFI is connected via an internal EHCI controller. + */ + printf("ADT: /arm-io/wlan not found\n"); + return 0; + } uint8_t info[16]; if (ADT_GETPROP_ARRAY(adt, anode, "wifi-antenna-sku-info", info) < 0) From 682705bbf88180fece19a2980370677771ee8d7f Mon Sep 17 00:00:00 2001 From: Nick Chan Date: Sun, 25 Aug 2024 15:40:29 +0800 Subject: [PATCH 15/19] kboot: Reserve secondary CPU stacks The secondary CPU may potentially use the stack after leaving WFE. Signed-off-by: Nick Chan --- src/kboot.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/kboot.c b/src/kboot.c index 5e499ffff..d1cb11643 100644 --- a/src/kboot.c +++ b/src/kboot.c @@ -408,6 +408,14 @@ static int dt_set_cpus(void) cpu++; node = next; continue; + } else { + printf("FDT: Reserving stack for CPU %d 0x%lx\n", cpu, (uint64_t)secondary_stacks[cpu]); + fdt_add_mem_rsv(dt, (uint64_t)secondary_stacks[cpu], SECONDARY_STACK_SIZE); + if (has_el3()) { + printf("FDT: Reserving EL3 stack for CPU %d 0x%lx\n", cpu, + (uint64_t)secondary_stacks_el3[cpu]); + fdt_add_mem_rsv(dt, (uint64_t)secondary_stacks_el3[cpu], SECONDARY_STACK_SIZE); + } } u64 mpidr = smp_get_mpidr(cpu); From 4d813aeea3e36c2db67e8804c822da489ad5453c Mon Sep 17 00:00:00 2001 From: Nick Chan Date: Mon, 30 Sep 2024 14:56:35 +0800 Subject: [PATCH 16/19] exceptions: fix el0_call() and el1_call() when running in EL1 Signed-off-by: Nick Chan --- src/exception.c | 6 +++++- src/exception_asm.S | 13 +++++++++++++ src/utils.h | 5 +++++ 3 files changed, 23 insertions(+), 1 deletion(-) diff --git a/src/exception.c b/src/exception.c index 8588aeb9f..944f1a247 100644 --- a/src/exception.c +++ b/src/exception.c @@ -246,7 +246,11 @@ void exc_sync(u64 *regs) if ((spsr & 0xf) == 0 && ((esr >> 26) & 0x3f) == 0x3c) { // On clean EL0 return, let the normal exception return // path take us back to the return thunk. - msr(SPSR_EL1, 0x09); // EL2h + if (has_el2()) + msr(SPSR_EL1, 0x09); // EL2h + else + msr(SPSR_EL1, 0x05); // EL1h + msr(ELR_EL1, el0_ret); return; } diff --git a/src/exception_asm.S b/src/exception_asm.S index 8c8d01f92..5f22c0291 100644 --- a/src/exception_asm.S +++ b/src/exception_asm.S @@ -101,12 +101,17 @@ _exc_return: el0_call: str x30, [sp, #-16]! + mrs x5, CurrentEL + cmp x5, #4 + beq 1f + // Disable EL1 mrs x5, hcr_el2 orr x5, x5, #(1 << 27) msr hcr_el2, x5 isb + 1: mrs x5, daif msr daifclr, 3 msr spsr_el1, x5 @@ -149,6 +154,10 @@ el0_ret: el1_call: str x30, [sp, #-16]! + mrs x5, CurrentEL + cmp x5, #4 + beq _el1_thunk + // Enable EL1, but only if not already done. // this check is here because writes to hcr_el2 are only possible from GL2 // if that mode has been enabled @@ -183,6 +192,10 @@ _el1_thunk: blr x5 + mrs x5, CurrentEL + cmp x5, #4 + beq el1_ret + hvc 0 .long 0 diff --git a/src/utils.h b/src/utils.h index 6ce9e0428..28403b6ce 100644 --- a/src/utils.h +++ b/src/utils.h @@ -353,6 +353,11 @@ static inline int has_el3(void) return !!(mrs(ID_AA64PFR0_EL1) & 0xf000); } +static inline int has_el2(void) +{ + return !!(mrs(ID_AA64PFR0_EL1) & 0xf00); +} + static inline bool is_16k(void) { return ((mrs(ID_AA64MMFR0_EL1) >> 20) & 0xf) == 0x1; From 0641be9ecdee8c3882e2e0e1fa2e89a77a7bf4fb Mon Sep 17 00:00:00 2001 From: Nick Chan Date: Mon, 30 Sep 2024 15:29:34 +0800 Subject: [PATCH 17/19] exceptions: add el3_call() Signed-off-by: Nick Chan --- proxyclient/m1n1/proxy.py | 5 +++++ src/exception.c | 4 ++++ src/exception.h | 1 + src/exception_asm.S | 6 ++++++ src/proxy.c | 3 +++ src/proxy.h | 1 + src/smp.c | 6 ++++++ src/smp.h | 5 ++++- src/startup.c | 4 +++- 9 files changed, 33 insertions(+), 2 deletions(-) diff --git a/proxyclient/m1n1/proxy.py b/proxyclient/m1n1/proxy.py index 2ac999304..8428c8f5b 100644 --- a/proxyclient/m1n1/proxy.py +++ b/proxyclient/m1n1/proxy.py @@ -494,6 +494,7 @@ class M1N1Proxy(Reloadable): P_PUT_SIMD_STATE = 0x00f P_REBOOT = 0x010 P_SLEEP = 0x011 + P_EL3_CALL = 0x012 P_WRITE64 = 0x100 P_WRITE32 = 0x101 @@ -760,6 +761,10 @@ def reboot(self): self.request(self.P_REBOOT, no_reply=True) def sleep(self, deep=False): self.request(self.P_SLEEP, deep, no_reply=True) + def el3_call(self, addr, *args): + if len(args) > 4: + raise ValueError("Too many arguments") + return self.request(self.P_EL3_CALL, addr, *args) def write64(self, addr, data): '''write 8 byte value to given address''' diff --git a/src/exception.c b/src/exception.c index 944f1a247..5c01deedd 100644 --- a/src/exception.c +++ b/src/exception.c @@ -281,6 +281,10 @@ void exc_sync(u64 *regs) // Monitor call u32 imm = mrs(ESR_EL3) & 0xffff; switch (imm) { + case 42: + regs[0] = ((uint64_t(*)(uint64_t, uint64_t, uint64_t, uint64_t))regs[0])( + regs[1], regs[2], regs[3], regs[4]); + return; default: printf("Unknown SMC: 0x%x\n", imm); break; diff --git a/src/exception.h b/src/exception.h index 786f38f7d..49c47b3b3 100644 --- a/src/exception.h +++ b/src/exception.h @@ -49,6 +49,7 @@ void print_regs(u64 *regs, int el12); uint64_t el0_call(void *func, uint64_t a, uint64_t b, uint64_t c, uint64_t d); uint64_t el1_call(void *func, uint64_t a, uint64_t b, uint64_t c, uint64_t d); +uint64_t el3_call(void *func, uint64_t a, uint64_t b, uint64_t c, uint64_t d); #endif diff --git a/src/exception_asm.S b/src/exception_asm.S index 5f22c0291..5c4bdfaeb 100644 --- a/src/exception_asm.S +++ b/src/exception_asm.S @@ -242,3 +242,9 @@ _el1_vectors_start: hvc 0x1e .align 7 hvc 0x1f + +.globl el3_call +.type el3_call, @function +el3_call: + smc 42 + ret \ No newline at end of file diff --git a/src/proxy.c b/src/proxy.c index 49b33825f..c59225ca2 100644 --- a/src/proxy.c +++ b/src/proxy.c @@ -116,6 +116,9 @@ int proxy_process(ProxyRequest *request, ProxyReply *reply) case P_SLEEP: cpu_sleep(request->args[0]); break; + case P_EL3_CALL: + reply->retval = el3_call((void *)request->args[0], request->args[1], request->args[2], + request->args[3], request->args[4]); case P_WRITE64: exc_guard = GUARD_SKIP; diff --git a/src/proxy.h b/src/proxy.h index c6c5006fe..34c419eed 100644 --- a/src/proxy.h +++ b/src/proxy.h @@ -24,6 +24,7 @@ typedef enum { P_PUT_SIMD_STATE, P_REBOOT, P_SLEEP, + P_EL3_CALL, P_WRITE64 = 0x100, // Generic register functions P_WRITE32, diff --git a/src/smp.c b/src/smp.c index 0367e2e83..6e683b49b 100644 --- a/src/smp.c +++ b/src/smp.c @@ -107,6 +107,12 @@ void smp_secondary_entry(void) } } +void smp_secondary_prep_el3(void) +{ + msr(TPIDR_EL3, target_cpu); + return; +} + static void smp_start_cpu(int index, int die, int cluster, int core, u64 impl, u64 cpu_start_base) { int i; diff --git a/src/smp.h b/src/smp.h index 223d2a311..029697864 100644 --- a/src/smp.h +++ b/src/smp.h @@ -14,6 +14,7 @@ extern u8 *secondary_stacks[MAX_CPUS]; extern u8 *secondary_stacks_el3[MAX_EL3_CPUS]; void smp_secondary_entry(void); +void smp_secondary_prep_el3(void); void smp_start_secondaries(void); void smp_stop_secondaries(bool deep_sleep); @@ -35,7 +36,9 @@ void smp_send_ipi(int cpu); static inline int smp_id(void) { - if (in_el2()) + if (in_el3()) + return mrs(TPIDR_EL3); + else if (in_el2()) return mrs(TPIDR_EL2); else return mrs(TPIDR_EL1); diff --git a/src/startup.c b/src/startup.c index 70bf25896..e7bbd9842 100644 --- a/src/startup.c +++ b/src/startup.c @@ -193,8 +193,10 @@ void _cpu_reset_c(void *stack) exception_initialize(); - if (in_el3()) + if (in_el3()) { + smp_secondary_prep_el3(); return; + } if (!is_boot_cpu()) smp_secondary_entry(); From 956acd4558d94075d1ecc8105946f96cebf67142 Mon Sep 17 00:00:00 2001 From: Nick Chan Date: Sat, 12 Oct 2024 20:51:01 +0800 Subject: [PATCH 18/19] pmgr: Fix struct for older SoCs At some point Apple ran out of bits and have to widen the device field to 16-bit. This adds support for the old 8-bit layout. Signed-off-by: Nick Chan --- src/pmgr.c | 63 +++++++++++++++++++++++++++++++++++++++++++----------- 1 file changed, 50 insertions(+), 13 deletions(-) diff --git a/src/pmgr.c b/src/pmgr.c index 930a4396f..5808fcd8c 100644 --- a/src/pmgr.c +++ b/src/pmgr.c @@ -21,14 +21,24 @@ #define PMGR_FLAG_VIRTUAL 0x10 struct pmgr_device { - u32 flags; - u16 parent[2]; - u8 unk1[2]; + u8 flags; + u16 unk1; + u8 id1; + union { + struct { + u8 parent[2]; + u8 unk2[2]; + } u8id; + struct { + u16 parent[2]; + } u16id; + }; + u8 unk3[2]; u8 addr_offset; u8 psreg_idx; - u8 unk2[14]; - u16 id; - u8 unk3[4]; + u8 unk4[14]; + u16 id2; + u8 unk5[4]; const char name[0x10]; } PACKED; @@ -44,6 +54,8 @@ static u32 pmgr_ps_regs_len = 0; static const struct pmgr_device *pmgr_devices = NULL; static u32 pmgr_devices_len = 0; +static bool pmgr_u8id = false; + static uintptr_t pmgr_get_psreg(u8 idx) { if (idx * 12 >= pmgr_ps_regs_len) { @@ -76,11 +88,19 @@ int pmgr_set_mode(uintptr_t addr, u8 target_mode) return 0; } +static u16 pmgr_adt_get_id(const struct pmgr_device *device) +{ + if (pmgr_u8id) + return device->id1; + else + return device->id2; +} + static int pmgr_find_device(u16 id, const struct pmgr_device **device) { for (size_t i = 0; i < pmgr_devices_len; ++i) { const struct pmgr_device *i_device = &pmgr_devices[i]; - if (i_device->id != id) + if (pmgr_adt_get_id(i_device) != id) continue; *device = i_device; @@ -102,6 +122,17 @@ static uintptr_t pmgr_device_get_addr(u8 die, const struct pmgr_device *device) return addr; } +static void pmgr_adt_get_parents(const struct pmgr_device *device, u16 parent[2]) +{ + if (pmgr_u8id) { + parent[0] = device->u8id.parent[0]; + parent[1] = device->u8id.parent[1]; + } else { + parent[0] = device->u16id.parent[0]; + parent[1] = device->u16id.parent[1]; + } +} + static int pmgr_set_mode_recursive(u8 die, u16 id, u8 target_mode, bool recurse) { if (!pmgr_initialized) { @@ -127,9 +158,10 @@ static int pmgr_set_mode_recursive(u8 die, u16 id, u8 target_mode, bool recurse) if (recurse) for (int i = 0; i < 2; i++) { - if (device->parent[i]) { - u16 parent = FIELD_GET(PMGR_DEVICE_ID, device->parent[i]); - int ret = pmgr_set_mode_recursive(die, parent, target_mode, true); + u16 parents[2]; + pmgr_adt_get_parents(device, parents); + if (parents[i]) { + int ret = pmgr_set_mode_recursive(die, parents[i], target_mode, true); if (ret < 0) return ret; } @@ -346,6 +378,9 @@ int pmgr_init(void) for (size_t i = 0; i < pmgr_devices_len; ++i) { const struct pmgr_device *device = &pmgr_devices[i]; + if (device->id1) + pmgr_u8id = true; + if ((device->flags & PMGR_FLAG_VIRTUAL)) continue; @@ -357,10 +392,12 @@ int pmgr_init(void) if (reg & PMGR_AUTO_ENABLE || FIELD_GET(PMGR_PS_TARGET, reg) == PMGR_PS_ACTIVE) { for (int j = 0; j < 2; j++) { - if (device->parent[j]) { + u16 parent[2]; + pmgr_adt_get_parents(device, parent); + if (parent[j]) { const struct pmgr_device *pdevice; - if (pmgr_find_device(device->parent[j], &pdevice)) { - printf("pmgr: Failed to find parent #%d for %s\n", device->parent[j], + if (pmgr_find_device(parent[j], &pdevice)) { + printf("pmgr: Failed to find parent #%d for %s\n", parent[j], device->name); continue; } From 6a40eef20d5ee384edac205e2007181700837259 Mon Sep 17 00:00:00 2001 From: Nick Chan Date: Mon, 23 Sep 2024 23:57:56 +0800 Subject: [PATCH 19/19] usb: Skip USB init for now on A7-A11 SoCs. We do not support the USB controller on A7-A11 SoCs yet, but still do not try to init dwc3 on them. Signed-off-by: Nick Chan --- src/usb.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/usb.c b/src/usb.c index 86eedc603..49d27674f 100644 --- a/src/usb.c +++ b/src/usb.c @@ -253,6 +253,16 @@ void usb_init(void) return; } + /* + * A7-A11 uses a custom internal otg controller with the peripheral part + * being dwc2. + */ + if (adt_path_offset(adt, "/arm-io/otgphyctrl") > 0 && + adt_path_offset(adt, "/arm-io/usb-complex") > 0) { + /* We do not support the custom controller and dwc2 (yet). */ + return; + } + i2c_dev_t *i2c = i2c_init("/arm-io/i2c0"); if (!i2c) { printf("usb: i2c init failed.\n");