I have come across the fact that Arm V7 ISA supports unaligned memory access for some load and store instructions and the A bit in SCTLR controls whether an alignment fault is raised when unaligned access is tried .I wanted to know what instruction can be used to write or read the SCTLR .I found MRS /MSR will act only on CPSR
From Cortex-A9 TRM 4.3.9:
MRC p15, 0,<Rd>, c1, c0, 0; Read SCTLR
MCR p15, 0,<Rd>, c1, c0, 0; Write SCTLR
Additional notes:
Attempts to read or write the SCTLR from secure or Non-secure User modes result in an Undefined Instruction exception.
Attempts to write to this register in secure privileged mode when CP15SDISABLE is HIGH result in an Undefined Instruction exception.
Attempts to write secure modify only bits in non-secure privileged modes are ignored.
Attempts to read secure modify only bits return the secure bit value.
Attempts to modify RO bits are ignored.
Related
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.
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.
According to some tutorials, we will disable MMU and I/D-Caches at the beginning of bootlaoder. If I understand correctly, it aims to use the physical address directly in the program, so please correct me if I'm wrong. Thank you!
Secondly, we do this to disable MMU and Caches:
mrc P15, 0, R0, C1, C0, 0
bic R0, R0, #0x00002300 # clear bits 13, 9:8
bic R0, R0, #0x00000087 # clear bits 7, 2:0
orr R0, R0, #0x00000002 # set bit 2 (A) Align
orr R0, R0, #0x00001000 # set bit 12 (I) I-Cache
mcr P15, 0, R0, C1, C0, 0
D-Cache, MMU and Data Address Alignment Fault Checking have been disabled by clear bits 2:0, but why we enable bit 2 immediately in the following instrument? To make sure this manipulation is valid?
Last question is why D-cache is disabled but I-caches is able? To speed up instrument process?
Last question is why D-cache is disabled but I-caches is able? To speed up instrument process?
The MMU has settings to determine which memory regions are cacheable or not. If you do not have the mmu on but you have the data cache on (if possible) then you cannot safely talk to peripherals. if you read the uart status register for example that goes through the cache just like any other data operation, whatever that status is stays in the cache for subsequent reads until such time as that cache line is evicted and you get one more shot at the actual register. Lets say for example you have some code that polls the uart status register waiting for a character in the rx buffer. If that first read shows there is no character, that status goes in the cache, you will remain in the loop forever since you will never get to talk to the status register again you will simply get the cached copy of the register. if there was a character in there then that status also gets cached, you read the rx register, and perhaps do something, if when you come back again if the status has not been evicted from the data cache then you get the stale status which shows there is a character, you rx buffer read may or may not also be cached so you may get the stale value in the cache, you may get a stale value or whatever the peripheral does when you read and there is no new value or you might get a new value, but what you dont get in these situations is proper access to the peripheral. When the mmu is on, you use the mmu to mark the address space used by that peripheral as non-(data)-cacheable, and you dont have this problem. With the mmu off you need the data cache off for arm systems.
Leaving the I-cache on is okay because instruction fetches only read instructions...Well for a bare metal application that is okay, it helps for example if you are using a flash that has a potential for read disturb (spi or i2c flashes). The problem is this application is a bootloader, so you must take some extra care. For example your bootloader has some code at address 0x8000 that it runs through at least once, then you choose to use it as a bootloader, the bootloader might be at say address 0x10000000 allowing you to load a new program at 0x8000, this load uses data accesses so it does not go through the instruction cache. So there is a potential that the instruction cache has some or all of the code from the last time you were in the 0x8000 area, and when you branch to the bootloaded code at 0x8000 you will get either the old program from cache or a nasty mixture of old program and new program for the parts that are cached and not cached. So if your bootloader allows for the i-cache to be on, you need to invalidate the cache before branching to bootloaded code.
Lastly, if you or anyone using this bootloader wants to use jtag, then you have that same problem but worse, data cycles that do not go through the i-cache are used to write the new program to ram, when you tell the jtag debugger to then run the new program you will get 1) only the new program, 2) a mixture of the new program and old program fragments from cache 3) the old program from cache.
So d-cache is bad without an mmu because of things that are not in ram, peripherals, etc. The i-cache is a use at your own risk kind of thing which you can mitigate except for the times that jtag is used for debugging.
If you have concerns or have confirmed read-disturb in your (external) flash, then I recommend turn on the i-cache, use a tight loop to copy your application to ram, branch to the ram copy and run there, turn off the i-cache (or use at your own risk) and dont touch the flash again, certainly not heavy read accesses to small areas. A tight uart polling loop like you might have for a command line parser, is a really good place to get hit with read-disturb.
You did not specified on which ARM you are working. Capabilities may vary from one ARM to an other (there is a huge gap between an ARM9 and an ARM Cortex A15).
In the given code, bit 2 is cleared and then set, but it does not matter, as those changes are done in R0. There is no change in the ARM behavior until the write in CP15 register (done by the instruction mcr P15, 0, R0, C1, C0, 0).
Concerning d-cache/i-cache enabling, it is only a matter of choice, there is no requirement. On the products I work on, the bootloader enables L1 I-cache, D-cache, L2 cache, and MMU (and it disables all that stuff before jumping on Linux). Be sure to follow ARM documentations about cache invalidation and memory barriers (according to your actual ARM Core) if you use cache and MMU in your bootloader.
This question will be short and sweet.
I know an instruction can occur between instruction but can an interrupt happen during an instruction? Can a load multiple instruction be interrupted before it's loaded all the values into the registers?
mov r0, r1
< interrupt can happen here
ldm r0, {r1-r4} < can an interrupt happen **during** a load multiple instruction?
The load multiple instructions are explicitly not atomic. See section A3.5.3 of the ARM V7C architecture reference manual.
LDM, LDC, LDC2, LDRD, STM, STC, STC2, STRD, PUSH, POP, RFE, SRS, VLDM,
VLDR, VSTM, and VSTR instructions are executed as a sequence of
word-aligned word accesses. Each 32-bit word access is guaranteed to
be single-copy atomic. The architecture does not require subsequences
of two or more word accesses from the sequence to be single-copy
atomic.
If you read on, you'll find out that the LDM/STM instructions can be aborted by an interrupt (and restarted from the beginning on interrupt return). LDM and STM instructions can always be interrupted by a data abort, so they're non atomic in that sense. Otherwise, the ARMv7-A architecture does its best to help you out. For interrupts, they can only be interrupted if low interrupt latency is enabled, AND normal memory is being accessed. So at the very least, you won't get repeated accesses to device memory. You don't want to do anything that expects atomic read/writes of normal memory though.
On v7-M, LDM and STM can be interrupted at any time (see section B1.5.10 of the ARMv7-M Architecture Reference Manual). It's implementation defined whether or not the instruction is restarted from the beginning of the list of loads/stores, or whether it's restarted from where it left off. As the ARM says:
The ARMv7-M architecture supports continuation of, or restarting from
the beginning, an abandoned LDM or STM instruction as outlined below.
Where an LDM or STM is abandoned and restarted (ICI bits are not
supported), the instructions should not be used with volatile memory.
In other words, don't rely on LDM or STM being atomic if you're trying to write portable code.
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.