bootuf2.c 13 KB

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