Until today I was programming on a single core, now I need to run my codes on multiple core.
I'm researching for about 1 week and had some questions about this.
I'm using Zynq 702, Arm DS-5 and Dstream by the way. And I'm trying to achive this while I'm using my already present codes running on Core0.
I really did nothing on core1, just connected to it and just want to observe that it jumps to 0xFFFFFFF0 and to the value of this address. I didn't set any interrupt handler that targets core1. Is it OK with my only "observe" situation? Or I really need some configurations to be set? How can I achieve this by the easiest way?
I connect to core1 and observe its state while my program continues on core0. There is no application running on core1 by the way.. It goes up to address 0x300, at this address there is a WFE command and right after it there is a B(ranch) command which is branching to 0x300 again. This is like a loop and my code stays about 0.5Second on WFE command, jumps to next instruction B and branch to the WFE again......
I think core1 should stay right there after executing WFE command unless I send an EVENT, not to execute following B(ranch) command right? If so, does it mean core1 is getting evets periodicly from somewhere?
Does connecting the board with Dstream Debugger causes EVENTs ?
If I set the value of address 0xFFFFFFF0, what makes the core1 to jump to the address at 0xFFFFFFF0, Is a simple SEV command enough while core1 is in the WFE/WFI state?
If 0xFFFFFFF0 has a value of 0x00000000, then what happens? Does Core1 go back to the calling WFE/WFI again? Or something else?
If core1 is in an WFE loop (state) the SEV cmd on core0 wakes up core1. If you enter WFE, you go into standby and the SEV is a wakeup, a request from the SCU can also do a wakeup (for a cache coherency operation in an MP system).
note:
After APU reset, core1 is in an WFE state, executing code from 0xFFFFFE00 to 0xFFFFFFF0
After boot, core1 is in an WFE state. If core1 gets an SEV it jumps to the address stored at 0xFFFFFFF0. If you update the destination address after the SEV, then core1 returns to the WFE state. This is because 0xFFFFFFF0 has the address of the WFE instruction.
The correct "startup sequence" is:
Write the address of the core1 app to 0xFFFFFFF0
Execute the SEV instruction
(Have a look at page 158 (6.1.10) in the Zynq-7000 All Programmable SoC Technical Reference Manual)
If 0xFFFFFFF0 has a value of 0x00000000 you will get unpredictable results. (depending on your cpu state).
In my case (Cyclone V SoC) after cold reset CPU1 have "hold in reset" state.
For starting CPU1 from CPU0 I add code to Reset_Handler:
;System Manager addr is 0xFFD08000
LDR r0, =0xFFD080C4 ;cpu1startaddr
MOV r1, #0x02000000 ;start addr from linker script
STR r1, [r0]
;Reset Manager add is 0xFFD05000
LDR r0, =0xFFD05010 ;MPU Module Reset Register
MOV r1, #0
STR r1, [r0] ; write 0 to power_on cpu1
Related
I'm researching the the Arm Architecture Reference Manual ARMv7-A ARMv7-R edition document these days. When I read about the exception handling part of this manual, it comes across a confusions to me. The problem is about how to decide the LR value when ARMv7-A architecture implementation takes an IRQ exception.
EXAMPLE: Suppose that the processor is executing an instruction at the address of 0x_0000_1000 and an IRQ is taken.First, we have to calculate some parameters to be used to calculate the LR.
preferred return address,which is the Address of next instruction to execute in this case. So preferred return address = 0x_0000_1002 in thumb instruction set or preferred return address = 0x_0000_1004 for arm instruction set.preferred return address for the exception
PC,which is the program counter and holds the current program address.In this case, PC = 0x_0000_1004 in thumb instruction state or PC = 0x_0000_1008 in arm instruction state.how to calculate PC
Then, here are 2 methods mentioned in the document to decide the LR value when taking this IRQ exception.
by using preferred return address. LR = preferred return address + offset that depends on the instruction set state when the exception was taken.In this case LR = 0x_0000_1002 + 4 in thumb instruction state or LR = 0x_0000_1004 + 4 in arm instruction state.Offsets applied to Link value for exceptions taken to PL1 modes
by using PC. LR = PC-0 if in thumb instruction set or LR = PC-4 when in arm instruction set.In this case LR = 0x_0000_1004 - 0 in thumb instruction set or LR = 0x_0000_1008 - 4 in arm instruction state. Pseudocode description of taking the IRQ exception
Problem:the LR results calculated by the 2 methods are different both in thumb set state and arm set state(with first method we get LR = 0x_0000_1006 or LR = 0x_0000_1008,but second method we get LR = 0x_0000_1004 or LR = 0x_0000_1004). which one is correct or is there any wrong with my understanding?
TL;DR - the IRQ LR will point to the next instruction to complete work as would normally be run without an interrupt. Otherwise, code would not execute the same in the presence of interrupts.
It is confusing as the ARM documents may refer to PC in many different contexts and they are not the same.
EXAMPLE:Suppose that the processor is executing an instruction at the address of 0x_0000_1000 and an IRQ is taken. First, we have to calculate some parameters to be used to calculate the LR.
preferred return address,which is the Address of next instruction to execute in this case. So preferred return address = 0x_0000_1002 in thumb instruction set or preferred return address = 0x_0000_1004 for arm instruction set.preferred return address for the exception
This is not correct. The ARM cpu has a pipeline and the last instruction that it has deemed to have completed is the next instruction. Take for example this sequence,
0: cmp r1, #42
1: bne 4f ; interrupt happens as this completes.
2: add r2, r2, #4
3: b 5f
4: sub r2, r2, #2
5: ; more code.
If the interrupt happens as label '1:' happens, the next instruction will be either '2:' or '4:'. If you followed your rule this would either increase interrupt latency by never allowing an interrupt in such cases, or interrupts would cause incorrect code. Specifically, your link says next instruction to execute.
PC,which is the program counter and holds the current program address.In this case, PC = 0x_0000_1004 in thumb instruction state or PC = 0x_0000_1008 in arm instruction state.how to calculate PC
Here you are mixing concepts. One is when you use a value like ldr r0, [pc, #42]. When you calculate the offset, you must add two to the current ldr instruction. The actual PC is not necessarily this value. At some point (original version), the ARM was a two stage pipeline. In order to keep behaviour the same, subsequent ARM cpus follow the rule of being two ahead when calculating ldr r0, [pc, #42] type addresses. However, the actual PC may be much different inside the CPU. The concept above describes the programmer visible PC for use with addressing.
The CPU will make a decision, sometimes base on configuration, on what work to complete. For instance, ldm sp!, {r0-r12} may take some time to complete. The CPU may decide to abort this instruction to keep interrupt latency low. Alternatively, it may perform 12 memory reads which could have wait states. The LR_irq will be set to the ldm instruction or the next instruction depending whether it is aborted or not.
I am trying to evict the memory address in which the stack pointer is pointing to it in an ARM Cortex-A8 processor. I am trying to do that with the below code:
cpy r3, sp
mcr p15, 0x0, r3, cr7, cr6, 0x1
I have run the above code in a loadable kernel module. after running the above code in the kernel, OS crashes and needs a restart. but the above instructions work fine for flushing a variable from the cache.
Can anyone give me any advice to solve the problem?
Thanks to artless noise, actually ARM cortex-a8 has 3 types of command for cache manipulation based on Modified Virtual address:
Invalidate (C6, 1) (just invalidate the cache line)
Clean (C10, 1) (Update memory if the cache line is dirty)
Clean & Invalidate (C14, 1) (Update memory then invalidate cache line)
and as you can see in the question I used Invalidate instruction and it caused that memory to have invalid data for the stack. but after using Clean&Invalidate instruction the problem was solved. so the final code is as below:
cpy r3, sp
mcr p15, 0x0, r3, cr7, cr14, 0x1
DSB SY
I would like to create a data abort and pre-fetch abort to test whether the exception handlers for the same are getting called properly or not. As per my understanding that dereferencing a NULL pointer can cause data abort. But I am not getting how to create a pre-fetch abort for testing. I am working on armv7a. I am not using any OS, working on the boot code.
both of these are bus faults, jumping into unknown code is going to result in an undefined instruction not prefetch abort. I would focus on unaigned accesses do an ldr with bit 1 set and do a bx with bit 1 set (but bit 0 not set) would be where I start. If those dont work it might not be possible with a test fixture inside the chip.
There may be portions of the address space that dont respond, those should simply hang the processor, but you might get lucky and the memory controller returns a fault.
if you have parity or ecc in your system those would be the best way, assuming you have a way to inject an error into those memories to force a parity or ecc fault (also assuming that the memory controller, etc for that design (little to no logic that is relevant to your question is part of the ARM processor) returns a fault on a parity or ecc error).
cortex-m might fault on some address spaces as they to some extent dictate where you are supposed to go.
If one of the newer cores you can use the mmus protection and I dont know if that returns a data/prefetch fault or not, setup the mmu such that some space is at a different access level than the code you are going to hit it with and see what fault you get.
EDIT
Have to look for an armv7 but on an armv6 (pi 1 for example) if I enable alignment checking in the control register, and do an ldr of say address 0x1001 which is an alignment fault then it gives me a data abort.
save a line of code and use address 0x01
mrc p15, 0, r0, c1, c0, 0
orr r0,#2
mcr p15, 0, r0, c1, c0, 0
mov r0,#0x1
ldr r0,[r0]
jumping into an invalid instruction causes an undefined not a prefetch abort, the memory system has to assert the abort, so you can use the mmu for this most likely,
undefined exception
.globl TEST
TEST:
.word 0xFFFFFFFF
bx lr
easiest way to make a prefetch abort (as stated in the ARM ARM).
.globl TEST
TEST:
bkpt
For a data abort you can just attempt to read an unmapped or non-readable memory region. For example try reading/writing a NULL pointer.
For prefetch abort just try jumping to a random address in some unmapped, non-readable or non-executable region (do you have MMU enabled at this stage?):
mov r0, #0xFFFFFFFF ; Some address that is satisfying the above
push r0 ; push it to the stack
pop pc ; jump to that address
Note, that just jumping to a random address might result in an Undefined abort instead, as it might be executable but contain an unknown instruction.
Was going through basics of arm exception handling, and come to this doubt:
(I am taking example of abort exception)
Lets assume processor is running in user mode.
When an exception happens the processor will save the current pc to abort_mode LR and CPSR to abort mode SPSR and the execution jumps to vector address for the abort, so PC will now contain the vector address for the abort.
So what I get here is before transferring the flow to abort mode(having pc to abort vector).
CPU will perform below task:
"Current pc to abort_mode LR and CPSR to abort mode SPSR and then execution jumps to vector address for the abort," as mentioned above.
In which mode and from where instructions are executed to perform above task?
When an abort exception happens, the text you are quoting is correct. Other exceptions use different modes.
The copying of PC to the exception mode LR and the CPSR to SPSR and setting the PC to the exception vector is what the processor does for you automatically on taking the exception. There are no instructions required. It also switches to the SP used by that exception mode.
The exception handler is what comes next. and is completely in software.
Can you explain how the ARM mode get changed in case of a system call handling?
I heard ARM mode change can happen only in privileged mode, but in case of a system call handling while the ARM is in user mode (which is a non-privileged mode), how does the ARM mode change?
Can anybody explain the whole action flow for the user mode case, and also more generally the system call handling (especially how the ARM mode change)?
Thanks in advance.
In the case of system calls on ARM, normally the system call causes a SWI instruction to be executed. Anytime the processor executes a SWI (software interrupt) instruction, it goes into SVC mode, which is privileged, and jumps to the SWI exception handler. The SWI handler then looks at the cause of the interrupt (embedded in the instruction) and then does whatever the OS programmer decided it should do. The other exceptions - reset, undefined instruction, prefetch abort, data abort, interrupt, and fast interrupt - all also cause the processor to enter privileged modes.
How file handling works is entirely up to whoever wrote your operating system - there's nothing ARM specific about that at all.
You need to get a copy of the ARM ARM (Architectural Reference Manual).
http://infocenter.arm.com -> ARM Architecture -> Reference Manuals -> ARMv5 Architectural Reference Manual then download the pdf.
It used to be a single ARM ARM for the ARM world but there are too many cores and starting to diverge so they split off the old one as ARMv5 ARM and made new Architectural Reference Manuals for each of the major ARM processor families.
In the Programmers Model chapter it talks about the modes, it says that you can change freely among the modes other than user. ARM startup code will often go through a series of mode changes so that the stack pointers, etc can be configured. Then as needed go back to System mode or User mode.
In that same chapter look at the Exceptions section, this describes the exceptions and what mode the processor switches to for each exception.
The Software interrupt exception which happens when an SWI instruction is executed, is a way to implement system calls. The processor is put in Supervisor mode and if in thumb mode switches to arm mode.
There needs to be code to support that exception handler of course. You need to verify with the operating system, if any, you are running, what is supported and what the calling convention is, etc.
Not all ARM processors work this way. The Cortex-M (ARMv7-M) does not have the same modes and same exception table, etc. As with any time you are using an ARM (at this level) you need to get the ARM ARM for the family you are using and you need to get the TRM (Techincal Reference Manual) for the core(s) you are using, ideally the exact revision, even if ARM marks the TRM as having been replaced by a newer version the chip manufacturer has purchased and uses a specific rev of the core and there can be enough differences between revs that you will want the correct manual.
When an SVC instruction is encountered by the PC, the following behaviour takes place:
The current status (CPSR) is saved (to the supervisor SPSR)
The mode is switched to supervisor mode
Normal (IRQ) interrupts are disabled
ARM mode is entered (if not already in use)
The address of the following instruction (the return address) is saved into the link register (R14) - It's worth noting that this is
the link register that belongs to the supervisor mode
The PC is altered to jump to address 0x00000008
An exception vector (just a branch instruction) should be at the address 0x0000008, which will branch the program to another area of code used to determine which supervisor call has been made.
Determining which supervisor call has been made is usually accomplished by loading the SVC instruction into a register (by offsetting the LR by one word - since the LR is still pointing to the instruction next to the supervisor call), bit clearing the last 8 bits and using the value in the remaining 24 bits of the register to calculate an offset in a jump table, to branch to the corresponding SVC code.
When the supervisor call code wishes to return to the user application, the processor needs to context switch back into user mode and return to the address contained within the LR (which is only available in supervisor mode, since certain registers are banked for both modes). This problem is overcome using the MOVS instruction, as illustrated below:
(consider this to also be your explanation on how to change mode)
MRS R0, CPSR ; load CPSR into R0
BIC R0, R0, #&1F ; clear mode field
ORR R0, R0, #&10 ; user mode code
MSR SPSR, R0 ; store modified CPSR into SPSR
MOVS PC, LR ; context switch and branch
The MRS and MSR instructions are used to transfer content between an ARM register and the CPSR or SPSR.
The MOVS instruction is a special instruction, which operates as a standard MOV instruction, but also sets the CPSR equal to the SPSR upon branching. This allows the processor to branch back (since we're moving the LR into the PC) and change mode to the mode specified by the SPSR.
I quote from the ARM documentation available here:
http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.dui0471c/BABDCIEH.html
When an exception is generated, the processor performs the following
actions:
Copies the CPSR into the appropriate SPSR. This saves the current mode, interrupt mask, and condition flags.
Switches state automatically if the current state does not match the instruction set used in the exception vector table.
Changes the appropriate CPSR mode bits to:
Change to the appropriate mode, and map in the appropriate banked out registers for that mode.
Disable interrupts. IRQs are disabled when any exception occurs. FIQs are disabled when an FIQ occurs and on reset.
Sets the appropriate LR to the return address.
Sets the PC to the vector address for the exception.
where, CPSR refers to Current Program Status Register and SPSR to Saved Program Status register used to restore the state of the process that was interrupted. Thus, as seen in point 3, the processor circuitry is designed in a way that the hardware itself changes the mode when user mode executes a Supervisor call instruction.
"I heard ARM mode change can happen only in privileged mode". You are partly right here. By partly I mean the control field of the CPSR register can be manually modified (manually modified means through code) in the privileged modes only not in the unprivileged mode (i.e. user mode). When a system call happens in the user mode it happens because of SWI instruction. An SWI instruction has inbuilt mechanism to change the mode to supervisor mode.
So to conclude , there are two ways to change the mode:
1) Explicitly through code. Only allowed in a privileged mode.
2) Implicitly through IRQ, FIQ, SWI, RESET, undefined instruction encountered, data abort, prefetch abort. This is allowed in all the modes.