Skip to content

Instantly share code, notes, and snippets.

@GXTX
Last active June 22, 2020 20:01
Show Gist options
  • Save GXTX/3bd63bc3d67e50aab27bb6d0c71e3ba3 to your computer and use it in GitHub Desktop.
Save GXTX/3bd63bc3d67e50aab27bb6d0c71e3ba3 to your computer and use it in GitHub Desktop.
/*
backup.c
An application which will backup the manufacturing config sectors &
eeprom while optionally clearing the config sector.
----------------
Copyright (C) 2020 wutno (https://github.com/GXTX)
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program 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 General Public License for more details.
You should have received a copy of the GNU General Public License along
with this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#include <hal/debug.h>
#include <hal/video.h>
#include <nxdk/mount.h>
#include <windows.h>
#include <stdint.h>
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
BOOL read_config(unsigned char *config_buffer)
{
HANDLE file_handle;
IO_STATUS_BLOCK status_block;
OBJECT_ATTRIBUTES obj_attributes;
ANSI_STRING file_name;
NTSTATUS return_status;
LARGE_INTEGER read_offset = { 0x00, 0x00 };
unsigned int sector_size = 0x80000;
RtlInitAnsiString(&file_name, "\\Device\\Harddisk0\\Partition0");
InitializeObjectAttributes(&obj_attributes, &file_name, OBJ_CASE_INSENSITIVE, NULL, NULL);
return_status = NtOpenFile(&file_handle, GENERIC_ALL, &obj_attributes, &status_block, FILE_SHARE_READ, 0);
if (!NT_SUCCESS(return_status)) {
debugPrint("Failed opening drive. Status: 0x%08X\n", return_status);
NtClose(file_handle);
return FALSE;
}
return_status = NtReadFile(file_handle, NULL, NULL, NULL, &status_block, config_buffer, sector_size, &read_offset);
if (!NT_SUCCESS(return_status)) {
debugPrint("Failed reading from the drive. Status: 0x%08X\n", return_status);
NtClose(file_handle);
return FALSE;
}
NtClose(file_handle);
return TRUE;
}
BOOL clear_config(unsigned char *current_config)
{
HANDLE file_handle;
IO_STATUS_BLOCK status_block;
OBJECT_ATTRIBUTES obj_attributes;
ANSI_STRING file_name;
NTSTATUS return_status;
RtlInitAnsiString(&file_name, "\\Device\\Harddisk0\\Partition0");
InitializeObjectAttributes(&obj_attributes, &file_name, OBJ_CASE_INSENSITIVE, NULL, NULL);
return_status = NtOpenFile(&file_handle, GENERIC_ALL, &obj_attributes, &status_block, FILE_SHARE_WRITE, 0);
if (!NT_SUCCESS(return_status)) {
debugPrint("Failed opening drive. Status: 0x%08X\n", return_status);
NtClose(file_handle);
return FALSE;
}
debugPrint("Writing to drive...\n");
LARGE_INTEGER read_offset = { 0x00, 0x00 };
memset((current_config + 0x600 + 0x10), 0x00, (0x80000 - 0x600 + 0x10));
return_status = NtWriteFile(file_handle, NULL, NULL, NULL, &status_block, current_config, 0x80000, &read_offset);
if (!NT_SUCCESS(return_status)) {
debugPrint("Failed writing to the drive. Status: 0x%08X\n", return_status);
NtClose(file_handle);
return FALSE;
} else {
debugPrint("Sucessfully cleared config sector.\n");
}
NtClose(file_handle);
return TRUE;
}
BOOL read_eeprom(unsigned char *eeprom_buffer)
{
ULONG bytes_read;
ULONG eeprom_type;
ExQueryNonVolatileSetting(0xFFFF, &eeprom_type, eeprom_buffer, 256, &bytes_read);
if (bytes_read != 256) {
debugPrint("Failed reading the eeprom. Expected 256, got %02d.\n", bytes_read);
return FALSE;
}
return TRUE;
}
BOOL write_file(const char *name, unsigned char *buffer, size_t buffer_size){
FILE *file;
file = fopen(name, "w");
if (file == NULL) {
debugPrint("Failed opening file to write.\n");
return FALSE;
}
if (fwrite(buffer, 1, buffer_size, file) != buffer_size) {
debugPrint("Failed writing the buffer to disk.\n");
fclose(file);
return FALSE;
}
fclose(file);
return TRUE;
}
int main(void)
{
XVideoSetMode(640, 480, 32, REFRESH_DEFAULT);
if (!nxMountDrive('E', "\\Device\\Harddisk0\\Partition1\\")) {
debugPrint("Failed to mount E: drive!\n");
goto go_to_end;
}
unsigned char *config_buffer = malloc(0x80000);
unsigned char* eeprom_buffer = malloc(0x100);
const char *config_name = "E:\\config.bin";
const char *eeprom_name = "E:\\eeprom.bin";
debugPrint("Reading config sector...\n");
if (!read_config(config_buffer)) {
goto go_to_end;
}
debugPrint("Reading EEPROM...\n");
if (!read_eeprom(eeprom_buffer)) {
goto go_to_end;
}
if (!write_file(config_name, config_buffer, 0x80000) || !write_file(eeprom_name, eeprom_buffer, 0x100)) {
goto go_to_end;
}
debugPrint("Sucessfully wrote backup files.\n");
//debugPrint("Clearing the config sector.\n");
// Remove me if you don't want to clear the config sector.
//clear_config(config_buffer);
go_to_end:
Sleep(10000);
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment