I'm reading about linux/arch/arm/boot/compressed/head.S
I figured out about the angel boot. It's my first time about this word
#ifndef CONFIG_CPU_V7M
/*
* Booting from Angel - need to enter SVC mode and disable
* FIQs/IRQs (numeric definitions from angel arm.h source).
* We only do this if we were in user mode on entry.
*/
mrs r2, cpsr # get current mode
tst r2, #3 # not user?
bne not_angel
mov r0, #0x17 # angel_SWIreason_EnterSVC
ARM( swi 0x123456 ) # angel_SWI_ARM
THUMB( svc 0xab ) # angel_SWI_THUMB
not_angel:
safe_svcmode_maskall r0
msr spsr_cxsf, r9 # Save the CPU boot mode in
# SPSR
#endif
So i googled and read the linux documentation located in linux/Documentation/arm/Booting
There's no clear definition about angel booting in any website and linux documentation only mentioned angel as like bellow
For CPUs which do not include the ARM virtualization extensions, the
CPU must be in SVC mode. (A special exception exists for Angel)
So I want to know about clear definition about angel boot
Thank you for your answer
Refers to the content from ARM Information center, "Angel is a debug monitor that allows rapid development and debugging of applications running on ARM-based hardware."
http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.dui0066d/Babdcdih.html
It seems you can debug your software through Angel using debuggers like gdb - when your board is set up with Angel.
It offers a feature which is called "Semihosting" - a board-host input/output bridging. It is done on SWI context.
http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.dui0058d/CIHDICHH.html
Related
Where can I check to know if the Linux kernel is running in non-secure (EL2) or secure (EL3) mode ?
How can I change this mode ?
I run on the ARMv8 64 bits.
Thanks in advance
Where can I check to know if the Linux kernel is running in non-secure (EL2) or secure (EL3) mode ?
I'm going to give a cheeky answer.
Adapt what is the current execution mode/exception level, etc? and hack your region of interest:
diff --git a/init/main.c b/init/main.c
index 18f8f0140fa0..840f886d17b3 100644
--- a/init/main.c
+++ b/init/main.c
## -533,6 +533,10 ## asmlinkage __visible void __init start_kernel(void)
char *command_line;
char *after_dashes;
+ register u64 x0 __asm__ ("x0");
+ __asm__ ("mrs x0, CurrentEL;" : : : "%x0");
+ pr_info("EL = %llu\n", (unsigned long long)(x0 >> 2));
+
set_task_stack_end_magic(&init_task);
smp_setup_processor_id();
debug_objects_early_init();
Output at the start of boot.
EL = 1
The default Linux kernel v4.19 boot logs also tell us that by default:
CPU: All CPU(s) started at EL1
How can I change this mode?
Traditionally the kernel ran on EL1 only, and EL2 was left for a hypervisor like Xen, and EL3 for a bootloader like ARM Trusted Firmware.
However, with the introduction of the ARMv8.1 VHE extension, EL2 kernel became efficient and was added into Linux mainline: What are Ring 0 and Ring 3 in the context of operating systems? Not sure which config turns it on though, have a look.
EL3 I don't think there's anything mainline. There are some people trying to adapt kernel code to be the booloader as well, have a look e.g. at: https://github.com/kexecboot/kexecboot
I am trying to read kernel image and calculate a checksum value of this image. Firstly, I used a smc instruction to trigger a exception, and in the exception handler, I tried to read the first bytes of the image. I don't really know what the address is, but from some documents, I know the kernel image is decompressed in address like 0x20008000, 0x30008000 or 0xC0008000(they call this ZRELADDR, i don't really know whether this is the right address...). So I tried to read the memory like this:
uint32_t test;
test = * (uint32_t *)0x30008000;
DMSG("test : %x\n",test);
But the system crashed with a data abort exception,
core data-abort at address 0x30008000
fsr 0x00000005 ttbr0 0x7df7006a ttbr1 0x7df7006a cidr 0x0
cpu #0 cpsr 0x200001b3
r0 0x00000090 r4 0x7df4bf51 r8 0x00000000 r12 0x00000000
r1 0x09010000 r5 0x806665e0 r9 0x00000000 sp 0x7df77f50
r2 0x0000000d r6 0x7f002000 r10 0x00000000 lr 0x7df273ff
r3 0x30008000 r7 0x7df77f60 r11 0x00000000 pc 0x7df052f0
ERR TEE-CORE:tee_pager_handle_fault:602: Unexpected page fault! Trap CPU
PANIC: tee_pager_handle_fault core/arch/arm/mm/tee_pager.c:603
I guess I am on the wrong way. Does anyone know how to read the kernel image in runtime environment?
Thanks for your help!
EDIT:Thanks for your reply. I am talking about secure kernel. I am trying to check the integrity of the kernel under TrustZone, and to insure the kernel haven't be compromised. So I guess a checksum like hash value may help me. Also, I am a novice who is trying to be familiar with the memory system of arm, so I tried to start with simple read some certain memory address. I have tried to read 0xc0000000 as Artless Noise said, but the same error occurs again. Again I tried to find "_test" and "stext" address in System.map, which is 0x80008000, and error occurs again.
The beginning of the RAM is usually mapped at 0xC0000000. This depends on CONFIG_PAGE_OFFSET:
- VMSPLIT_3G: 0xC0000000
- VMSPLIT_2G: 0x80000000
- VMSPLIT_1G: 0x40000000
Note that this is a virtual address if you have an MMU (usual case), the physical address will depend on your actual architecture (it may or may not be 0x00000000). The kernel is loaded a few pages after that, at an offset of 0x8000.
So, you can probably find the (uncompressed) kernel at 0xC0008000 but it may as well be located somewhere else.
You can also try to ioremap() offset 0x8000 of your RAM.
Can you give us a bit more information on the particular SoC you are working on?
If you are in secure mode and you believe that in secure mode it access physical address then from below these macro you can deduce the physical address.
The physical address at which kernel loads is PHYS_OFFSET + TEXT_OFFSET (text offset is 0x8000),
PHYS_OFFSET definition will be depend on the CONFIG_ARM_PATCH_PHYS_VIRT patch.
if CONFIG_ARM_PATCH_PHYS_VIRT is defined, then PHYS_OFFSET will be equal to __pv_phys_offset otherwise PHYS_OFFSET will be defined as CONFIG_PHYS_OFFSET in your kernel config file.
I have a pretty weird thing I need to do: Access some "secure" instructions for things that don't really need to be done in a secure context. In short: I need to get in to Secure Mode, but not because I want Hardware TPM-ish functionality or anything. I just need access to certain instructions that I wouldn't otherwise have.
We're doing this on Gumstix Overo FireSTORM COMs. It is my understanding these boot securely, but then somewhere (MLO? u-boot?) they switch to non-secure mode, but I could be wrong. The point is that we're certainly doing this from nonsecure (but privileged, see below) mode.
(I authored this question, about direct access to the GHB/BTB of the A8 branch predictor, if you're curious about what I'm looking to do: Write directly to the global history buffer (GHB) or BTB in the branch predictor of a ARM Cortex A8?)
Now, all of this will be done from u-boot (we've got Overo FireSTORM COMs), so luckily I have "privileged" execution. No worries there. And I've looked at other StackOverflow questions, but there doesn't seem to be anything on how, exactly, to get to secure mode. All I really wanna do is access some CP15 registers, and then go back to non-secure mode (and potentially repeat the process).
I've looked into the SMC instruction, but I can't find any documentation on how to appropriately trap the call/where the call goes to/how to set that up, etc.
Is that information anywhere?
To recap, here's what I want to do:
FROM PRIVILEGED EXECUTION:
Do stuff
Tweak GHB // requires secure execution
Do more stuff
Tweak GHB
Do more stuff
...
...
...
Do stuff
Any help would CERTAINLY be appreciated!
Thanks to #artlessnoise, I found this file in the u-boot source: /u-boot/arch/arm/cpu/armv7/nonsec_virt.S.
It contains the following code:
/*
* secure monitor handler
* U-boot calls this "software interrupt" in start.S
* This is executed on a "smc" instruction, we use a "smc #0" to switch
* to non-secure state.
* We use only r0 and r1 here, due to constraints in the caller.
*/
.align 5
_secure_monitor:
mrc p15, 0, r1, c1, c1, 0 # read SCR
bic r1, r1, #0x4e # clear IRQ, FIQ, EA, nET bits
orr r1, r1, #0x31 # enable NS, AW, FW bits
#ifdef CONFIG_ARMV7_VIRT
mrc p15, 0, r0, c0, c1, 1 # read ID_PFR1
and r0, r0, #CPUID_ARM_VIRT_MASK # mask virtualization bits
cmp r0, #(1 << CPUID_ARM_VIRT_SHIFT)
orreq r1, r1, #0x100 # allow HVC instruction
#endif
mcr p15, 0, r1, c1, c1, 0 # write SCR (with NS bit set)
#ifdef CONFIG_ARMV7_VIRT
mrceq p15, 0, r0, c12, c0, 1 # get MVBAR value
mcreq p15, 4, r0, c12, c0, 0 # write HVBAR
#endif
movs pc, lr # return to non-secure SVC
Presumably if I modified the mask for the mcr p15 instruction, I could simply "turn off" the move to nonsecure mode. This will probably kill u-boot, however.
So the question is, then: How do I set the appropriate vector so when I make the SMC call, I jump back into secure mode, and am able to do my GHB/BTB tinkering?
Any other help is appreciated!
The DM3730 on the Gumstix is a GP (general purpose) device, which means it has TrustZone disabled. There's no way you can get in to it.
See https://stackoverflow.com/a/8028948/6839
I'm porting u-boot to P2040 based board these days.
As u-boot/arch/powerpc/mpc85xx/start.s commented:
The processor starts at 0xffff_fffc and the code is first executed in the last 4K page in flash/rom.
In u-boot/arch/powerpc/mpc85xx/resetvec.S:
.section .resetvec,"ax"
b _start_e500
And in u-boot.lds linker script:
.resetvec RESET_VECTOR_ADDRESS :
{
KEEP(*(.resetvec))
} :text = 0xffff
The reset vector is at 0xffff_fffc, which contains a jump instruction to _start_e500.
The E500MCRM Chapter 6.6 mentioned:
This default TLB entry translates the first instruction fetch out of reset(at effective address 0xffff_fffc).
This instruction should be a branch to the beginning of this page.
So, if I configure the HCW to let powerpc boot from Nor Flash, why should I suppose that the Nor Flash's
last 4K is mapped to 0xffff_f000~0xffff_ffff? Since there're no LAW setup yet and the default BR0/OR0 of Local Bus
does not match that range. I’m confused about how Nor Flash be access at the very beginning of core startup.
Another question is:
Does P2040 always have MMU enabled so as to translate effective address to real address even at u-boot stage?
If so, beside accessing to CCSRBAR, all other memory access should have TLB entry setup first.
Best Regards,
Hook Guo
The following code snippet is taken from linux v2.6.11. Something similar is present in v3.8 as well.
mrs r13, cpsr
bic r13, r13, #MODE_MASK
orr r13, r13, #MODE_SVC
msr spsr_cxsf, r13 # switch to SVC_32 mode
and lr, lr, #15
ldr lr, [pc, lr, lsl #2]
movs pc, lr # Changes mode and branches
Check out the following link for the actual file:
http://lxr.linux.no/linux+v2.6.11/arch/arm/kernel/entry-armv.S
I think writing into the mode bits of CPSR can change the current ARM mode. But how writing into SPSR (instead of CPSR), has resulted in switching to SVC_32 mode?
(or) Is something happening in the last instruction "movs pc, lr". Could someone help me understand this?
A mov or sub instruction with the 'S' suffix and the program counter as its destination register means a exception return.
It copies the contents of the SPSR to the CPSR and moves the value of the source register into the program counter (in this case, the link register).
In your example, this effectively sets the mode to SVC mode and returns from the function in one go.
There's more information on this in the ARM reference manual.
I am answering the SPSR Vs CPSR question here.
CPSR is user/system mode register, and doesn't exist in other modes, like fiq or irq modes. Whereas, SPSR exists in fiq and irq modes. On a mode change CPSR is copied into SPSR and the changed mode has to use SPSR to make any changes to the current status of the processor. SPSR is not available in user mode. And any changes made to CPSR in non-user mode won't take effect.
CPSR - Current Program Status Register
SPSR - Saved Program Status Register