I am working on TI Jacinto6(ARM CortexA15) based board. I am understanding U-boot source.
As per start.S file, following assembly instructions are executed to disable L1 I/D cache and TLB. This instructions are from start.s(http://git.denx.de/?p=u-boot.git;a=blob;f=arch/arm/cpu/armv7/start.S;h=fedd7c8f7e00d0427405173849e6c0743d6b886f;hb=524123a70761110c5cf3ccc5f52f6d4da071b959)
mov r0, #0 # set up for MCR
mcr p15, 0, r0, c8, c7, 0 # invalidate TLBs
mcr p15, 0, r0, c7, c5, 0 # invalidate icache
mcr p15, 0, r0, c7, c5, 6 # invalidate BP array
mcr p15, 0, r0, c7, c10, 4 # DSB
mcr p15, 0, r0, c7, c5, 4 # ISB
As per ARM documents CortexA15 is having 4 cores.
The above code will disable the cache and TLB on the core which it is running, then what about the other cores cache and TLB. Will the U-boot source runs on only one core? If so then how other cores will be disabled?
Will the U-boot source runs on only one core?
The U-Boot binary (not the source) executes on only one processor core.
The functionality of a bootloader does not require parallel processing.
Also the Linux kernel expects only one core to be enabled when it starts.
If so then how other cores will be disabled?
Typically after a processor/system reset, only one core is enabled; everything else is quiescent or disabled.
So Kernel will enable the other cores while booting?
The OS, assuming it supports SMP (symmetric multiprocessors), will enable the other cores as part of its initialization.
can you please share the kernel source link(git) which enables the other cores.
For an ARM Cortex-A9 quad-core (an A15 would be similar) the Linux kernel outputs:
Booting Linux on physical CPU 0x0
Linux version 3.10.60+wandboard_1.0.2+1.0.0-wandboard (root#host) (gcc version 4.8.3 (crosstool-NG 1.19.0) ) #7 SMP Mon Dec 29 18:49:06 PST 2014
CPU: ARMv7 Processor [412fc09a] revision 10 (ARMv7), cr=10c53c7d
CPU: PIPT / VIPT nonaliasing data cache, VIPT aliasing instruction cache
Machine: Freescale i.MX6 Quad/DualLite (Device Tree), model: Wandboard Quad based on Freescale i.MX6 Quad
...
L310 cache controller enabled
l2x0: 16 ways, CACHE_ID 0x410000c7, AUX_CTRL 0x32070000, Cache size: 1048576 B
...
CPU: Testing write buffer coherency: ok
CPU0: thread -1, cpu 0, socket 0, mpidr 80000000
Setting up static identity map for 0x804bdd30 - 0x804bdd88
CPU1: Booted secondary processor
CPU1: thread -1, cpu 1, socket 0, mpidr 80000001
CPU2: Booted secondary processor
CPU2: thread -1, cpu 2, socket 0, mpidr 80000002
CPU3: Booted secondary processor
CPU3: thread -1, cpu 3, socket 0, mpidr 80000003
Brought up 4 CPUs
SMP: Total of 4 processors activated (6324.22 BogoMIPS).
CPU: All CPU(s) started in SVC mode.
devtmpfs: initialized
...
The Linux kernel begins execution of its C code in start_kernel() in init/main.c.
The second procedure called is the ARM version of smp_setup_processor_id(), which is responsible for the Booting Linux on physical CPU ... message text.
Towards the end of start_kernel(), the ARM version of check_bugs() will invoke check_writebuffer_bugs(), which is responsible for the CPU: Testing write buffer coherency: ... message text.
At the end of start_kernel(), rest_init() eventually initializes the other processor cores through the ARM version of secondary_start_kernel() (CPUn: Booted secondary processor), invoked somehow through smp_init() (Brought up N CPUs).
Related
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 have written code to enable performance monitoring register as user accessible by setting bit as 1. I getting ARM_BAD_INSTRUCTION at MCR instruction and MRC is going fine.
I am using armv7(cortex a5)
.cfi_startproc
MRC p15, 0, r0, c9, c14, 0 # Read PMUSERENR Register
ORR r0, r0, #0x01 # Set EN bit (bit 0)
MCR p15, 0, r0, c9, c14, 0 # Write PMUSERENR Register
ISB # Synchronize context
BX lr
.cfi_endproc
As per the documentation, PMUSERENR is only writeable from privileged modes, thus an attempt to write to it from unprivileged userspace will indeed raise an undefined instruction exception.
If you want to enable userspace access, you need to do it from the kernel (or possibly from a hypervisor/firmware in the case of a kernel which doesn't know about PMUs itself).
If you don't have control of any such privileged software, well then you're not getting yourself direct access, because that's rather the point of the notion of privilege. What you might have, however, is some userspace API provided by the OS - such as perf events on Linux - to let you profile and measure stuff without the hassle of managing the hardware directly; frankly that's usually the better option even if you could enable direct access, because userspace still has no way to properly handle all the necessary event filtering, scheduling, overflow interrupts, etc. on a multitasking system.
On arm platform, the u-boot will invalidate TLBs, icache and BP array at beginning, but what's the reason? Is it necessary?
cpu_init_crit:
/*
* Invalidate L1 I/D
*/
mov r0, #0 # set up for MCR
mcr p15, 0, r0, c8, c7, 0 # invalidate TLBs
mcr p15, 0, r0, c7, c5, 0 # invalidate icache
mcr p15, 0, r0, c7, c5, 6 # invalidate BP array
mcr p15, 0, r0, c7, c10, 4 # DSB
mcr p15, 0, r0, c7, c5, 4 # ISB
A reset may be hard or soft. It is possible for something to jump to a reset vector. If cache is enabled with stale entries, the code may crash resulting in a system not booting. This can be more common than you think as SDRAM may miss behave after a cold power on and mis-read causing a crash. Often a watchdog or unrecoverable faults will jump to the reset vector. Finally, there maybe u-boot systems in XIP NOR flash. Some systems/code may just jump to this code to perform a soft reset.
In all of these cases, the debug available is NIL. You may have a working system in 99.9999% of the cases. Having to trouble shoot a boot failure on particular hardware which only occurs in a hot bar or an ice cream freezer might make you enjoy this extra code. Ie, there are rare circumstances where it is needed.
Hardware failures are much more common as supply rails come on line. Datasheets describe properly behaving systems with power/temperature, etc in range. u-boot may not operate in this ideal world. If your concern is boot time, you are much better to write your own loader (keep this code though) or optimize things like BSS clearing, etc.
On A15/A7/A12 you do not need to do cache/mmu/btb invalidation on post-reset, so this is done just for "paranoia" reasons. However, there might be cores which do not perform auto-invalidate on reset so this code just makes sure that the same behavior is preserved across different core types.
This is necessary in the cases where the invalidation is not done in hardware on a reset (cold or warm). Another more practical reason is that U-Boot is typically not the first piece of code that runs on the hardware. In most cases there would be the ROM code that runs before U-Boot and to avoid making any assumptions regarding the state of the hardware when U-Boot got control of the system it's safer to always try and get the hardware to a known state and proceed from there.
This question has already been answered for x86 however, I couldn't find much about ARM MP cpus like Cortex-A9, Cortex-A15 etc...
More importantly i want to know if interrupts can be raised on non-primary cpu without any configuration etc.
I am working on a software which deals only with the primary cpu hence i put the rest in WFI state however I am unaware of how interrupts work on the MP arm cpus, Is it possible that the main cpu continues executing code and one of the secondary cpu picks it up and jumps to the instruction in vector table and execute that code ?
btw here is the code I'm using to put them to low power mode
uint32_t reg;
__asm__ volatile("mrc p15, 0, %0, c0, c0, 5" : "=r" (reg));
reg &= 0xF;
if(reg > 0)
goto spin;
<code snipped>
spin:
for(;;)
cpu_idle(); // cpu_idle -> wfi
The short and for practical purposes correct answer is that what you ask for is not possible without some configuration being performed on the secondary cores...
The interrupt controller architecture is described (in quite some detail) in http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.ihi0048b/index.html
To prepare the secondary cores to receive IPIs, you need to:
Enable the GIC Distributor (once, for the whole system)
Enable the GIC CPU interface (for each core)
Enable the IPIs you want to receive (for each core)
Set the priorities for each IPI you want to receive (for each core)
Ensure the CPU interface Interrupt Priority Mask Register (for each core) is set to priority level lower (higher number) than the interrupt priority you set above.
Clear the CPSR I-bit (for each core)
If you don't intend to implement an interrupt handler, skip the clearing of the I-bit. The core will come out of WFI and continue executing. That is normally what you want for a system boot operation.
Which mode does the ARM SVC handler start in? Basically, I want to know which mode the ARM core is in when an SVC exception is raised?
Can't seem to find it in the ARM ARM, but my guess would be that it starts in Supervisor.
Are you talking about the SWI handler? Yes, I see some places they refer to it as the SWI instruction but sometimes the SVC instruction.
Note: In older versions of the ARM architecture, SVC was called SWI, Software Interrupt.
From the ARM ARM
Exception type Mode Address
----------------------------------------------
Reset Supervisor 0x00000000
Undefined Instruction Undefined 0x00000004
Software Interrupt (SWI) Supervisor 0x00000008
Prefetch Abort Abort 0x0000000C
Data Abort Abort 0x00000010
IRQ IRQ 0x00000018
FIQ FIQ 0x0000001C
...
Software Interrupt exception
The Software Interrupt instruction (SWI) enters Supervisor mode to request a particular supervisor (operating system) function. When a SWI is executed, the following actions are performed:
R14_svc = address of next instruction after the SWI instruction
SPSR_svc = CPSR
CPSR[4:0] = 0b10011 /* Enter Supervisor mode */
CPSR[5] = 0 /* Execute in ARM state */
/* CPSR[6] is unchanged */
CPSR[7]= 1 /* Disable normal interrupts */
/* CPSR[8] is unchanged */
CPSR[9] = CP15_reg1_EEbit /* Endianness on exception entry */
PC = 0x00000008
To return after performing the SWI operation, use the following instruction to restore the PC (from R14_svc) and CPSR (from SPSR_svc) and return to the instruction following the SWI:
MOVS PC,R14