; Copyright 2016 Castle Technology Ltd ; ; Licensed under the Apache License, Version 2.0 (the "License"); ; you may not use this file except in compliance with the License. ; You may obtain a copy of the License at ; ; http://www.apache.org/licenses/LICENSE-2.0 ; ; Unless required by applicable law or agreed to in writing, software ; distributed under the License is distributed on an "AS IS" BASIS, ; WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. ; See the License for the specific language governing permissions and ; limitations under the License. ; ; This file is duplicated in the kernel sources and CallASWI. Please try and ; keep them in sync! [ :LNOT: :DEF: InKernel GBLL InKernel InKernel SETL {TRUE} ] ; Non-feature register flags: ; * ROM & CPU alignment modes? ; * NOP after banked LDM? ; * StrongARM MSR bug? ; * ARM2 TEQP bug? FeatureOp_BIC * 0 << 3 FeatureOp_AND * 1 << 3 FeatureOp_OR * 2 << 3 MACRO CPUFeature $register, $field, $minval, $feature, $op ASSERT ($register < 8) ASSERT ($field :AND: 28) == $field ASSERT ($minval < 16) [ "$op" <> "" DCB $register + $op | DCB $register + FeatureOp_OR ] DCB $field DCB $minval DCB CPUFeature_$feature MEND FeatureRegsTable CPUFeature 0, 24, 2, UDIV_SDIV CPUFeature 0, 20, 1, BKPT CPUFeature 0, 08, 1, BFC_BFI_SBFX_UBFX CPUFeature 0, 04, 1, CLZ CPUFeature 0, 00, 1, SWP_SWPB CPUFeature 1, 24, 1, BX CPUFeature 1, 24, 2, BLX CPUFeature 1, 24, 3, Interworking_MOV_pc CPUFeature 1, 20, 1, MOVW_MOVT CPUFeature 1, 12, 1, SXTB_SXTH_UXTB_UXTH CPUFeature 1, 12, 2, SXTAB_SXTAH_UXTAB_UXTAH CPUFeature 1, 12, 2, SXTB16_SXTAB16_UXTB16_UXTAB16 CPUFeature 1, 08, 1, SRS_RFE_CPS CPUFeature 2, 28, 1, REV_REV16_REVSH CPUFeature 2, 28, 2, RBIT CPUFeature 2, 24, 1, MRS_MSR CPUFeature 2, 20, 1, UMULL_UMLAL CPUFeature 2, 20, 2, UMAAL CPUFeature 2, 16, 1, SMULL_SMLAL CPUFeature 2, 16, 2, SMLAxy_SMLALxy_SMLAWy_SMULxy_SMULWy CPUFeature 2, 16, 2, PSR_Q_bit CPUFeature 2, 16, 3, SMLAlDx_SMLSlDx_SMMLAr_SMMLSr_SMMULr_SMUADx_SMUSDx CPUFeature 2, 12, 2, MLS CPUFeature 2, 08, 0, LDM_STM_noninterruptible CPUFeature 2, 08, 1, LDM_STM_noninterruptible, FeatureOp_BIC CPUFeature 2, 08, 1, LDM_STM_restartable CPUFeature 2, 08, 2, LDM_STM_restartable, FeatureOp_BIC CPUFeature 2, 08, 2, LDM_STM_continuable CPUFeature 2, 04, 1, PLD CPUFeature 2, 04, 3, PLI CPUFeature 2, 04, 4, PLDW CPUFeature 2, 00, 1, LDRD_STRD CPUFeature 2, 00, 2, LDAx_STLx CPUFeature 3, 24, 1, NOP_hints CPUFeature 3, 12, 1, LDREX_STREX CPUFeature 3, 12, 1, CLREX_LDREXB_LDREXH_STREXB_STREXH CPUFeature 4, 20, 3, CLREX_LDREXB_LDREXH_STREXB_STREXH, FeatureOp_AND CPUFeature 3, 12, 2, CLREX_LDREXB_LDREXH_STREXB_STREXH CPUFeature 3, 12, 2, LDREXD_STREXD CPUFeature 3, 04, 1, SSAT_USAT CPUFeature 3, 04, 1, PSR_Q_bit CPUFeature 3, 04, 3, PKHxy_xADD16_xADD8_xASX_xSUB16_xSUB8_xSAX_SEL CPUFeature 3, 04, 3, PSR_GE_bits CPUFeature 3, 04, 3, SXTB16_SXTAB16_UXTB16_UXTAB16, FeatureOp_AND CPUFeature 3, 00, 1, QADD_QDADD_QDSUB_QSUB CPUFeature 3, 00, 1, PSR_Q_bit CPUFeature 4, 28, 1, SWP_SWPB_uniproc CPUFeature 0, 00, 1, SWP_SWPB_uniproc, FeatureOp_BIC CPUFeature 4, 16, 1, DMB_DSB_ISB CPUFeature 4, 12, 1, SMC CPUFeature 4, 00, 2, LDRHT_LDRSBT_LDRSHT_STRHT CPUFeature 5, 16, 1, CRC32B_CRC32H_CRC32W_CRC32CB_CRC32CH_CRC32CW CPUFeature 5, 12, 1, SHA256H_SHA256H2_SHA256SU0_SHA256SU1 CPUFeature 5, 08, 1, SHA1C_SHA1P_SHA1M_SHA1H_SHA1SU0_SHA1SU1 CPUFeature 5, 04, 1, AESE_AESD_AESMC_AESIMC CPUFeature 5, 00, 1, SEVL FeatureRegsTableEnd [ :LNOT: InKernel ARMv3 * 0 ARMv4 * 1 ARMv4T * 2 ARMv5 * 3 ARMv5T * 4 ARMv5TE * 5 ARMv5TEJ * 6 ARMv6 * 7 ARMvF * &F ; int Init_ARMarch(void) ; Returns architecture, as above in r2. Also EQ if ARMv3, NE if ARMv4 or later. Init_ARMarch ROUT Entry "ip" MRC p15, 0, ip, c0, c0, 0 ANDS r2, ip, #&0000F000 EXIT EQ ; ARM 3 or ARM 6 TEQ r2, #&00007000 BNE %FT20 TST ip, #&00800000 ; ARM 7 - check for Thumb MOVNE r2, #ARMv4T MOVEQ r2, #ARMv3 EXIT 20 ANDS r2, ip, #&000F0000 ; post-ARM 7 MOV r2, r2, LSR #16 EXIT CPUFeatures DCD 0 DCD 0 CPUFeatures_Size * 8 | CPUFeatures_Size * ?CPUFeatures ] MACRO SetFeature$cc $feature LDR$cc.B lr, [r2, #CPUFeature_$feature :SHR: 3] ORR$cc lr, lr, #1 :SHL: (CPUFeature_$feature :AND: 7) STR$cc.B lr, [r2, #CPUFeature_$feature :SHR: 3] MEND ASSERT CPUFeatures_Size * 8 >= CPUFeature_Max CalcCPUFeatures ROUT ; In: ; r0 -> instruction set feature registers ; r1 = number of registers ; r2 = CPU architecture field from MIDR, or -1 if ARM3 or older ; Out: ; CPUFeatures populated Entry "r2-r8" [ InKernel LDR r2, =ZeroPage+CPUFeatures | ADR r2, CPUFeatures ] ASSERT CPUFeatures_Size == 8 MOV r3, #0 STR r3, [r2] STR r3, [r2, #4] ; Fill in the features defined by the instruction set feature registers ADR r3, FeatureRegsTable ADR r4, FeatureRegsTableEnd MOV r8, #1 10 LDRB r5, [r3], #4 AND r6, r5, #7 CMP r6, r1 LDRLT r6, [r0, r6, LSL #2] MOVGE r6, #0 ; n.b. can't skip registers which are zero, we must still process them LDRB r7, [r3, #-3] MOV r6, r6, LSR r7 LDRB r7, [r3, #-2] AND r6, r6, #15 CMP r6, r7 LDRB r6, [r3, #-1] BIC r5, r5, #7 LDRB r7, [r2, r6, LSR #3] AND lr, r6, #7 ASSERT FeatureOp_BIC < FeatureOp_AND ASSERT FeatureOp_AND < FeatureOp_OR ; If we failed the test, massage the flags so that AND becomes BIC, and BIC and OR become a no-op (AND) EORLT r5, r5, #FeatureOp_BIC :EOR: FeatureOp_AND BICLT r5, r5, #FeatureOp_OR CMP r5, #FeatureOp_AND BICLT r7, r7, r8, LSL lr ORRGT r7, r7, r8, LSL lr STRNEB r7, [r2, r6, LSR #3] CMP r3, r4 BNE %BT10 ; Fill in extra features which we care about [ InKernel LDR r3, =ZeroPage LDR r3, [r3, #ProcessorFlags] | Push "r0-r1" MOV r0, #OSPlatformFeatures_ReadCodeFeatures SWI XOS_PlatformFeatures MOVVC r3, r0 MOVVS r3, #0 Pull "r0-r1" ] TST r3, #CPUFlag_No26bitMode ; Trust the current kernel about whether 26bit modes are supported, rather than trying to work it out ourselves SetFeatureEQ TEQP FRAMLDR r4,,r2 CMP r4, #ARMv4 SetFeatureGE LDRSB SetFeatureGE SYS_mode SetFeatureLE MULS_flag_corruption [ InKernel ; Kernel init is too early for SWIs, just check target machine type instead [ "$Machine" <> "IOMD" SetFeatureGE LDRH_LDRSH_STRH ] | BNE %FT35 ; ARMv4. For simplicity assume that if IOMD is present LDRH/STRH won't work. Push "r0-r4" MOV r0, #2 SWI XOS_ReadSysInfo AND r0, r0, #&ff00 CMP r0, #&ff00 Pull "r0-r4" 35 SetFeatureGE LDRH_LDRSH_STRH ; ARMv5+, or ARMv4 without IOMD ] ; Be careful with ARMv6 comparisons, GT condition could still be ARMv6 CMP r4, #ARMv6 SetFeatureLT MUL_Rd_Rn_restriction SetFeatureLT LDR_STR_Rd_Rn_restriction SetFeatureLE Rotated_loads BLT %FT40 SetFeature Unaligned_loads ; Look at the cache type register to work out whether this is ARMv6 or ARMv7+ MRC p15, 0, r5, c0, c0, 1 ; Cache type register TST r5, #1<<31 ; EQ = ARMv6, NE = ARMv7+ SetFeatureEQ Rotated_loads ; Guess whether WFE does something useful by whether we're a multicore chip (i.e. MPIDR is implemented) MRC p15, 0, r5, c0, c0, 5 ; MPIDR MRC p15, 0, r6, c0, c0, 0 ; MIDR TEQ r5, r6 SetFeatureNE WFE ; Detect instructions introduced by virtualisation extensions MRC p15, 0, r5, c0, c1, 1 ; ID_PFR1 TST r5, #15<<12 ; ARMv7 SetFeatureNE HVC TSTEQ r5, #15<<24 ; ARMv8 SetFeatureNE ERET_MSR_MRS_banked 40 EXIT ReadCPUFeatures ROUT ; Out: ; CPUFeatures populated Entry "r0-r2" [ InKernel LDR r2, =ZeroPage LDRB r2, [r2, #ProcessorArch] | ; Check if the MIDR should be present (do a dummy MRS) MOV r0, #0 MRS r0, CPSR TEQ r0, #0 ADRNE lr, %FT20 BNE Init_ARMarch ; ARM2, ARM250 or ARM3 ; Use the information that was collected by the main CallASWI code to work out which it is MOV r2, #-1 ADR r0, Features_ARM3 LDR r1, nomrc CMP r1, #0 ADRNE r0, Features_ARM250 LDRNE r1, noswp CMPNE r1, #0 ADRNE r0, Features_ARM2 B %FT30 ] 20 CMP r2, #ARMvF BGE %FT50 ; Old architecture, use fake ISAR registers ADR r0, Features_ARMv3 ASSERT Features_ARMv4 = Features_ARMv3 + 20 ASSERT Features_ARMv4T = Features_ARMv4 + 20 ASSERT Features_ARMv5T = Features_ARMv4T + 20 ASSERT Features_ARMv5TE = Features_ARMv5T + 20 ASSERT Features_ARMv5TEJ = Features_ARMv5TE + 20 ASSERT Features_ARMv6 = Features_ARMv5TEJ + 20 ADD r0, r0, r2, LSL #4 ADD r0, r0, r2, LSL #2 ; n.b. not dealing with plain ARMv5 properly CMP r2, #ARMv5 SUBGE r0, r0, #20 30 MOV r1, #5 BL CalcCPUFeatures EXIT 50 ; Read the ISAR registers directly MRC p15, 0, lr, c0, c2, 5 MRC p15, 0, r1, c0, c2, 4 MRC p15, 0, r0, c0, c2, 3 STMDB sp!, {r0-r1,lr} MRC p15, 0, lr, c0, c2, 2 MRC p15, 0, r1, c0, c2, 1 MRC p15, 0, r0, c0, c2, 0 STMDB sp!, {r0-r1,lr} MOV r0, sp MOV r1, #6 BL CalcCPUFeatures ADD sp, sp, #24 EXIT PlatFeatSWI_ReadCPUFeatures ROUT ; In: r1 = >=0: flag bit to read ; <0: return bit masks for page NOT r1 ; LR stacked ; Out: Reading single flag: ; r0 = 0/1 flag bit value, or -1 if not known ; Reading bit masks: ; r0-r3 = flag values ; r4-r7 = validity masks ASSERT CPUFeature_Max <= 128 CMP r1, #-1 BEQ %FT20 BLT %FT40 ; Read single flag CMP r1, #CPUFeature_Max MOVGE r0, #-1 BGE %FT30 [ InKernel LDR r0, =ZeroPage+CPUFeatures | ADR r0, CPUFeatures ] AND lr, r1, #7 LDRB r0, [r0, r1, LSR #3] MOV r0, r0, LSR lr AND r0, r0, #1 B %FT30 20 ; Read page 0 of flags (the only page) [ InKernel LDR r0, =ZeroPage+CPUFeatures | ADR r0, CPUFeatures ] ASSERT CPUFeatures_Size == 8 LDMIA r0, {r0-r1} ASSERT CPUFeature_Max >= 32 MOV r4, #-1 ASSERT CPUFeature_Max <= 64 LDR r5, =&ffffffff :SHR: (64 - CPUFeature_Max) 25 MOV r2, #0 MOV r3, #0 MOV r6, #0 MOV r7, #0 30 Pull "lr" B SLVK 40 ; Read unimplemented page of flags MOV r0, #0 MOV r1, #0 MOV r4, #0 MOV r5, #0 B %BT25 ; Fake ISAR registers for old architectures ; Thumb instruction details might not be entirely correct, but we don't really care about that [ :LNOT: InKernel Features_ARM2 DCD &00000000 DCD &00000010 DCD &00001000 DCD &00000100 DCD &00000141 Features_ARM250 DCD &00000001 DCD &00000010 DCD &00001000 DCD &00000100 DCD &00000141 Features_ARM3 DCD &00010001 DCD &00000010 DCD &00001000 DCD &00000100 DCD &00000141 ] Features_ARMv3 DCD &00010001 DCD &00000010 DCD &01001000 DCD &00000100 DCD &00000141 Features_ARMv4 DCD &00010001 DCD &00000010 DCD &01111000 DCD &00000100 DCD &00000141 Features_ARMv4T DCD &00010001 DCD &01000010 DCD &01111000 DCD &00000100 DCD &00000141 Features_ARMv5T DCD &00120011 DCD &02000010 DCD &01111000 DCD &00000100 DCD &00000141 Features_ARMv5TE DCD &00130011 DCD &02000010 DCD &01121011 DCD &00000101 DCD &00000141 Features_ARMv5TEJ DCD &00130011 DCD &12000010 DCD &01121011 DCD &00000101 DCD &00000141 Features_ARMv6 DCD &00140011 DCD &12002111 DCD &11231011 DCD &00001131 DCD &00000141 ; Assume any ARMv6 chip with extensions will use the CPUID scheme LTORG END