Difference between revisions of "/dev/flash"

From WiiBrew
Jump to navigation Jump to search
(New page: ==Description== /dev/flash provides a raw interface to the NAND flash memory. No file system permissions restrict the access to the NAND memory, however, the contents are encrypted.)
 
(Undo revision 100488 by BrianJones (talk))
 
(10 intermediate revisions by 6 users not shown)
Line 1: Line 1:
 
==Description==
 
==Description==
 
/dev/flash provides a raw interface to the NAND flash memory. No file system permissions restrict the access to the NAND memory, however, the contents are encrypted.
 
/dev/flash provides a raw interface to the NAND flash memory. No file system permissions restrict the access to the NAND memory, however, the contents are encrypted.
 +
 +
Be careful when using these interfaces! Calling the wrong ioctl (or calling write() instead of read()) could have unfortunate results.
 +
 +
=== Reading ===
 +
/dev/flash may be read to get the raw, encrypted contents of the Wii NAND flash chip. You must either read with a block size of 2048 or 2112 (2048 + 64); the former will give you the normal contents of one page, and the latter will give you the same data plus the 64 bytes of OOB / spare / ECC data. The read buffer must be 32 Byte aligned, because a hardware engine is used for copying data. If you hope to use this to eventually restore the contents of your Wii, you MUST back up the spare data.
 +
 +
In between each read, you should seek() to the page number you are trying to read; for example, seeking to 0x200 would put you at page 0x200, the start of the encrypted filesystem. That is to say, you must seek before every access, and the "file position" is in terms of pages, not bytes. There are 256K (262,144) total pages.
 +
 +
=== Ioctls ===
 +
{| class="wikitable"
 +
|-
 +
! Ioctl
 +
! Inputs
 +
! Outputs
 +
! Function
 +
|-
 +
| 1
 +
| 0
 +
| 0x1c bytes
 +
| get_flash_stats
 +
|-
 +
| 2
 +
| 0
 +
| 0x198 bytes
 +
| ?
 +
|-
 +
| 3
 +
| 4 bytes
 +
| 0
 +
| Erase block?
 +
|-
 +
| 4
 +
| 0
 +
| 0
 +
| check_bad_block: if return value is -13, indicates that the block at the current fpos is bad
 +
|}
 +
=== Return Codes ===
 +
(These names were taken from a NAND flash diagnostic program scraped from flash)
 +
 +
* -1: NAND_RESULT_ACCESS
 +
* -3: NAND_RESULT_ECC_CRIT
 +
* -4: NAND_RESULT_CORRUPT
 +
* -5: NAND_RESULT_BUSY
 +
* -6: NAND_RESULT_EXISTS
 +
* -8: NAND_RESULT_INVALID
 +
* -9: NAND_RESULT_MAXBLOCKS
 +
* -10: NAND_RESULT_MAXFD
 +
* -11: NAND_RESULT_MAXFILES
 +
* -12: NAND_RESULT_NOEXISTS
 +
* -13: NAND_RESULT_NOTEMPTY
 +
* -14: NAND_RESULT_OPENFD
 +
* -64: NAND_RESULT_UNKNOWN
 +
* -128: NAND_RESULT_FATALERROR
 +
 +
=== Example Dump Code ===
 +
 +
Here is an example code for dumping complete NAND including ECC:
 +
 +
<source lang="c">
 +
#define NAND_BLOCK_SIZE 0x840
 +
#define NAND_SIZE 0x40000
 +
 +
int dumpnand(void)
 +
{
 +
s32 fd = -1;
 +
FILE *fout = NULL;
 +
static unsigned char buffer[NAND_BLOCK_SIZE] __attribute__ ((aligned(32)));
 +
int rv;
 +
int sector;
 +
 +
printf("NAND dump!\n");
 +
 +
if (!fatInitDefault()) {
 +
printf("Failed to initialize FAT.\n");
 +
return 0;
 +
}
 +
chdir ("fat:/");
 +
fout = fopen("nanddump.bin", "wb");
 +
if (fout == NULL) {
 +
printf("Failed to write nanddump.bin on SD card.\n");
 +
return 0;
 +
}
 +
 +
fd = IOS_Open("/dev/flash", 0);
 +
if (fd < 0) {
 +
fclose(fout);
 +
fatUnmount(PI_DEFAULT);
 +
printf("Failed to open /dev/flash (ret = %d)\n", fd);
 +
return 0;
 +
}
 +
for (sector = 0; sector < NAND_SIZE; sector++) {
 +
rv = IOS_Seek(fd, sector, 0);
 +
if (rv != sector) {
 +
printf("IOS_Seek failed, sector 0x%02x (rv = %d).\n", sector, rv);
 +
break;
 +
}
 +
if ((sector & 0x1f) == 0) {
 +
printf("Sector 0x%02x of 0x%02x\n", sector, NAND_SIZE);
 +
}
 +
rv = IOS_Read(fd, buffer, NAND_BLOCK_SIZE);
 +
if (rv != NAND_BLOCK_SIZE) {
 +
printf("Failed to read NAND sector 0x%02x (rv = %d)\n", sector, rv);
 +
if (rv == -12) {
 +
/* Flash sector seems to be unreadable. Use erase value. */
 +
memset(buffer, 0xFF, NAND_BLOCK_SIZE);
 +
} else {
 +
break;
 +
}
 +
}
 +
rv = fwrite(buffer, NAND_BLOCK_SIZE, 1, fout);
 +
if (rv != 1) {
 +
printf("Failed to write SD card (rv = %d)\n", rv);
 +
break;
 +
}
 +
}
 +
 +
IOS_Close(fd);
 +
fclose(fout);
 +
fatUnmount(PI_DEFAULT);
 +
 +
printf("Finished dump.\n");
 +
return 0;
 +
}
 +
</source>
 +
 +
[[Category:Wii Filesystem]]

Latest revision as of 07:00, 5 August 2012

Description

/dev/flash provides a raw interface to the NAND flash memory. No file system permissions restrict the access to the NAND memory, however, the contents are encrypted.

Be careful when using these interfaces! Calling the wrong ioctl (or calling write() instead of read()) could have unfortunate results.

Reading

/dev/flash may be read to get the raw, encrypted contents of the Wii NAND flash chip. You must either read with a block size of 2048 or 2112 (2048 + 64); the former will give you the normal contents of one page, and the latter will give you the same data plus the 64 bytes of OOB / spare / ECC data. The read buffer must be 32 Byte aligned, because a hardware engine is used for copying data. If you hope to use this to eventually restore the contents of your Wii, you MUST back up the spare data.

In between each read, you should seek() to the page number you are trying to read; for example, seeking to 0x200 would put you at page 0x200, the start of the encrypted filesystem. That is to say, you must seek before every access, and the "file position" is in terms of pages, not bytes. There are 256K (262,144) total pages.

Ioctls

Ioctl Inputs Outputs Function
1 0 0x1c bytes get_flash_stats
2 0 0x198 bytes ?
3 4 bytes 0 Erase block?
4 0 0 check_bad_block: if return value is -13, indicates that the block at the current fpos is bad

Return Codes

(These names were taken from a NAND flash diagnostic program scraped from flash)

  • -1: NAND_RESULT_ACCESS
  • -3: NAND_RESULT_ECC_CRIT
  • -4: NAND_RESULT_CORRUPT
  • -5: NAND_RESULT_BUSY
  • -6: NAND_RESULT_EXISTS
  • -8: NAND_RESULT_INVALID
  • -9: NAND_RESULT_MAXBLOCKS
  • -10: NAND_RESULT_MAXFD
  • -11: NAND_RESULT_MAXFILES
  • -12: NAND_RESULT_NOEXISTS
  • -13: NAND_RESULT_NOTEMPTY
  • -14: NAND_RESULT_OPENFD
  • -64: NAND_RESULT_UNKNOWN
  • -128: NAND_RESULT_FATALERROR

Example Dump Code

Here is an example code for dumping complete NAND including ECC:

#define NAND_BLOCK_SIZE 0x840
#define NAND_SIZE 0x40000

int dumpnand(void)
{
	s32 fd = -1;
	FILE *fout = NULL;
	static unsigned char buffer[NAND_BLOCK_SIZE] __attribute__ ((aligned(32)));
	int rv;
	int sector;

	printf("NAND dump!\n");

	if (!fatInitDefault()) {
		printf("Failed to initialize FAT.\n");
		return 0;
	}
	chdir ("fat:/");
	fout = fopen("nanddump.bin", "wb");
	if (fout == NULL) {
		printf("Failed to write nanddump.bin on SD card.\n");
		return 0;
	}

	fd = IOS_Open("/dev/flash", 0);
	if (fd < 0) {
		fclose(fout);
		fatUnmount(PI_DEFAULT);
		printf("Failed to open /dev/flash (ret = %d)\n", fd);
		return 0;
	}
	for (sector = 0; sector < NAND_SIZE; sector++) {
		rv = IOS_Seek(fd, sector, 0);
		if (rv != sector) {
			printf("IOS_Seek failed, sector 0x%02x (rv = %d).\n", sector, rv);
			break;
		}
		if ((sector & 0x1f) == 0) {
			printf("Sector 0x%02x of 0x%02x\n", sector, NAND_SIZE);
		}
		rv = IOS_Read(fd, buffer, NAND_BLOCK_SIZE);
		if (rv != NAND_BLOCK_SIZE) {
			printf("Failed to read NAND sector 0x%02x (rv = %d)\n", sector, rv);
			if (rv == -12) {
				/* Flash sector seems to be unreadable. Use erase value. */
				memset(buffer, 0xFF, NAND_BLOCK_SIZE);
			} else {
				break;
			}
		}
		rv = fwrite(buffer, NAND_BLOCK_SIZE, 1, fout);
		if (rv != 1) {
			printf("Failed to write SD card (rv = %d)\n", rv);
			break;
		}
	}
	
	IOS_Close(fd);
	fclose(fout);
	fatUnmount(PI_DEFAULT);

	printf("Finished dump.\n");
	return 0;
}