工具与软件:
您好!
我正在尝试访问堆栈以检查其溢出。 我导致输入默认处理程序。 我想这是因为堆栈空间受到 MPU 的保护。
应用程序是否有机会进入处理模式? (内部控制寄存器是否可用于应用?)
Cortex-M0+中使用 Arm6-M 的 API 在哪里? 我只找到 mpu_armv7.h 但 MSPM0使用 Arm6-M 是否有示例?
谢谢!
起重机
This thread has been locked.
If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.
工具与软件:
您好!
我正在尝试访问堆栈以检查其溢出。 我导致输入默认处理程序。 我想这是因为堆栈空间受到 MPU 的保护。
应用程序是否有机会进入处理模式? (内部控制寄存器是否可用于应用?)
Cortex-M0+中使用 Arm6-M 的 API 在哪里? 我只找到 mpu_armv7.h 但 MSPM0使用 Arm6-M 是否有示例?
谢谢!
起重机
尊敬的 EASON:
感谢您的答复。
我检查了这两个示例、但没有看到它们使用的是 MPU。 两个示例都只是进行了计算。 附带的是我得到的东西。
e2e.ti.com/.../mathacl_5F00_mpy_5F00_div_5F00_op.c
e2e.ti.com/.../mathacl_5F00_trig_5F00_op.c
此致、
起重机
抱歉、我误解了 MPU。 由于这是 ARM CPU 的纯外设、因此我们不提供示例。
在提及我的同事后、我在内部找到了一个示例。 请检查它。
谢谢伊森!
似乎 mpu_armv7.h 中的 API 也适用于 MCU。
另一个问题出现了。
我将为所有区域的访问权限设置为特权级和非特权级完全访问权限、如示例中所示。 (MPU_RASR 寄存器 AP 值为011)。
我将子区控制更改为"全部启用"。 (MPU_RASR 寄存器的 SRD 位全部为0)。
但它仅在特权启用时才用于访问 RAM、如示例所示。 (MPU_CTRL 寄存器 PRIVDEFENA 位为1)。
我的理解是、只要 AP 和 SRD 在 RAM 区域设置为"完全访问"、那么无论是否在 MPU 控制寄存器中启用特权、RAM 都应该是可访问的。
我的经验是无论8个子区域全部设置为0或1、SRD 都无法控制。
我的理解不正确或有什么遗漏。
谢谢!
起重机
抱歉、正如我说过的、该代码是由我的同事提供的。 以下是 Chatgpt 的回复:
根据您的观察结果、您遇到的行为似乎与 MPU_CTRL 寄存器中的 PRIVDEFENA 位有关。 如果 PRIVDEFENA 位设置为1、则使用特权模式的默认存储器映射、这可能会限制对 RAM 区域的访问。 要允许特权模式和非特权模式对 RAM 区域进行完全访问、您可能需要确保 PRIVDEFENA 位设置为0。
我的建议是:
1.检查当 PRIVDEFENA =0时是否有用
2.在调试模式下检查寄存器是否设置正确。
不会保持不变。
根据我的理解、只要该区域设置为完全访问(AP 011)并且其 子区域已启用(特定子区域的 SRD 0)、就应该可以访问 RAM、无论是否启用特权模式(PRIVDEFENA 0或1)。
但并非如此、只有在启用特权模式(PRIVDEFENA 1)时、才能访问 RAM。 一旦被禁用、无论 AP 和 SRD 如何设置、访问 RAM 都将始终导致故障。
昨天、我回读这些 MPU 寄存器的真实值以确认它们是否设置正确。 根据上一次发布中的屏幕截图、将其设置为我要设置的值。
(在配置中、RAM 是第一个区域。 从屏幕截图中、RAM 区域设置为"完全访问"(AP 为0x3)、其 SRD 为0xC0。
访问0x20207C00会导致故障、这是可以理解的、因为0x207C00所在子区域的 SRD 为1。
但是、访问0x20202000也会导致出现故障。 我不明白为什么这也会导致故障、因为它的 SRD 为0。
在相同设置下、我还尝试将 整个 RAM 的 SRD 更改为0x00 以启用所有子区域、但访问0x207C00仍会导致故障。
)
不过、我的问题是:我对该区域上的 AP、SRD、PRIVDEFENA 控制的理解是不正确的、或者在配置这些寄存器时是否存在任何缺失?
谢谢!
起重机
尊敬的 Crane:
我曾使用 MPU 演示进行测试。 我的测试指的是以下内容:(项目优化级别设置为"0")
#include "ti_msp_dl_config.h" #define MAIN_SRAM_BASE_ADDRESS (0x20200000U) #define MAIN_SRAM_TEST_ADDRESS (0x20204000U) #define MAIN_FLASH_BASE_ADDRESS (0x00000000U) #define MAIN_FLASH_TEST_ADDRESS (0x00002000U) /* 32-bit data to write to flash */ uint32_t gData32 = 0x12345678; uint32_t rData32 = 0; volatile DL_FLASHCTL_COMMAND_STATUS gCmdStatus; /* Codes to understand where error occured */ volatile uint8_t gErrorType = 0; #define NO_ERROR 0 #define ERROR_ERASE 1 #define ERROR_8BIT_W 2 #define ERROR_16BIT_W 3 #define ERROR_32BIT_W 4 #define ERROR_64BIT_W 5 /* SRAM absolute address variable */ uint32_t ramData __attribute__((location(MAIN_SRAM_TEST_ADDRESS))) = 0x1; /* MPU TEST function */ void FLASH_TEST(void); void SRAM_TEST(void); void PERI_TEST(void); int main(void) { SYSCFG_DL_init(); /* Default is privileged mode in thread mode*/ /* IMPORTANT: Only privileged software can write to the CONTROL register to change the privilege level for software execution in Thread mode. */ // __set_CONTROL(__get_CONTROL() & ~CONTROL_nPRIV_Msk); /* Disable MPU */ ARM_MPU_Disable(); /*------------------------------------------*/ /* Configure Flash Region */ /* Region 0 - Device Type, Instruction access disable, No data access permission */ MPU->RBAR = ARM_MPU_RBAR(0, MAIN_FLASH_BASE_ADDRESS); MPU->RASR = ARM_MPU_RASR_EX(1, ARM_MPU_AP_NONE, ARM_MPU_ACCESS_DEVICE(0), 0, ARM_MPU_REGION_SIZE_128KB); /* Region 1 - Device Type, Instruction access enable, Data access permission-Privileged access */ MPU->RBAR = ARM_MPU_RBAR(1, MAIN_FLASH_BASE_ADDRESS); MPU->RASR = ARM_MPU_RASR_EX(0, ARM_MPU_AP_PRIV, ARM_MPU_ACCESS_DEVICE(0), 0, ARM_MPU_REGION_SIZE_64KB); /* Region 2 - Normal Type, Instruction access enable, Data access permission-Full */ MPU->RBAR = ARM_MPU_RBAR(2, MAIN_FLASH_BASE_ADDRESS); MPU->RASR = ARM_MPU_RASR_EX(0, ARM_MPU_AP_FULL, ARM_MPU_ACCESS_NORMAL(1,1,0), 0, ARM_MPU_REGION_SIZE_32KB); /*------------------------------------------*/ /* Configure SRAM Region */ /* Region 3 - Normal Type, Instruction access enable, Data access permission-Privileged read only */ MPU->RBAR = ARM_MPU_RBAR(3, MAIN_SRAM_BASE_ADDRESS); MPU->RASR = ARM_MPU_RASR_EX(0, ARM_MPU_AP_FULL, ARM_MPU_ACCESS_NORMAL(1,1,0), 0, ARM_MPU_REGION_SIZE_32KB); // 0KB-32KB Full Access MPU->RBAR = ARM_MPU_RBAR(4, MAIN_SRAM_TEST_ADDRESS); MPU->RASR = ARM_MPU_RASR_EX(0, ARM_MPU_AP_PRO, ARM_MPU_ACCESS_NORMAL(1,1,0), 0, ARM_MPU_REGION_SIZE_8KB); // 16KB-24KB SRAM read only /*------------------------------------------*/ /* Configure Peripheral Region */ /* Region 4 - Device Type, Instruction access disable, Data access permission-Full */ MPU->RBAR = ARM_MPU_RBAR(5, GPIOA_BASE); MPU->RASR = ARM_MPU_RASR_EX(1, ARM_MPU_AP_FULL, ARM_MPU_ACCESS_DEVICE(0), 0, ARM_MPU_REGION_SIZE_8KB); /* Region 5 - Device Type, Instruction access disable, Data access permission-Privileged access */ MPU->RBAR = ARM_MPU_RBAR(6, GPIOB_BASE); MPU->RASR = ARM_MPU_RASR_EX(1, ARM_MPU_AP_PRIV, ARM_MPU_ACCESS_DEVICE(0), 0, ARM_MPU_REGION_SIZE_8KB); /*------------------------------------------*/ /* Enable MPU */ /* Enables use of the default memory map as a background region for privileged software accesses. */ ARM_MPU_Enable(0x5); /*------------------------------------------*/ /* TEST MPU Access */ // FLASH_TEST(); // SRAM_TEST(); // PERI_TEST(); while (1) { } } void HardFault_Handler(void){ /* Enter an infinite loop. */ while (1) { } } void FLASH_TEST(void){ /*---------------FLASH TEST-----------------*/ /* Unprotect sector in main memory with ECC generated by hardware */ DL_FlashCTL_unprotectSector( FLASHCTL, MAIN_FLASH_TEST_ADDRESS, DL_FLASHCTL_REGION_SELECT_MAIN); /* Erase sector in main memory */ gCmdStatus = DL_FlashCTL_eraseMemoryFromRAM( FLASHCTL, MAIN_FLASH_TEST_ADDRESS, DL_FLASHCTL_COMMAND_SIZE_SECTOR); if (gCmdStatus == DL_FLASHCTL_COMMAND_STATUS_FAILED) { /* If command was not successful, set error flag */ gErrorType = ERROR_ERASE; } if (gErrorType == NO_ERROR) { /* 32-bit write to flash in main memory with ECC generated by hardware */ DL_FlashCTL_unprotectSector( FLASHCTL, MAIN_FLASH_TEST_ADDRESS, DL_FLASHCTL_REGION_SELECT_MAIN); gCmdStatus = DL_FlashCTL_programMemoryFromRAM32WithECCGenerated( FLASHCTL, MAIN_FLASH_TEST_ADDRESS, &gData32); if (gCmdStatus == DL_FLASHCTL_COMMAND_STATUS_FAILED) { /* If command was not successful, set error flag */ gErrorType = ERROR_32BIT_W; } } unsigned int flashRead_8KB = *(unsigned int *)(MAIN_FLASH_TEST_ADDRESS); rData32 = flashRead_8KB; __BKPT(0); // Flash write-read pass at 0x2000 (8KB) unsigned int flashRead_32KB = *(unsigned int *)(4*MAIN_FLASH_TEST_ADDRESS); __BKPT(0); // Flash read pass at 0x8000 (32KB) unsigned int flashRead_64KB = *(unsigned int *)(8*MAIN_FLASH_TEST_ADDRESS); __BKPT(0); // Flash read at 0x10000 (64KB) -> expected to trigger hardfault /*------------------------------------------*/ } void SRAM_TEST(void){ /*---------------SRAM TEST-----------------*/ rData32 = ramData; __BKPT(0); // SRAM read pass at 0x20204000 (16KB) // ramData = 0x2; // __BKPT(0); // SRAM write at 0x20204000 (16KB) -> expected to trigger hardfault __set_CONTROL(__get_CONTROL() | CONTROL_nPRIV_Msk); // Unprivileged thread mode rData32 = 2; __BKPT(0); // SRAM write pass at &rData32 rData32 = ramData; __BKPT(0); // SRAM read at 0x20204000 (16KB) -> expected to trigger hardfault /*------------------------------------------*/ } void PERI_TEST(void){ /*-------------Peripheral TEST--------------*/ __set_CONTROL(__get_CONTROL() | CONTROL_nPRIV_Msk); // Unprivileged thread mode DL_GPIO_reset(GPIOA); DL_GPIO_enablePower(GPIOA); delay_cycles(POWER_STARTUP_DELAY); __BKPT(0); // GPIOA operation pass DL_GPIO_reset(GPIOB); DL_GPIO_enablePower(GPIOB); delay_cycles(POWER_STARTUP_DELAY); __BKPT(0); // GPIOB operation -> expected to trigger hardfault /*------------------------------------------*/ }
在 SRAM_TEST 中、我可以在非特权模式下访问完全访问 SRAM 值(0x20200000)。
如果您设置了访问类型的较高顺序、它将覆盖您的较低顺序设置(如果地址重叠)。 一阶是最低优先级。
也许您可以检查这个部件。
B.R.
SAL
尊敬的 Sal:
我意识到该故障不是 在访问 RAM 时引起的、而是从 MPU init 函数返回时引起的。 该函数如下所示:
void drvMpu_init(void) { uint32_t i; __DMB(); // Make sure outstanding transfers are done MPU->CTRL = 0; // Disable the MPU for ( i= 0; i < 4; i ++) { // Configure only 4 regions MPU->RNR = i; // Select which MPU region to configure MPU->RBAR = mpu_RBAR_config[i]; // Configure region base address register MPU->RASR = mpu_RASR_config[i]; // Configure region attribute and size register } for (i = 4; i < 8; i ++) {// Disabled unused regions MPU->RNR = i; // Select which MPU region to configure MPU->RBAR = 0; // Configure region base address register MPU->RASR = 0; // Configure region attribute and size register } MPU->CTRL = MPU_CTRL_ENABLE_Msk; // Enable the MPU //MPU->CTRL = MPU_CTRL_ENABLE_Msk | MPU_CTRL_PRIVDEFENA_Msk; // Enable the MPU and privileged access __DSB(); // Memory barriers to ensure subsequence data & instruction __ISB(); // transfers using updated MPU settings }
启用特权模式后、将正常运行、稍后从该函数返回并访问 RAM。
但是、如果未启用特权模式、 则 在从该函数返回到主函数后立即产生故障。 为什么会发生这种情况?
从 EASON 分享的原始示例中、我不知道该函数在其中被调用。 我想知道未启用特权模式时、此功能是否存在任何问题。
谢谢!
起重机
尊敬的 Sal:
我 在函数返回后立即发现为什么会出现硬故障。 这不是因为 第7行、而是因为堆栈的 可访问性。
以下是如何设置区域:
如果堆栈区域设置为完全访问、但所有子区域都被禁用并且权限级别未启用、那么在该函数返回后会立即引起硬故障。
如果堆栈区域被设置为 FULL ACCESS、那么所有子区域都被启用、但特权级未被启用、那么该函数可以成功返回、但稍后访问堆栈仍会导致硬故障。
最后、将问题缩小至以下范围:
为什么即使堆栈区域设置为完全访问(AP = 3)、其子区域都处于启用状态(SRD = 0x00)且特权未启用、堆栈也仍然不可访问? 该区域是否受 MPU 保护之外的其他保护?
这是所有区域的 MPU 配置。
区域0:MPU_RBAR:0x20200000 MPU_RASR:0x0302C01D -> RAM
区域1:MPU_RBAR:0x00000001 MPU_RASR:0x0302C021 ->闪存
区域2:MPU_RBAR:0x400A0002 MPU_RASR:0x0301011F ->外设
区域3:MPU_RBAR:0x400C0003 MPU_RASR:0x0301001F -> Flash 控制
区域4:MPU_RBAR:0x20207804 MPU_RASR:0x03020015 -> RAM 中的堆栈
区域4是堆栈(0x20207800 ~ 0x20208000)。 应在非特权级访问它。 但不能。
谢谢!
起重机
尊敬的 Sal:
我发现了问题。 这不是因为栈不可访问,而是因为 printf()的其他原因。 如果我使用自己的 printf()、调用字符串函数(如 strlen()、strcpy())时会出现硬错误。 我 想知道特权模式如何影响 printf()和 strlen()的执行。 栈大小对于 printf()足够大。 有什么想法吗?
我努力想要控制住。 由于设置断点在这段代码中不起作用、我无法确认哪个语句导致了这种情况。
tempMsg[0U] = '\0'; for(uint32_t i=0; i<CONSOLE_BUFFER_LEN; i++) { tempMsg[i] = '\0'; } len = strlen(message); strncpy(oldMsg, message, len);
如果我根本不使用 printf (从 string.h 和我自己的都使用)、从以下函数返回时仍会导致硬错误:
__STATIC_INLINE uint32_t DL_SPI_getRawInterruptStatus( SPI_Regs *spi, uint32_t interruptMask) { return (spi->CPU_INT.RIS & interruptMask); }
顺便说一下、进入非特权模式的方法是仅启用 MPU、而不启用特权模式、即选择第23行并注释掉第24行。
谢谢!
起重机
尊敬的 Crane:
顺便说一句、进入非特权模式的方法是仅启用 MPU、而不启用特权模式、即选择第23行并注释出第24行。
第24行用于将默认存储器映射设置为特权级软件访问的后台区域。 如果该位未置位、访问将在特权模式下导致硬故障。
对于进入 unpriviledge 模式、可以使用以下代码:
//__SET_CONTROL (__GET_CONTROL ()&~CONTROL_nPRIV_MSK);//特权线程模式、 在非特权边沿模式下不工作
//__set_control (__get_control ()| CONTROL_nPRIV_MSK);//非特权线程模式
如果我根本不使用 printf (来自 string.h 和我自己的)、从该函数返回时仍将导致硬故障:
如果您注释掉第24行、这是一个闪存区域(SPI)、如果您未将默认存储器映射定义为特权软件访问的后台区域、对该区域进行访问将触发硬故障。 如果注释掉第23行并使用第24行、它将仅在非特权模式下触发硬故障。
我尝试跟踪。 由于此代码段中的设置断点不起作用、因此我无法确认哪个语句导致了此问题。
我建议您通过单步运行进行测试、这样便可让代码逐步开始、您可以缩小测试范围。 (您可以进入反汇编单步运行)。
[报价 userid="527652" url="~/support/microcontrollers/arm-based-microcontrollers-group/arm-based-microcontrollers/f/arm-based-microcontrollers-forum/1386995/mspm0g3507-is-there-any-example-for-mpu-control-and-where-are-the-mpu-control-apis/5325196 #5325196"]区域0:MPU_RBAR:0x20200000 MPU_RASR:0x0302C01D -> RAM[/QUOT]在这里、您将1100 0000设置为 SRD、然后禁用最后的8KB。
[报价 userid="527652" url="~/support/microcontrollers/arm-based-microcontrollers-group/arm-based-microcontrollers/f/arm-based-microcontrollers-forum/1386995/mspm0g3507-is-there-any-example-for-mpu-control-and-where-are-the-mpu-control-apis/5325196 #5325196"]区域4:MPU_RBAR:0x20207804 MPU_RASR:0x03020015. -> RAM[/报价]中的堆栈在这里、您为堆栈设置2KB。 如果使用24行、则 SRAM 中的24kB-30KB 将具有默认的存储器映射。 如果使用线路23、则当您在两种模式下访问硬故障时、它将触发。
也许您可以检查您的代码是否访问未定义的区域。
B.R.
SAL
感谢 Sal 的详细答复。
我认为 、该问题源于对 MPU_CTRL 中 PRIVDEFENA 位的理解。
以下是用户指南中的说明:
如果我选择第23行、PRIVDEFENA 将为0。 默认存储器映射将被禁用。 然后、如果我指定所有类似如下的区域:
区域0:MPU_RBAR:0x20200000 MPU_RASR:0x0302001D
区域1:MPU_RBAR:0x00000001 MPU_RASR:0x03020021
区域2:MPU_RBAR:0x400A0002 MPU_RASR:0x0301001F
区域3:MPU_RBAR:0x400C0003 MPU_RASR:0x0301001F
区域4:MPU_RBAR:0x20207804 MPU_RASR:0x03020015
区域5:MPU_RBAR:0x20206005 MPU_RASR:0x03020015
区域6:MPU_RBAR:0x00000006 MPU_RASR:0x00000000
区域7:MPU_RBAR:0x00000007 MPU_RASR:0x00000000
结果、 SPI 访问仍将导致硬故障。
如果我使用我自己的 printf()、它也会导致硬错误。 当我在反汇编代码中跟踪 printf()函数时、我发现它在这里停止。 它应该位于访问数据段时。
但两个访问都在启用的区域中、包括 其子区域。
这是否意味着、当 PRIVDEFENA 设置为0且启用 MPU 时、应用程序处于非特权模式、无法访问任何存储器空间?
谢谢!
起重机
尊敬的 Crane:
结果是 SPI 访问仍将导致硬故障。 [报价]实际上您 的 区域定义中不包含 SPI 寄存器。
因此、如果您选择 LIN 23、预计会触发硬故障。
[报价 userid="527652" url="~/support/microcontrollers/arm-based-microcontrollers-group/arm-based-microcontrollers/f/arm-based-microcontrollers-forum/1386995/mspm0g3507-is-there-any-example-for-mpu-control-and-where-are-the-mpu-control-apis/5330255 #5330255"]区域0:MPU_RBAR:0x20200000 MPU_RASR:0x0302001D[/QUOT]您已将 SRAM 32KB 设置为完全访问区域、它应该在非特权模式下工作。
如果您查看 ARM m0plus 用户指南:
您为 S-C-B 设置 值为"0x0302001D"的010b。 这不遵循用户指南建议、如下所示:
顺便说一下、对于保留位:[位:19-21]、MSPM0 MPU 单元为它们提供了一个定义。 如果您查看"mpu_armv7.h"和"core_cm0plus.h":
我建议您调用库来设置访问权限属性。 也许这也是使您的 SRAM 访问超出预期的另外一部分。
对于区域0 (SRAM)、 我将 MPU_RASR 设置为 0x0329001D、由生成
"ARM_MPU_RASR_EX (0、ARM_MPU_AP_FULL、ARM_MPU_ACCESS_NORMAL (1、1、1)、0、ARM_MPU_REGION_SIZE_32KB)"
B.R.
SAL
尊敬的 Sal:
显然、我忽略了 UART0和 SPI1的实际 RAM 空间。 只要添加 UART0的初始化,调用我自己的 printf()引起的硬错误就会消失。
区域0:MPU_RBAR:0x20200000 MPU_RASR:0x0302C01D
区域1:MPU_RBAR:0x00000001 MPU_RASR:0x0302C021
区域2:MPU_RBAR:0x400A0002 MPU_RASR:0x0301011F
区域3:MPU_RBAR:0x400C0003 MPU_RASR:0x0301001F
区域4:MPU_RBAR:0x20207804 MPU_RASR:0x03020015
区域5:MPU_RBAR:0x20206005 MPU_RASR:0x03020015
区域6:MPU_RBAR:0x40108006 MPU_RASR:0x03020019
区域7:MPU_RBAR:0x00000007 MPU_RASR:0x00000000
但它并不是停止访问 UART0寄存器、而是停止昨天发布的数组 tempMsg[]。 还不知道为什么。
在 S-C-B 控制方面、我没有做任何改动、效果不错。 我会记住未来看看它们是如何影响 MPU 控制的。
非常感谢您的帮助!
此致、
起重机