bootuf2.c 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463
  1. /*
  2. * Copyright (c) 2024, sakumisu
  3. * Copyright (c) 2024, Egahp
  4. *
  5. * SPDX-License-Identifier: Apache-2.0
  6. */
  7. #include "bootuf2.h"
  8. #include "usbd_core.h"
  9. char file_INFO[] = {
  10. "CherryUSB UF2 BOOT\r\n"
  11. "Model: " CONFIG_PRODUCT "\r\n"
  12. "Board-ID: " CONFIG_BOARD "\r\n"
  13. };
  14. const char file_IDEX[] = {
  15. "<!doctype html>\n"
  16. "<html>"
  17. "<body>"
  18. "<script>\n"
  19. "location.replace(\"" CONFIG_BOOTUF2_INDEX_URL "\");\n"
  20. "</script>"
  21. "</body>"
  22. "</html>\n"
  23. };
  24. const char file_JOIN[] = {
  25. "<!doctype html>\n"
  26. "<html>"
  27. "<body>"
  28. "<script>\n"
  29. "location.replace(\"" CONFIG_BOOTUF2_JOIN_URL "\");\n"
  30. "</script>"
  31. "</body>"
  32. "</html>\n"
  33. };
  34. const char file_ID__[12] = BOOTUF2_FAMILYID_ARRAY;
  35. static struct bootuf2_FILE files[] = {
  36. [0] = { .Name = file_ID__, .Content = NULL, .FileSize = 0 },
  37. [1] = { .Name = "INFO_UF2TXT", .Content = file_INFO, .FileSize = sizeof(file_INFO) - 1 },
  38. [2] = { .Name = "INDEX HTM", .Content = file_IDEX, .FileSize = sizeof(file_IDEX) - 1 },
  39. [3] = { .Name = "JOIN HTM", .Content = file_JOIN, .FileSize = sizeof(file_JOIN) - 1 },
  40. };
  41. struct bootuf2_data {
  42. const struct bootuf2_DBR *const DBR;
  43. struct bootuf2_STATE *const STATE;
  44. uint8_t *const fbuff;
  45. uint8_t *const erase;
  46. size_t page_count;
  47. uint8_t *const cache;
  48. const size_t cache_size;
  49. uint32_t cached_address;
  50. size_t cached_bytes;
  51. };
  52. /*!< define DBRs */
  53. static const struct bootuf2_DBR bootuf2_DBR = {
  54. .JMPInstruction = { 0xEB, 0x3C, 0x90 },
  55. .OEM = "UF2 UF2 ",
  56. .BPB = {
  57. .BytesPerSector = CONFIG_BOOTUF2_SECTOR_SIZE,
  58. .SectorsPerCluster = CONFIG_BOOTUF2_SECTOR_PER_CLUSTER,
  59. .ReservedSectors = CONFIG_BOOTUF2_SECTOR_RESERVED,
  60. .NumberOfFAT = CONFIG_BOOTUF2_NUM_OF_FAT,
  61. .RootEntries = CONFIG_BOOTUF2_ROOT_ENTRIES,
  62. .Sectors = (BOOTUF2_SECTORS(0) > 0xFFFF) ? 0 : BOOTUF2_SECTORS(0),
  63. .MediaDescriptor = 0xF8,
  64. .SectorsPerFAT = BOOTUF2_SECTORS_PER_FAT(0),
  65. .SectorsPerTrack = 1,
  66. .Heads = 1,
  67. .HiddenSectors = 0,
  68. .SectorsOver32MB = (BOOTUF2_SECTORS(0) > 0xFFFF) ? BOOTUF2_SECTORS(0) : 0,
  69. .BIOSDrive = 0x80,
  70. .Reserved = 0,
  71. .ExtendBootSignature = 0x29,
  72. .VolumeSerialNumber = 0x00420042,
  73. .VolumeLabel = "CHERRYUF2",
  74. .FileSystem = "FAT16 ",
  75. },
  76. };
  77. /*!< define mask */
  78. static uint8_t __attribute__((aligned(4))) bootuf2_mask[BOOTUF2_BLOCKSMAX / 8 + 1] = { 0 };
  79. /*!< define state */
  80. static struct bootuf2_STATE bootuf2_STATE = {
  81. .NumberOfBlock = 0,
  82. .NumberOfWritten = 0,
  83. .Mask = bootuf2_mask,
  84. .Enable = 1,
  85. };
  86. /*!< define flash cache */
  87. static uint8_t __attribute__((aligned(4))) bootuf2_disk_cache[CONFIG_BOOTUF2_CACHE_SIZE];
  88. /*!< define flash buff */
  89. static uint8_t __attribute__((aligned(4))) bootuf2_disk_fbuff[256];
  90. /*!< define erase flag buff */
  91. static uint8_t __attribute__((aligned(4))) bootuf2_disk_erase[BOOTUF2_DIVCEIL(CONFIG_BOOTUF2_PAGE_COUNTMAX, 8)];
  92. /*!< define disk */
  93. static struct bootuf2_data bootuf2_disk = {
  94. .DBR = &bootuf2_DBR,
  95. .STATE = &bootuf2_STATE,
  96. .fbuff = bootuf2_disk_fbuff,
  97. .erase = bootuf2_disk_erase,
  98. .cache = bootuf2_disk_cache,
  99. .cache_size = sizeof(bootuf2_disk_cache),
  100. };
  101. static void fname_copy(char *dst, char const *src, uint16_t len)
  102. {
  103. for (size_t i = 0; i < len; ++i) {
  104. if (*src)
  105. *dst++ = *src++;
  106. else
  107. *dst++ = ' ';
  108. }
  109. }
  110. static void fcalculate_cluster(struct bootuf2_data *ctx)
  111. {
  112. /*!< init files cluster */
  113. uint16_t cluster_beg = 2;
  114. for (int i = 0; i < ARRAY_SIZE(files); i++) {
  115. files[i].ClusterBeg = cluster_beg;
  116. files[i].ClusterEnd = -1 + cluster_beg +
  117. BOOTUF2_DIVCEIL(files[i].FileSize,
  118. ctx->DBR->BPB.BytesPerSector *
  119. ctx->DBR->BPB.SectorsPerCluster);
  120. cluster_beg = files[i].ClusterEnd + 1;
  121. }
  122. }
  123. static int ffind_by_cluster(uint32_t cluster)
  124. {
  125. if (cluster >= 0xFFF0) {
  126. return -1;
  127. }
  128. for (uint32_t i = 0; i < ARRAY_SIZE(files); i++) {
  129. if ((files[i].ClusterBeg <= cluster) &&
  130. (cluster <= files[i].ClusterEnd)) {
  131. return i;
  132. }
  133. }
  134. return -1;
  135. }
  136. static bool bootuf2block_check_writable(struct bootuf2_STATE *STATE,
  137. struct bootuf2_BLOCK *uf2, uint32_t block_max)
  138. {
  139. if (uf2->NumberOfBlock) {
  140. if (uf2->BlockIndex < block_max) {
  141. uint8_t mask = 1 << (uf2->BlockIndex % 8);
  142. uint32_t pos = uf2->BlockIndex / 8;
  143. if ((STATE->Mask[pos] & mask) == 0) {
  144. return true;
  145. }
  146. }
  147. }
  148. return false;
  149. }
  150. static void bootuf2block_state_update(struct bootuf2_STATE *STATE,
  151. struct bootuf2_BLOCK *uf2, uint32_t block_max)
  152. {
  153. if (uf2->NumberOfBlock) {
  154. if (STATE->NumberOfBlock != uf2->NumberOfBlock) {
  155. if ((uf2->NumberOfBlock >= BOOTUF2_BLOCKSMAX) ||
  156. STATE->NumberOfBlock) {
  157. /*!< uf2 block only can be update once */
  158. /*!< this will cause never auto reboot */
  159. STATE->NumberOfBlock = 0xffffffff;
  160. } else {
  161. STATE->NumberOfBlock = uf2->NumberOfBlock;
  162. }
  163. }
  164. if (uf2->BlockIndex < block_max) {
  165. uint8_t mask = 1 << (uf2->BlockIndex % 8);
  166. uint32_t pos = uf2->BlockIndex / 8;
  167. if ((STATE->Mask[pos] & mask) == 0) {
  168. STATE->Mask[pos] |= mask;
  169. STATE->NumberOfWritten++;
  170. }
  171. }
  172. }
  173. USB_LOG_DBG("UF2 block total %d written %d index %d\r\n",
  174. uf2->NumberOfBlock, STATE->NumberOfWritten, uf2->BlockIndex);
  175. }
  176. static bool bootuf2block_state_check(struct bootuf2_STATE *STATE)
  177. {
  178. return (STATE->NumberOfWritten >= STATE->NumberOfBlock) &&
  179. STATE->NumberOfBlock;
  180. }
  181. static int bootuf2_flash_flush(struct bootuf2_data *ctx)
  182. {
  183. int err;
  184. if (ctx->cached_bytes == 0) {
  185. return 0;
  186. }
  187. err = bootuf2_flash_write(ctx->cached_address, ctx->cache, ctx->cached_bytes);
  188. if (err) {
  189. USB_LOG_ERR("UF2 slot flash write error %d at offset %08lx len %d\r\n",
  190. err, ctx->cached_address, ctx->cached_bytes);
  191. return -1;
  192. }
  193. ctx->cached_bytes = 0;
  194. return 0;
  195. }
  196. int bootuf2_flash_write_internal(struct bootuf2_data *ctx, struct bootuf2_BLOCK *uf2)
  197. {
  198. /*!< 1.cache not empty and address not continue */
  199. /*!< 2.cache full */
  200. if ((ctx->cached_bytes && ((ctx->cached_address + ctx->cached_bytes) != uf2->TargetAddress)) ||
  201. (ctx->cached_bytes == ctx->cache_size)) {
  202. int err = bootuf2_flash_flush(ctx);
  203. if (err)
  204. return err;
  205. }
  206. /*!< write len always is 256, cache_size always is a multiple of 256 */
  207. memcpy(ctx->cache + ctx->cached_bytes, uf2->Data, uf2->PayloadSize);
  208. ctx->cached_address = uf2->TargetAddress - ctx->cached_bytes;
  209. ctx->cached_bytes += uf2->PayloadSize;
  210. return 0;
  211. }
  212. void bootuf2_init(void)
  213. {
  214. struct bootuf2_data *ctx;
  215. ctx = &bootuf2_disk;
  216. fcalculate_cluster(ctx);
  217. ctx->cached_bytes = 0;
  218. ctx->cached_address = 0;
  219. }
  220. int boot2uf2_read_sector(uint32_t start_sector, uint8_t *buff, uint32_t sector_count)
  221. {
  222. struct bootuf2_data *ctx;
  223. ctx = &bootuf2_disk;
  224. while (sector_count) {
  225. memset(buff, 0, ctx->DBR->BPB.BytesPerSector);
  226. uint32_t sector_relative = start_sector;
  227. /*!< DBR sector */
  228. if (start_sector == BOOTUF2_SECTOR_DBR_END) {
  229. memcpy(buff, ctx->DBR, sizeof(struct bootuf2_DBR));
  230. buff[510] = 0x55;
  231. buff[511] = 0xaa;
  232. }
  233. /*!< FAT sector */
  234. else if (start_sector < BOOTUF2_SECTOR_FAT_END(ctx->DBR)) {
  235. uint16_t *buff16 = (uint16_t *)buff;
  236. sector_relative -= BOOTUF2_SECTOR_RSVD_END(ctx->DBR);
  237. /*!< Perform the same operation on all FAT tables */
  238. while (sector_relative >= ctx->DBR->BPB.SectorsPerFAT) {
  239. sector_relative -= ctx->DBR->BPB.SectorsPerFAT;
  240. }
  241. uint16_t cluster_unused = files[ARRAY_SIZE(files) - 1].ClusterEnd + 1;
  242. uint16_t cluster_absolute_first = sector_relative *
  243. BOOTUF2_FAT16_PER_SECTOR(ctx->DBR);
  244. /*!< cluster used link to chain, or unsed */
  245. for (uint16_t i = 0, cluster_absolute = cluster_absolute_first;
  246. i < BOOTUF2_FAT16_PER_SECTOR(ctx->DBR);
  247. i++, cluster_absolute++) {
  248. if (cluster_absolute >= cluster_unused)
  249. buff16[i] = 0;
  250. else
  251. buff16[i] = cluster_absolute + 1;
  252. }
  253. /*!< cluster 0 and 1 */
  254. if (sector_relative == 0) {
  255. buff[0] = ctx->DBR->BPB.MediaDescriptor;
  256. buff[1] = 0xff;
  257. buff16[1] = 0xffff;
  258. }
  259. /*!< cluster end of file */
  260. for (uint32_t i = 0; i < ARRAY_SIZE(files); i++) {
  261. uint16_t cluster_file_last = files[i].ClusterEnd;
  262. if (cluster_file_last >= cluster_absolute_first) {
  263. uint16_t idx = cluster_file_last - cluster_absolute_first;
  264. if (idx < BOOTUF2_FAT16_PER_SECTOR(ctx->DBR)) {
  265. buff16[idx] = 0xffff;
  266. }
  267. }
  268. }
  269. }
  270. /*!< root entries */
  271. else if (start_sector < BOOTUF2_SECTOR_ROOT_END(ctx->DBR)) {
  272. sector_relative -= BOOTUF2_SECTOR_FAT_END(ctx->DBR);
  273. struct bootuf2_ENTRY *ent = (void *)buff;
  274. int remain_entries = BOOTUF2_ENTRY_PER_SECTOR(ctx->DBR);
  275. uint32_t file_index_first;
  276. /*!< volume label entry */
  277. if (sector_relative == 0) {
  278. fname_copy(ent->Name, (char const *)ctx->DBR->BPB.VolumeLabel, 11);
  279. ent->Attribute = 0x28;
  280. ent++;
  281. remain_entries--;
  282. file_index_first = 0;
  283. } else {
  284. /*!< -1 to account for volume label in first sector */
  285. file_index_first = sector_relative * BOOTUF2_ENTRY_PER_SECTOR(ctx->DBR) - 1;
  286. }
  287. for (uint32_t idx = file_index_first;
  288. (remain_entries > 0) && (idx < ARRAY_SIZE(files));
  289. idx++, ent++) {
  290. const uint32_t cluster_beg = files[idx].ClusterBeg;
  291. const struct bootuf2_FILE *f = &files[idx];
  292. if ((0 == f->FileSize) &&
  293. (0 != idx)) {
  294. continue;
  295. }
  296. fname_copy(ent->Name, f->Name, 11);
  297. ent->Attribute = 0x05;
  298. ent->CreateTimeTeenth = BOOTUF2_SECONDS_INT % 2 * 100;
  299. ent->CreateTime = BOOTUF2_DOS_TIME;
  300. ent->CreateDate = BOOTUF2_DOS_DATE;
  301. ent->LastAccessDate = BOOTUF2_DOS_DATE;
  302. ent->FirstClustH16 = cluster_beg >> 16;
  303. ent->UpdateTime = BOOTUF2_DOS_TIME;
  304. ent->UpdateDate = BOOTUF2_DOS_DATE;
  305. ent->FirstClustL16 = cluster_beg & 0xffff;
  306. ent->FileSize = f->FileSize;
  307. }
  308. }
  309. /*!< data */
  310. else if (start_sector < BOOTUF2_SECTOR_DATA_END(ctx->DBR)) {
  311. sector_relative -= BOOTUF2_SECTOR_ROOT_END(ctx->DBR);
  312. int fid = ffind_by_cluster(2 + sector_relative / ctx->DBR->BPB.SectorsPerCluster);
  313. if (fid >= 0) {
  314. const struct bootuf2_FILE *f = &files[fid];
  315. uint32_t sector_relative_file =
  316. sector_relative -
  317. (files[fid].ClusterBeg - 2) * ctx->DBR->BPB.SectorsPerCluster;
  318. size_t fcontent_offset = sector_relative_file * ctx->DBR->BPB.BytesPerSector;
  319. size_t fcontent_length = f->FileSize;
  320. if (fcontent_length > fcontent_offset) {
  321. const void *src = (void *)((uint8_t *)(f->Content) + fcontent_offset);
  322. size_t copy_size = fcontent_length - fcontent_offset;
  323. if (copy_size > ctx->DBR->BPB.BytesPerSector) {
  324. copy_size = ctx->DBR->BPB.BytesPerSector;
  325. }
  326. memcpy(buff, src, copy_size);
  327. }
  328. }
  329. }
  330. /*!< unknown sector, ignore */
  331. start_sector++;
  332. sector_count--;
  333. buff += ctx->DBR->BPB.BytesPerSector;
  334. }
  335. return 0;
  336. }
  337. int bootuf2_write_sector(uint32_t start_sector, const uint8_t *buff, uint32_t sector_count)
  338. {
  339. struct bootuf2_data *ctx;
  340. ctx = &bootuf2_disk;
  341. while (sector_count) {
  342. struct bootuf2_BLOCK *uf2 = (void *)buff;
  343. if (!((uf2->MagicStart0 == BOOTUF2_MAGIC_START0) &&
  344. (uf2->MagicStart1 == BOOTUF2_MAGIC_START1) &&
  345. (uf2->MagicEnd == BOOTUF2_MAGIC_END) &&
  346. (uf2->Flags & BOOTUF2_FLAG_FAMILID_PRESENT) &&
  347. !(uf2->Flags & BOOTUF2_FLAG_NOT_MAIN_FLASH))) {
  348. goto next;
  349. }
  350. if (uf2->FamilyID == CONFIG_BOOTUF2_FAMILYID) {
  351. if (bootuf2block_check_writable(ctx->STATE, uf2, CONFIG_BOOTUF2_FLASHMAX)) {
  352. bootuf2_flash_write_internal(ctx, uf2);
  353. bootuf2block_state_update(ctx->STATE, uf2, CONFIG_BOOTUF2_FLASHMAX);
  354. } else {
  355. USB_LOG_DBG("UF2 block %d already written\r\n",
  356. uf2->BlockIndex);
  357. }
  358. } else {
  359. USB_LOG_DBG("UF2 block illegal id %08x\r\n", uf2->FamilyID);
  360. }
  361. next:
  362. start_sector++;
  363. sector_count--;
  364. buff += ctx->DBR->BPB.BytesPerSector;
  365. }
  366. return 0;
  367. }
  368. uint16_t bootuf2_get_sector_size(void)
  369. {
  370. return bootuf2_disk.DBR->BPB.BytesPerSector;
  371. }
  372. uint32_t bootuf2_get_sector_count(void)
  373. {
  374. return bootuf2_disk.DBR->BPB.SectorsOver32MB + bootuf2_disk.DBR->BPB.Sectors;
  375. }
  376. bool bootuf2_is_write_done(void)
  377. {
  378. if (bootuf2block_state_check(bootuf2_disk.STATE)) {
  379. bootuf2_flash_flush(&bootuf2_disk);
  380. USB_LOG_DBG("UF2 update ok\r\n");
  381. return true;
  382. } else {
  383. return false;
  384. }
  385. }