2014年2月21日 星期五

作業系統之前的程式 for stm32f4discovery (7) - mpu

mpu 暫存器有點多, 用法似乎也有點複雜, 注意 base, size 的設定:

MPU Region Base Address Register 有 align 的問題, 若是要設定區域 size 為 64k, base 需為 0x10000, 0x20000 ... 以此類推 (計算機拿出來按吧), 我的範例 size 是 256 bye, reg1 的位址是 0x20000100, 0x20000200 也可以, 0x20000202 就不行了。

先來談談遇到的問題:

沒有正確設定 mpu regions, 需要設定一個 base: 0x0, size: 4g 的 region, 因為我的 privdefena = 0, privdefena = 1 的話是另外一個情形。這導致我 enable mpu 之後, 立刻引起 hard-hault (其實應該要引起 mem-manage 比較正常)

觸發 hard-fault 而不是 MemManage exception:
SYSTEM_HANDLER_CTRL_STATE_REG |= (1 << 16); // enable mem-fault exception
搞定

in mm_isr, after mm_isr return, 仍然會執行修改變數那行, 所以又回到 mm_isr, 真奇怪, 不是應該要執行下一行嗎? 不過 pc 的確紀錄著修改變數那行程式碼, 所以會一直執行 mm_isr。看不懂我在寫什麼吧? 舉個例子

r.gdb
1   >│0x8000142 <mymain()+22>         ldr    r3, [pc, #28]   ; (0x8000160 <mymain\
2 ()+52>│
3    │0x8000144 <mymain()+24>         mov.w  r2, #10                             \
4    │0x8000148 <mymain()+28>         str    r2, [r3, #0]
5    │0x800014a <mymain()+30> mov.w  r3, #5                                      \

r.gdb L4 會發生存取問題 (我設定 read only, 這是一個寫的動作), 這時會跳到 mm_isr, 但從 mm_isr 回來的時候應該要執行 L5, 但實際還是執行 L4, 所以就會再一次執行 mm_isr, 一直重複。我不知道這是不是正常行為?

mycpp.cpp
 1 // mpu test
 2 #include "stm32.h"
 3 #include "type.h"
 4 
 5 #define MPU_TYPE_REG_ADDR 0xe000ed90
 6 #define MPU_TYPE_REG (*((u32 volatile *)MPU_TYPE_REG_ADDR))
 7 
 8 #define MPU_CTRL_REG_ADDR 0xe000ed94
 9 #define MPU_CTRL_REG (*((u32 volatile *)MPU_CTRL_REG_ADDR))
10 
11 #define MPU_NUM_REG_ADDR 0xe000ed98
12 #define MPU_NUM_REG (*((u32 volatile *)MPU_NUM_REG_ADDR))
13 
14 #define MPU_BASE_REG_ADDR 0xe000ed9c
15 #define MPU_BASE_REG (*((u32 volatile *)MPU_BASE_REG_ADDR))
16 
17 #define MPU_ATTR_SIZE_REG_ADDR 0xe000eda0
18 #define MPU_ATTR_SIZE_REG (*((u32 volatile *)MPU_ATTR_SIZE_REG_ADDR))
19 
20 extern u32 mpu_reg1_begin_;
21 extern u32 mpu_reg1_end_;
22 
23 extern u32 mpu_reg2_begin_, mpu_reg2_end_;
24 
25 __attribute__ ((section (".mpu_r1")))
26 int reg1[256];
27 
28 __attribute__ ((section (".mpu_r2")))
29 void test_mpu()
30 {
31   int i=1;
32   ++i;
33 }
34 
35 bool init_mpu();
36 
37 // ref: http://blog.feabhas.com/2013/02/setting-up-the-cortex-m34-armv7-m-memory-protection-unit-mpu/
38 // mymain is extern "C" declare
39 void mymain()
40 {
41   SYSTEM_HANDLER_CTRL_STATE_REG |= (1 << 16); // enable mem-fault exception
42   init_mpu();
43   reg1[0] = 10;
44   //int a = reg1[0];
45   //test_mpu();
46   int i=5;
47   while(1)
48   {
49     i++;
50   }
51 }
52 
53 
54 // ref: arm cortex-m3: 嵌入式系統設計入門 p13-9
55 bool init_mpu()
56 {
57   // ref: Cortex™-M3 Technical Reference Manual 9.2 (file name: DDI0337E_cortex_m3_r1p1_trm.pdf)
58   // in stm32f4discovery the value is 0x800
59   // so there are 8 regions
60   // qemu-system-arm -M lm3s6965evb -kernel list.bin -S -gdb tcp::1234
61   // the mpu_type is 0x0
62 #if 0
63   u32 volatile *mpu_type_reg_addr = (u32*)0xe000ed90; 
64   if (*mpu_type_reg_addr == 0) // there is no mpu
65     return false;
66 #endif
67 
68   if (MPU_TYPE_REG == 0) // there is no mpu
69     return false;
70 
71   // base 0x0, 4g size
72   MPU_NUM_REG = 0;
73   MPU_BASE_REG = 0
74   MPU_ATTR_SIZE_REG = 0x307003f;
75   //(*((u32 volatile *)MPU_BASE_REG_ADDR)) = 0x307002f;
76   MPU_NUM_REG = 1;
77   MPU_BASE_REG = (u32)&mpu_reg1_begin_;
78   MPU_ATTR_SIZE_REG = 0x707000F; // read only
79   //MPU_ATTR_SIZE_REG = 0x307000F; // r/w
80   // ap: 111 read only
81   // size: 256 byte
82   // S: 1, C: 1, B: 1
83   // TEX: 000
84 
85 #if 0
86   MPU_NUM_REG = 2;
87   MPU_BASE_REG = (u32)&mpu_reg2_begin_;
88   MPU_ATTR_SIZE_REG = 0x1007000F;
89   // disable execute
90 #endif
91 
92   MPU_CTRL_REG = 1; // enable MPU
93 
94   __asm__ ("isb");
95   __asm__ ("dsb");
96 
97   return true;
98 }
99 

這是程式碼, 是 c++ 的版本, 沒意外的話, 接下來的例子都以 c++ 為主。這是參考 arm cortex-m3: 嵌入式系統設計入門 p13-9 上的程式, 不過我遇到上面提到的問題, 所以實作真的不容易, 總是會有其他的問題發生。3 個暫存器就可以搞定, 在加上一個 enable mpu 的暫存器。

設定 0 號 region, base, size/屬性 ...
設定 1 號 region, base,size/屬性 ...
屬性程式碼碼有註解, 搭配書中解釋應該沒問題。

最後的
__asm__ ("isb");
__asm__ ("dsb");
別忘記。

直接貼
http://blog.feabhas.com/2013/02/setting-up-the-cortex-m34-armv7-m-memory-protection-unit-mpu/
的解釋:

After the MPU has been enabled, ISB and DSB barrier calls have been added to 
ensure that the pipeline is flushed and no further operations are executed until 
the memory access that enables the MPU completes.

使用 gdb 跑一次, 這樣就大功告成。

source code:
https://github.com/descent/stm32f4_prog/tree/master/mpu/cpp


沒有留言:

張貼留言

使用 google 的 reCAPTCHA 驗證碼, 總算可以輕鬆留言了。

我實在受不了 spam 了, 又不想讓大家的眼睛花掉, 只好放棄匿名留言。這是沒辦法中的辦法了。留言的朋友需要有 google 帳號。