cpu/cortexm_common: add function to check address for validity#10051
cpu/cortexm_common: add function to check address for validity#10051olegart wants to merge 1 commit intoRIOT-OS:masterfrom
Conversation
|
See #10052 for example |
|
@olegart would you address the codays issue please? |
jcarrano
left a comment
There was a problem hiding this comment.
Interesting functionality. Please see the issues regarding CPS and interrupts.
cpu/cortexm_common/cortexm_init.c
Outdated
| is_valid = false; | ||
| } | ||
|
|
||
| __asm volatile ("cpsie f;"); |
There was a problem hiding this comment.
What if the mask was disabled when calling this function. They will be enabled. Maybe it's better to save/restore the flag.
There was a problem hiding this comment.
I'm pretty sure people should not play with FAULTMASK without a very solid reason, so it should be enabled at all times except when doind some very specific things.
Also, not sure if it's a good idea to write FAULTMASK register directly - there's MSR/MRS instructions to do so, but I can't find if there are any undesired consequences compared to using CPS instructions. I've tried and MSR/MRS (__get_FAULTMASK / __set_FAULTMASK from CMSIS) work, but still not sure if it's ok to use it so.
Regular interrupts (controlled by irq_enable / irq_disable) won't change anyway, it's PRIMASK, not FAULTMASK.
P.S. Changed assember to inline CMSIS instructions.
There was a problem hiding this comment.
I'm pretty sure people should not play with FAULTMASK without a very solid reason, so it should be enabled at all times except when doind some very specific things.
Agreed, but I wanted to prevent any surprising weird interaction.
Also, not sure if it's a good idea to write FAULTMASK register directly
If you look at https://github.com/RIOT-OS/RIOT/blob/master/cpu/cortexm_common/irq_arch.c it is doing that (it's even using cmsis builtins). I'm not sure why it is doing what it is doing in irq_enable (I just opened a bug report - #10076).
It may work to have a fault_disable/fault_restore.
There was a problem hiding this comment.
Ok, as no one sees no harm either, I've changed CPS to direct access with MRS with FAULTMASK state preservation. Moved BFHFNMIGN after interrupts disables too.
P.S. Don't think we need separate fault_disable function in public API.
|
@PeterKietzmann Codacy is in disagreement with GCC here. |
7d7dd69 to
86a6a6e
Compare
In any case, using |
cpu/cortexm_common/cortexm_init.c
Outdated
| SCB->CFSR |= BFARVALID_MASK; | ||
|
|
||
| /* Ignore BusFault by enabling BFHFNMIGN */ | ||
| SCB->CCR |= SCB_CCR_BFHFNMIGN_Msk; |
There was a problem hiding this comment.
Sorry for not raising this before. Why is BFHFNMIGN set before disabling interrupts?
Doesn't work in newlib-nano. It builds, but produces some garbage. |
cpu/cortexm_common/cortexm_init.c
Outdated
| (void) address; | ||
|
|
||
| printf("[warning] %s: Cortex-M0 doesn't have BusFault\n", __func__); | ||
| return true; |
There was a problem hiding this comment.
Is there a use-case for having this compiled in on Cortex-M0? If not, I suggest guarding the whole function.
(returning true seems wrong)
There was a problem hiding this comment.
Or wouldn't it be possible to catch an "expected" hardfault and that way somehow replicate the functionality on M0?
There was a problem hiding this comment.
@kaspar030 Yes, just wrote a catcher for M0.
|
Added address probing for Cortex-M0 cores too. M0 doesn't have BusFault, so we need to catch intended HardFaults by looking for some magic numbers in registers, than set some other register to indicate HardFault has occured and return from HardFault to the next instruction. Here R1 and R2 are set with magic numbers (two different numbers just to be sure) and R5 is modified inside HardFault. Tested with STM32F042K6T6:
|
jcarrano
left a comment
There was a problem hiding this comment.
I ran the test in the SAMR21 (M0+) and KW22D (M4) . Seems to work. I wonder if there is some address that is invalid for most ARM chips, so that the test can be made automated (I prefer automated tests).
There's a couple of issues in the test that I missed in the previous reviews. Other than that I'm fine.
| @@ -0,0 +1,8 @@ | |||
| include ../Makefile.tests_common | |||
|
|
|||
| BOARD = nucleo-l152re | |||
There was a problem hiding this comment.
Please use a ?= for the board. It took me some time and a reboot to figure out why I could not flash.
| char *address; | ||
| uint32_t address_value; | ||
|
|
||
| sscanf(argv[1] + 2, "%lx", &address_value); /* ignore 0x prefix */ |
There was a problem hiding this comment.
Sorry for missing this one too. If argv[1] is shorter than 3 this code is dangerous. It also causes weirdness when inputting a number not in 0x format.
I suggest strtol with base=0.
There was a problem hiding this comment.
And some code to check if the parse is successful.
There was a problem hiding this comment.
Fixed.
No way to check parsing, as strtol outputs 0 in case of error, and 0 is a valid address. Still, user will see it.
There was a problem hiding this comment.
It can be done, but just leave it, it's a test after all. The important thing is that it does not blow up and that is already fixed.
BTW, here is how to do it:
In particular, if *nptr is not '\0' but **endptr is '\0' on return, the entire string is valid.
There was a problem hiding this comment.
All issues addressed. Code tested in M0+ and M3.
I think @kaspar030's issues regarding M0 support were addressed too.
|
@olegart Squash, fix the whitespace issue and we're ready to go (I was waiting for @kaspar030 because I did not want to just dismiss his review.) |
e2f8ad9 to
066d508
Compare
|
Done.
Addresses above 0xEFFFFFFF should be. And 0xE0000000 should be valid on all Cortex-M as it's the beginning of a Cortex Private Peripheral Bus. |
|
Seems like clang does not like the assembly code. Also, what happened to the test? Are you splitting it up? |
066d508 to
ecdc79e
Compare
|
Yep, it seems GCC and CLANG have a bit different assembler understanding. This should satisfy both. |
|
The test is failing because the CI is trying to build it for non-ARM boards. Unfortunately we don't have a way to blacklist based on architecture. Two options:
|
|
@olegart @jcarrano Hi, I would like to use the PR to get low power for stm32l1, it seems this was ready to merge except for the white list part. @olegart do you think you can add the whitelist part and rebase it? if not, and if you don't mind I can use your branch and implement the changes needed to merge. |
|
@fjmolinas I'm not the author, but I think it should be fine. I already took over one of @olegart's PRs dealing with AES. He will get credited anyway. I'll review it. |
Contribution description
Adds extremely useful function to check memory addresses for validity on Cortex-M3/M4/M7 MCUs.
Can be used to determine memory sizes, peripherals availability, etc. in runtime to build firmware that runs effectively on a differenent MCUs without recompiling.
Testing procedure
Build and run tests/cpu_cortexm_address_check for your board, then type 'check address' in the shell, where address is a memory address in hex notation (with '0x' prefix). Check your MCUs' datasheet for memory map.
E.g. on STM32L152RET6:
(0x1FF01999 is an upper address of the System Memory section)
Issues/PRs references
Cortex-M0 not supported, it needs completely different approach.P.S. Will provide real-world usage example in the next PR.