storage.c 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290
  1. /*
  2. * This file is part of the MicroPython project, http://micropython.org/
  3. *
  4. * The MIT License (MIT)
  5. *
  6. * Copyright (c) 2013-2018 Damien P. George
  7. *
  8. * Permission is hereby granted, free of charge, to any person obtaining a copy
  9. * of this software and associated documentation files (the "Software"), to deal
  10. * in the Software without restriction, including without limitation the rights
  11. * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  12. * copies of the Software, and to permit persons to whom the Software is
  13. * furnished to do so, subject to the following conditions:
  14. *
  15. * The above copyright notice and this permission notice shall be included in
  16. * all copies or substantial portions of the Software.
  17. *
  18. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  19. * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  20. * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  21. * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  22. * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  23. * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  24. * THE SOFTWARE.
  25. */
  26. #include <stdint.h>
  27. #include <string.h>
  28. #include "py/runtime.h"
  29. #include "extmod/vfs_fat.h"
  30. #include "led.h"
  31. #include "storage.h"
  32. #include "irq.h"
  33. #if MICROPY_HW_ENABLE_STORAGE
  34. #define FLASH_PART1_START_BLOCK (0x100)
  35. #if defined(MICROPY_HW_BDEV2_IOCTL)
  36. #define FLASH_PART2_START_BLOCK (FLASH_PART1_START_BLOCK + MICROPY_HW_BDEV2_IOCTL(BDEV_IOCTL_NUM_BLOCKS, 0))
  37. #endif
  38. static bool storage_is_initialised = false;
  39. void storage_init(void) {
  40. if (!storage_is_initialised) {
  41. storage_is_initialised = true;
  42. MICROPY_HW_BDEV_IOCTL(BDEV_IOCTL_INIT, 0);
  43. #if defined(MICROPY_HW_BDEV2_IOCTL)
  44. MICROPY_HW_BDEV2_IOCTL(BDEV_IOCTL_INIT, 0);
  45. #endif
  46. // Enable the flash IRQ, which is used to also call our storage IRQ handler
  47. // It needs to go at a higher priority than all those components that rely on
  48. // the flash storage (eg higher than USB MSC).
  49. NVIC_SetPriority(FLASH_IRQn, IRQ_PRI_FLASH);
  50. HAL_NVIC_EnableIRQ(FLASH_IRQn);
  51. }
  52. }
  53. uint32_t storage_get_block_size(void) {
  54. return FLASH_BLOCK_SIZE;
  55. }
  56. uint32_t storage_get_block_count(void) {
  57. #if defined(MICROPY_HW_BDEV2_IOCTL)
  58. return FLASH_PART2_START_BLOCK + MICROPY_HW_BDEV2_IOCTL(BDEV_IOCTL_NUM_BLOCKS, 0);
  59. #else
  60. return FLASH_PART1_START_BLOCK + MICROPY_HW_BDEV_IOCTL(BDEV_IOCTL_NUM_BLOCKS, 0);
  61. #endif
  62. }
  63. void storage_irq_handler(void) {
  64. MICROPY_HW_BDEV_IOCTL(BDEV_IOCTL_IRQ_HANDLER, 0);
  65. #if defined(MICROPY_HW_BDEV2_IOCTL)
  66. MICROPY_HW_BDEV2_IOCTL(BDEV_IOCTL_IRQ_HANDLER, 0);
  67. #endif
  68. }
  69. void storage_flush(void) {
  70. MICROPY_HW_BDEV_IOCTL(BDEV_IOCTL_SYNC, 0);
  71. #if defined(MICROPY_HW_BDEV2_IOCTL)
  72. MICROPY_HW_BDEV2_IOCTL(BDEV_IOCTL_SYNC, 0);
  73. #endif
  74. }
  75. static void build_partition(uint8_t *buf, int boot, int type, uint32_t start_block, uint32_t num_blocks) {
  76. buf[0] = boot;
  77. if (num_blocks == 0) {
  78. buf[1] = 0;
  79. buf[2] = 0;
  80. buf[3] = 0;
  81. } else {
  82. buf[1] = 0xff;
  83. buf[2] = 0xff;
  84. buf[3] = 0xff;
  85. }
  86. buf[4] = type;
  87. if (num_blocks == 0) {
  88. buf[5] = 0;
  89. buf[6] = 0;
  90. buf[7] = 0;
  91. } else {
  92. buf[5] = 0xff;
  93. buf[6] = 0xff;
  94. buf[7] = 0xff;
  95. }
  96. buf[8] = start_block;
  97. buf[9] = start_block >> 8;
  98. buf[10] = start_block >> 16;
  99. buf[11] = start_block >> 24;
  100. buf[12] = num_blocks;
  101. buf[13] = num_blocks >> 8;
  102. buf[14] = num_blocks >> 16;
  103. buf[15] = num_blocks >> 24;
  104. }
  105. bool storage_read_block(uint8_t *dest, uint32_t block) {
  106. //printf("RD %u\n", block);
  107. if (block == 0) {
  108. // fake the MBR so we can decide on our own partition table
  109. for (int i = 0; i < 446; i++) {
  110. dest[i] = 0;
  111. }
  112. build_partition(dest + 446, 0, 0x01 /* FAT12 */, FLASH_PART1_START_BLOCK, MICROPY_HW_BDEV_IOCTL(BDEV_IOCTL_NUM_BLOCKS, 0));
  113. #if defined(MICROPY_HW_BDEV2_IOCTL)
  114. build_partition(dest + 462, 0, 0x01 /* FAT12 */, FLASH_PART2_START_BLOCK, MICROPY_HW_BDEV2_IOCTL(BDEV_IOCTL_NUM_BLOCKS, 0));
  115. #else
  116. build_partition(dest + 462, 0, 0, 0, 0);
  117. #endif
  118. build_partition(dest + 478, 0, 0, 0, 0);
  119. build_partition(dest + 494, 0, 0, 0, 0);
  120. dest[510] = 0x55;
  121. dest[511] = 0xaa;
  122. return true;
  123. #if defined(MICROPY_HW_BDEV_READBLOCK)
  124. } else if (FLASH_PART1_START_BLOCK <= block && block < FLASH_PART1_START_BLOCK + MICROPY_HW_BDEV_IOCTL(BDEV_IOCTL_NUM_BLOCKS, 0)) {
  125. return MICROPY_HW_BDEV_READBLOCK(dest, block - FLASH_PART1_START_BLOCK);
  126. #endif
  127. } else {
  128. return false;
  129. }
  130. }
  131. bool storage_write_block(const uint8_t *src, uint32_t block) {
  132. //printf("WR %u\n", block);
  133. if (block == 0) {
  134. // can't write MBR, but pretend we did
  135. return true;
  136. #if defined(MICROPY_HW_BDEV_WRITEBLOCK)
  137. } else if (FLASH_PART1_START_BLOCK <= block && block < FLASH_PART1_START_BLOCK + MICROPY_HW_BDEV_IOCTL(BDEV_IOCTL_NUM_BLOCKS, 0)) {
  138. return MICROPY_HW_BDEV_WRITEBLOCK(src, block - FLASH_PART1_START_BLOCK);
  139. #endif
  140. } else {
  141. return false;
  142. }
  143. }
  144. mp_uint_t storage_read_blocks(uint8_t *dest, uint32_t block_num, uint32_t num_blocks) {
  145. #if defined(MICROPY_HW_BDEV_READBLOCKS)
  146. if (FLASH_PART1_START_BLOCK <= block_num && block_num + num_blocks <= FLASH_PART1_START_BLOCK + MICROPY_HW_BDEV_IOCTL(BDEV_IOCTL_NUM_BLOCKS, 0)) {
  147. return MICROPY_HW_BDEV_READBLOCKS(dest, block_num - FLASH_PART1_START_BLOCK, num_blocks);
  148. }
  149. #endif
  150. #if defined(MICROPY_HW_BDEV2_READBLOCKS)
  151. if (FLASH_PART2_START_BLOCK <= block_num && block_num + num_blocks <= FLASH_PART2_START_BLOCK + MICROPY_HW_BDEV2_IOCTL(BDEV_IOCTL_NUM_BLOCKS, 0)) {
  152. return MICROPY_HW_BDEV2_READBLOCKS(dest, block_num - FLASH_PART2_START_BLOCK, num_blocks);
  153. }
  154. #endif
  155. for (size_t i = 0; i < num_blocks; i++) {
  156. if (!storage_read_block(dest + i * FLASH_BLOCK_SIZE, block_num + i)) {
  157. return 1; // error
  158. }
  159. }
  160. return 0; // success
  161. }
  162. mp_uint_t storage_write_blocks(const uint8_t *src, uint32_t block_num, uint32_t num_blocks) {
  163. #if defined(MICROPY_HW_BDEV_WRITEBLOCKS)
  164. if (FLASH_PART1_START_BLOCK <= block_num && block_num + num_blocks <= FLASH_PART1_START_BLOCK + MICROPY_HW_BDEV_IOCTL(BDEV_IOCTL_NUM_BLOCKS, 0)) {
  165. return MICROPY_HW_BDEV_WRITEBLOCKS(src, block_num - FLASH_PART1_START_BLOCK, num_blocks);
  166. }
  167. #endif
  168. #if defined(MICROPY_HW_BDEV2_WRITEBLOCKS)
  169. if (FLASH_PART2_START_BLOCK <= block_num && block_num + num_blocks <= FLASH_PART2_START_BLOCK + MICROPY_HW_BDEV2_IOCTL(BDEV_IOCTL_NUM_BLOCKS, 0)) {
  170. return MICROPY_HW_BDEV2_WRITEBLOCKS(src, block_num - FLASH_PART2_START_BLOCK, num_blocks);
  171. }
  172. #endif
  173. for (size_t i = 0; i < num_blocks; i++) {
  174. if (!storage_write_block(src + i * FLASH_BLOCK_SIZE, block_num + i)) {
  175. return 1; // error
  176. }
  177. }
  178. return 0; // success
  179. }
  180. /******************************************************************************/
  181. // MicroPython bindings
  182. //
  183. // Expose the flash as an object with the block protocol.
  184. // there is a singleton Flash object
  185. STATIC const mp_obj_base_t pyb_flash_obj = {&pyb_flash_type};
  186. STATIC mp_obj_t pyb_flash_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) {
  187. // check arguments
  188. mp_arg_check_num(n_args, n_kw, 0, 0, false);
  189. // return singleton object
  190. return MP_OBJ_FROM_PTR(&pyb_flash_obj);
  191. }
  192. STATIC mp_obj_t pyb_flash_readblocks(mp_obj_t self, mp_obj_t block_num, mp_obj_t buf) {
  193. mp_buffer_info_t bufinfo;
  194. mp_get_buffer_raise(buf, &bufinfo, MP_BUFFER_WRITE);
  195. mp_uint_t ret = storage_read_blocks(bufinfo.buf, mp_obj_get_int(block_num), bufinfo.len / FLASH_BLOCK_SIZE);
  196. return MP_OBJ_NEW_SMALL_INT(ret);
  197. }
  198. STATIC MP_DEFINE_CONST_FUN_OBJ_3(pyb_flash_readblocks_obj, pyb_flash_readblocks);
  199. STATIC mp_obj_t pyb_flash_writeblocks(mp_obj_t self, mp_obj_t block_num, mp_obj_t buf) {
  200. mp_buffer_info_t bufinfo;
  201. mp_get_buffer_raise(buf, &bufinfo, MP_BUFFER_READ);
  202. mp_uint_t ret = storage_write_blocks(bufinfo.buf, mp_obj_get_int(block_num), bufinfo.len / FLASH_BLOCK_SIZE);
  203. return MP_OBJ_NEW_SMALL_INT(ret);
  204. }
  205. STATIC MP_DEFINE_CONST_FUN_OBJ_3(pyb_flash_writeblocks_obj, pyb_flash_writeblocks);
  206. STATIC mp_obj_t pyb_flash_ioctl(mp_obj_t self, mp_obj_t cmd_in, mp_obj_t arg_in) {
  207. mp_int_t cmd = mp_obj_get_int(cmd_in);
  208. switch (cmd) {
  209. case BP_IOCTL_INIT: storage_init(); return MP_OBJ_NEW_SMALL_INT(0);
  210. case BP_IOCTL_DEINIT: storage_flush(); return MP_OBJ_NEW_SMALL_INT(0); // TODO properly
  211. case BP_IOCTL_SYNC: storage_flush(); return MP_OBJ_NEW_SMALL_INT(0);
  212. case BP_IOCTL_SEC_COUNT: return MP_OBJ_NEW_SMALL_INT(storage_get_block_count());
  213. case BP_IOCTL_SEC_SIZE: return MP_OBJ_NEW_SMALL_INT(storage_get_block_size());
  214. default: return mp_const_none;
  215. }
  216. }
  217. STATIC MP_DEFINE_CONST_FUN_OBJ_3(pyb_flash_ioctl_obj, pyb_flash_ioctl);
  218. STATIC const mp_rom_map_elem_t pyb_flash_locals_dict_table[] = {
  219. { MP_ROM_QSTR(MP_QSTR_readblocks), MP_ROM_PTR(&pyb_flash_readblocks_obj) },
  220. { MP_ROM_QSTR(MP_QSTR_writeblocks), MP_ROM_PTR(&pyb_flash_writeblocks_obj) },
  221. { MP_ROM_QSTR(MP_QSTR_ioctl), MP_ROM_PTR(&pyb_flash_ioctl_obj) },
  222. };
  223. STATIC MP_DEFINE_CONST_DICT(pyb_flash_locals_dict, pyb_flash_locals_dict_table);
  224. const mp_obj_type_t pyb_flash_type = {
  225. { &mp_type_type },
  226. .name = MP_QSTR_Flash,
  227. .make_new = pyb_flash_make_new,
  228. .locals_dict = (mp_obj_dict_t*)&pyb_flash_locals_dict,
  229. };
  230. void pyb_flash_init_vfs(fs_user_mount_t *vfs) {
  231. vfs->base.type = &mp_fat_vfs_type;
  232. vfs->flags |= FSUSER_NATIVE | FSUSER_HAVE_IOCTL;
  233. vfs->fatfs.drv = vfs;
  234. vfs->fatfs.part = 1; // flash filesystem lives on first partition
  235. vfs->readblocks[0] = MP_OBJ_FROM_PTR(&pyb_flash_readblocks_obj);
  236. vfs->readblocks[1] = MP_OBJ_FROM_PTR(&pyb_flash_obj);
  237. vfs->readblocks[2] = MP_OBJ_FROM_PTR(storage_read_blocks); // native version
  238. vfs->writeblocks[0] = MP_OBJ_FROM_PTR(&pyb_flash_writeblocks_obj);
  239. vfs->writeblocks[1] = MP_OBJ_FROM_PTR(&pyb_flash_obj);
  240. vfs->writeblocks[2] = MP_OBJ_FROM_PTR(storage_write_blocks); // native version
  241. vfs->u.ioctl[0] = MP_OBJ_FROM_PTR(&pyb_flash_ioctl_obj);
  242. vfs->u.ioctl[1] = MP_OBJ_FROM_PTR(&pyb_flash_obj);
  243. }
  244. #endif