/* ***************************************************************************** * usage/backup.c -- backup software elements of the calculator. * Copyright (C) 2016-2017 Thomas "Cakeisalie5" Touhey * * This file is part of libp7. * libp7 is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation; either version 3.0 of the License, * or (at your option) any later version. * * libp7 is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with libp7; if not, see . * ************************************************************************** */ #include #include /* ************************************************************************** */ /* Decode a CASIOWIN entry */ /* ************************************************************************** */ /* Raw structure */ struct casiowin_entry { /* contains "CASIOWIN" */ unsigned char magic[0x08]; /* code that calls the subroutine at address 0x00010080 */ unsigned char call_os[0x0A]; /* alignment? */ unsigned char _align[0x0A]; /* marker for the OS updater PC program * (appeared in 1.01, no longer used in OS2) * - fx-9860G AU: "365E" * - fx-9860G SD Slim: 0x80005D7C */ unsigned char marker[0x04]; /* version (added in OS 1.02): "xx.xx.xxxx" */ unsigned char version[0x0A]; /* alignment? */ unsigned char _align2[0x06]; /* unused */ unsigned char _unused[0x40]; /* syscall code */ unsigned char call_sys[0x0A]; /* alignment? */ unsigned char _align3[0x02]; /* syscall table address */ uint32_t syscall_table; }; /** * decode_entry: * Decode an entry. * * @arg handle the handle. * @arg entry the decoded thing. * @arg raw the raw thing (uncasted). * @return the error code (0 if ok) */ static int decode_entry(p7_handle_t *handle, p7_casiowin_entry_t *entry, struct casiowin_entry *raw) { (void)handle; /* check the maaa-gic */ if (!memcmp(raw->magic, "CASIOWIN", 8)) return (p7_error_checksum); /* decode */ g1m_decode_version((char*)raw->version, &entry->p7_casiowin_entry_version); entry->p7_casiowin_entry_syscall_table_offset = be32toh(raw->syscall_table); /* log */ log_info("OS version is %.10s", raw->version); log_info("OS syscall table offset is 0x%08" PRIxP7INT, entry->p7_casiowin_entry_syscall_table_offset); /* no error */ return (0); } /* ************************************************************************** */ /* Get a CASIOWIN entry */ /* ************************************************************************** */ /** * p7_backup_casiowin_entry: * Backup the CASIOWIN entry. * * @arg handle the libp7 handle * @arg entry the entry to fill (0x80 bytes). * @return the error code (0 if ok) */ p7_define_ufunc(p7_backup_casiowin_entry, p7_attrs_backup_casiowin_entry, p7_handle_t *handle, p7_casiowin_entry_t *entry) { int err; /* make checks */ chk_handle(handle); chk_seven(handle); chk_active(handle); /* send command packet */ log_info("sending command"); if ((err = p7_seven_send_cmdbak_reqcwe(handle))) { log_fatal("couldn't send command/get response"); return (err); } else if (response.p7_seven_packet_type == p7_seven_type_error && response.p7_seven_packet_code == p7_seven_err_other) { log_fatal("backup is unsupported."); return (p7_error_unsupported); } else if (response.p7_seven_packet_type != p7_seven_type_ack) { log_fatal("received an invalid answer"); return (p7_error_unknown); } /* send the roleswap */ log_info("sending the roleswap"); if ((err = p7_seven_send_swp(handle))) { log_fatal("couldn't send roleswap"); return (err); } else if (response.p7_seven_packet_type != p7_seven_type_cmd || response.p7_seven_packet_code != 0x53) { log_fatal("didn't receive correct command"); return (p7_error_unknown); } /* get the data */ struct casiowin_entry raw; err = p7_seven_get_data(handle, &raw, sizeof(struct casiowin_entry), 0, NULL); if (err) return (err); /* decode and return */ return (decode_entry(handle, entry, &raw)); } /* ************************************************************************** */ /* Backup the bootcode */ /* ************************************************************************** */ /** * p7_backup_boot: * Backup the boot code. * * My current theory is that the bootcode size is in the bootcode, that * the OS reads it or not, and that even if the OS accepts bootcode backup * and reads it, the bootcode had blanked its size... so in order to make it * work correctly, I'll have to hardcode the size of the bootcode (64 KiB * on all of the known models until now). * * @arg handle the libp7 handle * @arg buffer the destination buffer. * @arg disp the display function * @return the error code (0 if ok) */ #define bootcode_size (0x10000) p7_define_ufunc(p7_backup_boot, p7_attrs_backup_boot, p7_handle_t *handle, const p7_buffer_t *buffer, p7_disp_t *disp) { int err; /* make checks */ chk_handle(handle); chk_seven(handle); chk_active(handle); chk_bufwrite(buffer); /* send command packet */ log_info("sending command"); if ((err = p7_seven_send_cmdbak_reqboot(handle))) { log_fatal("couldn't send command/get response"); return (err); } else if (response.p7_seven_packet_type == p7_seven_type_error && response.p7_seven_packet_code == p7_seven_err_other) { log_fatal("backup is unsupported."); return (p7_error_unsupported); } else if (response.p7_seven_packet_type != p7_seven_type_ack) { log_fatal("received an invalid answer"); return (p7_error_unknown); } /* send the roleswap */ log_info("sending the roleswap"); if ((err = p7_seven_send_swp(handle))) { log_fatal("couldn't send roleswap"); return (err); } else if (response.p7_seven_packet_type != p7_seven_type_cmd) { log_fatal("didn't receive command"); return (p7_error_unknown); } /* get the data */ if ((err = p7_seven_get_buffer(handle, buffer, bootcode_size, 0, disp))) return (err); /* we're good */ return (0); } #ifndef P7_DISABLED_FILE /** * p7_backup_bootfile: * Backup the boot to a FILE. * * @arg handle the handle. * @arg file the FILE. * @arg disp the display callback. * @return the error code (0 if ok). */ p7_define_ufunc(p7_backup_bootfile, p7_attrs_backup_bootfile, p7_handle_t *handle, FILE *file, p7_disp_t *disp) { chk_iswrite(file); p7_buffer_t buffer = { .p7_buffer_cookie = file, .p7_buffer_write = p7_filebuffer_write }; return (p7_backup_boot(handle, &buffer, disp)); } #endif /* ************************************************************************** */ /* Backup the ROM */ /* ************************************************************************** */ /** * p7_backup_rom: * Backup the Flash ROM. * * @arg handle the libp7 handle. * @arg file the filestream. * @arg disp the display function. * @return the error code (0 if ok) */ #define rom_size (handle->_server.p7_server_flash_rom_capacity) p7_define_ufunc(p7_backup_rom, p7_attrs_backup_rom, p7_handle_t *handle, const p7_buffer_t *buffer, p7_disp_t *disp) { int err; /* make checks */ chk_handle(handle); chk_seven(handle); chk_active(handle); chk_bufwrite(buffer); /* send command packet */ log_info("sending command"); if ((err = p7_seven_send_cmdbak_reqrom(handle))) { log_fatal("couldn't send command/get response"); return (err); } else if (response.p7_seven_packet_type == p7_seven_type_error && response.p7_seven_packet_code == p7_seven_err_other) { log_fatal("backup is unsupported."); return (p7_error_unsupported); } else if (response.p7_seven_packet_type != p7_seven_type_ack) { log_fatal("received an invalid answer"); return (p7_error_unknown); } /* send the roleswap */ log_info("sending the roleswap"); if ((err = p7_seven_send_roleswp(handle))) { log_fatal("couldn't send roleswap"); return (err); } else if (response.p7_seven_packet_type != p7_seven_type_cmd) { log_fatal("didn't receive command"); return (p7_error_unknown); } /* get the data */ if ((err = p7_seven_get_buffer(handle, buffer, rom_size, 0, disp))) return (err); /* we're good */ return (0); } #ifndef P7_DISABLED_FILE /** * p7_backup_romfile: * Backup the ROM to a FILE. * * @arg handle the handle. * @arg file the FILE. * @arg disp the display callback. * @return the error code (0 if ok). */ p7_define_ufunc(p7_backup_romfile, p7_attrs_backup_romfile, p7_handle_t *handle, FILE *file, p7_disp_t *disp) { chk_iswrite(file); p7_buffer_t buffer = { .p7_buffer_cookie = file, .p7_buffer_write = p7_filebuffer_write }; return (p7_backup_rom(handle, &buffer, disp)); } #endif /* ************************************************************************** */ /* Backup the RAM */ /* ************************************************************************** */ /** * p7_backup_ram: * Backup the RAM. * * @arg handle the libp7 handle. * @arg file the filestream. * @arg disp the display function. * @return the error code (0 if ok) */ #define ram_size (0x10000) p7_define_ufunc(p7_backup_ram, p7_attrs_backup_ram, p7_handle_t *handle, const p7_buffer_t *buffer, p7_disp_t *disp) { int err; /* make checks */ chk_handle(handle); chk_seven(handle); chk_active(handle); chk_bufwrite(buffer); /* send command packet */ log_info("sending command"); if ((err = p7_seven_send_cmdbak_reqram(handle))) { log_fatal("couldn't send command/get response"); return (err); } else if (response.p7_seven_packet_type == p7_seven_type_error && response.p7_seven_packet_code == p7_seven_err_other) { log_fatal("backup is unsupported."); return (p7_error_unsupported); } else if (response.p7_seven_packet_type != p7_seven_type_ack) { log_fatal("received an invalid answer"); return (p7_error_unknown); } /* send the roleswap */ log_info("sending the roleswap"); if ((err = p7_seven_send_roleswp(handle))) { log_fatal("couldn't send roleswap"); return (err); } else if (response.p7_seven_packet_type != p7_seven_type_cmd) { log_fatal("didn't receive command"); return (p7_error_unknown); } /* get the data */ if ((err = p7_seven_get_buffer(handle, buffer, ram_size, 0, disp))) return (err); /* we're good */ return (0); } #ifndef P7_DISABLED_FILE /** * p7_backup_ramfile: * Backup the RAM to a FILE. * * @arg handle the handle. * @arg file the FILE. * @arg disp the display callback. * @return the error code (0 if ok). */ p7_define_ufunc(p7_backup_ramfile, p7_attrs_backup_ramfile, p7_handle_t *handle, FILE *file, p7_disp_t *disp) { chk_iswrite(file); p7_buffer_t buffer = { .p7_buffer_cookie = file, .p7_buffer_write = p7_filebuffer_write }; return (p7_backup_ram(handle, &buffer, disp)); } #endif