Cortex M3 in privileged mode - arm

I want ot make output debug information via SWO (use ITM). Core Cortex M3 can do it.
The ITM is a an application driven trace source that supports printf style debugging to trace
Operating System (OS) and application events, and emits diagnostic system information...
link
For this I have to configure ITM registers.Part of them I can write only in privileged mode.
ITM Trace Privilege Register
Use the ITM Trace Privilege Register to enable an operating system to control which stimulus ports are accessible by user code.
Note:
You can only write to this register in privileged mode. see ITM Trace Privilege Register
What is the best way to switch in privileged mode if IRQs SVC, PendSV, SysTick has already used? (I use FreeRTOS) Is it real?

Either you configure ITM before starting FreeRTOS (considering the FreeRTOS tasks run in non-privilege mode).
Or you add support for a new SVC. FreeRTOS SVC uses svc 0, you could add support for a new svc, let's call it svc 1 and your SVC_Handler() will either redirect svc 0 to FreeRTOS or svc 1 to your ITM configuration code.

Related

How do I enter supervisor mode on the ARM Cortex m4 to disable interrupts?

Im trying to find out how I can disable and enable interrupts on the STM32L4x6RG Nucleo?
After a bit of googling I found the macros __disble_irq() and __enable_irq() but I'm not convinced these are disabling interrupts.
After more investigation it seems that the cpsid instruction this macro maps to only has effect when it runs in supervisor context. So the question becomes how do I move to supervisor mode to disable interrupts and back again??
I found the macros __disble_irq() and __enable_irq() but I'm not
convinced these are disabling interrupts.
They do, unless you (or the OS you are using) explicitly leave privileged mode with the MSR control, Rn instruction, or the __set_CONTROL() function, which does the same.
So the question becomes how do I move to supervisor mode to disable
interrupts and back again??
The processor is in privileged mode after reset, and stays in it unless you tell it otherwise. It also enters privileged mode temporarily when executing an exception handler.
You can use the SVC instruction to call the SVC exception handler from user code, and run some code in privileged mode. There is a problem though, that the SVC handler invocation would be blocked too by __disable_irq(), so there would be no way to reenable them afterwards. Instead of __disable_irq(), you can adjust the BASEPRI register to selectively disable lower priority interrupts, and set SVC priority higher so that it would not be blocked.
The processor boots in privileged mode so unless you are running your application on top of an operating system or have switched to unprivileged mode yourself you should already be in privileged mode. If you are running you application on top of an OS you should use its services to handle interrupts and if no such service exists you should leave the interrupts alone.
If you have switched to unprivileged-mode yourself, you can use the svc instruction to trigger an svc-exception and the handler for the exception executes in privileged mode.

Enter Hypervisor Mode on ARMv7 through Kernel Module

I am working on a project where I have a router with ARMv7 processor (Cortex A15) and OpenWRT OS. I have a shell on the router and can load kernel modules with insmod.
My goal is to write a kernel module in C which changes the HVBAR register and then executes the hvc instruction to get the processor in the hyp mode.
This is a scientific project where I want to check if I can place my own hypervisor on a running system. But before I start to write my own hypervisor I want to check if and how I can bring the processor in the hyp mode.
According to this picture take from armv7-a manual B.9.3.4 the system must be in insecure mode, not in user mode and the SCR.HCE bit must be set to 1.
My question is how I can prepare the processor with a C kernel module and inline assembly and then execute the hvc instruction. I want to do this with a kernel module because then I start in PL1. This pseudocode describes what I want to achieve:
call smc // to get in monitor mode
set SRC.HCE to 1 // to enable hvc instruction
set SRC.NS to 1 // to set the system to not secure
call hvc #0 // call the hvc instruction to produce a hypervisor exception
The easiest way to elevate privilege is to start off in the needed privilege mode already: You've a root shell. Is the boot chain verified? Could you replace bootloader or kernel, so your code naturally runs in PL2 (HYP) mode? If so, that's probably the easiest way to do it.
If you can't replace the relevant part of the boot chain, the details of writing the rootkit depend a lot on information about your system left out: In which mode is Linux started? Is KVM support enabled and active? Was PL2 initialized? Was it locked? Is there "secure" firmware you can exploit?
The objective is always the same: have HVBAR point at some code you can control and do a hvc. Depending on your environment, solutions may range from spraying as much RAM as possible with your code and hope (perhaps after some reboots) an uninitialized HVBAR would point at an instruction you control to inhibiting KVM from running and accessing the early hypervisor stub to install yourself instead.
Enumerating such exploits is a bit out of scope for a StackOverflow answer; this is rather dissertation material. Indeed, there's a doctoral thesis exactly on this topic:
Strengthening system security on the ARMv7 processor architecture with hypervisor-based security mechanisms

Checking if ARM is in supervisor mode or interrupt mode during kernel bootup

I have to check whether the ARM processor is in SVC or IRQ mode during kernel bootup. That is, I want to insert some code to check the ARM mode into start_kernel() function before the interrupts are enabled and after the interrupts are enabled.
I know that I need the SPSR or CPSR values(bits) to check the mode in ARM, but how can I write code for that in start_kernel function since the code for reading bits of CPSR/SPSR is in assembly? Where do I put the assembly code to check the ARM mode during bootup time? Is there any way to dump the SPSR/CPSR values?
I don't dare imagine why this should be a concern, but fortunately there's an easy answer:
It's in SVC mode.
The very first thing* the kernel entrypoint does is to forcibly switch into SVC mode and mask interrupts. To somehow be in the wrong mode by the time you reach C code in start_kernel way later would need the system to be unimaginably horribly broken. The only way I can conceive of that even being possible is if there is some Secure firmware running asynchronously (e.g. off a Secure timer interrupt) which deliberately corrupts the Non-secure state, and that's sufficiently ridiculous to discount.
* OK, the second thing if the kernel is built with KVM support and entered in HYP, but hey...
after the boot the ARM processor is in secure SVC mode during this mode you can access CPSR register(first 6 bits) to check in which mode however when the kernel is runing you are in user non-secure mode and in this mode non secure you can't access the the CPSR and SPSR register and also copro 15 register .
The only way is to write a code that generate an exception to switch monitor mode " using SMC assebmbly instruction" to jump to monitor secure mode then in that mode you reset the "NS" bit to switch to non-secure then you generate another exception to switch the SVC mode(SVC instruction assembly call) now you are in supervisor secure mode and you can then access CPSR and SPSR register

RTOS within an RTOS

I'm planning to run an RTOS e.g Nuttx as a Process of another RTOS e.g FreeRTOS such that freertos tasks and the Nuttx running as a Freertos task would co-exist.
Would this be feasible implementation given that the underlying hardware is an ARM cortex A8 single core processor? What changes could be required if the implementation is not based on VM concept?
Your requirement, in a nutshell, is to allow a GUEST RTOS to completely work within the realms of an underlying HOST RTOS. First answer would be to use virtualization extension, but A8 processor does not have that, hence will rule this option out. Without Virtualization extensions you have to resort to one of the following methods and would require a lot of code changes.
Option 1 - Port your GUEST OS API's
Take all your GUEST OS API's and replace their implementation, so that it mimics the required API behavior by making use of HOST OS's API's. Technically now your GUEST OS will not have a scheduler, and will be reduced to a porting layer on top of your HOST OS. This method is used by companies when they need their software solutions to work across multiple RTOS's. They would write their software solution based on an RTOS. When a customer comes to them with a requirement to run the software on their RTOS, they would simply port the RTOS API implementations on to the customer's RTOS.
Option 2 - Para-virtualization
Your guest RTOS user and kernel space should both work inside the userspace of your host RTOS. Let us break the problem into a few parts.
Handling Privileged Instructions
When your Guest OS, while executing in "Kernel mode" tries to execute a privileged instruction, will cause an undef instruction abort. You have to modify the undef instruction abort handler of your host kernel to trap/intercept these instructions and act on them. Every single privileged instructions has to be trapped/intercepted and 'simulated'. There are some instructions that wouldn't trap but would need to be handled by modifying code. Eg. If your kernel code reads CPSR to confirm the execution mode, CPSR would say the mode is User mode. (This instruction wouldn't cause an instruction abort, so you could not follow the trap and simulate model. The only way is to identify, search and replace these instructions in your GUEST OS codebase.)
Memory Management Unit
If a privilege violation happens the Data Abort will be triggered to your host OS. It has to be forwarded to your guest OS.
Interrupts
You would have to replace your GUEST OS's interrupt controller driver with dummy SVC calls that would call into your HOST OS to setup interrupts.
Timers
You would have to modify your GUEST timer driver to account for 'lost' ticks when you were running your HOST OS tasks.
Hardware Drivers
All other hardware drivers used by your GUEST OS have to be modified to allow device sharing between GUEST and HOST.
Schedulers
Your GUEST OS scheduler now works inside (and thus is at the mercy of ) another scheduler (HOST OS Scheduler).
It is feasible.
You need to separate resources: memory, timers, IRQs, etc. So that, "Host" OS (FreeRTOS) don't even "know" about resources used by "Guest" OS (Nuttx).
For Cortex-A8 you may want to use IRQ for FreeRTOS and FIQ for GuestOS. It will let you not to rewrite IRQ controller (but again, make sure Host does not control FIQ after GuestOS started).
And some changes might be required for context switch: you need to differ Host-Host context switch, Host-Guest (and Guest-Host) and Guest-Guest context switch.
Though not direct answer to your question, address this problem at design level, do a separation of code that depends hardware (create API) and make the application level code independent of the underlying OS or runtime i.e rather depend on particular implementation let it depend on the API.
where ever needed port the hardware (OS) dependent code to the underlying OS/Runtime

ARM TrustZone, Hypervisor: Hypervisor functionality WITHOUT Virtualization Extensions

I have found some interesting information regarding CPU virtualization for ARM and I'm wondering if you guys could help me understand more about it.
Basically, folks at some company called SierraWare have developed an ARM secure-mode OS called SierraTEE that (they say) virtualizes a guest OS like Linux/Android running in non-secure mode, needing only the Security Extensions. A piece of information from one of their presentation documents has caught my attention, specifically at page 19 of this PDF http://www.sierraware.com/sierraware_tee_hypervisor_overview.pdf they state:
Integrity checks for Rootkits and Kernel Hacks:
Monitor Syscall interrupt and interrupt handler. This will ensure that core syscalls are not tampered with.
By "Syscall interrupt" I understand SVC (=old SWI) instruction executions (correct me if I'm wrong), but by "monitoring" I'm not really sure because it could be real-time monitoring, from-time-to-time monitoring or on certain-events monitoring. In my mind they could monitor the SVC handler to prevent tampering-with by either:
Inspect SVC handler from time to time (timer interrupt for instance, since IRQs and FIQs can be routed to monitor mode) - PatchGuard-like approach, doesn't seem very useful to me
Inspect SVC handler on SVC instruction execution (=certain-events monitoring)
Trap SVC handlers memory region write-access (=real-time monitoring)
Regarding approach 2: would it be possible to trap non-secure SVC instruction executions from secure-mode?
Regarding approach 3: would it be possible to hook non-secure memory-region writes by using only the Security Extensions?
Thanks very much in advance
"Monitor" here may refer to the Monitor mode, the new mode added by the Security Extensions.
I'm not very familiar with the Security Extensions but I imagine it should be possible to mark specific memory regions as secure so any access to them will result in a Monitor mode trap, which can then handle the access and resume the non-secure code execution.
However, I just found this notice in the ARM ARM (B1.8.7 Summaries of asynchronous exception behavior):
In an implementation that includes the Security Extensions but does
not include the Virtualization Extensions, the following
configurations permit the Non-secure state to deny service to the
Secure state. Therefore, ARM recommends that, wherever possible, these
configurations are not used:
Setting SCR.IRQ to 1. With this configuration, Non-secure PL1 software can set CPSR.I to 1, denying the required routing of IRQs to
Monitor mode.
Setting SCR.FW to 1 when SCR.FIQ is set to 1. With this configuration, Non-secure PL1 software can set CPSR.F to 1, denying
the required routing of FIQs to Monitor mode.
The changes introduced by the Virtualization Extensions remove these
possible denials of service.
So it would seem it's not possible to achieve perfect virtualization with just Security Extensions.

Resources