1 /*
2  * Copyright (c) 2024, sakumisu
3  * Copyright (c) 2024, Egahp
4  *
5  * SPDX-License-Identifier: Apache-2.0
6  */
7 #ifndef BOOTUF2_H
8 #define BOOTUF2_H
9 
10 #include <stdint.h>
11 #include <stddef.h>
12 #include <string.h>
13 #include <stdbool.h>
14 #include <stdio.h>
15 #include <bootuf2_config.h>
16 
17 #ifndef __PACKED
18 #define __PACKED __attribute__((packed))
19 #endif
20 
21 #ifndef ARRAY_SIZE
22 #define ARRAY_SIZE(array) \
23     ((int)((sizeof(array) / sizeof((array)[0]))))
24 #endif
25 
26 struct bootuf2_BLOCK
27 {
28     // 32 byte header
29     uint32_t MagicStart0;
30     uint32_t MagicStart1;
31     uint32_t Flags;
32     uint32_t TargetAddress;
33     uint32_t PayloadSize;
34     uint32_t BlockIndex;
35     uint32_t NumberOfBlock;
36     uint32_t FamilyID; // or file_size
37     uint8_t Data[476];
38     uint32_t MagicEnd;
39 } __PACKED;
40 //BUILD_ASSERT(sizeof(struct bootuf2_BLOCK) == 512, "bootuf2_BLOCK not sector sized");
41 
42 struct bootuf2_STATE
43 {
44     uint32_t NumberOfBlock;
45     uint32_t NumberOfWritten;
46     uint8_t *const Mask;
47     uint8_t Enable;
48 };
49 
50 struct bootuf2_DBR
51 {
52     /*!< offset 0   */
53     uint8_t JMPInstruction[3];
54     /*!< offset 3   */
55     uint8_t OEM[8];
56     /*!< offset 11  */
57     struct
58     {
59         uint16_t BytesPerSector;
60         uint8_t SectorsPerCluster;
61         uint16_t ReservedSectors;
62         uint8_t NumberOfFAT;
63         uint16_t RootEntries;
64         uint16_t Sectors;
65         uint8_t MediaDescriptor;
66         uint16_t SectorsPerFAT;
67         uint16_t SectorsPerTrack;
68         uint16_t Heads;
69         uint32_t HiddenSectors;
70         uint32_t SectorsOver32MB;
71         uint8_t BIOSDrive;
72         uint8_t Reserved;
73         uint8_t ExtendBootSignature;
74         uint32_t VolumeSerialNumber;
75         uint8_t VolumeLabel[11];
76         uint8_t FileSystem[8];
77     } __PACKED BPB;
78     /*!< offset 62  */
79     /*!< BootLoader */
80     /*!< offset 511 */
81     /*!< 0x55 0xAA  */
82 } __PACKED;
83 //BUILD_ASSERT(sizeof(struct bootuf2_DBR) == 62, "bootuf2_DBR size must be 62 byte");
84 
85 struct bootuf2_ENTRY
86 {
87     char Name[11];
88     uint8_t Attribute;
89     uint8_t NTReserved;
90     uint8_t CreateTimeTeenth;
91     uint16_t CreateTime;
92     uint16_t CreateDate;
93     uint16_t LastAccessDate;
94     uint16_t FirstClustH16;
95     uint16_t UpdateTime;
96     uint16_t UpdateDate;
97     uint16_t FirstClustL16;
98     uint32_t FileSize;
99 } __PACKED;
100 //BUILD_ASSERT(sizeof(struct bootuf2_ENTRY) == 32, "bootuf2_ENTRY size must be 32 byte");
101 
102 struct bootuf2_FILE
103 {
104     const char *const Name;
105     const void *const Content;
106     uint32_t FileSize;
107     uint16_t ClusterBeg;
108     uint16_t ClusterEnd;
109 };
110 
111 #define BOOTUF2_DIVCEIL(_v, _d) (((_v) / (_d)) + ((_v) % (_d) ? 1 : 0))
112 
113 #define BOOTUF2_MAGIC_START0 0x0A324655u
114 #define BOOTUF2_MAGIC_START1 0x9E5D5157u
115 #define BOOTUF2_MAGIC_SERIAL 0x251B18BDu
116 #define BOOTUF2_MAGIC_END 0x0AB16F30u
117 
118 #define BOOTUF2_FLAG_NOT_MAIN_FLASH 0x00000001u
119 #define BOOTUF2_FLAG_FILE_CONTAINER 0x00001000u
120 #define BOOTUF2_FLAG_FAMILID_PRESENT 0x00002000u
121 #define BOOTUF2_FLAG_MD5_PRESENT 0x00004000u
122 
123 #define BOOTUF2_CMD_READ 0
124 #define BOOTUF2_CMD_SYNC 1
125 
126 #define BOOTUF2_BLOCKSMAX (((CONFIG_BOOTUF2_FLASHMAX) / 256) + (((CONFIG_BOOTUF2_FLASHMAX) % 256) ? 1 : 0))
127 
128 #define BOOTUF2_FAMILYID_POSNUM(n) (((CONFIG_BOOTUF2_FAMILYID) / (0x10000000 >> ((n) * 4))) % 0x10)
129 #define BOOTUF2_FAMILYID_ARRAY                                                                                           \
130     {                                                                                                                    \
131         ((BOOTUF2_FAMILYID_POSNUM(0) >= 10) ? BOOTUF2_FAMILYID_POSNUM(0) - 10 + 'A' : BOOTUF2_FAMILYID_POSNUM(0) + '0'), \
132         ((BOOTUF2_FAMILYID_POSNUM(1) >= 10) ? BOOTUF2_FAMILYID_POSNUM(1) - 10 + 'A' : BOOTUF2_FAMILYID_POSNUM(1) + '0'), \
133         ((BOOTUF2_FAMILYID_POSNUM(2) >= 10) ? BOOTUF2_FAMILYID_POSNUM(2) - 10 + 'A' : BOOTUF2_FAMILYID_POSNUM(2) + '0'), \
134         ((BOOTUF2_FAMILYID_POSNUM(3) >= 10) ? BOOTUF2_FAMILYID_POSNUM(3) - 10 + 'A' : BOOTUF2_FAMILYID_POSNUM(3) + '0'), \
135         ((BOOTUF2_FAMILYID_POSNUM(4) >= 10) ? BOOTUF2_FAMILYID_POSNUM(4) - 10 + 'A' : BOOTUF2_FAMILYID_POSNUM(4) + '0'), \
136         ((BOOTUF2_FAMILYID_POSNUM(5) >= 10) ? BOOTUF2_FAMILYID_POSNUM(5) - 10 + 'A' : BOOTUF2_FAMILYID_POSNUM(5) + '0'), \
137         ((BOOTUF2_FAMILYID_POSNUM(6) >= 10) ? BOOTUF2_FAMILYID_POSNUM(6) - 10 + 'A' : BOOTUF2_FAMILYID_POSNUM(6) + '0'), \
138         ((BOOTUF2_FAMILYID_POSNUM(7) >= 10) ? BOOTUF2_FAMILYID_POSNUM(7) - 10 + 'A' : BOOTUF2_FAMILYID_POSNUM(7) + '0'), \
139         ('I'),                                                                                                           \
140         ('D'),                                                                                                           \
141         (' '),                                                                                                           \
142         ('\0'),                                                                                                          \
143     };
144 
145 #define BOOTUF2_FAT16_PER_SECTOR(pDBR) (pDBR->BPB.BytesPerSector / 2)
146 #define BOOTUF2_ENTRY_PER_SECTOR(pDBR) (pDBR->BPB.BytesPerSector / sizeof(struct bootuf2_ENTRY))
147 #define BOOTUF2_CLUSTERSMAX (0xFFF0 - 2)
148 #define BOOTUF2_SECTOR_DBR_END (0)
149 #define BOOTUF2_SECTOR_RSVD_END(pDBR) BOOTUF2_SECTOR_DBR_END + (pDBR->BPB.ReservedSectors)
150 #define BOOTUF2_SECTOR_FAT_END(pDBR) BOOTUF2_SECTOR_RSVD_END(pDBR) + (pDBR->BPB.SectorsPerFAT * pDBR->BPB.NumberOfFAT)
151 #define BOOTUF2_SECTOR_ROOT_END(pDBR) BOOTUF2_SECTOR_FAT_END(pDBR) + (pDBR->BPB.RootEntries / (pDBR->BPB.BytesPerSector / sizeof(struct bootuf2_ENTRY)))
152 #define BOOTUF2_SECTOR_DATA_END(pDBR) (pDBR->BPB.Sectors + pDBR->BPB.SectorsOver32MB)
153 
154 #define BOOTUF2_SECTORS_PER_FAT(n) \
155     BOOTUF2_DIVCEIL(BOOTUF2_CLUSTERSMAX, (CONFIG_BOOTUF2_SECTOR_SIZE / 2))
156 #define BOOTUF2_SECTORS_FOR_ENTRIES(n) \
157     (CONFIG_BOOTUF2_ROOT_ENTRIES / (CONFIG_BOOTUF2_SECTOR_SIZE / sizeof(struct bootuf2_ENTRY)))
158 #define BOOTUF2_SECTORS(n)                                \
159     (CONFIG_BOOTUF2_SECTOR_RESERVED +                         \
160      CONFIG_BOOTUF2_NUM_OF_FAT * BOOTUF2_SECTORS_PER_FAT(n) + \
161      BOOTUF2_SECTORS_FOR_ENTRIES(n) +                     \
162      BOOTUF2_CLUSTERSMAX * CONFIG_BOOTUF2_SECTOR_PER_CLUSTER)
163 
164 #define BOOTUF2_YEAR_INT (         \
165     (__DATE__[7u] - '0') * 1000u + \
166     (__DATE__[8u] - '0') * 100u +  \
167     (__DATE__[9u] - '0') * 10u +   \
168     (__DATE__[10u] - '0') * 1u)
169 
170 #define BOOTUF2_MONTH_INT (                                      \
171     (__DATE__[2u] == 'n' && __DATE__[1u] == 'a')   ? 1u  /*Jan*/ \
172     : (__DATE__[2u] == 'b')                        ? 2u  /*Feb*/ \
173     : (__DATE__[2u] == 'r' && __DATE__[1u] == 'a') ? 3u  /*Mar*/ \
174     : (__DATE__[2u] == 'r')                        ? 4u  /*Apr*/ \
175     : (__DATE__[2u] == 'y')                        ? 5u  /*May*/ \
176     : (__DATE__[2u] == 'n')                        ? 6u  /*Jun*/ \
177     : (__DATE__[2u] == 'l')                        ? 7u  /*Jul*/ \
178     : (__DATE__[2u] == 'g')                        ? 8u  /*Aug*/ \
179     : (__DATE__[2u] == 'p')                        ? 9u  /*Sep*/ \
180     : (__DATE__[2u] == 't')                        ? 10u /*Oct*/ \
181     : (__DATE__[2u] == 'v')                        ? 11u /*Nov*/ \
182                                                    : 12u /*Dec*/)
183 
184 #define BOOTUF2_DAY_INT (                                  \
185     (__DATE__[4u] == ' ' ? 0 : __DATE__[4u] - '0') * 10u + \
186     (__DATE__[5u] - '0'))
187 
188 #define BOOTUF2_HOUR_INT ( \
189     (__TIME__[0u] == '?' ? 0 : __TIME__[0u] - '0') * 10u + (__TIME__[1u] == '?' ? 0 : __TIME__[1u] - '0'))
190 
191 #define BOOTUF2_MINUTE_INT ( \
192     (__TIME__[3u] == '?' ? 0 : __TIME__[3u] - '0') * 10u + (__TIME__[4u] == '?' ? 0 : __TIME__[4u] - '0'))
193 
194 #define BOOTUF2_SECONDS_INT ( \
195     (__TIME__[6u] == '?' ? 0 : __TIME__[6u] - '0') * 10u + (__TIME__[7u] == '?' ? 0 : __TIME__[7u] - '0'))
196 
197 #define BOOTUF2_DOS_DATE (               \
198     ((BOOTUF2_YEAR_INT - 1980u) << 9u) | \
199     (BOOTUF2_MONTH_INT << 5u) |          \
200     (BOOTUF2_DAY_INT << 0u))
201 
202 #define BOOTUF2_DOS_TIME (       \
203     (BOOTUF2_HOUR_INT << 11u) |  \
204     (BOOTUF2_MINUTE_INT << 5u) | \
205     (BOOTUF2_SECONDS_INT << 0u))
206 
207 void bootuf2_init(void);
208 int boot2uf2_read_sector(uint32_t start_sector, uint8_t *buff, uint32_t sector_count);
209 int bootuf2_write_sector(uint32_t start_sector, const uint8_t *buff, uint32_t sector_count);
210 uint16_t bootuf2_get_sector_size(void);
211 uint32_t bootuf2_get_sector_count(void);
212 
213 bool bootuf2_is_write_done(void);
214 
215 void boot2uf2_flash_init(void);
216 int bootuf2_flash_write(uint32_t address, const uint8_t *data, size_t size);
217 
218 #endif /*  BOOTUF2_H */
219