Open Nathan-Stohs opened 10 years ago
I think we can unlock GPT0 and GPT1. We should check whether GPT0 is being used elsewhere during Android execution, possibly indicated by it still being locked but the contents of GPT0_EN, GPT0_MTCH, or GPT0_CLR being changed. ARM Current Program Status Register (CPSR) bits 4:0 indicate the mode (either User, FIQ, IRQ, Supervisor, Monitor, Abort, Undefined, or System. Hypervisor mode is not supported in Krait v1). User mode is unprivileged. Monitor mode cannot be interrupted by IRQ signals. IRQ, FIQ, and abort signals can be controlled to trigger either their respective modes, or a handler in Monitor mode. The Little Kernel runs in Supervisor mode, and the TrustZone runs in Monitor mode. ARM Coprocessor 15's Secure Configuration Register (SCR) is privileged -- a program running in User mode cannot read or write to SCR. SCR bit 0 is the "non-secure" (NS) bit -- when set to 1, the processor is in a non-secure state, and certain registers are protected. Setting SCR's NS bit to 0 then escalates the privilege of the processor mode into the secure world. In the secure world, almost all registers can be accessed, including registers that control privileged-mode access to groups of registers. An example is the APCS_TMRSECURE register, which is protected by the NS bit, and in turn APCS_TMRSECURE protects APCS_GPT0_EN. APCS_TMRSECURE cannot be read/written in the non-secure world, even if in the privileged supervisor mode. APCS_TMRSECURE configures whether APCS_GPT0_EN can be accessed in the non-secure world. So to access APCS_GPT0_EN, the program running in supervisor mode must set SCR.NS = 0, then set APCS_TMRSECURE bit field GPT0 to 1 to allow non-secure access to APCS_GPT0_EN, the exit the secure world by setting SCR.NS = 1. I've only used the JTAG to enter/exit the secure world because I was using the JTAG to read secure registers. The SCR.NS bit and some other configurations are reset upon exiting Secure Monitor Mode, so a proper test would include making sure the Secure Monitor Mode's exit doesn't reset the desired security settings. Specifically, I've observed the TrustZone reset CPMR0's NOPWFI bit. While I've seen the TrustZone set and unset SCR's NS bit during its execution in Monitor Mode, I can't find any android code built with ADAPT that touches SCR.NS, unless such accesses are in Qualcomm's prebuilt drivers. So there isn't equivalent security configuration in Android. Here's two starter functions if we want to add a library for security configuration. Take this as pseudo-code as I haven't taken the next step of writing a test function and compiling, it probably needs "cpsid if" and it's late in the evening etc.
#define SCR_NET (1 << 6)
#define SCR_AW (1 << 5)
#define SCR_FW (1 << 4)
#define SCR_EF (1 << 3)
#define SCR_FIQ (1 << 2)
#define SCR_IRQ (1 << 1)
#define SCR_NS (1 << 0)
static uint32_t cp15_masked_write_scr(uint32_t mask, uint32_t val) {
uint32_t reg;
__asm__ __volatile__ ("MRC p15, 0, %0, c1, c1, 0" : "=r" (reg));
reg &= ~mask;
reg |= val & mask;
__asm__ __volatile__ ("MCR p15, 0, %0, c1, c1, 0" : : "r" (reg));
return reg;
}
#define APCS_TMR_PHYS 0x0200A000
#define APCS_TMRSECURE_OFFSET 0
#define APCS_TMRSECURE_WDT0 (1 << 4)
#define APCS_TMRSECURE_WDT1 (1 << 3)
#define APCS_TMRSECURE_GPT0 (1 << 2)
#define APCS_TMRSECURE_GPT1 (1 << 1)
#define APCS_TMRSECURE_DGT (1 << 0)
#define APCS_GPT0_EN_OFFSET 0xC
#define APCS_GPT0_EN_CLR_ON_MTCH_EN (1 << 1)
#define APCS_GPT0_EN_EN (1 << 0)
static uint32_t reg_masked_write(uint32_t addr, uint32_t mask, uin32_t val) {
uint32_t reg;
reg = __volatile__ *(unsigned int *)addr; //or use __raw_readl etc.
reg &= mask;
reg |= val;
*(__volatile__ unsigned int*) addr = reg;
return reg;
}
int test_fcn(void) {
cp15_masked_write_scr(SCR_NS, 0);
reg_masked_write(APCS_TMR_PHYS + APCS_TMRSECURE_OFFSET, APCS_TMRSECURE_GPT0, APCS_TMRSECURE_GPT0);
cp15_masked_write_scr(SCR_NS, 1);
reg_masked_write(APCS_TMR_PHYS + APCS_GPT0_EN_OFFSET, APCS_GPT0_EN_EN, APCS_GPT0_EN_EN);
return (*(__volatile__ unsigned int*) (APCS_TMR_PHYS + APCS_GPT0_EN_OFFSET)) & APCS_GPT0_EN_EN; //FIXME: check if GPT0_EN's write worked.
}
The attached image should not be taken seriously, it's missing some lines etc and I can't remember where it came from, but it illustrates different modes and FIQ interrupts.
I understand the different security states etc, I'm just worried we are somehow required to take a detour through the trustzone. Is it really that simple that we can do a cp15 call to get there?
I've seen Android code that uses the GPTs, yet I like you said I didn't see anywhere where the SCR was manipulated. But since the GPTs are used they must be unlocked somehow, which is why I thought perhaps its hidden in the TrustZone binary.
The Krait core actually has 3 timers available to it, GPT0, GPT1, and DGT (debug timer).
Unfortunately, GPT0 and GPT1 are locked down in secure mode by default (by the bootloaders?). For the moment we are forced to do all timing on the DGT such as the system time and one-shots.
The is a little awkward but doable especially after my time/timer driver re-write (the previous version was prone to losing time).
TASK: Figure out this secure/non-secure mode business. This is probably biting us elsewhere.
Alternatively we could potentially ask SIMcom to provide bootloaders with GPTs unlocked which assumes they don't just pass from Qualcomm (not unlikely).