19 #ifdef SD_CONTENT_SUPPORT
33 #include <sys/types.h>
39 #define MAX_IMPORT_FILE_SIZE 1000000
44 static int our_data_partition;
50 static const Uint8 fat_bytes[12] = {
55 static const Uint8 dir_bytes[15] = {0x08,0x00,0x00,0x53,0xae,0x93,0x4a,0x93,0x4a,0x00,0x00,0x53,0xae,0x93,0x4a};
56 static const Uint8 default_volume_name[11] =
"M.E.G.A.65!";
57 static const char default_disk_image[] =
"mega65.d81";
58 static const char xemu_disk_image[] =
"external.d81";
59 static const Uint8 sys_part_magic[] = {
'M',
'E',
'G',
'A',
'6',
'5',
'S',
'Y',
'S',
'0',
'0'};
60 static const Uint8 boot_bytes[258] = {
64 0x4d, 0x45, 0x47, 0x41, 0x36, 0x35, 0x72, 0x31,
77 0x00, 0x00, 0x00, 0x00,
78 0x00, 0xe8, 0x0f, 0x00,
79 0xf8, 0x03, 0x00, 0x00,
82 0x02, 0x00 ,0x00, 0x00,
85 0x00, 0x00, 0x00, 0x00,
86 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 ,0x00, 0x00,
90 0x6d, 0x66, 0x62, 0x61,
91 0x4d, 0x2e, 0x45, 0x2e, 0x47,
92 0x2e, 0x41 ,0x2e, 0x20, 0x36, 0x35,
93 0x46, 0x41, 0x54, 0x33, 0x32, 0x20, 0x20, 0x20,
95 0x0e, 0x1f, 0xbe, 0x77 ,0x7c, 0xac,
96 0x22, 0xc0, 0x74, 0x0b, 0x56, 0xb4, 0x0e, 0xbb,
97 0x07, 0x00, 0xcd, 0x10, 0x5e, 0xeb ,0xf0, 0x32,
98 0xe4, 0xcd, 0x16, 0xcd, 0x19, 0xeb, 0xfe,
101 0x4d, 0x45, 0x47, 0x41, 0x36, 0x35, 0x20,
103 'H',
'Y',
'P',
'P',
'O',
'B',
'O',
'O',
'T',
104 0x20, 0x56, 0x30, 0x30, 0x2e, 0x31, 0x31,
105 0x0d, 0x0a, 0x0d, 0x3f, 0x4e, 0x4f, 0x20, 0x34,
106 0x35, 0x47, 0x53, 0x30, 0x32, 0x2c, 0x20, 0x34,
107 0x35, 0x31, 0x30, 0x2c, 0x20, 0x36, 0x35, 0x5b,
108 0x63, 0x65, 0x5d, 0x30, 0x32, 0x2c, 0x20, 0x36,
109 0x35, 0x31, 0x30, 0x20, 0x4f, 0x52, 0x20, 0x38,
110 0x35, 0x31, 0x30, 0x20, 0x50, 0x52, 0x4f, 0x43,
111 0x45, 0x53, 0x53, 0x4f, 0x52, 0x20, 0x20, 0x45,
112 0x52, 0x52, 0x4f, 0x52, 0x0d, 0x0a, 0x49, 0x4e, 0x53,
113 0x45, 0x52, 0x54, 0x20, 0x44, 0x49, 0x53, 0x4b,
114 0x20, 0x49, 0x4e, 0x20, 0x52, 0x45, 0x41, 0x4c,
115 0x20, 0x43, 0x4f, 0x4d, 0x50, 0x55, 0x54, 0x45,
116 0x52, 0x20, 0x41, 0x4e, 0x44, 0x20, 0x54, 0x52,
117 0x59, 0x20, 0x41, 0x47, 0x41, 0x49, 0x4e, 0x2e,
118 0x0a, 0x0a, 0x52, 0x45, 0x41, 0x44, 0x59, 0x2e,
122 #define ZERO_BUFFER() memset(block,0,512)
123 #define WRITE_BLOCK(n) do { if (sdcard_write_block(n,block)) return -1; } while(0)
124 #define WRITE_BLOCK_RANGE(n1,n2) do { for (Uint32 i = n1; i <= n2; i++) if (sdcard_write_block(i,block)) return -1; } while(0)
126 static inline void block_uint32 (
unsigned int ofs,
Uint32 data )
133 static inline void block_uint16 (
unsigned int ofs,
Uint16 data )
142 static int mkfs_fat32 (
Uint32 start_block,
Uint32 number_of_blocks )
144 DEBUGPRINT(
"SDCARD: FAT32FS: creating file system between sectors $%X-$%X, $%X sectors (%uK) in size" NL, start_block, start_block + number_of_blocks - 1, number_of_blocks, number_of_blocks >> 11);
146 const Uint8 sectors_per_cluster = 8;
148 const Uint32 reserved_sectors = boot_bytes[0xE] + (boot_bytes[0xF] << 8);
149 const Uint32 fat_available_sectors = number_of_blocks - reserved_sectors;
150 Uint32 fs_clusters = fat_available_sectors / sectors_per_cluster;
151 Uint32 fat_sectors = fs_clusters/(512 / 4);
152 if (fs_clusters % (512 / 4))
154 Uint32 sectors_required = 2 * fat_sectors+((fs_clusters - 2) * sectors_per_cluster);
155 while (sectors_required > fat_available_sectors) {
156 Uint32 excess_sectors = sectors_required - fat_available_sectors;
157 Uint32 delta = (excess_sectors / (1 + sectors_per_cluster));
160 fs_clusters -= delta;
161 fat_sectors = fs_clusters / (512 / 4);
162 if (fs_clusters % (512 / 4))
164 sectors_required = 2 * fat_sectors + ((fs_clusters - 2) * sectors_per_cluster);
166 Uint32 fat1_sector = reserved_sectors;
167 Uint32 fat2_sector = fat1_sector + fat_sectors;
168 Uint32 rootdir_sector = fat2_sector + fat_sectors;
171 memcpy(
block, boot_bytes,
sizeof boot_bytes);
175 block_uint32(0x20, number_of_blocks);
179 block_uint32(0x24, fat_sectors);
183 WRITE_BLOCK(start_block);
184 WRITE_BLOCK(start_block + 6);
198 block_uint32(0x1e8, 0xFFFFFFFFU);
201 block_uint32(0x1ec, 0xFFFFFFFFU);
205 WRITE_BLOCK(start_block + 1);
206 WRITE_BLOCK(start_block + 7);
209 memcpy(
block, fat_bytes,
sizeof fat_bytes);
210 WRITE_BLOCK(start_block + fat1_sector);
211 WRITE_BLOCK(start_block + fat2_sector);
214 memcpy(
block, default_volume_name, 11);
215 memcpy(
block + 11, dir_bytes,
sizeof dir_bytes);
216 WRITE_BLOCK(start_block + rootdir_sector);
219 WRITE_BLOCK_RANGE(start_block + 1 + 1, start_block + 6 - 1);
220 WRITE_BLOCK_RANGE(start_block + 6 + 1, start_block + fat1_sector - 1);
221 WRITE_BLOCK_RANGE(start_block + fat1_sector + 1, start_block + fat2_sector - 1);
222 WRITE_BLOCK_RANGE(start_block + fat2_sector + 1, start_block + rootdir_sector - 1);
223 WRITE_BLOCK_RANGE(start_block + rootdir_sector + 1, start_block + rootdir_sector + 1 + sectors_per_cluster - 1);
229 static int mksyspart (
Uint32 start_block,
Uint32 number_of_blocks )
231 Uint32 slot_size = 512 * 1024 / 512;
234 Uint32 reserved_sectors = 1024 * 1024 / 512;
235 Uint32 slot_count = (number_of_blocks - reserved_sectors) / (slot_size * 2 + 1);
236 if (slot_count >= 0xffff)
238 Uint16 dir_size = 1 + (slot_count / 4);
239 Uint16 freeze_dir_sectors = dir_size;
240 Uint16 service_dir_sectors = dir_size;
242 Uint32 sys_partition_freeze_dir = reserved_sectors;
244 Uint32 sys_partition_service_dir = sys_partition_freeze_dir + slot_size * slot_count;
247 memcpy(
block, sys_part_magic,
sizeof sys_part_magic);
248 block_uint32(0x10, 0);
249 block_uint32(0x14, slot_size * slot_count + dir_size);
250 block_uint32(0x18, slot_size);
251 block_uint16(0x1c, slot_count);
252 block_uint16(0x1e, dir_size);
253 block_uint32(0x20, slot_size * slot_count + dir_size);
254 block_uint32(0x24, slot_size * slot_count + dir_size);
255 block_uint32(0x28, slot_size);
256 block_uint16(0x2c, slot_count);
257 block_uint16(0x2e, dir_size);
259 sys_partition_freeze_dir += start_block;
260 sys_partition_service_dir += start_block;
261 WRITE_BLOCK(start_block);
277 memcpy(
block + 0x10, default_disk_image, strlen(default_disk_image));
280 WRITE_BLOCK(start_block + 1U);
284 WRITE_BLOCK_RANGE(start_block + 2, start_block + 1023);
286 WRITE_BLOCK_RANGE(sys_partition_freeze_dir, sys_partition_freeze_dir + freeze_dir_sectors - 1);
288 WRITE_BLOCK_RANGE(sys_partition_service_dir, sys_partition_service_dir + service_dir_sectors - 1);
297 static int fdisk (
Uint32 device_size )
299 our_data_partition = -1;
300 DEBUGPRINT(
"SDCARD: FDISK: creating partition table ..." NL);
302 Uint32 sys_part_sects = (device_size - 0x0800) >> 1;
303 if (sys_part_sects > 0x400000)
304 sys_part_sects = 0x400000;
305 sys_part_sects &= 0xfffff800;
306 Uint32 usr_part_sects = device_size - 0x0800 - sys_part_sects;
307 Uint32 usr_part_start = 0x0800;
308 Uint32 sys_part_start = usr_part_start + usr_part_sects;
322 block[0x1c6] = (usr_part_start ) & 0xff;
323 block[0x1c7] = (usr_part_start >> 8) & 0xff;
324 block[0x1c8] = (usr_part_start >> 16) & 0xff;
325 block[0x1c9] = (usr_part_start >> 24) & 0xff;
326 block[0x1ca] = (usr_part_sects ) & 0xff;
327 block[0x1cb] = (usr_part_sects >> 8) & 0xff;
328 block[0x1cc] = (usr_part_sects >> 16) & 0xff;
329 block[0x1cd] = (usr_part_sects >> 24) & 0xff;
332 block[0x1d6] = (sys_part_start ) & 0xff;
333 block[0x1d7] = (sys_part_start >> 8) & 0xff;
334 block[0x1d8] = (sys_part_start >> 16) & 0xff;
335 block[0x1d9] = (sys_part_start >> 24) & 0xff;
336 block[0x1da] = (sys_part_sects ) & 0xff;
337 block[0x1db] = (sys_part_sects >> 8) & 0xff;
338 block[0x1dc] = (sys_part_sects >> 16) & 0xff;
339 block[0x1dd] = (sys_part_sects >> 24) & 0xff;
342 if (mkfs_fat32(usr_part_start, usr_part_sects))
345 if (mksyspart(sys_part_start, sys_part_sects))
352 FATAL(
"First partition entry is not valid even after FDISK!");
354 FATAL(
"First partition cannot be used as FAT32FS even after FDISK/MKFS!");
355 our_data_partition = 0;
372 static int update_sdcard_file (
const char *on_card_name,
int options,
const char *fn_or_data,
int size_to_install )
375 DEBUGPRINT(
"SDCONTENT: about to updating file %s ..." NL, on_card_name);
376 if (size_to_install <= 0) {
379 ERROR_WINDOW(
"SD-card image updater cannot open file:\n%s\n(%s)", fn_or_data, strerror(errno));
380 goto error_on_maybe_sys_file;
383 if (oft ==
OFF_T_ERROR || (size_to_install < 0 && oft != (off_t)(-size_to_install))) {
385 ERROR_WINDOW(
"Bad file, size is incorrect or other I/O error\n%s", fn_or_data);
386 goto error_on_maybe_sys_file;
388 size_to_install = (int)oft;
389 if (!size_to_install)
396 goto error_on_maybe_sys_file;
398 while (size_to_install) {
400 int need = (size_to_install <
sizeof buffer) ? size_to_install :
sizeof buffer;
401 if (need <
sizeof(buffer))
402 memset(buffer + need, 0,
sizeof(buffer) - need);
414 memcpy(buffer, fn_or_data, need);
419 size_to_install -= need;
424 error_on_maybe_sys_file:
425 if ((
options & SDCONTENT_SYS_FILE))
427 "This file is a must for Xemu/MEGA65, however it's under\n"
428 "copyright by their respective owners.\n"
429 "It's totally the user's responsibility to get/use/own/handle this file!\n%s",
439 static int update_from_directory (
const char *dirname,
int options )
441 DIR *
dir = opendir(dirname);
443 ERROR_WINDOW(
"Cannot update SD image / virtual-disk:\nCannot open specified directory:\n%s\n%s",
451 struct dirent *entry = readdir(
dir);
454 if (entry->d_name[0] ==
'.')
457 snprintf(
fn,
sizeof(
fn),
"%s" DIRSEP_STR "%s", dirname, entry->d_name);
460 DEBUGPRINT(
"SDCARD: CONTENT: skipping updating file \"%s\": start() did not worked: %s" NL,
fn, strerror(errno));
463 if ((
st.st_mode & S_IFMT) != S_IFREG) {
464 DEBUGPRINT(
"SDCARD: CONTENT: skipping updating file \"%s\": not a regular file" NL,
fn);
467 if (
st.st_size == 0 ||
st.st_size > MAX_IMPORT_FILE_SIZE) {
468 DEBUGPRINT(
"SDCARD: CONTENT: skipping updating file \"%s\": too large (limit is %d bytes) or null-sized file" NL,
fn, MAX_IMPORT_FILE_SIZE);
471 int ret = update_sdcard_file(entry->d_name,
options,
fn, -(
int)
st.st_size);
472 DEBUGPRINT(
"SDCARD: CONTENT: updated file \"%s\" status is %d" NL,
fn, ret);
481 static int system_files_directory_update_item (
const char *dir_name,
const char *fn_name,
Uint8 *
data, off_t
size,
int options )
498 if ((
options & SDCONENT_UPDATE_SYSDIR) &&
data && !reinstall)
503 fd = open(
fn, O_WRONLY | O_TRUNC | O_CREAT |
O_BINARY, 0666);
514 static int system_files_directory_check (
const char *dir_name,
int policy )
526 memcpy(d81 + 0x61800, d81_at_61800,
sizeof d81_at_61800);
527 memcpy(d81 + 0x61900, d81_at_61900,
sizeof d81_at_61900);
528 ret |= system_files_directory_update_item(dir_name, default_disk_image, d81,
D81_SIZE, policy);
530 ret |= system_files_directory_update_item(dir_name, xemu_disk_image, d81,
D81_SIZE, policy);
539 static const char xemu_sdcard_info_block_id[] =
"XemuInfoBlock_PleaseDoNotDeleteOrModifyThanks";
542 int sdcontent_check_xemu_signature (
void )
550 const int r = strlen(xemu_sdcard_info_block_id) + 1;
551 if (memcmp(xemu_sdcard_info_block_id, buffer,
r)) {
555 ret = (int)(
Uint32)(buffer[
r] + (buffer[
r + 1] << 8) + (buffer[
r + 2] << 16) + (buffer[
r + 3] << 24));
562 static int sdcontent_put_xemu_signature (
void )
565 memset(buffer, 0,
sizeof buffer);
566 strcpy((
char*)buffer, xemu_sdcard_info_block_id);
567 const int r = strlen(xemu_sdcard_info_block_id) + 1;
576 int sdcontent_write_rom_stub (
void )
587 int sdcontent_handle (
Uint32 size_in_blocks,
const char *update_dir_path,
int options )
589 static int init_done = 0;
600 FATAL(
"Cannot read MBR of SD-Card");
602 our_data_partition = -1;
603 if ((
options & SDCONTENT_FORCE_FDISK)) {
606 const char *p = NULL;
609 if (has_block_nonzero_byte(
block)) {
616 p =
"No valid partition entry found for FAT32FS";
618 p =
"Invalid/bad FAT32FS on the data partition";
620 our_data_partition =
part;
624 p =
"Empty MBR (new/empty image?)";
627 if ((
options & SDCONTENT_ASK_FDISK)) {
629 snprintf(msg,
sizeof msg,
"SD-card image seems to have invalid format!\nReason: %s\nCan I format it?\nALL DATA WILL BE LOST!", p);
632 DEBUGPRINT(
"SDCARD: WARNING(SDCONTENT_ASK_FDISK was not requested, but problem detected): %s" NL, p);
637 if (fdisk(size_in_blocks))
640 if ((
options & (SDCONTENT_FORCE_FDISK | SDCONTENT_ASK_FDISK)) && (our_data_partition < 0)) {
641 ERROR_WINDOW(
"Warning! SD-card image content (partitions/fat32fs) seems to be invalid!\nCannot proceed with further SD-card Xemu FS level operations!");
644 if (our_data_partition >= 0) {
645 DEBUGPRINT(
"SDCARD: great, it seems the card format is valid." NL);
650 options &= SDCONTENT_ASK_FILES | SDCONTENT_DO_FILES | SDCONTENT_OVERWRITE_FILES;
652 if (our_data_partition < 0)
653 FATAL(
"System file update/check requested, but format/FS was not validated!");
655 char rom_path[PATH_MAX];
676 ERROR_WINDOW(
"Some error occured while updating your SD-card image file!");
678 sdcontent_put_xemu_signature();
681 if (update_dir_path) {
682 if (our_data_partition < 0)
683 FATAL(
"User directory based file update/check requested, but format/FS was not validated!");
684 return update_from_directory(update_dir_path, SDCONTENT_OVERWRITE_FILES);