delete old stage2

This commit is contained in:
Jan Hofmeier 2023-10-30 16:07:09 +01:00
parent 609c97a5a6
commit 2de4eaf48d
61 changed files with 0 additions and 43335 deletions

View File

@ -1,102 +0,0 @@
#include "aes.h"
#include "latte.h"
#include "utils.h"
#include "memory.h"
#include "string.h"
#define AES_CMD_RESET 0
#define AES_CMD_ENCRYPT 0x9000
#define AES_CMD_DECRYPT 0x9800
static inline void aes_command(u16 cmd, u8 iv_keep, u32 blocks)
{
if (blocks != 0)
blocks--;
write32(AES_CTRL, (cmd << 16) | (iv_keep ? 0x1000 : 0) | (blocks&0x7f));
while (read32(AES_CTRL) & 0x80000000);
}
void aes_reset(void)
{
write32(AES_CTRL, 0);
while (read32(AES_CTRL) != 0);
}
void aes_set_iv(u8 *iv)
{
int i;
for(i = 0; i < 4; i++) {
write32(AES_IV, *(u32 *)iv);
iv += 4;
}
}
void aes_empty_iv(void)
{
int i;
for(i = 0; i < 4; i++)
write32(AES_IV, 0);
}
void aes_set_key(u8 *key)
{
int i;
for(i = 0; i < 4; i++) {
write32(AES_KEY, *(u32 *)key);
key += 4;
}
}
void aes_decrypt(u8 *src, u8 *dst, u32 blocks, u8 keep_iv)
{
dc_flushrange(src, blocks * 16);
dc_invalidaterange(dst, blocks * 16);
ahb_flush_to(RB_AES);
int this_blocks = 0;
while(blocks > 0) {
this_blocks = blocks;
if (this_blocks > 0x80)
this_blocks = 0x80;
write32(AES_SRC, dma_addr(src));
write32(AES_DEST, dma_addr(dst));
aes_command(AES_CMD_DECRYPT, keep_iv, this_blocks);
blocks -= this_blocks;
src += this_blocks<<4;
dst += this_blocks<<4;
keep_iv = 1;
}
ahb_flush_from(WB_AES);
ahb_flush_to(RB_IOD);
}
void aes_encrypt(u8 *src, u8 *dst, u32 blocks, u8 keep_iv)
{
dc_flushrange(src, blocks * 16);
dc_invalidaterange(dst, blocks * 16);
ahb_flush_to(RB_AES);
int this_blocks = 0;
while(blocks > 0) {
this_blocks = blocks;
if (this_blocks > 0x80)
this_blocks = 0x80;
write32(AES_SRC, dma_addr(src));
write32(AES_DEST, dma_addr(dst));
aes_command(AES_CMD_ENCRYPT, keep_iv, this_blocks);
blocks -= this_blocks;
src += this_blocks<<4;
dst += this_blocks<<4;
keep_iv = 1;
}
ahb_flush_from(WB_AES);
ahb_flush_to(RB_IOD);
}

View File

@ -1,29 +0,0 @@
/*
* minute - a port of the "mini" IOS replacement for the Wii U.
*
* Copyright (C) 2016 SALT
* Copyright (C) 2016 Daz Jones <daz@dazzozo.com>
*
* Copyright (C) 2008, 2009 Haxx Enterprises <bushing@gmail.com>
* Copyright (C) 2008, 2009 Sven Peter <svenpeter@gmail.com>
* Copyright (C) 2008, 2009 Hector Martin "marcan" <marcan@marcansoft.com>
*
* This code is licensed to you under the terms of the GNU GPL, version 2;
* see file COPYING or http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt
*/
#ifndef __AES_H__
#define __AES_H__
#include "types.h"
#define AES_BLOCK_SIZE 16
void aes_reset(void);
void aes_set_iv(u8 *iv);
void aes_empty_iv();
void aes_set_key(u8 *key);
void aes_decrypt(u8 *src, u8 *dst, u32 blocks, u8 keep_iv);
void aes_encrypt(u8 *src, u8 *dst, u32 blocks, u8 keep_iv);
#endif /* __AES_H__ */

View File

@ -1,73 +0,0 @@
/*
* minute - a port of the "mini" IOS replacement for the Wii U.
*
* Copyright (C) 2016 SALT
* Copyright (C) 2016 Daz Jones <daz@dazzozo.com>
*
* This code is licensed to you under the terms of the GNU GPL, version 2;
* see file COPYING or http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt
*/
#include "types.h"
#include "utils.h"
#include "memory.h"
#include "debug.h"
#include <string.h>
#include <sys/errno.h>
#include <stdio.h>
#include "sha.h"
#include "crypto.h"
#include "smc.h"
#include "ancast.h"
void ancast_iop_clear(u8* buffer)
{
memset(&buffer[0], 0, 0x200);
}
u32 ancast_iop_load(u8* buffer, size_t size)
{
u32 magic = read32((u32) buffer);
if(magic != ANCAST_MAGIC) {
DEBUG("ancast_iop_load: not an ancast image (magic is 0x%08lX, expected 0x%08lX).\n", magic, ANCAST_MAGIC);
return 0;
}
u32 sig_offset = read32((u32) &buffer[0x08]);
u32 sig_type = read32((u32) &buffer[sig_offset]);
if (sig_type != 0x02) {
DEBUG("ancast_iop_load: unexpected signature type 0x%02lX.\n", sig_type);
return 0;
}
ancast_header* ancast = (ancast_header*)&buffer[0x1A0];
u8 target = ancast->device >> 4;
if(target != ANCAST_TARGET_IOP) {
DEBUG("ancast: not an IOP image (target is 0x%02X, expected 0x%02X).\n", target, ANCAST_TARGET_IOP);
return 0;
}
u8* body = (u8*)(ancast + 1);
u32 hash[SHA_HASH_WORDS] = {0};
sha_hash(body, hash, ancast->body_size);
u32* h1 = ancast->body_hash;
u32* h2 = hash;
if(memcmp(h1, h2, SHA_HASH_SIZE) != 0) {
DEBUG("ancast: body hash check failed.\n");
DEBUG(" expected: %08lX%08lX%08lX%08lX%08lX\n", h1[0], h1[1], h1[2], h1[3], h1[4]);
DEBUG(" calculated: %08lX%08lX%08lX%08lX%08lX\n", h2[0], h2[1], h2[2], h2[3], h2[4]);
return 0;
}
ios_header* header = (ios_header*)body;
u32 vector = (u32) &body[header->header_size];
return vector;
}

View File

@ -1,43 +0,0 @@
/*
* minute - a port of the "mini" IOS replacement for the Wii U.
*
* Copyright (C) 2016 SALT
* Copyright (C) 2016 Daz Jones <daz@dazzozo.com>
*
* This code is licensed to you under the terms of the GNU GPL, version 2;
* see file COPYING or http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt
*/
#ifndef _ANCAST_H
#define _ANCAST_H
#include "types.h"
#include "sha.h"
#define ANCAST_MAGIC (0xEFA282D9l)
#define ANCAST_TARGET_IOP (0x02)
#define ANCAST_ADDRESS_IOP (0x01000000)
typedef struct {
u16 unk1;
u8 unk2;
u8 unk3;
u32 device;
u32 type;
u32 body_size;
u32 body_hash[SHA_HASH_WORDS];
u32 version;
u8 padding[0x38];
} ancast_header;
typedef struct {
u32 header_size;
u32 loader_size;
u32 elf_size;
u32 ddr_init;
} ios_header;
void ancast_iop_clear(u8* buffer);
u32 ancast_iop_load(u8* buffer, size_t size);
#endif

View File

@ -1,37 +0,0 @@
/*
* minute - a port of the "mini" IOS replacement for the Wii U.
*
* Copyright (C) 2016 SALT
* Copyright (C) 2016 Daz Jones <daz@dazzozo.com>
*
* Copyright (C) 2008, 2009 Sven Peter <svenpeter@gmail.com>
*
* This code is licensed to you under the terms of the GNU GPL, version 2;
* see file COPYING or http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt
*/
#ifndef __BSDTYPES_H__
#define __BSDTYPES_H__
#include "types.h"
#include "errno.h"
#include <sys/types.h>
//typedef u32 u_int;
typedef u32 u_int32_t;
typedef u16 u_int16_t;
typedef u8 u_int8_t;
typedef u8 u_char;
typedef u32 bus_space_tag_t;
typedef u32 bus_space_handle_t;
#define MIN(a, b) (((a)>(b))?(b):(a))
#define wakeup(...)
#define ISSET(var, mask) (((var) & (mask)) ? 1 : 0)
#define SET(var, mask) ((var) |= (mask))
#endif

View File

@ -1,36 +0,0 @@
/*
* minute - a port of the "mini" IOS replacement for the Wii U.
*
* Copyright (C) 2016 SALT
* Copyright (C) 2016 Daz Jones <daz@dazzozo.com>
*
* Copyright (C) 2008, 2009 Haxx Enterprises <bushing@gmail.com>
* Copyright (C) 2008, 2009 Sven Peter <svenpeter@gmail.com>
*
* This code is licensed to you under the terms of the GNU GPL, version 2;
* see file COPYING or http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt
*/
#include "crypto.h"
#include "latte.h"
#include "utils.h"
#include "memory.h"
#include "irq.h"
#include "string.h"
#include "aes.h"
otp_t otp;
void crypto_read_otp(void)
{
u32 *otpd = (u32*)&otp;
int word, bank;
for (bank = 0; bank < 8; bank++)
{
for (word = 0; word < 0x20; word++)
{
write32(LT_OTPCMD, 0x80000000 | bank << 8 | word);
*otpd++ = read32(LT_OTPDATA);
}
}
}

View File

@ -1,136 +0,0 @@
/*
* minute - a port of the "mini" IOS replacement for the Wii U.
*
* Copyright (C) 2016 SALT
* Copyright (C) 2016 Daz Jones <daz@dazzozo.com>
*
* Copyright (C) 2008, 2009 Haxx Enterprises <bushing@gmail.com>
* Copyright (C) 2008, 2009 Sven Peter <svenpeter@gmail.com>
* Copyright (C) 2008, 2009 Hector Martin "marcan" <marcan@marcansoft.com>
*
* This code is licensed to you under the terms of the GNU GPL, version 2;
* see file COPYING or http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt
*/
#ifndef __CRYPTO_H__
#define __CRYPTO_H__
#include "types.h"
typedef struct
{
// Bank 0 (Wii)
struct {
u8 wii_boot1_hash[20];
u8 wii_common_key[16];
u32 wii_ng_id;
union {
struct {
u8 wii_ng_priv[30];
u8 _wii_wtf1[18];
};
struct {
u8 _wii_wtf2[28];
u8 wii_nand_hmac[20];
};
};
u8 wii_nand_key[16];
u8 wii_rng_key[16];
u32 wii_unk1;
u32 wii_unk2; // 0x00000007
};
// Bank 1 (Wii U)
struct {
u32 security_level;
u32 iostrength_flag;
u32 seeprom_pulse;
u32 unk1;
u8 fw_ancast_key[16];
u8 seeprom_key[16];
u8 unk2[16];
u8 unk3[16];
u8 vwii_common_key[16];
u8 common_key[16];
u8 unk4[16];
};
// Bank 2 (Wii U)
struct {
u8 unk5[16];
u8 unk6[16];
u8 ssl_master_key[16];
u8 external_master_key[16];
u8 unk7[16];
u8 xor_key[16];
u8 rng_key[16];
u8 nand_key[16];
};
// Bank 3 (Wii U)
struct {
u8 emmc_key[16];
u8 dev_master_key[16];
u8 drh_key[16];
u8 unk8[48];
u8 nand_hmac[20];
u8 unk9[12];
};
// Bank 4 (Wii U)
struct {
u8 unk10[16];
union {
u8 external_seed_full[16];
struct {
u8 _wtf1[12];
u8 external_seed[4];
};
};
u8 vwii_ng_priv[32];
u8 unk11[32];
union {
u8 rng_seed_full[16];
struct {
u32 rng_seed;
u8 _wtf2[12];
};
};
u8 unk12[16];
};
// Bank 5 (Wii U)
struct {
u32 rootca_version;
u32 rootca_ms;
u32 unk13;
u8 rootca_signature[64];
u8 unk14[20];
u8 unk15[32];
};
// Bank 6 (Wii SEEPROM)
struct {
u8 wii_seeprom_certificate[96];
u8 wii_seeprom_signature[32];
};
// Bank 7 (Misc.)
struct {
u8 unk16[32];
u8 boot1_key[16];
u8 unk17[16];
u8 _empty1[32];
u8 unk18[16];
char ascii_tag[12];
u32 jtag_status;
};
} __attribute__((packed, aligned(4))) otp_t;
_Static_assert(sizeof(otp_t) == 0x400, "OTP size must be 0x400!");
extern otp_t otp;
void crypto_read_otp();
#endif

View File

@ -1,28 +0,0 @@
/*
* minute - a port of the "mini" IOS replacement for the Wii U.
*
* Copyright (C) 2016 SALT
* Copyright (C) 2016 Daz Jones <daz@dazzozo.com>
*
* Copyright (C) 2008, 2009 Haxx Enterprises <bushing@gmail.com>
* Copyright (C) 2008, 2009 Sven Peter <svenpeter@gmail.com>
* Copyright (C) 2008, 2009 Hector Martin "marcan" <marcan@marcansoft.com>
*
* This code is licensed to you under the terms of the GNU GPL, version 2;
* see file COPYING or http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt
*/
#ifndef __DEBUG_H__
#define __DEBUG_H__
#include "types.h"
#include "stdio.h"
#ifndef ENABLE_DEBUG
static inline void DEBUG(char *fmt, ...) {}
#else
#define DEBUG(...) printf(__VA_ARGS__)
#endif
#endif /* __DEBUG_H__ */

View File

@ -1,167 +0,0 @@
/*-----------------------------------------------------------------------*/
/* Low level disk I/O module skeleton for FatFs (C)ChaN, 2014 */
/*-----------------------------------------------------------------------*/
/* If a working storage control module is available, it should be */
/* attached to the FatFs via a glue function rather than modifying it. */
/* This is an example of glue functions to attach various exsisting */
/* storage control modules to the FatFs module with a defined API. */
/*-----------------------------------------------------------------------*/
#include "diskio.h" /* FatFs lower layer API */
#include "ff.h"
#include <wctype.h>
#include "string.h"
#include "sdcard.h"
#include "sdhc.h"
#include "utils.h"
static u8 buffer[SDMMC_DEFAULT_BLOCKLEN * SDHC_BLOCK_COUNT_MAX] ALIGNED(32);
/*-----------------------------------------------------------------------*/
/* Get Disk Status */
/*-----------------------------------------------------------------------*/
DSTATUS disk_status (
BYTE pdrv /* Physical drive number to identify the drive */
)
{
(void)pdrv;
switch(sdcard_check_card()) {
case SDMMC_INSERTED:
return 0;
case SDMMC_NEW_CARD:
return STA_NOINIT;
default:
return STA_NODISK;
}
}
/*-----------------------------------------------------------------------*/
/* Initialize a Drive */
/*-----------------------------------------------------------------------*/
DSTATUS disk_initialize (
BYTE pdrv /* Physical drive number to identify the drive */
)
{
if (sdcard_check_card() == SDMMC_NO_CARD)
return STA_NODISK;
sdcard_ack_card();
return disk_status(pdrv);
}
/*-----------------------------------------------------------------------*/
/* Read Sector(s) */
/*-----------------------------------------------------------------------*/
DRESULT disk_read (
BYTE pdrv, /* Physical drive number to identify the drive */
BYTE *buff, /* Data buffer to store read data */
DWORD sector, /* Sector address in LBA */
UINT count /* Number of sectors to read */
)
{
(void)pdrv;
while(count) {
u32 work = min(count, SDHC_BLOCK_COUNT_MAX);
if(sdcard_read(sector, work, buffer) != 0)
return RES_ERROR;
memcpy(buff, buffer, work * SDMMC_DEFAULT_BLOCKLEN);
sector += work;
count -= work;
buff += work * SDMMC_DEFAULT_BLOCKLEN;
}
return RES_OK;
}
/*-----------------------------------------------------------------------*/
/* Write Sector(s) */
/*-----------------------------------------------------------------------*/
#if _USE_WRITE
DRESULT disk_write (
BYTE pdrv, /* Physical drive number to identify the drive */
const BYTE *buff, /* Data to be written */
DWORD sector, /* Sector address in LBA */
UINT count /* Number of sectors to write */
)
{
(void)pdrv;
while(count) {
u32 work = min(count, SDHC_BLOCK_COUNT_MAX);
memcpy(buffer, buff, work * SDMMC_DEFAULT_BLOCKLEN);
if(sdcard_write(sector, work, buffer) != 0)
return RES_ERROR;
sector += work;
count -= work;
buff += work * SDMMC_DEFAULT_BLOCKLEN;
}
return RES_OK;
}
#endif
/*-----------------------------------------------------------------------*/
/* Miscellaneous Functions */
/*-----------------------------------------------------------------------*/
#if _USE_IOCTL
DRESULT disk_ioctl (
BYTE pdrv, /* Physical drive number to identify the drive */
BYTE cmd, /* Control code */
void *buff /* Buffer to send/receive control data */
)
{
(void)pdrv;
if (cmd == CTRL_SYNC)
return RES_OK;
if (cmd == GET_SECTOR_SIZE) {
*(u32*)buff = SDMMC_DEFAULT_BLOCKLEN;
return RES_OK;
}
if (cmd == GET_BLOCK_SIZE) {
*(u32*)buff = 1;
return RES_OK;
}
if (cmd == GET_SECTOR_COUNT) {
int sectors = sdcard_get_sectors();
if(sectors < 0) return RES_ERROR;
*(u32*)buff = sectors;
return RES_OK;
}
return RES_PARERR;
}
#endif
DWORD get_fattime()
{
// NO
return 0;
}
#include "option/unicode.c"

View File

@ -1,79 +0,0 @@
/*-----------------------------------------------------------------------/
/ Low level disk interface modlue include file (C)ChaN, 2014 /
/-----------------------------------------------------------------------*/
#ifndef _DISKIO_DEFINED
#define _DISKIO_DEFINED
#ifdef __cplusplus
extern "C" {
#endif
#define _USE_WRITE 1 /* 1: Enable disk_write function */
#define _USE_IOCTL 1 /* 1: Enable disk_ioctl fucntion */
#include "integer.h"
/* Status of Disk Functions */
typedef BYTE DSTATUS;
/* Results of Disk Functions */
typedef enum {
RES_OK = 0, /* 0: Successful */
RES_ERROR, /* 1: R/W Error */
RES_WRPRT, /* 2: Write Protected */
RES_NOTRDY, /* 3: Not Ready */
RES_PARERR /* 4: Invalid Parameter */
} DRESULT;
/*---------------------------------------*/
/* Prototypes for disk control functions */
DSTATUS disk_initialize (BYTE pdrv);
DSTATUS disk_status (BYTE pdrv);
DRESULT disk_read (BYTE pdrv, BYTE* buff, DWORD sector, UINT count);
DRESULT disk_write (BYTE pdrv, const BYTE* buff, DWORD sector, UINT count);
DRESULT disk_ioctl (BYTE pdrv, BYTE cmd, void* buff);
/* Disk Status Bits (DSTATUS) */
#define STA_NOINIT 0x01 /* Drive not initialized */
#define STA_NODISK 0x02 /* No medium in the drive */
#define STA_PROTECT 0x04 /* Write protected */
/* Command code for disk_ioctrl fucntion */
/* Generic command (Used by FatFs) */
#define CTRL_SYNC 0 /* Complete pending write process (needed at _FS_READONLY == 0) */
#define GET_SECTOR_COUNT 1 /* Get media size (needed at _USE_MKFS == 1) */
#define GET_SECTOR_SIZE 2 /* Get sector size (needed at _MAX_SS != _MIN_SS) */
#define GET_BLOCK_SIZE 3 /* Get erase block size (needed at _USE_MKFS == 1) */
#define CTRL_TRIM 4 /* Inform device that the data on the block of sectors is no longer used (needed at _USE_TRIM == 1) */
/* Generic command (Not used by FatFs) */
#define CTRL_POWER 5 /* Get/Set power status */
#define CTRL_LOCK 6 /* Lock/Unlock media removal */
#define CTRL_EJECT 7 /* Eject media */
#define CTRL_FORMAT 8 /* Create physical format on the media */
/* MMC/SDC specific ioctl command */
#define MMC_GET_TYPE 10 /* Get card type */
#define MMC_GET_CSD 11 /* Get CSD */
#define MMC_GET_CID 12 /* Get CID */
#define MMC_GET_OCR 13 /* Get OCR */
#define MMC_GET_SDSTAT 14 /* Get SD status */
/* ATA/CF specific ioctl command */
#define ATA_GET_REV 20 /* Get F/W revision */
#define ATA_GET_MODEL 21 /* Get model name */
#define ATA_GET_SN 22 /* Get serial number */
#ifdef __cplusplus
}
#endif
#endif

File diff suppressed because it is too large Load Diff

View File

@ -1,350 +0,0 @@
/*---------------------------------------------------------------------------/
/ FatFs - FAT file system module include R0.11a (C)ChaN, 2015
/----------------------------------------------------------------------------/
/ FatFs module is a free software that opened under license policy of
/ following conditions.
/
/ Copyright (C) 2015, ChaN, all right reserved.
/
/ 1. Redistributions of source code must retain the above copyright notice,
/ this condition and the following disclaimer.
/
/ This software is provided by the copyright holder and contributors "AS IS"
/ and any warranties related to this software are DISCLAIMED.
/ The copyright owner or contributors be NOT LIABLE for any damages caused
/ by use of this software.
/---------------------------------------------------------------------------*/
#ifndef _FATFS
#define _FATFS 64180 /* Revision ID */
#ifdef __cplusplus
extern "C" {
#endif
#include "integer.h" /* Basic integer types */
#include "ffconf.h" /* FatFs configuration options */
#if _FATFS != _FFCONF
#error Wrong configuration file (ffconf.h).
#endif
/* Definitions of volume management */
#if _MULTI_PARTITION /* Multiple partition configuration */
typedef struct {
BYTE pd; /* Physical drive number */
BYTE pt; /* Partition: 0:Auto detect, 1-4:Forced partition) */
} PARTITION;
extern PARTITION VolToPart[]; /* Volume - Partition resolution table */
#define LD2PD(vol) (VolToPart[vol].pd) /* Get physical drive number */
#define LD2PT(vol) (VolToPart[vol].pt) /* Get partition index */
#else /* Single partition configuration */
#define LD2PD(vol) (BYTE)(vol) /* Each logical drive is bound to the same physical drive number */
#define LD2PT(vol) 0 /* Find first valid partition or in SFD */
#endif
/* Type of path name strings on FatFs API */
#if _LFN_UNICODE /* Unicode string */
#if !_USE_LFN
#error _LFN_UNICODE must be 0 at non-LFN cfg.
#endif
#ifndef _INC_TCHAR
typedef WCHAR TCHAR;
#define _T(x) L ## x
#define _TEXT(x) L ## x
#endif
#else /* ANSI/OEM string */
#ifndef _INC_TCHAR
typedef char TCHAR;
#define _T(x) x
#define _TEXT(x) x
#endif
#endif
/* File system object structure (FATFS) */
typedef struct {
BYTE fs_type; /* FAT sub-type (0:Not mounted) */
BYTE drv; /* Physical drive number */
BYTE csize; /* Sectors per cluster (1,2,4...128) */
BYTE n_fats; /* Number of FAT copies (1 or 2) */
BYTE wflag; /* win[] flag (b0:dirty) */
BYTE fsi_flag; /* FSINFO flags (b7:disabled, b0:dirty) */
WORD id; /* File system mount ID */
WORD n_rootdir; /* Number of root directory entries (FAT12/16) */
#if _MAX_SS != _MIN_SS
WORD ssize; /* Bytes per sector (512, 1024, 2048 or 4096) */
#endif
#if _FS_REENTRANT
_SYNC_t sobj; /* Identifier of sync object */
#endif
#if !_FS_READONLY
DWORD last_clust; /* Last allocated cluster */
DWORD free_clust; /* Number of free clusters */
#endif
#if _FS_RPATH
DWORD cdir; /* Current directory start cluster (0:root) */
#endif
DWORD n_fatent; /* Number of FAT entries, = number of clusters + 2 */
DWORD fsize; /* Sectors per FAT */
DWORD volbase; /* Volume start sector */
DWORD fatbase; /* FAT start sector */
DWORD dirbase; /* Root directory start sector (FAT32:Cluster#) */
DWORD database; /* Data start sector */
DWORD winsect; /* Current sector appearing in the win[] */
BYTE win[_MAX_SS]; /* Disk access window for Directory, FAT (and file data at tiny cfg) */
} FATFS;
/* File object structure (FIL) */
typedef struct {
FATFS* fs; /* Pointer to the related file system object (**do not change order**) */
WORD id; /* Owner file system mount ID (**do not change order**) */
BYTE flag; /* Status flags */
BYTE err; /* Abort flag (error code) */
DWORD fptr; /* File read/write pointer (Zeroed on file open) */
DWORD fsize; /* File size */
DWORD sclust; /* File start cluster (0:no cluster chain, always 0 when fsize is 0) */
DWORD clust; /* Current cluster of fpter (not valid when fprt is 0) */
DWORD dsect; /* Sector number appearing in buf[] (0:invalid) */
#if !_FS_READONLY
DWORD dir_sect; /* Sector number containing the directory entry */
BYTE* dir_ptr; /* Pointer to the directory entry in the win[] */
#endif
#if _USE_FASTSEEK
DWORD* cltbl; /* Pointer to the cluster link map table (Nulled on file open) */
#endif
#if _FS_LOCK
UINT lockid; /* File lock ID origin from 1 (index of file semaphore table Files[]) */
#endif
#if !_FS_TINY
BYTE buf[_MAX_SS]; /* File private data read/write window */
#endif
} FIL;
/* Directory object structure (FDIR) */
typedef struct {
FATFS* fs; /* Pointer to the owner file system object (**do not change order**) */
WORD id; /* Owner file system mount ID (**do not change order**) */
WORD index; /* Current read/write index number */
DWORD sclust; /* Table start cluster (0:Root dir) */
DWORD clust; /* Current cluster */
DWORD sect; /* Current sector */
BYTE* dir; /* Pointer to the current SFN entry in the win[] */
BYTE* fn; /* Pointer to the SFN (in/out) {file[8],ext[3],status[1]} */
#if _FS_LOCK
UINT lockid; /* File lock ID (index of file semaphore table Files[]) */
#endif
#if _USE_LFN
WCHAR* lfn; /* Pointer to the LFN working buffer */
WORD lfn_idx; /* Last matched LFN index number (0xFFFF:No LFN) */
#endif
#if _USE_FIND
const TCHAR* pat; /* Pointer to the name matching pattern */
#endif
} FDIR;
/* File information structure (FILINFO) */
typedef struct {
DWORD fsize; /* File size */
WORD fdate; /* Last modified date */
WORD ftime; /* Last modified time */
BYTE fattrib; /* Attribute */
TCHAR fname[13]; /* Short file name (8.3 format) */
#if _USE_LFN
TCHAR* lfname; /* Pointer to the LFN buffer */
UINT lfsize; /* Size of LFN buffer in TCHAR */
#endif
} FILINFO;
/* File function return code (FRESULT) */
typedef enum {
FR_OK = 0, /* (0) Succeeded */
FR_DISK_ERR, /* (1) A hard error occurred in the low level disk I/O layer */
FR_INT_ERR, /* (2) Assertion failed */
FR_NOT_READY, /* (3) The physical drive cannot work */
FR_NO_FILE, /* (4) Could not find the file */
FR_NO_PATH, /* (5) Could not find the path */
FR_INVALID_NAME, /* (6) The path name format is invalid */
FR_DENIED, /* (7) Access denied due to prohibited access or directory full */
FR_EXIST, /* (8) Access denied due to prohibited access */
FR_INVALID_OBJECT, /* (9) The file/directory object is invalid */
FR_WRITE_PROTECTED, /* (10) The physical drive is write protected */
FR_INVALID_DRIVE, /* (11) The logical drive number is invalid */
FR_NOT_ENABLED, /* (12) The volume has no work area */
FR_NO_FILESYSTEM, /* (13) There is no valid FAT volume */
FR_MKFS_ABORTED, /* (14) The f_mkfs() aborted due to any parameter error */
FR_TIMEOUT, /* (15) Could not get a grant to access the volume within defined period */
FR_LOCKED, /* (16) The operation is rejected according to the file sharing policy */
FR_NOT_ENOUGH_CORE, /* (17) LFN working buffer could not be allocated */
FR_TOO_MANY_OPEN_FILES, /* (18) Number of open files > _FS_LOCK */
FR_INVALID_PARAMETER /* (19) Given parameter is invalid */
} FRESULT;
/*--------------------------------------------------------------*/
/* FatFs module application interface */
FRESULT f_open (FIL* fp, const TCHAR* path, BYTE mode); /* Open or create a file */
FRESULT f_close (FIL* fp); /* Close an open file object */
FRESULT f_read (FIL* fp, void* buff, UINT btr, UINT* br); /* Read data from a file */
FRESULT f_write (FIL* fp, const void* buff, UINT btw, UINT* bw); /* Write data to a file */
FRESULT f_forward (FIL* fp, UINT(*func)(const BYTE*,UINT), UINT btf, UINT* bf); /* Forward data to the stream */
FRESULT f_lseek (FIL* fp, DWORD ofs); /* Move file pointer of a file object */
FRESULT f_truncate (FIL* fp); /* Truncate file */
FRESULT f_sync (FIL* fp); /* Flush cached data of a writing file */
FRESULT f_opendir (FDIR* dp, const TCHAR* path); /* Open a directory */
FRESULT f_closedir (FDIR* dp); /* Close an open directory */
FRESULT f_readdir (FDIR* dp, FILINFO* fno); /* Read a directory item */
FRESULT f_findfirst (FDIR* dp, FILINFO* fno, const TCHAR* path, const TCHAR* pattern); /* Find first file */
FRESULT f_findnext (FDIR* dp, FILINFO* fno); /* Find next file */
FRESULT f_mkdir (const TCHAR* path); /* Create a sub directory */
FRESULT f_unlink (const TCHAR* path); /* Delete an existing file or directory */
FRESULT f_rename (const TCHAR* path_old, const TCHAR* path_new); /* Rename/Move a file or directory */
FRESULT f_stat (const TCHAR* path, FILINFO* fno); /* Get file status */
FRESULT f_chmod (const TCHAR* path, BYTE attr, BYTE mask); /* Change attribute of the file/dir */
FRESULT f_utime (const TCHAR* path, const FILINFO* fno); /* Change times-tamp of the file/dir */
FRESULT f_chdir (const TCHAR* path); /* Change current directory */
FRESULT f_chdrive (const TCHAR* path); /* Change current drive */
FRESULT f_getcwd (TCHAR* buff, UINT len); /* Get current directory */
FRESULT f_getfree (const TCHAR* path, DWORD* nclst, FATFS** fatfs); /* Get number of free clusters on the drive */
FRESULT f_getlabel (const TCHAR* path, TCHAR* label, DWORD* vsn); /* Get volume label */
FRESULT f_setlabel (const TCHAR* label); /* Set volume label */
FRESULT f_mount (FATFS* fs, const TCHAR* path, BYTE opt); /* Mount/Unmount a logical drive */
FRESULT f_mkfs (const TCHAR* path, BYTE sfd, UINT au, UINT start, UINT end); /* Create a file system on the volume */
FRESULT f_fdisk (BYTE pdrv, const DWORD szt[], void* work); /* Divide a physical drive into some partitions */
int f_putc (TCHAR c, FIL* fp); /* Put a character to the file */
int f_puts (const TCHAR* str, FIL* cp); /* Put a string to the file */
int f_printf (FIL* fp, const TCHAR* str, ...); /* Put a formatted string to the file */
TCHAR* f_gets (TCHAR* buff, int len, FIL* fp); /* Get a string from the file */
#define f_eof(fp) ((int)((fp)->fptr == (fp)->fsize))
#define f_error(fp) ((fp)->err)
#define f_tell(fp) ((fp)->fptr)
#define f_size(fp) ((fp)->fsize)
#define f_rewind(fp) f_lseek((fp), 0)
#define f_rewinddir(dp) f_readdir((dp), 0)
#ifndef EOF
#define EOF (-1)
#endif
/*--------------------------------------------------------------*/
/* Additional user defined functions */
/* RTC function */
#if !_FS_READONLY && !_FS_NORTC
DWORD get_fattime (void);
#endif
/* Unicode support functions */
#if _USE_LFN /* Unicode - OEM code conversion */
WCHAR ff_convert (WCHAR chr, UINT dir); /* OEM-Unicode bidirectional conversion */
WCHAR ff_wtoupper (WCHAR chr); /* Unicode upper-case conversion */
#if _USE_LFN == 3 /* Memory functions */
void* ff_memalloc (UINT msize); /* Allocate memory block */
void ff_memfree (void* mblock); /* Free memory block */
#endif
#endif
/* Sync functions */
#if _FS_REENTRANT
int ff_cre_syncobj (BYTE vol, _SYNC_t* sobj); /* Create a sync object */
int ff_req_grant (_SYNC_t sobj); /* Lock sync object */
void ff_rel_grant (_SYNC_t sobj); /* Unlock sync object */
int ff_del_syncobj (_SYNC_t sobj); /* Delete a sync object */
#endif
/*--------------------------------------------------------------*/
/* Flags and offset address */
/* File access control and file status flags (FIL.flag) */
#define FA_READ 0x01
#define FA_OPEN_EXISTING 0x00
#if !_FS_READONLY
#define FA_WRITE 0x02
#define FA_CREATE_NEW 0x04
#define FA_CREATE_ALWAYS 0x08
#define FA_OPEN_ALWAYS 0x10
#define FA__WRITTEN 0x20
#define FA__DIRTY 0x40
#endif
/* FAT sub type (FATFS.fs_type) */
#define FS_FAT12 1
#define FS_FAT16 2
#define FS_FAT32 3
/* File attribute bits for directory entry */
#define AM_RDO 0x01 /* Read only */
#define AM_HID 0x02 /* Hidden */
#define AM_SYS 0x04 /* System */
#define AM_VOL 0x08 /* Volume label */
#define AM_LFN 0x0F /* LFN entry */
#define AM_DIR 0x10 /* Directory */
#define AM_ARC 0x20 /* Archive */
#define AM_MASK 0x3F /* Mask of defined bits */
/* Fast seek feature */
#define CREATE_LINKMAP 0xFFFFFFFF
/*--------------------------------*/
/* Multi-byte word access macros */
#if _WORD_ACCESS == 1 /* Enable word access to the FAT structure */
#define LD_WORD(ptr) (WORD)(*(WORD*)(BYTE*)(ptr))
#define LD_DWORD(ptr) (DWORD)(*(DWORD*)(BYTE*)(ptr))
#define ST_WORD(ptr,val) *(WORD*)(BYTE*)(ptr)=(WORD)(val)
#define ST_DWORD(ptr,val) *(DWORD*)(BYTE*)(ptr)=(DWORD)(val)
#else /* Use byte-by-byte access to the FAT structure */
#define LD_WORD(ptr) (WORD)(((WORD)*((BYTE*)(ptr)+1)<<8)|(WORD)*(BYTE*)(ptr))
#define LD_DWORD(ptr) (DWORD)(((DWORD)*((BYTE*)(ptr)+3)<<24)|((DWORD)*((BYTE*)(ptr)+2)<<16)|((WORD)*((BYTE*)(ptr)+1)<<8)|*(BYTE*)(ptr))
#define ST_WORD(ptr,val) *(BYTE*)(ptr)=(BYTE)(val); *((BYTE*)(ptr)+1)=(BYTE)((WORD)(val)>>8)
#define ST_DWORD(ptr,val) *(BYTE*)(ptr)=(BYTE)(val); *((BYTE*)(ptr)+1)=(BYTE)((WORD)(val)>>8); *((BYTE*)(ptr)+2)=(BYTE)((DWORD)(val)>>16); *((BYTE*)(ptr)+3)=(BYTE)((DWORD)(val)>>24)
#endif
#ifdef __cplusplus
}
#endif
#endif /* _FATFS */

View File

@ -1,276 +0,0 @@
/*---------------------------------------------------------------------------/
/ FatFs - FAT file system module configuration file R0.11a (C)ChaN, 2015
/---------------------------------------------------------------------------*/
#define _FFCONF 64180 /* Revision ID */
/*---------------------------------------------------------------------------/
/ Function Configurations
/---------------------------------------------------------------------------*/
#define _FS_READONLY 1
/* This option switches read-only configuration. (0:Read/Write or 1:Read-only)
/ Read-only configuration removes writing API functions, f_write(), f_sync(),
/ f_unlink(), f_mkdir(), f_chmod(), f_rename(), f_truncate(), f_getfree()
/ and optional writing functions as well. */
#define _FS_MINIMIZE 2
/* This option defines minimization level to remove some basic API functions.
/
/ 0: All basic functions are enabled.
/ 1: f_stat(), f_getfree(), f_unlink(), f_mkdir(), f_chmod(), f_utime(),
/ f_truncate() and f_rename() function are removed.
/ 2: f_opendir(), f_readdir() and f_closedir() are removed in addition to 1.
/ 3: f_lseek() function is removed in addition to 2. */
#define _USE_STRFUNC 1
/* This option switches string functions, f_gets(), f_putc(), f_puts() and
/ f_printf().
/
/ 0: Disable string functions.
/ 1: Enable without LF-CRLF conversion.
/ 2: Enable with LF-CRLF conversion. */
#define _USE_FIND 1
/* This option switches filtered directory read feature and related functions,
/ f_findfirst() and f_findnext(). (0:Disable or 1:Enable) */
#define _USE_MKFS 0
/* This option switches f_mkfs() function. (0:Disable or 1:Enable) */
#define _USE_FASTSEEK 1
/* This option switches fast seek feature. (0:Disable or 1:Enable) */
#define _USE_LABEL 0
/* This option switches volume label functions, f_getlabel() and f_setlabel().
/ (0:Disable or 1:Enable) */
#define _USE_FORWARD 0
/* This option switches f_forward() function. (0:Disable or 1:Enable)
/ To enable it, also _FS_TINY need to be set to 1. */
/*---------------------------------------------------------------------------/
/ Locale and Namespace Configurations
/---------------------------------------------------------------------------*/
#define _CODE_PAGE 932
/* This option specifies the OEM code page to be used on the target system.
/ Incorrect setting of the code page can cause a file open failure.
/
/ 1 - ASCII (No extended character. Non-LFN cfg. only)
/ 437 - U.S.
/ 720 - Arabic
/ 737 - Greek
/ 771 - KBL
/ 775 - Baltic
/ 850 - Latin 1
/ 852 - Latin 2
/ 855 - Cyrillic
/ 857 - Turkish
/ 860 - Portuguese
/ 861 - Icelandic
/ 862 - Hebrew
/ 863 - Canadian French
/ 864 - Arabic
/ 865 - Nordic
/ 866 - Russian
/ 869 - Greek 2
/ 932 - Japanese (DBCS)
/ 936 - Simplified Chinese (DBCS)
/ 949 - Korean (DBCS)
/ 950 - Traditional Chinese (DBCS)
*/
#define _USE_LFN 1
#define _MAX_LFN 255
/* The _USE_LFN option switches the LFN feature.
/
/ 0: Disable LFN feature. _MAX_LFN has no effect.
/ 1: Enable LFN with static working buffer on the BSS. Always NOT thread-safe.
/ 2: Enable LFN with dynamic working buffer on the STACK.
/ 3: Enable LFN with dynamic working buffer on the HEAP.
/
/ When enable the LFN feature, Unicode handling functions (option/unicode.c) must
/ be added to the project. The LFN working buffer occupies (_MAX_LFN + 1) * 2 bytes.
/ When use stack for the working buffer, take care on stack overflow. When use heap
/ memory for the working buffer, memory management functions, ff_memalloc() and
/ ff_memfree(), must be added to the project. */
#define _LFN_UNICODE 0
/* This option switches character encoding on the API. (0:ANSI/OEM or 1:Unicode)
/ To use Unicode string for the path name, enable LFN feature and set _LFN_UNICODE
/ to 1. This option also affects behavior of string I/O functions. */
#define _STRF_ENCODE 0
/* When _LFN_UNICODE is 1, this option selects the character encoding on the file to
/ be read/written via string I/O functions, f_gets(), f_putc(), f_puts and f_printf().
/
/ 0: ANSI/OEM
/ 1: UTF-16LE
/ 2: UTF-16BE
/ 3: UTF-8
/
/ When _LFN_UNICODE is 0, this option has no effect. */
#define _FS_RPATH 0
/* This option configures relative path feature.
/
/ 0: Disable relative path feature and remove related functions.
/ 1: Enable relative path feature. f_chdir() and f_chdrive() are available.
/ 2: f_getcwd() function is available in addition to 1.
/
/ Note that directory items read via f_readdir() are affected by this option. */
/*---------------------------------------------------------------------------/
/ Drive/Volume Configurations
/---------------------------------------------------------------------------*/
#define _VOLUMES 1
/* Number of volumes (logical drives) to be used. */
#define _STR_VOLUME_ID 1
#define _VOLUME_STRS "SDMC"
/* _STR_VOLUME_ID option switches string volume ID feature.
/ When _STR_VOLUME_ID is set to 1, also pre-defined strings can be used as drive
/ number in the path name. _VOLUME_STRS defines the drive ID strings for each
/ logical drives. Number of items must be equal to _VOLUMES. Valid characters for
/ the drive ID strings are: A-Z and 0-9. */
#define _MULTI_PARTITION 0
/* This option switches multi-partition feature. By default (0), each logical drive
/ number is bound to the same physical drive number and only an FAT volume found on
/ the physical drive will be mounted. When multi-partition feature is enabled (1),
/ each logical drive number is bound to arbitrary physical drive and partition
/ listed in the VolToPart[]. Also f_fdisk() funciton will be available. */
#define _MIN_SS 512
#define _MAX_SS 512
/* These options configure the range of sector size to be supported. (512, 1024,
/ 2048 or 4096) Always set both 512 for most systems, all type of memory cards and
/ harddisk. But a larger value may be required for on-board flash memory and some
/ type of optical media. When _MAX_SS is larger than _MIN_SS, FatFs is configured
/ to variable sector size and GET_SECTOR_SIZE command must be implemented to the
/ disk_ioctl() function. */
#define _USE_TRIM 0
/* This option switches ATA-TRIM feature. (0:Disable or 1:Enable)
/ To enable Trim feature, also CTRL_TRIM command should be implemented to the
/ disk_ioctl() function. */
#define _FS_NOFSINFO 0
/* If you need to know correct free space on the FAT32 volume, set bit 0 of this
/ option, and f_getfree() function at first time after volume mount will force
/ a full FAT scan. Bit 1 controls the use of last allocated cluster number.
/
/ bit0=0: Use free cluster count in the FSINFO if available.
/ bit0=1: Do not trust free cluster count in the FSINFO.
/ bit1=0: Use last allocated cluster number in the FSINFO if available.
/ bit1=1: Do not trust last allocated cluster number in the FSINFO.
*/
/*---------------------------------------------------------------------------/
/ System Configurations
/---------------------------------------------------------------------------*/
#define _FS_TINY 0
/* This option switches tiny buffer configuration. (0:Normal or 1:Tiny)
/ At the tiny configuration, size of the file object (FIL) is reduced _MAX_SS
/ bytes. Instead of private sector buffer eliminated from the file object,
/ common sector buffer in the file system object (FATFS) is used for the file
/ data transfer. */
#define _FS_NORTC 1
#define _NORTC_MON 1
#define _NORTC_MDAY 1
#define _NORTC_YEAR 2015
/* The _FS_NORTC option switches timestamp feature. If the system does not have
/ an RTC function or valid timestamp is not needed, set _FS_NORTC to 1 to disable
/ the timestamp feature. All objects modified by FatFs will have a fixed timestamp
/ defined by _NORTC_MON, _NORTC_MDAY and _NORTC_YEAR.
/ When timestamp feature is enabled (_FS_NORTC == 0), get_fattime() function need
/ to be added to the project to read current time form RTC. _NORTC_MON,
/ _NORTC_MDAY and _NORTC_YEAR have no effect.
/ These options have no effect at read-only configuration (_FS_READONLY == 1). */
#define _FS_LOCK 0
/* The _FS_LOCK option switches file lock feature to control duplicated file open
/ and illegal operation to open objects. This option must be 0 when _FS_READONLY
/ is 1.
/
/ 0: Disable file lock feature. To avoid volume corruption, application program
/ should avoid illegal open, remove and rename to the open objects.
/ >0: Enable file lock feature. The value defines how many files/sub-directories
/ can be opened simultaneously under file lock control. Note that the file
/ lock feature is independent of re-entrancy. */
#define _FS_REENTRANT 0
#define _FS_TIMEOUT 1000
#define _SYNC_t HANDLE
/* The _FS_REENTRANT option switches the re-entrancy (thread safe) of the FatFs
/ module itself. Note that regardless of this option, file access to different
/ volume is always re-entrant and volume control functions, f_mount(), f_mkfs()
/ and f_fdisk() function, are always not re-entrant. Only file/directory access
/ to the same volume is under control of this feature.
/
/ 0: Disable re-entrancy. _FS_TIMEOUT and _SYNC_t have no effect.
/ 1: Enable re-entrancy. Also user provided synchronization handlers,
/ ff_req_grant(), ff_rel_grant(), ff_del_syncobj() and ff_cre_syncobj()
/ function, must be added to the project. Samples are available in
/ option/syscall.c.
/
/ The _FS_TIMEOUT defines timeout period in unit of time tick.
/ The _SYNC_t defines O/S dependent sync object type. e.g. HANDLE, ID, OS_EVENT*,
/ SemaphoreHandle_t and etc.. A header file for O/S definitions needs to be
/ included somewhere in the scope of ff.c. */
#define _WORD_ACCESS 0
/* The _WORD_ACCESS option is an only platform dependent option. It defines
/ which access method is used to the word data on the FAT volume.
/
/ 0: Byte-by-byte access. Always compatible with all platforms.
/ 1: Word access. Do not choose this unless under both the following conditions.
/
/ * Address misaligned memory access is always allowed to ALL instructions.
/ * Byte order on the memory is little-endian.
/
/ If it is the case, _WORD_ACCESS can also be set to 1 to reduce code size.
/ Following table shows allowable settings of some type of processors.
/
/ ARM7TDMI 0 *2 ColdFire 0 *1 V850E 0 *2
/ Cortex-M3 0 *3 Z80 0/1 V850ES 0/1
/ Cortex-M0 0 *2 x86 0/1 TLCS-870 0/1
/ AVR 0/1 RX600(LE) 0/1 TLCS-900 0/1
/ AVR32 0 *1 RL78 0 *2 R32C 0 *2
/ PIC18 0/1 SH-2 0 *1 M16C 0/1
/ PIC24 0 *2 H8S 0 *1 MSP430 0 *2
/ PIC32 0 *1 H8/300H 0 *1 8051 0/1
/
/ *1:Big-endian.
/ *2:Unaligned memory access is not supported.
/ *3:Some compilers generate LDM/STM for mem_cpy function.
*/

View File

@ -1,33 +0,0 @@
/*-------------------------------------------*/
/* Integer type definitions for FatFs module */
/*-------------------------------------------*/
#ifndef _FF_INTEGER
#define _FF_INTEGER
#ifdef _WIN32 /* Development platform */
#include <windows.h>
#include <tchar.h>
#else /* Embedded platform */
/* This type MUST be 8-bit */
typedef unsigned char BYTE;
/* These types MUST be 16-bit */
typedef short SHORT;
typedef unsigned short WORD;
typedef unsigned short WCHAR;
/* These types MUST be 16-bit or 32-bit */
typedef int INT;
typedef unsigned int UINT;
/* These types MUST be 32-bit */
typedef long LONG;
typedef unsigned long DWORD;
#endif
#endif

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -1,348 +0,0 @@
/*------------------------------------------------------------------------*/
/* Unicode - Local code bidirectional converter (C)ChaN, 2015 */
/* (SBCS code pages) */
/*------------------------------------------------------------------------*/
/* 437 U.S.
/ 720 Arabic
/ 737 Greek
/ 771 KBL
/ 775 Baltic
/ 850 Latin 1
/ 852 Latin 2
/ 855 Cyrillic
/ 857 Turkish
/ 860 Portuguese
/ 861 Icelandic
/ 862 Hebrew
/ 863 Canadian French
/ 864 Arabic
/ 865 Nordic
/ 866 Russian
/ 869 Greek 2
*/
#include "../ff.h"
#if _CODE_PAGE == 437
#define _TBLDEF 1
static
const WCHAR Tbl[] = { /* CP437(0x80-0xFF) to Unicode conversion table */
0x00C7, 0x00FC, 0x00E9, 0x00E2, 0x00E4, 0x00E0, 0x00E5, 0x00E7, 0x00EA, 0x00EB, 0x00E8, 0x00EF, 0x00EE, 0x00EC, 0x00C4, 0x00C5,
0x00C9, 0x00E6, 0x00C6, 0x00F4, 0x00F6, 0x00F2, 0x00FB, 0x00F9, 0x00FF, 0x00D6, 0x00DC, 0x00A2, 0x00A3, 0x00A5, 0x20A7, 0x0192,
0x00E1, 0x00ED, 0x00F3, 0x00FA, 0x00F1, 0x00D1, 0x00AA, 0x00BA, 0x00BF, 0x2310, 0x00AC, 0x00BD, 0x00BC, 0x00A1, 0x00AB, 0x00BB,
0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x2561, 0x2562, 0x2556, 0x2555, 0x2563, 0x2551, 0x2557, 0x255D, 0x255C, 0x255B, 0x2510,
0x2514, 0x2534, 0x252C, 0x251C, 0x2500, 0x253C, 0x255E, 0x255F, 0x255A, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256C, 0x2567,
0x2568, 0x2564, 0x2565, 0x2559, 0x2558, 0x2552, 0x2553, 0x256B, 0x256A, 0x2518, 0x250C, 0x2588, 0x2584, 0x258C, 0x2590, 0x2580,
0x03B1, 0x00DF, 0x0393, 0x03C0, 0x03A3, 0x03C3, 0x00B5, 0x03C4, 0x03A6, 0x0398, 0x03A9, 0x03B4, 0x221E, 0x03C6, 0x03B5, 0x2229,
0x2261, 0x00B1, 0x2265, 0x2264, 0x2320, 0x2321, 0x00F7, 0x2248, 0x00B0, 0x2219, 0x00B7, 0x221A, 0x207F, 0x00B2, 0x25A0, 0x00A0
};
#elif _CODE_PAGE == 720
#define _TBLDEF 1
static
const WCHAR Tbl[] = { /* CP720(0x80-0xFF) to Unicode conversion table */
0x0000, 0x0000, 0x00E9, 0x00E2, 0x0000, 0x00E0, 0x0000, 0x00E7, 0x00EA, 0x00EB, 0x00E8, 0x00EF, 0x00EE, 0x0000, 0x0000, 0x0000,
0x0000, 0x0651, 0x0652, 0x00F4, 0x00A4, 0x0640, 0x00FB, 0x00F9, 0x0621, 0x0622, 0x0623, 0x0624, 0x00A3, 0x0625, 0x0626, 0x0627,
0x0628, 0x0629, 0x062A, 0x062B, 0x062C, 0x062D, 0x062E, 0x062F, 0x0630, 0x0631, 0x0632, 0x0633, 0x0634, 0x0635, 0x00AB, 0x00BB,
0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x2561, 0x2562, 0x2556, 0x2555, 0x2563, 0x2551, 0x2557, 0x255D, 0x255C, 0x255B, 0x2510,
0x2514, 0x2534, 0x252C, 0x251C, 0x2500, 0x253C, 0x255E, 0x255F, 0x255A, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256C, 0x2567,
0x2568, 0x2564, 0x2565, 0x2559, 0x2558, 0x2552, 0x2553, 0x256B, 0x256A, 0x2518, 0x250C, 0x2588, 0x2584, 0x258C, 0x2590, 0x2580,
0x0636, 0x0637, 0x0638, 0x0639, 0x063A, 0x0641, 0x00B5, 0x0642, 0x0643, 0x0644, 0x0645, 0x0646, 0x0647, 0x0648, 0x0649, 0x064A,
0x2261, 0x064B, 0x064C, 0x064D, 0x064E, 0x064F, 0x0650, 0x2248, 0x00B0, 0x2219, 0x00B7, 0x221A, 0x207F, 0x00B2, 0x25A0, 0x00A0
};
#elif _CODE_PAGE == 737
#define _TBLDEF 1
static
const WCHAR Tbl[] = { /* CP737(0x80-0xFF) to Unicode conversion table */
0x0391, 0x0392, 0x0393, 0x0394, 0x0395, 0x0396, 0x0397, 0x0398, 0x0399, 0x039A, 0x039B, 0x039C, 0x039D, 0x039E, 0x039F, 0x03A0,
0x03A1, 0x03A3, 0x03A4, 0x03A5, 0x03A6, 0x03A7, 0x03A8, 0x03A9, 0x03B1, 0x03B2, 0x03B3, 0x03B4, 0x03B5, 0x03B6, 0x03B7, 0x03B8,
0x03B9, 0x03BA, 0x03BB, 0x03BC, 0x03BD, 0x03BE, 0x03BF, 0x03C0, 0x03C1, 0x03C3, 0x03C2, 0x03C4, 0x03C5, 0x03C6, 0x03C7, 0x03C8,
0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x2561, 0x2562, 0x2556, 0x2555, 0x2563, 0x2551, 0x2557, 0x255D, 0x255C, 0x255B, 0x2510,
0x2514, 0x2534, 0x252C, 0x251C, 0x2500, 0x253C, 0x255E, 0x255F, 0x255A, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256C, 0x2567,
0x2568, 0x2564, 0x2565, 0x2559, 0x2558, 0x2552, 0x2553, 0x256B, 0x256A, 0x2518, 0x250C, 0x2588, 0x2584, 0x258C, 0x2590, 0x2580,
0x03C9, 0x03AC, 0x03AD, 0x03AE, 0x03CA, 0x03AF, 0x03CC, 0x03CD, 0x03CB, 0x03CE, 0x0386, 0x0388, 0x0389, 0x038A, 0x038C, 0x038E,
0x038F, 0x00B1, 0x2265, 0x2264, 0x03AA, 0x03AB, 0x00F7, 0x2248, 0x00B0, 0x2219, 0x00B7, 0x221A, 0x207F, 0x00B2, 0x25A0, 0x00A0
};
#elif _CODE_PAGE == 771
#define _TBLDEF 1
static
const WCHAR Tbl[] = { /* CP771(0x80-0xFF) to Unicode conversion table */
0x0410, 0x0411, 0x0412, 0x0413, 0x0414, 0x0415, 0x0416, 0x0417, 0x0418, 0x0419, 0x041A, 0x041B, 0x041C, 0x041D, 0x041E, 0x041F,
0x0420, 0x0421, 0x0422, 0x0423, 0x0424, 0x0425, 0x0426, 0x0427, 0x0428, 0x0429, 0x042A, 0x042B, 0x042C, 0x042D, 0x042E, 0x042F,
0x0430, 0x0431, 0x0432, 0x0433, 0x0434, 0x0435, 0x0436, 0x0437, 0x0438, 0x0439, 0x043A, 0x043B, 0x043C, 0x043D, 0x043E, 0x043F,
0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x2561, 0x2562, 0x2556, 0x2555, 0x2563, 0x2551, 0x2557, 0x255D, 0x255C, 0x2558, 0x2510,
0x2514, 0x2534, 0x252C, 0x251C, 0x2500, 0x253C, 0x255E, 0x255F, 0x255A, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256C, 0x2567,
0x2568, 0x2564, 0x2565, 0x2559, 0x2558, 0x2552, 0x2553, 0x256B, 0x256A, 0x2518, 0x250C, 0x2588, 0x0104, 0x0105, 0x010C, 0x010D,
0x0440, 0x0441, 0x0442, 0x0443, 0x0444, 0x0445, 0x0446, 0x0447, 0x0448, 0x0449, 0x044A, 0x044B, 0x044C, 0x044D, 0x044E, 0x044F,
0x0118, 0x0119, 0x0116, 0x0117, 0x012E, 0x012F, 0x0160, 0x0161, 0x0172, 0x0173, 0x016A, 0x016B, 0x017D, 0x017E, 0x25A0, 0x00A0
};
#elif _CODE_PAGE == 775
#define _TBLDEF 1
static
const WCHAR Tbl[] = { /* CP775(0x80-0xFF) to Unicode conversion table */
0x0106, 0x00FC, 0x00E9, 0x0101, 0x00E4, 0x0123, 0x00E5, 0x0107, 0x0142, 0x0113, 0x0156, 0x0157, 0x012B, 0x0179, 0x00C4, 0x00C5,
0x00C9, 0x00E6, 0x00C6, 0x014D, 0x00F6, 0x0122, 0x00A2, 0x015A, 0x015B, 0x00D6, 0x00DC, 0x00F8, 0x00A3, 0x00D8, 0x00D7, 0x00A4,
0x0100, 0x012A, 0x00F3, 0x017B, 0x017C, 0x017A, 0x201D, 0x00A6, 0x00A9, 0x00AE, 0x00AC, 0x00BD, 0x00BC, 0x0141, 0x00AB, 0x00BB,
0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x0104, 0x010C, 0x0118, 0x0116, 0x2563, 0x2551, 0x2557, 0x255D, 0x012E, 0x0160, 0x2510,
0x2514, 0x2534, 0x252C, 0x251C, 0x2500, 0x253C, 0x0172, 0x016A, 0x255A, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256C, 0x017D,
0x0105, 0x010D, 0x0119, 0x0117, 0x012F, 0x0161, 0x0173, 0x016B, 0x017E, 0x2518, 0x250C, 0x2588, 0x2584, 0x258C, 0x2590, 0x2580,
0x00D3, 0x00DF, 0x014C, 0x0143, 0x00F5, 0x00D5, 0x00B5, 0x0144, 0x0136, 0x0137, 0x013B, 0x013C, 0x0146, 0x0112, 0x0145, 0x2019,
0x00AD, 0x00B1, 0x201C, 0x00BE, 0x00B6, 0x00A7, 0x00F7, 0x201E, 0x00B0, 0x2219, 0x00B7, 0x00B9, 0x00B3, 0x00B2, 0x25A0, 0x00A0
};
#elif _CODE_PAGE == 850
#define _TBLDEF 1
static
const WCHAR Tbl[] = { /* CP850(0x80-0xFF) to Unicode conversion table */
0x00C7, 0x00FC, 0x00E9, 0x00E2, 0x00E4, 0x00E0, 0x00E5, 0x00E7, 0x00EA, 0x00EB, 0x00E8, 0x00EF, 0x00EE, 0x00EC, 0x00C4, 0x00C5,
0x00C9, 0x00E6, 0x00C6, 0x00F4, 0x00F6, 0x00F2, 0x00FB, 0x00F9, 0x00FF, 0x00D6, 0x00DC, 0x00F8, 0x00A3, 0x00D8, 0x00D7, 0x0192,
0x00E1, 0x00ED, 0x00F3, 0x00FA, 0x00F1, 0x00D1, 0x00AA, 0x00BA, 0x00BF, 0x00AE, 0x00AC, 0x00BD, 0x00BC, 0x00A1, 0x00AB, 0x00BB,
0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x00C1, 0x00C2, 0x00C0, 0x00A9, 0x2563, 0x2551, 0x2557, 0x255D, 0x00A2, 0x00A5, 0x2510,
0x2514, 0x2534, 0x252C, 0x251C, 0x2500, 0x253C, 0x00E3, 0x00C3, 0x255A, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256C, 0x00A4,
0x00F0, 0x00D0, 0x00CA, 0x00CB, 0x00C8, 0x0131, 0x00CD, 0x00CE, 0x00CF, 0x2518, 0x250C, 0x2588, 0x2584, 0x00A6, 0x00CC, 0x2580,
0x00D3, 0x00DF, 0x00D4, 0x00D2, 0x00F5, 0x00D5, 0x00B5, 0x00FE, 0x00DE, 0x00DA, 0x00DB, 0x00D9, 0x00FD, 0x00DD, 0x00AF, 0x00B4,
0x00AD, 0x00B1, 0x2017, 0x00BE, 0x00B6, 0x00A7, 0x00F7, 0x00B8, 0x00B0, 0x00A8, 0x00B7, 0x00B9, 0x00B3, 0x00B2, 0x25A0, 0x00A0
};
#elif _CODE_PAGE == 852
#define _TBLDEF 1
static
const WCHAR Tbl[] = { /* CP852(0x80-0xFF) to Unicode conversion table */
0x00C7, 0x00FC, 0x00E9, 0x00E2, 0x00E4, 0x016F, 0x0107, 0x00E7, 0x0142, 0x00EB, 0x0150, 0x0151, 0x00EE, 0x0179, 0x00C4, 0x0106,
0x00C9, 0x0139, 0x013A, 0x00F4, 0x00F6, 0x013D, 0x013E, 0x015A, 0x015B, 0x00D6, 0x00DC, 0x0164, 0x0165, 0x0141, 0x00D7, 0x010D,
0x00E1, 0x00ED, 0x00F3, 0x00FA, 0x0104, 0x0105, 0x017D, 0x017E, 0x0118, 0x0119, 0x00AC, 0x017A, 0x010C, 0x015F, 0x00AB, 0x00BB,
0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x00C1, 0x00C2, 0x011A, 0x015E, 0x2563, 0x2551, 0x2557, 0x255D, 0x017B, 0x017C, 0x2510,
0x2514, 0x2534, 0x252C, 0x251C, 0x2500, 0x253C, 0x0102, 0x0103, 0x255A, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256C, 0x00A4,
0x0111, 0x0110, 0x010E, 0x00CB, 0x010F, 0x0147, 0x00CD, 0x00CE, 0x011B, 0x2518, 0x250C, 0x2588, 0x2584, 0x0162, 0x016E, 0x2580,
0x00D3, 0x00DF, 0x00D4, 0x0143, 0x0144, 0x0148, 0x0160, 0x0161, 0x0154, 0x00DA, 0x0155, 0x0170, 0x00FD, 0x00DD, 0x0163, 0x00B4,
0x00AD, 0x02DD, 0x02DB, 0x02C7, 0x02D8, 0x00A7, 0x00F7, 0x00B8, 0x00B0, 0x00A8, 0x02D9, 0x0171, 0x0158, 0x0159, 0x25A0, 0x00A0
};
#elif _CODE_PAGE == 855
#define _TBLDEF 1
static
const WCHAR Tbl[] = { /* CP855(0x80-0xFF) to Unicode conversion table */
0x0452, 0x0402, 0x0453, 0x0403, 0x0451, 0x0401, 0x0454, 0x0404, 0x0455, 0x0405, 0x0456, 0x0406, 0x0457, 0x0407, 0x0458, 0x0408,
0x0459, 0x0409, 0x045A, 0x040A, 0x045B, 0x040B, 0x045C, 0x040C, 0x045E, 0x040E, 0x045F, 0x040F, 0x044E, 0x042E, 0x044A, 0x042A,
0x0430, 0x0410, 0x0431, 0x0411, 0x0446, 0x0426, 0x0434, 0x0414, 0x0435, 0x0415, 0x0444, 0x0424, 0x0433, 0x0413, 0x00AB, 0x00BB,
0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x0445, 0x0425, 0x0438, 0x0418, 0x2563, 0x2551, 0x2557, 0x255D, 0x0439, 0x0419, 0x2510,
0x2514, 0x2534, 0x252C, 0x251C, 0x2500, 0x253C, 0x043A, 0x041A, 0x255A, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256C, 0x00A4,
0x043B, 0x041B, 0x043C, 0x041C, 0x043D, 0x041D, 0x043E, 0x041E, 0x043F, 0x2518, 0x250C, 0x2588, 0x2584, 0x041F, 0x044F, 0x2580,
0x042F, 0x0440, 0x0420, 0x0441, 0x0421, 0x0442, 0x0422, 0x0443, 0x0423, 0x0436, 0x0416, 0x0432, 0x0412, 0x044C, 0x042C, 0x2116,
0x00AD, 0x044B, 0x042B, 0x0437, 0x0417, 0x0448, 0x0428, 0x044D, 0x042D, 0x0449, 0x0429, 0x0447, 0x0427, 0x00A7, 0x25A0, 0x00A0
};
#elif _CODE_PAGE == 857
#define _TBLDEF 1
static
const WCHAR Tbl[] = { /* CP857(0x80-0xFF) to Unicode conversion table */
0x00C7, 0x00FC, 0x00E9, 0x00E2, 0x00E4, 0x00E0, 0x00E5, 0x00E7, 0x00EA, 0x00EB, 0x00E8, 0x00EF, 0x00EE, 0x0131, 0x00C4, 0x00C5,
0x00C9, 0x00E6, 0x00C6, 0x00F4, 0x00F6, 0x00F2, 0x00FB, 0x00F9, 0x0130, 0x00D6, 0x00DC, 0x00F8, 0x00A3, 0x00D8, 0x015E, 0x015F,
0x00E1, 0x00ED, 0x00F3, 0x00FA, 0x00F1, 0x00D1, 0x011E, 0x011F, 0x00BF, 0x00AE, 0x00AC, 0x00BD, 0x00BC, 0x00A1, 0x00AB, 0x00BB,
0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x00C1, 0x00C2, 0x00C0, 0x00A9, 0x2563, 0x2551, 0x2557, 0x255D, 0x00A2, 0x00A5, 0x2510,
0x2514, 0x2534, 0x252C, 0x251C, 0x2500, 0x253C, 0x00E3, 0x00C3, 0x255A, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256C, 0x00A4,
0x00BA, 0x00AA, 0x00CA, 0x00CB, 0x00C8, 0x0000, 0x00CD, 0x00CE, 0x00CF, 0x2518, 0x250C, 0x2588, 0x2584, 0x00A6, 0x00CC, 0x2580,
0x00D3, 0x00DF, 0x00D4, 0x00D2, 0x00F5, 0x00D5, 0x00B5, 0x0000, 0x00D7, 0x00DA, 0x00DB, 0x00D9, 0x00EC, 0x00FF, 0x00AF, 0x00B4,
0x00AD, 0x00B1, 0x0000, 0x00BE, 0x00B6, 0x00A7, 0x00F7, 0x00B8, 0x00B0, 0x00A8, 0x00B7, 0x00B9, 0x00B3, 0x00B2, 0x25A0, 0x00A0
};
#elif _CODE_PAGE == 860
#define _TBLDEF 1
static
const WCHAR Tbl[] = { /* CP860(0x80-0xFF) to Unicode conversion table */
0x00C7, 0x00FC, 0x00E9, 0x00E2, 0x00E3, 0x00E0, 0x00C1, 0x00E7, 0x00EA, 0x00CA, 0x00E8, 0x00CD, 0x00D4, 0x00EC, 0x00C3, 0x00C2,
0x00C9, 0x00C0, 0x00C8, 0x00F4, 0x00F5, 0x00F2, 0x00DA, 0x00F9, 0x00CC, 0x00D5, 0x00DC, 0x00A2, 0x00A3, 0x00D9, 0x20A7, 0x00D3,
0x00E1, 0x00ED, 0x00F3, 0x00FA, 0x00F1, 0x00D1, 0x00AA, 0x00BA, 0x00BF, 0x00D2, 0x00AC, 0x00BD, 0x00BC, 0x00A1, 0x00AB, 0x00BB,
0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x2561, 0x2562, 0x2556, 0x2555, 0x2563, 0x2551, 0x2557, 0x255D, 0x255C, 0x2558, 0x2510,
0x2514, 0x2534, 0x252C, 0x251C, 0x2500, 0x253C, 0x255E, 0x255F, 0x255A, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256C, 0x2567,
0x2568, 0x2564, 0x2565, 0x2559, 0x2558, 0x2552, 0x2553, 0x256B, 0x256A, 0x2518, 0x250C, 0x2588, 0x2584, 0x258C, 0x2590, 0x2580,
0x03B1, 0x00DF, 0x0393, 0x03C0, 0x03A3, 0x03C3, 0x00B5, 0x03C4, 0x03A6, 0x0398, 0x03A9, 0x03B4, 0x221E, 0x03C6, 0x03B5, 0x2229,
0x2261, 0x00B1, 0x2265, 0x2264, 0x2320, 0x2321, 0x00F7, 0x2248, 0x00B0, 0x2219, 0x00B7, 0x221A, 0x207F, 0x00B2, 0x25A0, 0x00A0
};
#elif _CODE_PAGE == 861
#define _TBLDEF 1
static
const WCHAR Tbl[] = { /* CP861(0x80-0xFF) to Unicode conversion table */
0x00C7, 0x00FC, 0x00E9, 0x00E2, 0x00E4, 0x00E0, 0x00E6, 0x00E7, 0x00EA, 0x00EB, 0x00E8, 0x00D0, 0x00F0, 0x00DE, 0x00C4, 0x00C5,
0x00C9, 0x00E6, 0x00C6, 0x00F4, 0x00F6, 0x00FE, 0x00FB, 0x00DD, 0x00FD, 0x00D6, 0x00DC, 0x00F8, 0x00A3, 0x00D8, 0x20A7, 0x0192,
0x00E1, 0x00ED, 0x00F3, 0x00FA, 0x00C1, 0x00CD, 0x00D3, 0x00DA, 0x00BF, 0x2310, 0x00AC, 0x00BD, 0x00BC, 0x00A1, 0x00AB, 0x00BB,
0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x2561, 0x2562, 0x2556, 0x2555, 0x2563, 0x2551, 0x2557, 0x255D, 0x255C, 0x255B, 0x2510,
0x2514, 0x2534, 0x252C, 0x251C, 0x2500, 0x253C, 0x255E, 0x255F, 0x255A, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256C, 0x2567,
0x2568, 0x2564, 0x2565, 0x2559, 0x2558, 0x2552, 0x2553, 0x256B, 0x256A, 0x2518, 0x250C, 0x2588, 0x2584, 0x258C, 0x2590, 0x2580,
0x03B1, 0x00DF, 0x0393, 0x03C0, 0x03A3, 0x03C3, 0x00B5, 0x03C4, 0x03A6, 0x0398, 0x03A9, 0x03B4, 0x221E, 0x03C6, 0x03B5, 0x2229,
0x2261, 0x00B1, 0x2265, 0x2264, 0x2320, 0x2321, 0x00F7, 0x2248, 0x00B0, 0x2219, 0x00B7, 0x221A, 0x207F, 0x00B2, 0x25A0, 0x00A0
};
#elif _CODE_PAGE == 862
#define _TBLDEF 1
static
const WCHAR Tbl[] = { /* CP862(0x80-0xFF) to Unicode conversion table */
0x05D0, 0x05D1, 0x05D2, 0x05D3, 0x05D4, 0x05D5, 0x05D6, 0x05D7, 0x05D8, 0x05D9, 0x05DA, 0x05DB, 0x05DC, 0x05DD, 0x05DE, 0x05DF,
0x05E0, 0x05E1, 0x05E2, 0x05E3, 0x05E4, 0x05E5, 0x05E6, 0x05E7, 0x05E8, 0x05E9, 0x05EA, 0x00A2, 0x00A3, 0x00A5, 0x20A7, 0x0192,
0x00E1, 0x00ED, 0x00F3, 0x00FA, 0x00F1, 0x00D1, 0x00AA, 0x00BA, 0x00BF, 0x2310, 0x00AC, 0x00BD, 0x00BC, 0x00A1, 0x00AB, 0x00BB,
0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x2561, 0x2562, 0x2556, 0x2555, 0x2563, 0x2551, 0x2557, 0x255D, 0x255C, 0x255B, 0x2510,
0x2514, 0x2534, 0x252C, 0x251C, 0x2500, 0x253C, 0x255E, 0x255F, 0x255A, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256C, 0x2567,
0x2568, 0x2564, 0x2565, 0x2559, 0x2558, 0x2552, 0x2553, 0x256B, 0x256A, 0x2518, 0x250C, 0x2588, 0x2584, 0x258C, 0x2590, 0x2580,
0x03B1, 0x00DF, 0x0393, 0x03C0, 0x03A3, 0x03C3, 0x00B5, 0x03C4, 0x03A6, 0x0398, 0x03A9, 0x03B4, 0x221E, 0x03C6, 0x03B5, 0x2229,
0x2261, 0x00B1, 0x2265, 0x2264, 0x2320, 0x2321, 0x00F7, 0x2248, 0x00B0, 0x2219, 0x00B7, 0x221A, 0x207F, 0x00B2, 0x25A0, 0x00A0
};
#elif _CODE_PAGE == 863
#define _TBLDEF 1
static
const WCHAR Tbl[] = { /* CP863(0x80-0xFF) to Unicode conversion table */
0x00C7, 0x00FC, 0x00E9, 0x00E2, 0x00C2, 0x00E0, 0x00B6, 0x00E7, 0x00EA, 0x00EB, 0x00E8, 0x00EF, 0x00EE, 0x00EC, 0x2017, 0x00C0,
0x00C9, 0x00C8, 0x00CA, 0x00F4, 0x00CB, 0x00CF, 0x00FB, 0x00F9, 0x00A4, 0x00D4, 0x00DC, 0x00A2, 0x00A3, 0x00D9, 0x00DB, 0x0192,
0x00A6, 0x00B4, 0x00F3, 0x00FA, 0x00A8, 0x00BB, 0x00B3, 0x00AF, 0x00CE, 0x3210, 0x00AC, 0x00BD, 0x00BC, 0x00BE, 0x00AB, 0x00BB,
0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x2561, 0x2562, 0x2556, 0x2555, 0x2563, 0x2551, 0x2557, 0x255D, 0x255C, 0x255B, 0x2510,
0x2514, 0x2534, 0x252C, 0x251C, 0x2500, 0x253C, 0x255E, 0x255F, 0x255A, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256C, 0x2567,
0x2568, 0x2564, 0x2565, 0x2559, 0x2558, 0x2552, 0x2553, 0x256B, 0x256A, 0x2518, 0x250C, 0x2588, 0x2584, 0x258C, 0x2590, 0x2580,
0x03B1, 0x00DF, 0x0393, 0x03C0, 0x03A3, 0x03C3, 0x00B5, 0x03C4, 0x03A6, 0x0398, 0x03A9, 0x03B4, 0x221E, 0x03C6, 0x03B5, 0x2219,
0x2261, 0x00B1, 0x2265, 0x2264, 0x2320, 0x2321, 0x00F7, 0x2248, 0x00B0, 0x2219, 0x00B7, 0x221A, 0x207F, 0x00B2, 0x25A0, 0x00A0
};
#elif _CODE_PAGE == 864
#define _TBLDEF 1
static
const WCHAR Tbl[] = { /* CP864(0x80-0xFF) to Unicode conversion table */
0x00B0, 0x00B7, 0x2219, 0x221A, 0x2592, 0x2500, 0x2502, 0x253C, 0x2524, 0x252C, 0x251C, 0x2534, 0x2510, 0x250C, 0x2514, 0x2518,
0x03B2, 0x221E, 0x03C6, 0x00B1, 0x00BD, 0x00BC, 0x2248, 0x00AB, 0x00BB, 0xFEF7, 0xFEF8, 0x0000, 0x0000, 0xFEFB, 0xFEFC, 0x0000,
0x00A0, 0x00AD, 0xFE82, 0x00A3, 0x00A4, 0xFE84, 0x0000, 0x20AC, 0xFE8E, 0xFE8F, 0xFE95, 0xFE99, 0x060C, 0xFE9D, 0xFEA1, 0xFEA5,
0x0660, 0x0661, 0x0662, 0x0663, 0x0664, 0x0665, 0x0666, 0x0667, 0x0668, 0x0669, 0xFED1, 0x061B, 0xFEB1, 0xFEB5, 0xFEB9, 0x061F,
0x00A2, 0xFE80, 0xFE81, 0xFE83, 0xFE85, 0xFECA, 0xFE8B, 0xFE8D, 0xFE91, 0xFE93, 0xFE97, 0xFE9B, 0xFE9F, 0xFEA3, 0xFEA7, 0xFEA9,
0xFEAB, 0xFEAD, 0xFEAF, 0xFEB3, 0xFEB7, 0xFEBB, 0xFEBF, 0xFEC1, 0xFEC5, 0xFECB, 0xFECF, 0x00A6, 0x00AC, 0x00F7, 0x00D7, 0xFEC9,
0x0640, 0xFED3, 0xFED7, 0xFEDB, 0xFEDF, 0xFEE3, 0xFEE7, 0xFEEB, 0xFEED, 0xFEEF, 0xFEF3, 0xFEBD, 0xFECC, 0xFECE, 0xFECD, 0xFEE1,
0xFE7D, 0x0651, 0xFEE5, 0xFEE9, 0xFEEC, 0xFEF0, 0xFEF2, 0xFED0, 0xFED5, 0xFEF5, 0xFEF6, 0xFEDD, 0xFED9, 0xFEF1, 0x25A0, 0x0000
};
#elif _CODE_PAGE == 865
#define _TBLDEF 1
static
const WCHAR Tbl[] = { /* CP865(0x80-0xFF) to Unicode conversion table */
0x00C7, 0x00FC, 0x00E9, 0x00E2, 0x00E4, 0x00E0, 0x00E5, 0x00E7, 0x00EA, 0x00EB, 0x00E8, 0x00EF, 0x00EE, 0x00EC, 0x00C4, 0x00C5,
0x00C5, 0x00E6, 0x00C6, 0x00F4, 0x00F6, 0x00F2, 0x00FB, 0x00F9, 0x00FF, 0x00D6, 0x00DC, 0x00F8, 0x00A3, 0x00D8, 0x20A7, 0x0192,
0x00E1, 0x00ED, 0x00F3, 0x00FA, 0x00F1, 0x00D1, 0x00AA, 0x00BA, 0x00BF, 0x2310, 0x00AC, 0x00BD, 0x00BC, 0x00A1, 0x00AB, 0x00A4,
0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x2561, 0x2562, 0x2556, 0x2555, 0x2563, 0x2551, 0x2557, 0x255D, 0x255C, 0x2558, 0x2510,
0x2514, 0x2534, 0x252C, 0x251C, 0x2500, 0x253C, 0x255E, 0x255F, 0x255A, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256C, 0x2567,
0x2568, 0x2564, 0x2565, 0x2559, 0x2558, 0x2552, 0x2553, 0x256B, 0x256A, 0x2518, 0x250C, 0x2588, 0x2584, 0x258C, 0x2590, 0x2580,
0x03B1, 0x00DF, 0x0393, 0x03C0, 0x03A3, 0x03C3, 0x00B5, 0x03C4, 0x03A6, 0x0398, 0x03A9, 0x03B4, 0x221E, 0x03C6, 0x03B5, 0x2229,
0x2261, 0x00B1, 0x2265, 0x2264, 0x2320, 0x2321, 0x00F7, 0x2248, 0x00B0, 0x2219, 0x00B7, 0x221A, 0x207F, 0x00B2, 0x25A0, 0x00A0
};
#elif _CODE_PAGE == 866
#define _TBLDEF 1
static
const WCHAR Tbl[] = { /* CP866(0x80-0xFF) to Unicode conversion table */
0x0410, 0x0411, 0x0412, 0x0413, 0x0414, 0x0415, 0x0416, 0x0417, 0x0418, 0x0419, 0x041A, 0x041B, 0x041C, 0x041D, 0x041E, 0x041F,
0x0420, 0x0421, 0x0422, 0x0423, 0x0424, 0x0425, 0x0426, 0x0427, 0x0428, 0x0429, 0x042A, 0x042B, 0x042C, 0x042D, 0x042E, 0x042F,
0x0430, 0x0431, 0x0432, 0x0433, 0x0434, 0x0435, 0x0436, 0x0437, 0x0438, 0x0439, 0x043A, 0x043B, 0x043C, 0x043D, 0x043E, 0x043F,
0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x2561, 0x2562, 0x2556, 0x2555, 0x2563, 0x2551, 0x2557, 0x255D, 0x255C, 0x255B, 0x2510,
0x2514, 0x2534, 0x252C, 0x251C, 0x2500, 0x253C, 0x255E, 0x255F, 0x255A, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256C, 0x2567,
0x2568, 0x2564, 0x2565, 0x2559, 0x2558, 0x2552, 0x2553, 0x256B, 0x256A, 0x2518, 0x250C, 0x2588, 0x2584, 0x258C, 0x2590, 0x2580,
0x0440, 0x0441, 0x0442, 0x0443, 0x0444, 0x0445, 0x0446, 0x0447, 0x0448, 0x0449, 0x044A, 0x044B, 0x044C, 0x044D, 0x044E, 0x044F,
0x0401, 0x0451, 0x0404, 0x0454, 0x0407, 0x0457, 0x040E, 0x045E, 0x00B0, 0x2219, 0x00B7, 0x221A, 0x2116, 0x00A4, 0x25A0, 0x00A0
};
#elif _CODE_PAGE == 869
#define _TBLDEF 1
static
const WCHAR Tbl[] = { /* CP869(0x80-0xFF) to Unicode conversion table */
0x00B7, 0x00B7, 0x00B7, 0x00B7, 0x00B7, 0x00B7, 0x0386, 0x00B7, 0x00B7, 0x00AC, 0x00A6, 0x2018, 0x2019, 0x0388, 0x2015, 0x0389,
0x038A, 0x03AA, 0x038C, 0x00B7, 0x00B7, 0x038E, 0x03AB, 0x00A9, 0x038F, 0x00B2, 0x00B3, 0x03AC, 0x00A3, 0x03AD, 0x03AE, 0x03AF,
0x03CA, 0x0390, 0x03CC, 0x03CD, 0x0391, 0x0392, 0x0393, 0x0394, 0x0395, 0x0396, 0x0397, 0x00BD, 0x0398, 0x0399, 0x00AB, 0x00BB,
0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x039A, 0x039B, 0x039C, 0x039D, 0x2563, 0x2551, 0x2557, 0x255D, 0x039E, 0x039F, 0x2510,
0x2514, 0x2534, 0x252C, 0x251C, 0x2500, 0x253C, 0x0A30, 0x03A1, 0x255A, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256C, 0x03A3,
0x03A4, 0x03A5, 0x03A6, 0x03A7, 0x03A8, 0x03A9, 0x03B1, 0x03B2, 0x03B3, 0x2518, 0x250C, 0x2588, 0x2584, 0x03B4, 0x03B5, 0x2580,
0x03B6, 0x03B7, 0x03B8, 0x03B9, 0x03BA, 0x03BB, 0x03BC, 0x03BD, 0x03BE, 0x03BF, 0x03C0, 0x03C1, 0x03C3, 0x03C2, 0x03C4, 0x0384,
0x00AD, 0x00B1, 0x03C5, 0x03C6, 0x03C7, 0x00A7, 0x03C8, 0x0385, 0x00B0, 0x00A8, 0x03C9, 0x03CB, 0x03B0, 0x03CE, 0x25A0, 0x00A0
};
#endif
#if !_TBLDEF || !_USE_LFN
#error This file is not needed at current configuration. Remove from the project.
#endif
WCHAR ff_convert ( /* Converted character, Returns zero on error */
WCHAR chr, /* Character code to be converted */
UINT dir /* 0: Unicode to OEM code, 1: OEM code to Unicode */
)
{
WCHAR c;
if (chr < 0x80) { /* ASCII */
c = chr;
} else {
if (dir) { /* OEM code to Unicode */
c = (chr >= 0x100) ? 0 : Tbl[chr - 0x80];
} else { /* Unicode to OEM code */
for (c = 0; c < 0x80; c++) {
if (chr == Tbl[c]) break;
}
c = (c + 0x80) & 0xFF;
}
}
return c;
}
WCHAR ff_wtoupper ( /* Returns upper converted character */
WCHAR chr /* Unicode character to be upper converted */
)
{
static const WCHAR lower[] = { /* Lower case characters to be converted */
/* Latin Supplement */ 0xE0,0xE1,0xE2,0xE3,0xE4,0xE5,0xE6,0xE7,0xE8,0xE9,0xEA,0xEB,0xEC,0xED,0xEE,0xEF,0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF,
/* Latin Extended-A */ 0x101,0x103,0x105,0x107,0x109,0x10B,0x10D,0x10F,0x111,0x113,0x115,0x117,0x119,0x11B,0x11D,0x11F,0x121,0x123,0x125,0x127,0x129,0x12B,0x12D,0x12F,0x131,0x133,0x135,0x137,0x13A,0x13C,0x13E,0x140,0x142,0x144,0x146,0x148,0x14B,0x14D,0x14F,0x151,0x153,0x155,0x157,0x159,0x15B,0x15D,0x15F,0x161,0x163,0x165,0x167,0x169,0x16B,0x16D,0x16F,0x171,0x173,0x175,0x177,0x17A,0x17C,0x17E,
/* Latin Extended-B */ 0x183,0x185,0x188,0x18C,0x192,0x199,0x1A1,0x1A3,0x1A8,0x1AD,0x1B0,0x1B4,0x1B6,0x1B9,0x1BD,0x1C6,0x1C9,0x1CC,0x1CE,0x1D0,0x1D2,0x1D4,0x1D6,0x1D8,0x1DA,0x1DC,0x1DD,0x1DF,0x1E1,0x1E3,0x1E5,0x1E7,0x1E9,0x1EB,0x1ED,0x1EF,0x1F3,0x1F5,0x1FB,0x1FD,0x1FF,0x201,0x203,0x205,0x207,0x209,0x20B,0x20D,0x20F,0x211,0x213,0x215,0x217,
/* Greek, Coptic */ 0x3B1,0x3B2,0x3B3,0x3B4,0x3B5,0x3B6,0x3B7,0x3B8,0x3B9,0x3BA,0x3BB,0x3BC,0x3BD,0x3BE,0x3BF,0x3C0,0x3C1,0x3C3,0x3C4,0x3C5,0x3C6,0x3C7,0x3C8,0x3C9,0x3CA,0x3CB,0x3CC,0x3CD,0x3CE,0x3E3,0x3E5,0x3E7,0x3E9,0x3EB,
/* Cyrillic */ 0x430,0x431,0x432,0x433,0x434,0x435,0x436,0x437,0x438,0x439,0x43A,0x43B,0x43C,0x43D,0x43E,0x43F,0x440,0x441,0x442,0x443,0x444,0x445,0x446,0x447,0x448,0x449,0x44A,0x44B,0x44C,0x44D,0x44E,0x44F,0x452,0x453,0x454,0x455,0x456,0x457,0x458,0x459,0x45A,0x45B,0x45C,0x45E,0x45F,0x461,0x463,0x465,0x467,0x469,0x46B,0x46D,0x46F,0x471,0x473,0x475,0x477,0x479,0x47B,0x47D,0x47F,0x481,0x491,0x493,0x495,0x497,0x499,0x49B,0x49D,0x49F,0x4A1,0x4A3,0x4A5,0x4A7,0x4A9,0x4AB,0x4AD,0x4AF,0x4B1,0x4B3,0x4B5,0x4B7,0x4B9,0x4BB,0x4BD,0x4BF,0x4C2,0x4C4,0x4C8,0x4D1,0x4D3,0x4D5,0x4D7,0x4D9,0x4DB,0x4DD,0x4DF,0x4E1,0x4E3,0x4E5,0x4E7,0x4E9,0x4EB,0x4ED,0x4EF,0x4F1,0x4F3,0x4F5,0x4F9,
/* Armenian */ 0x561,0x562,0x563,0x564,0x565,0x566,0x567,0x568,0x569,0x56A,0x56B,0x56C,0x56D,0x56E,0x56F,0x570,0x571,0x572,0x573,0x574,0x575,0x576,0x577,0x578,0x579,0x57A,0x57B,0x57C,0x57D,0x57E,0x57F,0x580,0x581,0x582,0x583,0x584,0x585,0x586,
/* Latin Extended Additional */ 0x1E01,0x1E03,0x1E05,0x1E07,0x1E09,0x1E0B,0x1E0D,0x1E0F,0x1E11,0x1E13,0x1E15,0x1E17,0x1E19,0x1E1B,0x1E1D,0x1E1F,0x1E21,0x1E23,0x1E25,0x1E27,0x1E29,0x1E2B,0x1E2D,0x1E2F,0x1E31,0x1E33,0x1E35,0x1E37,0x1E39,0x1E3B,0x1E3D,0x1E3F,0x1E41,0x1E43,0x1E45,0x1E47,0x1E49,0x1E4B,0x1E4D,0x1E4F,0x1E51,0x1E53,0x1E55,0x1E57,0x1E59,0x1E5B,0x1E5D,0x1E5F,0x1E61,0x1E63,0x1E65,0x1E67,0x1E69,0x1E6B,0x1E6D,0x1E6F,0x1E71,0x1E73,0x1E75,0x1E77,0x1E79,0x1E7B,0x1E7D,0x1E7F,0x1E81,0x1E83,0x1E85,0x1E87,0x1E89,0x1E8B,0x1E8D,0x1E8F,0x1E91,0x1E93,0x1E95,0x1E97,0x1E99,0x1E9B,0x1E9D,0x1E9F,0x1EA1,0x1EA3,0x1EA5,0x1EA7,0x1EA9,0x1EAB,0x1EAD,0x1EAF,0x1EB1,0x1EB3,0x1EB5,0x1EB7,0x1EB9,0x1EBB,0x1EBD,0x1EBF,0x1EC1,0x1EC3,0x1EC5,0x1EC7,0x1EC9,0x1ECB,0x1ECD,0x1ECF,0x1ED1,0x1ED3,0x1ED5,0x1ED7,0x1ED9,0x1EDB,0x1EDD,0x1EDF,0x1EE1,0x1EE3,0x1EE5,0x1EE7,0x1EE9,0x1EEB,0x1EED,0x1EEF,0x1EF1,0x1EF3,0x1EF5,0x1EF7,0x1EF9,
/* Number forms */ 0x2170,0x2171,0x2172,0x2173,0x2174,0x2175,0x2176,0x2177,0x2178,0x2179,0x217A,0x217B,0x217C,0x217D,0x217E,0x217F,
/* Full-width */ 0xFF41,0xFF42,0xFF43,0xFF44,0xFF45,0xFF46,0xFF47,0xFF48,0xFF49,0xFF4A,0xFF4B,0xFF4C,0xFF4D,0xFF4E,0xFF4F,0xFF50,0xFF51,0xFF52,0xFF53,0xFF54,0xFF55,0xFF56,0xFF57,0xFF58,0xFF59,0xFF5A
};
static const WCHAR upper[] = { /* Upper case characters correspond to lower[] */
0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0x178,
0x100,0x102,0x104,0x106,0x108,0x10A,0x10C,0x10E,0x110,0x112,0x114,0x116,0x118,0x11A,0x11C,0x11E,0x120,0x122,0x124,0x126,0x128,0x12A,0x12C,0x12E,0x130,0x132,0x134,0x136,0x139,0x13B,0x13D,0x13F,0x141,0x143,0x145,0x147,0x14A,0x14C,0x14E,0x150,0x152,0x154,0x156,0x158,0x15A,0x15C,0x15E,0x160,0x162,0x164,0x166,0x168,0x16A,0x16C,0x16E,0x170,0x172,0x174,0x176,0x179,0x17B,0x17D,
0x182,0x184,0x187,0x18B,0x191,0x198,0x1A0,0x1A2,0x1A7,0x1AC,0x1AF,0x1B3,0x1B5,0x1B8,0x1BC,0x1C4,0x1C7,0x1CA,0x1CD,0x1CF,0x1D1,0x1D3,0x1D5,0x1D7,0x1D9,0x1DB,0x18E,0x1DE,0x1E0,0x1E2,0x1E4,0x1E6,0x1E8,0x1EA,0x1EC,0x1EE,0x1F1,0x1F4,0x1FA,0x1FC,0x1FE,0x200,0x202,0x204,0x206,0x208,0x20A,0x20C,0x20E,0x210,0x212,0x214,0x216,
0x391,0x392,0x393,0x394,0x395,0x396,0x397,0x398,0x399,0x39A,0x39B,0x39C,0x39D,0x39E,0x39F,0x3A0,0x3A1,0x3A3,0x3A4,0x3A5,0x3A6,0x3A7,0x3A8,0x3A9,0x3AA,0x3AB,0x38C,0x38E,0x38F,0x3E2,0x3E4,0x3E6,0x3E8,0x3EA,
0x410,0x411,0x412,0x413,0x414,0x415,0x416,0x417,0x418,0x419,0x41A,0x41B,0x41C,0x41D,0x41E,0x41F,0x420,0x421,0x422,0x423,0x424,0x425,0x426,0x427,0x428,0x429,0x42A,0x42B,0x42C,0x42D,0x42E,0x42F,0x402,0x403,0x404,0x405,0x406,0x407,0x408,0x409,0x40A,0x40B,0x40C,0x40E,0x40F,0x460,0x462,0x464,0x466,0x468,0x46A,0x46C,0x46E,0x470,0x472,0x474,0x476,0x478,0x47A,0x47C,0x47E,0x480,0x490,0x492,0x494,0x496,0x498,0x49A,0x49C,0x49E,0x4A0,0x4A2,0x4A4,0x4A6,0x4A8,0x4AA,0x4AC,0x4AE,0x4B0,0x4B2,0x4B4,0x4B6,0x4B8,0x4BA,0x4BC,0x4BE,0x4C1,0x4C3,0x5C7,0x4D0,0x4D2,0x4D4,0x4D6,0x4D8,0x4DA,0x4DC,0x4DE,0x4E0,0x4E2,0x4E4,0x4E6,0x4E8,0x4EA,0x4EC,0x4EE,0x4F0,0x4F2,0x4F4,0x4F8,
0x531,0x532,0x533,0x534,0x535,0x536,0x537,0x538,0x539,0x53A,0x53B,0x53C,0x53D,0x53E,0x53F,0x540,0x541,0x542,0x543,0x544,0x545,0x546,0x547,0x548,0x549,0x54A,0x54B,0x54C,0x54D,0x54E,0x54F,0x550,0x551,0x552,0x553,0x554,0x555,0x556,
0x1E00,0x1E02,0x1E04,0x1E06,0x1E08,0x1E0A,0x1E0C,0x1E0E,0x1E10,0x1E12,0x1E14,0x1E16,0x1E18,0x1E1A,0x1E1C,0x1E1E,0x1E20,0x1E22,0x1E24,0x1E26,0x1E28,0x1E2A,0x1E2C,0x1E2E,0x1E30,0x1E32,0x1E34,0x1E36,0x1E38,0x1E3A,0x1E3C,0x1E3E,0x1E40,0x1E42,0x1E44,0x1E46,0x1E48,0x1E4A,0x1E4C,0x1E4E,0x1E50,0x1E52,0x1E54,0x1E56,0x1E58,0x1E5A,0x1E5C,0x1E5E,0x1E60,0x1E62,0x1E64,0x1E66,0x1E68,0x1E6A,0x1E6C,0x1E6E,0x1E70,0x1E72,0x1E74,0x1E76,0x1E78,0x1E7A,0x1E7C,0x1E7E,0x1E80,0x1E82,0x1E84,0x1E86,0x1E88,0x1E8A,0x1E8C,0x1E8E,0x1E90,0x1E92,0x1E94,0x1E96,0x1E98,0x1E9A,0x1E9C,0x1E9E,0x1EA0,0x1EA2,0x1EA4,0x1EA6,0x1EA8,0x1EAA,0x1EAC,0x1EAE,0x1EB0,0x1EB2,0x1EB4,0x1EB6,0x1EB8,0x1EBA,0x1EBC,0x1EBE,0x1EC0,0x1EC2,0x1EC4,0x1EC6,0x1EC8,0x1ECA,0x1ECC,0x1ECE,0x1ED0,0x1ED2,0x1ED4,0x1ED6,0x1ED8,0x1EDA,0x1EDC,0x1EDE,0x1EE0,0x1EE2,0x1EE4,0x1EE6,0x1EE8,0x1EEA,0x1EEC,0x1EEE,0x1EF0,0x1EF2,0x1EF4,0x1EF6,0x1EF8,
0x2160,0x2161,0x2162,0x2163,0x2164,0x2165,0x2166,0x2167,0x2168,0x2169,0x216A,0x216B,0x216C,0x216D,0x216E,0x216F,
0xFF21,0xFF22,0xFF23,0xFF24,0xFF25,0xFF26,0xFF27,0xFF28,0xFF29,0xFF2A,0xFF2B,0xFF2C,0xFF2D,0xFF2E,0xFF2F,0xFF30,0xFF31,0xFF32,0xFF33,0xFF34,0xFF35,0xFF36,0xFF37,0xFF38,0xFF39,0xFF3A
};
UINT i, n, hi, li;
if (chr < 0x80) { /* ASCII characters (acceleration) */
if (chr >= 0x61 && chr <= 0x7A) chr -= 0x20;
} else { /* Non ASCII characters (table search) */
n = 12; li = 0; hi = sizeof lower / sizeof lower[0];
do {
i = li + (hi - li) / 2;
if (chr == lower[i]) break;
if (chr > lower[i]) li = i; else hi = i;
} while (--n);
if (n) chr = upper[i];
}
return chr;
}

View File

@ -1,151 +0,0 @@
/*------------------------------------------------------------------------*/
/* Sample code of OS dependent controls for FatFs */
/* (C)ChaN, 2014 */
/*------------------------------------------------------------------------*/
#include "../ff.h"
#if _FS_REENTRANT
/*------------------------------------------------------------------------*/
/* Create a Synchronization Object
/*------------------------------------------------------------------------*/
/* This function is called in f_mount() function to create a new
/ synchronization object, such as semaphore and mutex. When a 0 is returned,
/ the f_mount() function fails with FR_INT_ERR.
*/
int ff_cre_syncobj ( /* !=0:Function succeeded, ==0:Could not create due to any error */
BYTE vol, /* Corresponding logical drive being processed */
_SYNC_t *sobj /* Pointer to return the created sync object */
)
{
int ret;
*sobj = CreateMutex(NULL, FALSE, NULL); /* Win32 */
ret = (int)(*sobj != INVALID_HANDLE_VALUE);
// *sobj = SyncObjects[vol]; /* uITRON (give a static created sync object) */
// ret = 1; /* The initial value of the semaphore must be 1. */
// *sobj = OSMutexCreate(0, &err); /* uC/OS-II */
// ret = (int)(err == OS_NO_ERR);
// *sobj = xSemaphoreCreateMutex(); /* FreeRTOS */
// ret = (int)(*sobj != NULL);
return ret;
}
/*------------------------------------------------------------------------*/
/* Delete a Synchronization Object */
/*------------------------------------------------------------------------*/
/* This function is called in f_mount() function to delete a synchronization
/ object that created with ff_cre_syncobj function. When a 0 is returned,
/ the f_mount() function fails with FR_INT_ERR.
*/
int ff_del_syncobj ( /* !=0:Function succeeded, ==0:Could not delete due to any error */
_SYNC_t sobj /* Sync object tied to the logical drive to be deleted */
)
{
int ret;
ret = CloseHandle(sobj); /* Win32 */
// ret = 1; /* uITRON (nothing to do) */
// OSMutexDel(sobj, OS_DEL_ALWAYS, &err); /* uC/OS-II */
// ret = (int)(err == OS_NO_ERR);
// vSemaphoreDelete(sobj); /* FreeRTOS */
// ret = 1;
return ret;
}
/*------------------------------------------------------------------------*/
/* Request Grant to Access the Volume */
/*------------------------------------------------------------------------*/
/* This function is called on entering file functions to lock the volume.
/ When a 0 is returned, the file function fails with FR_TIMEOUT.
*/
int ff_req_grant ( /* 1:Got a grant to access the volume, 0:Could not get a grant */
_SYNC_t sobj /* Sync object to wait */
)
{
int ret;
ret = (int)(WaitForSingleObject(sobj, _FS_TIMEOUT) == WAIT_OBJECT_0); /* Win32 */
// ret = (int)(wai_sem(sobj) == E_OK); /* uITRON */
// OSMutexPend(sobj, _FS_TIMEOUT, &err)); /* uC/OS-II */
// ret = (int)(err == OS_NO_ERR);
// ret = (int)(xSemaphoreTake(sobj, _FS_TIMEOUT) == pdTRUE); /* FreeRTOS */
return ret;
}
/*------------------------------------------------------------------------*/
/* Release Grant to Access the Volume */
/*------------------------------------------------------------------------*/
/* This function is called on leaving file functions to unlock the volume.
*/
void ff_rel_grant (
_SYNC_t sobj /* Sync object to be signaled */
)
{
ReleaseMutex(sobj); /* Win32 */
// sig_sem(sobj); /* uITRON */
// OSMutexPost(sobj); /* uC/OS-II */
// xSemaphoreGive(sobj); /* FreeRTOS */
}
#endif
#if _USE_LFN == 3 /* LFN with a working buffer on the heap */
/*------------------------------------------------------------------------*/
/* Allocate a memory block */
/*------------------------------------------------------------------------*/
/* If a NULL is returned, the file function fails with FR_NOT_ENOUGH_CORE.
*/
void* ff_memalloc ( /* Returns pointer to the allocated memory block */
UINT msize /* Number of bytes to allocate */
)
{
return malloc(msize); /* Allocate a new memory block with POSIX API */
}
/*------------------------------------------------------------------------*/
/* Free a memory block */
/*------------------------------------------------------------------------*/
void ff_memfree (
void* mblock /* Pointer to the memory block to free */
)
{
free(mblock); /* Discard the memory block with POSIX API */
}
#endif

View File

@ -1,17 +0,0 @@
#include "../ff.h"
#if _USE_LFN != 0
#if _CODE_PAGE == 932 /* Japanese Shift_JIS */
#include "cc932.c"
#elif _CODE_PAGE == 936 /* Simplified Chinese GBK */
#include "cc936.c"
#elif _CODE_PAGE == 949 /* Korean */
#include "cc949.c"
#elif _CODE_PAGE == 950 /* Traditional Chinese Big5 */
#include "cc950.c"
#else /* Single Byte Character-Set */
#include "ccsbcs.c"
#endif
#endif

View File

@ -1,74 +0,0 @@
/*
* minute - a port of the "mini" IOS replacement for the Wii U.
*
* Copyright (C) 2008, 2009 Hector Martin "marcan" <marcan@marcansoft.com>
*
* This code is licensed to you under the terms of the GNU GPL, version 2;
* see file COPYING or http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt
*/
#ifndef __GPIO_H__
#define __GPIO_H__
enum {
GP_POWER = 0x00000001,
GP_SHUTDOWN = 0x00000002,
GP_FAN = 0x00000004,
GP_DCDC = 0x00000008,
GP_DISPIN = 0x00000010,
GP_SLOTLED = 0x00000020,
GP_EJECTBTN = 0x00000040,
GP_SLOTIN = 0x00000080,
GP_SENSORBAR = 0x00000100,
GP_DOEJECT = 0x00000200,
GP_EEP_CS = 0x00000400,
GP_EEP_CLK = 0x00000800,
GP_EEP_MOSI = 0x00001000,
GP_EEP_MISO = 0x00002000,
GP_AV0_SCL = 0x00004000,
GP_AV0_SDA = 0x00008000,
GP_DEBUG0 = 0x00010000,
GP_DEBUG1 = 0x00020000,
GP_DEBUG2 = 0x00040000,
GP_DEBUG3 = 0x00080000,
GP_DEBUG4 = 0x00100000,
GP_DEBUG5 = 0x00200000,
GP_DEBUG6 = 0x00400000,
GP_DEBUG7 = 0x00800000,
GP_AV1_SCL = 0x01000000,
GP_AV1_SDA = 0x02000000,
GP_MUTELAMP = 0x04000000,
GP_BT_MODE = 0x08000000,
GP_CCRH_RST = 0x10000000,
GP_WIFI_MODE = 0x20000000,
GP_SDSLOT0_PWR = 0x40000000,
};
enum {
GP2_FANSPEED = 0x00000001,
GP2_SMC_SCL = 0x00000002,
GP2_SMC_SDA = 0x00000004,
GP2_DCDC2 = 0x00000008,
GP2_AV_INT = 0x00000010,
GP2_CCRIO12 = 0x00000020,
GP2_AV_RST = 0x00000040,
};
#define GP_DEBUG_SHIFT 16
#define GP_DEBUG_MASK 0xFF0000
#define GP_ALL 0xFFFFFF
#define GP_OWNER_PPC (GP_AVE_SDA | GP_AVE_SCL | GP_DOEJECT | GP_SENSORBAR | GP_SLOTIN | GP_SLOTLED)
#define GP_OWNER_ARM (GP_ALL ^ GP_OWNER_PPC)
#define GP_INPUTS (GP_POWER | GP_EJECTBTN | GP_SLOTIN | GP_EEP_MISO | GP_AVE_SDA)
#define GP_OUTPUTS (GP_ALL ^ GP_INPUTS)
#define GP_ARM_INPUTS (GP_INPUTS & GP_OWNER_ARM)
#define GP_PPC_INPUTS (GP_INPUTS & GP_OWNER_PPC)
#define GP_ARM_OUTPUTS (GP_OUTPUTS & GP_OWNER_ARM)
#define GP_PPC_OUTPUTS (GP_OUTPUTS & GP_OWNER_PPC)
#define GP_DEFAULT_ON (GP_AVE_SCL | GP_DCDC | GP_FAN)
#define GP_ARM_DEFAULT_ON (GP_DEFAULT_ON & GP_OWNER_ARM)
#define GP_PPC_DEFAULT_ON (GP_DEFAULT_ON & GP_OWNER_PPC)
#endif

View File

@ -1,46 +0,0 @@
#include "hmac.h"
#include "sha.h"
#include "hmac.h"
#include "string.h"
#define HMAC_IPAD 0x36
#define HMAC_OPAD 0x5C
void hmac_init(hmac_ctx* ctx, const u8* key, int size)
{
int i;
memset(ctx->key, 0, sizeof(ctx->key));
if (size > sizeof(ctx->key))
sha_hash(key, ctx->key, size);
else
memcpy(ctx->key, key, size);
for (i = 0; i < sizeof(ctx->key); i++)
ctx->key[i] ^= HMAC_IPAD;
sha_init(&ctx->hash_ctx);
sha_update(&ctx->hash_ctx, ctx->key, sizeof(ctx->key));
}
void hmac_update(hmac_ctx* ctx, const void* data, int size)
{
sha_update(&ctx->hash_ctx, data, size);
}
void hmac_final(hmac_ctx* ctx, u8* hmac)
{
u8 hash[SHA_HASH_SIZE];
int i;
sha_final(&ctx->hash_ctx, hash);
for (i = 0; i < sizeof(ctx->key); i++)
ctx->key[i] ^= HMAC_IPAD ^ HMAC_OPAD;
sha_init(&ctx->hash_ctx);
sha_update(&ctx->hash_ctx, ctx->key, sizeof(ctx->key));
sha_update(&ctx->hash_ctx, hash, sizeof(hash));
sha_final(&ctx->hash_ctx, hmac);
}

View File

@ -1,18 +0,0 @@
#ifndef _HMAC_H
#define _HMAC_H
#include "types.h"
#include "sha.h"
#define HMAC_SIZE (SHA_HASH_SIZE)
typedef struct {
u8 key[SHA_BLOCK_SIZE];
sha_ctx hash_ctx;
} hmac_ctx;
void hmac_init(hmac_ctx* ctx, const u8* key, int size);
void hmac_update(hmac_ctx* ctx, const void* data, int size);
void hmac_final(hmac_ctx *ctx, u8 *hmac);
#endif /* _HMAC_H */

View File

@ -1,158 +0,0 @@
/*
* minute - a port of the "mini" IOS replacement for the Wii U.
*
* Copyright (C) 2016 SALT
* Copyright (C) 2016 Daz Jones <daz@dazzozo.com>
*
* Copyright (C) 2008, 2009 Hector Martin "marcan" <marcan@marcansoft.com>
* Copyright (C) 2008, 2009 Sven Peter <svenpeter@gmail.com>
* Copyright (C) 2009 Andre Heider "dhewg" <dhewg@wiibrew.org>
*
* This code is licensed to you under the terms of the GNU GPL, version 2;
* see file COPYING or http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt
*/
#include "irq.h"
#include "latte.h"
#include "utils.h"
#include "crypto.h"
#include "nand.h"
#include "sdcard.h"
#include "debug.h"
static u32 _alarm_frequency = 0;
void irq_setup_stack(void);
void irq_initialize(void)
{
irq_setup_stack();
write32(LT_INTMR_AHBALL_ARM, 0);
write32(LT_INTSR_AHBALL_ARM, 0xffffffff);
write32(LT_INTMR_AHBLT_ARM, 0);
write32(LT_INTSR_AHBLT_ARM, 0xffffffff);
irq_restore(CPSR_FIQDIS);
//???
write32(LT_INTMR_AHBALL_ARM2X, 0);
write32(LT_INTMR_AHBLT_ARM2X, 0);
write32(LT_ERROR_MASK, 0);
write32(LT_ALARM, 0);
}
void irq_shutdown(void)
{
write32(LT_INTMR_AHBALL_ARM, 0);
write32(LT_INTSR_AHBALL_ARM, 0xffffffff);
write32(LT_INTMR_AHBLT_ARM, 0);
write32(LT_INTSR_AHBLT_ARM, 0xffffffff);
irq_kill();
}
void irq_handler(void)
{
u32 all_enabled = read32(LT_INTMR_AHBALL_ARM);
u32 all_flags = read32(LT_INTSR_AHBALL_ARM);
u32 all_mask = all_enabled & all_flags;
u32 lt_enabled = read32(LT_INTMR_AHBLT_ARM);
u32 lt_flags = read32(LT_INTSR_AHBLT_ARM);
u32 lt_mask = lt_enabled & lt_flags;
/*DEBUG("In IRQ handler: ALL (0x%08x 0x%08x 0x%08x) LT (0x%08x 0x%08x 0x%08x)\n",
all_enabled, all_flags, all_mask, lt_enabled, lt_flags, lt_mask);*/
if(all_mask & IRQF_TIMER) {
if (_alarm_frequency)
write32(LT_ALARM, read32(LT_TIMER) + _alarm_frequency);
write32(LT_INTSR_AHBALL_ARM, IRQF_TIMER);
}
if(all_mask & IRQF_NAND) {
// DEBUG("IRQ: NAND\n");
write32(NAND_CTRL, 0x7fffffff); // shut it up
write32(LT_INTSR_AHBALL_ARM, IRQF_NAND);
nand_irq();
}
/*
if(all_mask & IRQF_GPIO1B) {
// DEBUG("IRQ: GPIO1B\n");
write32(HW_GPIO1BINTFLAG, 0xFFFFFF); // shut it up
write32(LT_INTSR_AHBALL_ARM, IRQF_GPIO1B);
}
if(all_mask & IRQF_GPIO1) {
// DEBUG("IRQ: GPIO1\n");
write32(HW_GPIO1INTFLAG, 0xFFFFFF); // shut it up
write32(LT_INTSR_AHBALL_ARM, IRQF_GPIO1);
}
if(all_mask & IRQF_RESET) {
// DEBUG("IRQ: RESET\n");
write32(LT_INTSR_AHBALL_ARM, IRQF_RESET);
}*/
if(all_mask & IRQF_SHA1) {
// DEBUG("IRQ: SHA1\n");
write32(LT_INTSR_AHBALL_ARM, IRQF_SHA1);
}
if(all_mask & IRQF_AES) {
// DEBUG("IRQ: AES\n");
write32(LT_INTSR_AHBALL_ARM, IRQF_AES);
}
if(all_mask & IRQF_SD0) {
// DEBUG("IRQ: SD0\n");
sdcard_irq();
write32(LT_INTSR_AHBALL_ARM, IRQF_SD0);
}
if(lt_mask & IRQLF_SD2) {
// DEBUG("IRQL: SD2\n");
//mlc_irq(); //Ash: don't need MLC support, turning it off
write32(LT_INTSR_AHBLT_ARM, IRQLF_SD2);
}
all_mask &= ~IRQF_ALL;
if(all_mask) {
DEBUG("IRQ: ALL unknown 0x%08lx\n", all_mask);
write32(LT_INTSR_AHBALL_ARM, all_mask);
}
lt_mask &= ~IRQLF_ALL;
if(lt_mask) {
DEBUG("IRQ: LT unknown 0x%08lx\n", lt_mask);
write32(LT_INTSR_AHBALL_ARM, lt_mask);
}
}
void irq_enable(u32 irq)
{
set32(LT_INTMR_AHBALL_ARM, 1<<irq);
}
void irql_enable(u32 irq)
{
set32(LT_INTMR_AHBLT_ARM, 1<<irq);
}
void irq_disable(u32 irq)
{
clear32(LT_INTMR_AHBALL_ARM, 1<<irq);
}
void irql_disable(u32 irq)
{
clear32(LT_INTMR_AHBLT_ARM, 1<<irq);
}
void irq_set_alarm(u32 ms, u8 enable)
{
_alarm_frequency = IRQ_ALARM_MS2REG(ms);
if (enable)
write32(LT_ALARM, read32(LT_TIMER) + _alarm_frequency);
}
void irq_wait(void)
{
u32 data = 0;
__asm__ volatile ( "mcr p15, 0, %0, c7, c0, 4" : : "r" (data) );
}

View File

@ -1,75 +0,0 @@
/*
* minute - a port of the "mini" IOS replacement for the Wii U.
*
* Copyright (C) 2016 SALT
* Copyright (C) 2016 Daz Jones <daz@dazzozo.com>
*
* Copyright (C) 2008, 2009 Hector Martin "marcan" <marcan@marcansoft.com>
* Copyright (C) 2008, 2009 Sven Peter <svenpeter@gmail.com>
*
* This code is licensed to you under the terms of the GNU GPL, version 2;
* see file COPYING or http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt
*/
#include "types.h"
#pragma once
#define IRQ_TIMER 0
#define IRQ_NAND 1
#define IRQ_AES 2
#define IRQ_SHA1 3
#define IRQ_EHCI 4
#define IRQ_OHCI0 5
#define IRQ_OHCI1 6
#define IRQ_SD0 7
#define IRQ_WIFI 8
#define IRQ_GPIO1B 10
#define IRQ_GPIO1 11
#define IRQ_RESET 17
#define IRQ_PPCIPC 30
#define IRQ_IPC 31
#define IRQL_SD2 0
#define IRQF_TIMER (1<<IRQ_TIMER)
#define IRQF_NAND (1<<IRQ_NAND)
#define IRQF_AES (1<<IRQ_AES)
#define IRQF_SHA1 (1<<IRQ_SHA1)
#define IRQF_SD0 (1<<IRQ_SD0)
#define IRQF_GPIO1B (1<<IRQ_GPIO1B)
#define IRQF_GPIO1 (1<<IRQ_GPIO1)
#define IRQF_RESET (1<<IRQ_RESET)
#define IRQF_IPC (1<<IRQ_IPC)
#define IRQLF_SD2 (1<<IRQL_SD2)
#define IRQF_ALL ( \
IRQF_TIMER|IRQF_NAND|IRQF_GPIO1B|IRQF_GPIO1| \
IRQF_RESET|IRQF_IPC|IRQF_AES|IRQF_SHA1|IRQF_SD0 \
)
#define IRQLF_ALL ( \
IRQLF_SD2 \
)
#define CPSR_IRQDIS 0x80
#define CPSR_FIQDIS 0x40
#define IRQ_ALARM_MS2REG(x) (1898 * x)
void irq_initialize(void);
void irq_shutdown(void);
void irq_enable(u32 irq);
void irq_disable(u32 irq);
void irql_enable(u32 irq);
void irql_disable(u32 irq);
u32 irq_kill(void);
void irq_restore(u32 cookie);
void irq_wait(void);
void irq_set_alarm(u32 ms, u8 enable);

View File

@ -1,56 +0,0 @@
/*
* minute - a port of the "mini" IOS replacement for the Wii U.
*
* Copyright (C) 2016 SALT
* Copyright (C) 2016 Daz Jones <daz@dazzozo.com>
*
* Copyright (C) 2008, 2009 Hector Martin "marcan" <marcan@marcansoft.com>
*
* This code is licensed to you under the terms of the GNU GPL, version 2;
* see file COPYING or http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt
*/
#include "latte.h"
//#include "irq.h"
.globl v_irq
.globl irq_setup_stack
.globl irq_kill
.globl irq_restore
.extern __irqstack_addr
.extern irq_handler
irq_setup_stack:
@ Switch to IRQ mode
mrs r0, cpsr
msr cpsr_c, #0xd2
@ Setup interrupt stack
ldr sp, =__irqstack_addr
@ Restore mode
msr cpsr_c, r0
bx lr
v_irq:
push {r0-r3, r9, r12, lr}
blx irq_handler
pop {r0-r3, r9, r12, lr}
subs pc, lr, #4
irq_kill:
mrs r1, cpsr
and r0, r1, #(0x80|0x40)
orr r1, r1, #(0x80|0x40)
msr cpsr_c, r1
bx lr
irq_restore:
mrs r1, cpsr
bic r1, r1, #(0x80|0x40)
orr r1, r1, r0
msr cpsr_c, r1
bx lr

View File

@ -1,22 +0,0 @@
#pragma once
#include "types.h"
#include "sha.h"
#include "hmac.h"
typedef struct {
u16 x1;
u16 uid;
char name[0x0C];
u32 iblk;
u32 ifst;
u32 x3;
u8 pad0[0x24];
} isfs_hmac_data;
_Static_assert(sizeof(isfs_hmac_data) == 0x40, "isfs_hmac_data size must be 0x40!");
typedef struct {
u8 pad0[0x12];
u16 cluster;
u8 pad1[0x2b];
} isfs_hmac_meta;
_Static_assert(sizeof(isfs_hmac_meta) == 0x40, "isfs_hmac_meta size must be 0x40!");

View File

@ -1,228 +0,0 @@
/*
* minute - a port of the "mini" IOS replacement for the Wii U.
*
* Copyright (C) 2016 SALT
* Copyright (C) 2016 Daz Jones <daz@dazzozo.com>
*
* This code is licensed to you under the terms of the GNU GPL, version 2;
* see file COPYING or http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt
*/
#include "types.h"
#include "utils.h"
#include "debug.h"
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include "nand.h"
#include "isfs/isfs.h"
#include "isfs/volume.h"
#include "isfs/super.h"
#include "isfs/isfshax.h"
static bool initialized = false;
int isfs_init(void)
{
isfs_ctx *ctx;
int res = 0;
if(initialized) return res;
ctx = isfs_get_volume(ISFSVOL_SLC);
ctx->mounted = !isfs_load_super(ctx, 0, ISFSHAX_GENERATION_FIRST);
initialized = true;
return 0;
}
int isfs_fini(void)
{
if(!initialized) return 0;
for(int i = 0; i < isfs_num_volumes(); i++)
isfs_get_volume(i)->mounted = false;
initialized = false;
return 0;
}
isfs_fst* isfs_stat(const char* path)
{
isfs_ctx* ctx = NULL;
path = isfs_do_volume(path, &ctx);
if(!ctx || !path) return NULL;
return isfs_find_fst(ctx, NULL, path);
}
int isfs_open(isfs_file* file, const char* path)
{
if(!file || !path) return -1;
isfs_ctx* ctx = NULL;
path = isfs_do_volume(path, &ctx);
if(!ctx) return -2;
isfs_fst* fst = isfs_find_fst(ctx, NULL, path);
if(!fst) return -3;
if(!isfs_fst_is_file(fst)) return -4;
memset(file, 0, sizeof(isfs_file));
file->volume = ctx->volume;
file->fst = fst;
file->cluster = fst->sub;
file->offset = 0;
return 0;
}
int isfs_close(isfs_file* file)
{
if(!file) return -1;
memset(file, 0, sizeof(isfs_file));
return 0;
}
int isfs_seek(isfs_file* file, s32 offset, int whence)
{
if(!file) return -1;
isfs_ctx* ctx = isfs_get_volume(file->volume);
isfs_fst* fst = file->fst;
if(!ctx || !fst) return -2;
switch(whence) {
case SEEK_SET:
if(offset < 0) return -1;
if(offset > fst->size) return -1;
file->offset = offset;
break;
case SEEK_CUR:
if(file->offset + offset > fst->size) return -1;
if(offset + fst->size < 0) return -1;
file->offset += offset;
break;
case SEEK_END:
if(file->offset + offset > fst->size) return -1;
if(offset + fst->size < 0) return -1;
file->offset = fst->size + offset;
break;
}
u16 sub = fst->sub;
size_t size = file->offset;
while(size > 8 * PAGE_SIZE) {
sub = isfs_get_fat(ctx)[sub];
size -= 8 * PAGE_SIZE;
}
file->cluster = sub;
return 0;
}
int isfs_read(isfs_file* file, void* buffer, size_t size, size_t* bytes_read)
{
if(!file || !buffer) return -1;
isfs_ctx* ctx = isfs_get_volume(file->volume);
isfs_fst* fst = file->fst;
if(!ctx || !fst) return -2;
if(size + file->offset > fst->size)
size = fst->size - file->offset;
size_t total = size;
while(size) {
size_t pos = file->offset % CLUSTER_SIZE;
size_t copy = CLUSTER_SIZE - pos;
if(copy > size) copy = size;
if (isfs_read_volume(ctx, file->cluster, 1, ISFSVOL_FLAG_ENCRYPTED, NULL, ctx->clbuf) < 0)
return -4;
memcpy(buffer, ctx->clbuf + pos, copy);
file->offset += copy;
buffer += copy;
size -= copy;
if((pos + copy) >= CLUSTER_SIZE)
file->cluster = isfs_get_fat(ctx)[file->cluster];
}
*bytes_read = total;
return 0;
}
int isfs_diropen(isfs_dir* dir, const char* path)
{
if(!dir || !path) return -1;
isfs_ctx* ctx = NULL;
path = isfs_do_volume(path, &ctx);
if(!ctx) return -2;
isfs_fst* fst = isfs_find_fst(ctx, NULL, path);
if(!fst) return -3;
if(!isfs_fst_is_dir(fst)) return -4;
if(fst->sub == 0xFFFF) return -2;
isfs_fst* root = isfs_get_fst(ctx);
memset(dir, 0, sizeof(isfs_dir));
dir->volume = ctx->volume;
dir->dir = fst;
dir->child = &root[fst->sub];
return 0;
}
int isfs_dirread(isfs_dir* dir, isfs_fst** info)
{
if(!dir) return -1;
isfs_ctx* ctx = isfs_get_volume(dir->volume);
isfs_fst* fst = dir->dir;
if(!ctx || !fst) return -2;
isfs_fst* root = isfs_get_fst(ctx);
if(!info) {
dir->child = &root[fst->sub];
return 0;
}
*info = dir->child;
if(dir->child != NULL) {
if(dir->child->sib == 0xFFFF)
dir->child = NULL;
else
dir->child = &root[dir->child->sib];
}
return 0;
}
int isfs_dirreset(isfs_dir* dir)
{
return isfs_dirread(dir, NULL);
}
int isfs_dirclose(isfs_dir* dir)
{
if(!dir) return -1;
memset(dir, 0, sizeof(isfs_dir));
return 0;
}

View File

@ -1,70 +0,0 @@
/*
* minute - a port of the "mini" IOS replacement for the Wii U.
*
* Copyright (C) 2016 SALT
* Copyright (C) 2016 Daz Jones <daz@dazzozo.com>
*
* This code is licensed to you under the terms of the GNU GPL, version 2;
* see file COPYING or http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt
*/
#ifndef _ISFS_H
#define _ISFS_H
#include "types.h"
#include <sys/iosupport.h>
#include <stdio.h>
#include "super.h"
typedef struct isfs_ctx {
int volume;
const char name[0x10];
const u32 bank;
const u32 super_count;
int index;
u8* const super;
u8* const clbuf;
u32 generation;
u32 version;
bool mounted;
void* key;
void* hmac;
devoptab_t devoptab;
} isfs_ctx;
typedef struct isfs_file {
int volume;
isfs_fst* fst;
size_t offset;
u16 cluster;
} isfs_file;
typedef struct isfs_dir {
int volume;
isfs_fst* dir;
isfs_fst* child;
} isfs_dir;
int isfs_init(void);
int isfs_fini(void);
isfs_fst* isfs_stat(const char* path);
int isfs_open(isfs_file* file, const char* path);
int isfs_close(isfs_file* file);
int isfs_seek(isfs_file* file, s32 offset, int whence);
int isfs_read(isfs_file* file, void* buffer, size_t size, size_t* bytes_read);
int isfs_diropen(isfs_dir* dir, const char* path);
int isfs_dirread(isfs_dir* dir, isfs_fst** info);
int isfs_dirreset(isfs_dir* dir);
int isfs_dirclose(isfs_dir* dir);
#ifdef ISFS_DEBUG
# define ISFS_debug(f, arg...) DEBUG("ISFS: " f, ##arg);
#else
# define ISFS_debug(f, arg...)
#endif
#endif

View File

@ -1,135 +0,0 @@
/*
* isfshax.c
*
* Copyright (C) 2021 rw-r-r-0644 <rwrr0644@gmail.com>
*
* This code is licensed to you under the terms of the GNU GPL, version 2;
* see file COPYING or http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt
*
*
* isfshax is installed to 4 superblock slots for redundancy
* against ecc errors and nand blocks wear out.
*
* when a boot1 superblock recommit attempt (due to ecc errors)
* is detected, the superblock will be rewritten to the next
* isfshax slot after correcting ecc errors.
*
* the generation number is incremented after each correction;
* once the maximum allowed genertion number is reached, all
* isfshax superblocks are rewritten with a lower generation number.
*
* if one of the blocks becomes bad during the rewrite,
* the range of used generations numbers is incremented to ensure
* the old superblock will not be used:
* 0 BAD BLOCKS -> generation no. 0xfffffaff-0xfffffbff
* ...
* 3 BAD BLOCKS -> generation no. 0xfffffdff-0xfffffeff
*
* bad block information is stored along with other informations in a
* separate isfshax info structure inside of the superblock, since all
* isfshax slots are already marked as bad to guard against IOSU intervention
* inside of the normal ISFS cluster allocation table.
*/
#include "types.h"
#include "isfs/isfs.h"
#include "isfs/super.h"
#include "isfs/volume.h"
#include "isfs/isfshax.h"
#include "malloc.h"
/* boot1 superblock loading address.
* this can be used to read the current generation
* and the list of isfshax superblock slots, but it
* can't be rewritten directly to nand as it has been
* modified by the stage1 payload. */
static const isfshax_super *
boot1_superblock = (const isfshax_super *)(0x01f80000);
static isfshax_super
superblock;
int isfshax_refresh()
{
isfs_ctx *slc = isfs_get_volume(ISFSVOL_SLC);
u32 curindex, offs, count = 1, written = 0;
u32 generation;
/* detect if the superblock contains ecc errors and boot1
* attempted to recommit the superblock */
if (boot1_superblock->generation == boot1_superblock->isfshax.generation)
return 0;
/* load the newest valid isfshax superblock slot */
curindex = boot1_superblock->isfshax.index;
for (offs = 0; offs < ISFSHAX_REDUNDANCY; offs++) {
u32 index = (curindex + offs) & (ISFSHAX_REDUNDANCY - 1);
u32 slot = boot1_superblock->isfshax.slots[index] & ~ISFSHAX_BAD_SLOT;
if (isfs_read_super(slc, &superblock, slot) >= 0) {
curindex = index;
break;
}
}
if (offs == ISFSHAX_REDUNDANCY)
return -2;
/* if the last valid generation is reached, rewrite/erase all
* isfshax superblocks with a lower generation number */
generation = superblock.generation + 1;
if (generation >= (superblock.isfshax.generationbase + ISFSHAX_GENERATION_RANGE)) {
generation = superblock.isfshax.generationbase;
count = ISFSHAX_REDUNDANCY;
}
for (offs = 1; (offs <= ISFSHAX_REDUNDANCY) && (written < count); offs++) {
u32 index = (curindex + offs) & (ISFSHAX_REDUNDANCY - 1);
u32 slot = superblock.isfshax.slots[index] & ~ISFSHAX_BAD_SLOT;
/* skip slots that became bad after a superblock rewrite */
if (superblock.isfshax.slots[index] & ISFSHAX_BAD_SLOT)
continue;
/* if the slot currently in use is being rewritten, ensure
* at least another slot was already successfully written */
if ((index == curindex) && !written)
continue;
/* update superblock informations */
superblock.isfshax.index = index;
superblock.isfshax.generation = generation;
superblock.generation = generation;
/* rewrite and verify the superblock */
if (isfs_write_super(slc, &superblock, slot) >= 0)
{
generation++;
written++;
continue;
}
/* block became bad during write operation, mark
* the block as bad and go to next generation range */
superblock.isfshax.slots[index] |= ISFSHAX_BAD_SLOT;
superblock.isfshax.generationbase += ISFSHAX_GENERATION_RANGE;
generation = superblock.isfshax.generationbase;
/* the current superblock became bad. ensure the other
* isfshax superblock are updated with the new generation range
* and bad slot information. */
if (index == curindex)
{
offs = 1;
written = 0;
}
}
/* all isfshax superblocks became bad, or the nand writing code stopped
* working correctly. either way the user should probably be informed. */
if (!written)
return -3;
return 0;
}

View File

@ -1,47 +0,0 @@
/*
* isfshax.h
*
* Copyright (C) 2021 rw-r-r-0644 <rwrr0644@gmail.com>
*
* This code is licensed to you under the terms of the GNU GPL, version 2;
* see file COPYING or http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt
*/
#pragma once
#include "types.h"
#include "nand.h"
#include "isfs/isfs.h"
#define ISFSHAX_MAGIC 0x48415858
#define ISFSHAX_REDUNDANCY (1 << 2)
#define ISFSHAX_GENERATION_FIRST 0xffff7fff
#define ISFSHAX_GENERATION_RANGE 0x100
#define ISFSHAX_BAD_SLOT 0x80
typedef struct isfshax_info
{
u32 magic;
u8 slots[ISFSHAX_REDUNDANCY];
u32 generation;
u32 generationbase;
u32 index;
} isfshax_info;
_Static_assert(sizeof(isfshax_info) == 0x14, "isfshax_info must be 0x14");
typedef struct isfshax_super
{
char magic[4];
u32 generation;
u32 x1;
u16 fat[CLUSTER_COUNT];
isfs_fst fst[6143];
isfshax_info isfshax;
} PACKED ALIGNED(NAND_DATA_ALIGN) isfshax_super;
_Static_assert(sizeof(isfshax_super) == ISFSSUPER_SIZE, "isfshax_super must be 0x40000");
int isfshax_refresh();

View File

@ -1,244 +0,0 @@
/*
* minute - a port of the "mini" IOS replacement for the Wii U.
*
* Copyright (C) 2016 SALT
* Copyright (C) 2016 Daz Jones <daz@dazzozo.com>
*
* This code is licensed to you under the terms of the GNU GPL, version 2;
* see file COPYING or http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt
*/
#include "types.h"
#include "utils.h"
#include "nand.h"
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include "debug.h"
#include "isfs/isfs.h"
#include "isfs/volume.h"
#include "isfs/hmac_seed.h"
#include "isfs/super.h"
#include "isfs/isfshax.h"
int isfs_get_super_version(void* buffer)
{
if(!memcmp(buffer, "SFFS", 4)) return 0;
if(!memcmp(buffer, "SFS!", 4)) return 1;
return -1;
}
u32 isfs_get_super_generation(void* buffer)
{
return read32((u32)buffer + 4);
}
isfs_hdr* isfs_get_hdr(isfs_ctx* ctx)
{
return (isfs_hdr*)&ctx->super[0];
}
u16* isfs_get_fat(isfs_ctx* ctx)
{
return (u16*)&ctx->super[0x0C];
}
isfs_fst* isfs_get_fst(isfs_ctx* ctx)
{
return (isfs_fst*)&ctx->super[0x10000 + 0x0C];
}
static isfs_fst* isfs_check_file(isfs_ctx* ctx, isfs_fst* fst, const char* path)
{
char fst_name[sizeof(fst->name) + 1] = {0};
memcpy(fst_name, fst->name, sizeof(fst->name));
//ISFS_debug("file: %s vs %s\n", path, fst_name);
if(!strcmp(fst_name, path))
return fst;
return NULL;
}
static isfs_fst* isfs_check_dir(isfs_ctx* ctx, isfs_fst* fst, const char* path)
{
isfs_fst* root = isfs_get_fst(ctx);
size_t size = strlen(path);
const char* remaining = strchr(path, '/');
if(remaining) size = remaining - path;
if(size > sizeof(fst->name)) return NULL;
char name[sizeof(fst->name) + 1] = {0};
memcpy(name, path, size);
char fst_name[sizeof(fst->name) + 1] = {0};
memcpy(fst_name, fst->name, sizeof(fst->name));
if(size == 0 || !strcmp(name, fst_name))
{
if(fst->sub != 0xFFFF && remaining != NULL && remaining[1] != '\0')
{
while(*remaining == '/') remaining++;
return isfs_find_fst(ctx, &root[fst->sub], remaining);
}
return fst;
}
return NULL;
}
int isfs_fst_get_type(const isfs_fst* fst)
{
return fst->mode & 3;
}
bool isfs_fst_is_file(const isfs_fst* fst)
{
return isfs_fst_get_type(fst) == 1;
}
bool isfs_fst_is_dir(const isfs_fst* fst)
{
return isfs_fst_get_type(fst) == 2;
}
isfs_fst* isfs_find_fst(isfs_ctx* ctx, isfs_fst* fst, const char* path)
{
isfs_fst* root = isfs_get_fst(ctx);
if(!fst) fst = root;
if(fst->sib != 0xFFFF) {
isfs_fst* result = isfs_find_fst(ctx, &root[fst->sib], path);
if(result) return result;
}
switch(isfs_fst_get_type(fst)) {
case 1:
return isfs_check_file(ctx, fst, path);
case 2:
return isfs_check_dir(ctx, fst, path);
default:
ISFS_debug("Unknown mode! (%d)\n", isfs_fst_get_type(fst));
break;
}
return NULL;
}
int isfs_super_check_slot(isfs_ctx *ctx, u32 index)
{
u32 offs, cluster = CLUSTER_COUNT - (ctx->super_count - index) * ISFSSUPER_CLUSTERS;
u16* fat = isfs_get_fat(ctx);
for (offs = 0; offs < ISFSSUPER_CLUSTERS; offs++)
if (fat[cluster + offs] != FAT_CLUSTER_RESERVED)
return -1;
return 0;
}
int isfs_super_mark_bad_slot(isfs_ctx *ctx, u32 index)
{
u32 offs, cluster = CLUSTER_COUNT - (ctx->super_count - index) * ISFSSUPER_CLUSTERS;
u16* fat = isfs_get_fat(ctx);
for (offs = 0; offs < ISFSSUPER_CLUSTERS; offs++)
fat[cluster + offs] = FAT_CLUSTER_BAD;
return 0;
}
int isfs_read_super(isfs_ctx *ctx, void *super, int index)
{
u32 cluster = CLUSTER_COUNT - (ctx->super_count - index) * ISFSSUPER_CLUSTERS;
isfs_hmac_meta seed = { .cluster = cluster };
return isfs_read_volume(ctx, cluster, ISFSSUPER_CLUSTERS, ISFSVOL_FLAG_HMAC, &seed, super);
}
int isfs_write_super(isfs_ctx *ctx, void *super, int index)
{
u32 cluster = CLUSTER_COUNT - (ctx->super_count - index) * ISFSSUPER_CLUSTERS;
isfs_hmac_meta seed = { .cluster = cluster };
return isfs_write_volume(ctx, cluster, ISFSSUPER_CLUSTERS, ISFSVOL_FLAG_HMAC | ISFSVOL_FLAG_READBACK, &seed, super);
}
int isfs_find_super(isfs_ctx* ctx, u32 min_generation, u32 max_generation, u32 *generation, u32 *version)
{
struct {
int index;
u32 generation;
u8 version;
} newest = {-1, 0, 0};
for(int i = 0; i < ctx->super_count; i++)
{
u32 cluster = CLUSTER_COUNT - (ctx->super_count - i) * ISFSSUPER_CLUSTERS;
if(isfs_read_volume(ctx, cluster, 1, 0, NULL, ctx->clbuf))
continue;
int cur_version = isfs_get_super_version(ctx->clbuf);
if(cur_version < 0) continue;
u32 cur_generation = isfs_get_super_generation(ctx->clbuf);
if((cur_generation < newest.generation) ||
(cur_generation < min_generation) ||
(cur_generation >= max_generation))
continue;
newest.index = i;
newest.generation = cur_generation;
newest.version = cur_version;
}
if(newest.index == -1)
{
ISFS_debug("Failed to find super block.\n");
return -3;
}
ISFS_debug("Found super block (device=%s, version=%u, index=%d, generation=0x%lX)\n",
ctx->name, newest.version, newest.index, newest.generation);
if(generation) *generation = newest.generation;
if(version) *version = newest.version;
return newest.index;
}
int isfs_load_super(isfs_ctx* ctx, u32 min_generation, u32 max_generation)
{
ctx->generation = max_generation;
while((ctx->index = isfs_find_super(ctx, min_generation, ctx->generation, &ctx->generation, &ctx->version)) >= 0)
if(isfs_read_super(ctx, ctx->super, ctx->index) >= 0)
break;
return (ctx->index >= 0) ? 0 : -1;
}
int isfs_commit_super(isfs_ctx* ctx)
{
isfs_get_hdr(ctx)->generation++;
for(int i = 1; i <= ctx->super_count; i++)
{
u32 index = (ctx->index + i) & (ctx->super_count - 1);
if (isfs_super_check_slot(ctx, index) < 0)
continue;
if (isfs_write_super(ctx, ctx->super, index) >= 0)
return 0;
isfs_super_mark_bad_slot(ctx, index);
isfs_get_hdr(ctx)->generation++;
}
return -1;
}

View File

@ -1,66 +0,0 @@
#pragma once
#include "isfs/isfs.h"
#include "nand.h"
#define ISFSSUPER_CLUSTERS 0x10
#define ISFSSUPER_SIZE (ISFSSUPER_CLUSTERS * CLUSTER_SIZE)
typedef struct isfs_fst {
char name[12];
u8 mode;
u8 attr;
u16 sub;
u16 sib;
u32 size;
u16 x1;
u16 uid;
u16 gid;
u32 x3;
} PACKED isfs_fst;
_Static_assert(sizeof(isfs_fst) == 0x20, "isfs_fst size must be 0x20!");
typedef struct isfs_hdr {
char magic[4];
u32 generation;
u32 x1;
} PACKED isfs_hdr;
_Static_assert(sizeof(isfs_hdr) == 0xC, "isfs_hdr size must be 0xC!");
typedef struct isfs_super {
isfs_hdr hdr;
u16 fat[CLUSTER_COUNT];
isfs_fst fst[6143];
u8 pad[20];
} PACKED ALIGNED(NAND_DATA_ALIGN) isfs_super;
_Static_assert(sizeof(isfs_super) == ISFSSUPER_SIZE, "isfs_super must be 0x40000");
#define FAT_CLUSTER_LAST 0xFFFB // last cluster within a chain
#define FAT_CLUSTER_RESERVED 0xFFFC // reserved cluster
#define FAT_CLUSTER_BAD 0xFFFD // bad block (marked at factory)
#define FAT_CLUSTER_EMPTY 0xFFFE // empty (unused / available) space
typedef struct isfs_ctx isfs_ctx;
int isfs_get_super_version(void* buffer);
u32 isfs_get_super_generation(void* buffer);
isfs_hdr* isfs_get_hdr(isfs_ctx* ctx);
u16* isfs_get_fat(isfs_ctx* ctx);
isfs_fst* isfs_get_fst(isfs_ctx* ctx);
void isfs_print_fst(isfs_fst* fst);
int isfs_fst_get_type(const isfs_fst* fst);
bool isfs_fst_is_file(const isfs_fst* fst);
bool isfs_fst_is_dir(const isfs_fst* fst);
isfs_fst* isfs_find_fst(isfs_ctx* ctx, isfs_fst* fst, const char* path);
int isfs_super_check_slot(isfs_ctx *ctx, u32 index);
int isfs_super_mark_bad_slot(isfs_ctx *ctx, u32 index);
int isfs_read_super(isfs_ctx *ctx, void *super, int index);
int isfs_write_super(isfs_ctx *ctx, void *super, int index);
int isfs_find_super(isfs_ctx* ctx, u32 min_generation, u32 max_generation, u32 *generation, u32 *version);
int isfs_load_super(isfs_ctx* ctx, u32 min_generation, u32 max_generation);
int isfs_commit_super(isfs_ctx* ctx);

View File

@ -1,248 +0,0 @@
#include "types.h"
#include "isfs/isfs.h"
#include "isfs/volume.h"
#include "nand.h"
#include "crypto.h"
#include "aes.h"
#include "hmac.h"
#include "string.h"
static u8 slc_super_buf[ISFSSUPER_SIZE] ALIGNED(NAND_DATA_ALIGN), slc_cluster_buf[CLUSTER_SIZE] ALIGNED(NAND_DATA_ALIGN);
isfs_ctx isfs[] = {
[ISFSVOL_SLC]
{
.volume = ISFSVOL_SLC,
.name = "slc",
.bank = BANK_SLC,
.key = &otp.nand_key,
.hmac = &otp.nand_hmac,
.super_count = 64,
.super = slc_super_buf,
.clbuf = slc_cluster_buf,
},
};
int isfs_num_volumes(void)
{
return sizeof(isfs) / sizeof(*isfs);
}
isfs_ctx* isfs_get_volume(int volume)
{
if(volume < isfs_num_volumes() && volume >= 0)
return &isfs[volume];
return NULL;
}
char* isfs_do_volume(const char* path, isfs_ctx** ctx)
{
isfs_ctx* volume = NULL;
if(!path) return NULL;
const char* filename = strchr(path, ':');
if(!filename) return NULL;
if(filename[1] != '/') return NULL;
char mount[sizeof(volume->name)] = {0};
memcpy(mount, path, filename - path);
for(int i = 0; i < isfs_num_volumes(); i++)
{
volume = &isfs[i];
if(strcmp(mount, volume->name)) continue;
if(!volume->mounted) return NULL;
*ctx = volume;
return (char*)(filename + 1);
}
return NULL;
}
int isfs_read_volume(const isfs_ctx* ctx, u32 start_cluster, u32 cluster_count, u32 flags, void *hmac_seed, void *data)
{
u8 saved_hmacs[2][20] = {0}, hmac[20] = {0};
int rc = ISFSVOL_OK;
u32 i, p;
/* enable slc or slccmpt bank */
nand_enable_banks(ctx->bank);
/* read all requested clusters */
for (i = 0; i < cluster_count; i++)
{
u32 cluster = start_cluster + i;
u8 *cluster_data = (u8 *)data + i * CLUSTER_SIZE;
u32 cluster_start = cluster * CLUSTER_PAGES;
/* read cluster pages */
for (p = 0; p < CLUSTER_PAGES; p++)
{
u8 spare[SPARE_SIZE] = {0};
/* attempt to read the page (and correct ecc errors) */
rc = nand_read_page(cluster_start + p, &cluster_data[p * PAGE_SIZE], spare);
/* uncorrectable ecc error or other issues */
if (rc < 0)
return ISFSVOL_ERROR_READ;
/* ECC errors, a refresh might be needed */
if (rc > 0)
rc = ISFSVOL_ECC_CORRECTED;
/* page 6 and 7 store the hmac */
if (p == 6)
{
memcpy(saved_hmacs[0], &spare[1], 20);
memcpy(saved_hmacs[1], &spare[21], 12);
}
if (p == 7)
memcpy(&saved_hmacs[1][12], &spare[1], 8);
}
/* decrypt cluster */
if (flags & ISFSVOL_FLAG_ENCRYPTED)
{
aes_reset();
aes_set_key(ctx->key);
aes_empty_iv();
aes_decrypt(cluster_data, cluster_data, CLUSTER_SIZE / AES_BLOCK_SIZE, 0);
}
}
/* verify hmac */
if (flags & ISFSVOL_FLAG_HMAC)
{
hmac_ctx calc_hmac;
int matched = 0;
/* compute clusters hmac */
hmac_init(&calc_hmac, ctx->hmac, 20);
hmac_update(&calc_hmac, (const u8 *)hmac_seed, SHA_BLOCK_SIZE);
hmac_update(&calc_hmac, (const u8 *)data, cluster_count * CLUSTER_SIZE);
hmac_final(&calc_hmac, hmac);
/* ensure at least one of the saved hmacs matches */
matched += !memcmp(saved_hmacs[0], hmac, sizeof(hmac));
matched += !memcmp(saved_hmacs[1], hmac, sizeof(hmac));
if (matched == 2)
rc = ISFSVOL_OK;
else if (matched == 1)
rc = ISFSVOL_HMAC_PARTIAL;
else
rc = ISFSVOL_ERROR_HMAC;
}
return rc;
}
int isfs_write_volume(const isfs_ctx* ctx, u32 start_cluster, u32 cluster_count, u32 flags, void *hmac_seed, void *data)
{
static u8 blockpg[64][PAGE_SIZE] ALIGNED(NAND_DATA_ALIGN), blocksp[64][SPARE_SIZE];
static u8 pgbuf[PAGE_SIZE] ALIGNED(NAND_DATA_ALIGN), spbuf[SPARE_SIZE];
u8 hmac[20] = {0};
int rc = ISFSVOL_OK;
u32 b, p;
/* enable slc or slccmpt bank */
nand_enable_banks(ctx->bank);
/* compute clusters hmac */
if (flags & ISFSVOL_FLAG_HMAC)
{
hmac_ctx calc_hmac;
hmac_init(&calc_hmac, ctx->hmac, 20);
hmac_update(&calc_hmac, (const u8 *)hmac_seed, SHA_BLOCK_SIZE);
hmac_update(&calc_hmac, (const u8 *)data, cluster_count * CLUSTER_SIZE);
hmac_final(&calc_hmac, hmac);
}
/* setup clusters encryption */
if (flags & ISFSVOL_FLAG_ENCRYPTED)
{
aes_reset();
aes_set_key(ctx->key);
aes_empty_iv();
}
u32 startpage = start_cluster * CLUSTER_PAGES;
u32 endpage = (start_cluster + cluster_count) * CLUSTER_PAGES;
u32 startblock = start_cluster / BLOCK_CLUSTERS;
u32 endblock = (start_cluster + cluster_count + BLOCK_CLUSTERS - 1) / BLOCK_CLUSTERS;
/* process data in nand blocks */
for (b = startblock; (b < endblock) && (rc >= 0); b++)
{
u32 firstblockpage = b * BLOCK_PAGES;
/* prepare block */
for (p = 0; p < 64; p++)
{
u32 curpage = firstblockpage + p; /* current page */
u32 clusidx = curpage % CLUSTER_PAGES; /* index in cluster */
/* if this page is unmodified, read it from nand */
if ((curpage < startpage) || (curpage >= endpage))
{
if (nand_read_page(curpage, blockpg[p], blocksp[p]) < 0)
return ISFSVOL_ERROR_READ;
continue;
}
/* place hmac in page 6 and 7 of a cluster */
memset(blocksp[p], 0, SPARE_SIZE);
switch (clusidx)
{
case 6:
memcpy(&blocksp[p][1], hmac, 20);
memcpy(&blocksp[p][21], hmac, 12);
break;
case 7:
memcpy(&blocksp[p][1], &hmac[12], 8);
break;
}
/* encrypt or copy the data */
u8 *srcdata = (u8*)data + (curpage - startpage) * PAGE_SIZE;
if (flags & ISFSVOL_FLAG_ENCRYPTED)
aes_encrypt(blockpg[p], srcdata, PAGE_SIZE / AES_BLOCK_SIZE, clusidx > 0);
else
memcpy(blockpg[p], srcdata, PAGE_SIZE);
}
/* erase block */
if (nand_erase_block(b) < 0)
return ISFSVOL_ERROR_ERASE;
/* write block */
for (p = 0; p < BLOCK_PAGES; p++)
if (nand_write_page(firstblockpage + p, blockpg[p], blocksp[p]) < 0)
rc = ISFSVOL_ERROR_WRITE;
/* check if pages should be verified after writing */
if (rc || !(flags & ISFSVOL_FLAG_READBACK))
continue;
/* read back pages */
for (p = 0; p < BLOCK_PAGES; p++)
{
if (nand_read_page(firstblockpage + p, pgbuf, spbuf) < 0)
return ISFSVOL_ERROR_READ;
/* page content doesn't match */
if (memcmp(blockpg[p], pgbuf, PAGE_SIZE) ||
memcmp(&blocksp[p][1], &spbuf[1], 0x20))
return ISFSVOL_ERROR_READBACK;
}
}
return rc;
}

View File

@ -1,25 +0,0 @@
#pragma once
#include "isfs/isfs.h"
#define ISFSVOL_SLC 0
#define ISFSVOL_SLCCMPT 1
#define ISFSVOL_FLAG_HMAC 1
#define ISFSVOL_FLAG_ENCRYPTED 2
#define ISFSVOL_FLAG_READBACK 4
#define ISFSVOL_OK 0
#define ISFSVOL_ECC_CORRECTED 0x10
#define ISFSVOL_HMAC_PARTIAL 0x20
#define ISFSVOL_ERROR_WRITE -0x10
#define ISFSVOL_ERROR_READ -0x20
#define ISFSVOL_ERROR_ERASE -0x30
#define ISFSVOL_ERROR_HMAC -0x40
#define ISFSVOL_ERROR_READBACK -0x50
int isfs_num_volumes(void);
isfs_ctx* isfs_get_volume(int volume);
char* isfs_do_volume(const char* path, isfs_ctx** ctx);
int isfs_read_volume(const isfs_ctx* ctx, u32 start_cluster, u32 cluster_count, u32 flags, void *hmac_seed, void *data);
int isfs_write_volume(const isfs_ctx* ctx, u32 start_cluster, u32 cluster_count, u32 flags, void *hmac_seed, void *data);

View File

@ -1,338 +0,0 @@
/*
* minute - a port of the "mini" IOS replacement for the Wii U.
*
* Copyright (C) 2016 SALT
* Copyright (C) 2016 Daz Jones <daz@dazzozo.com>
*
* This code is licensed to you under the terms of the GNU GPL, version 2;
* see file COPYING or http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt
*/
#ifndef _LATTE_H
#define _LATTE_H
/*
* Latte registers.
* http://wiiubrew.org/wiki/Hardware/Latte_Registers
*/
#define LT_REG_BASE (0x0D800000)
#define LT_IPC_PPCMSG_COMPAT (LT_REG_BASE + 0x000)
#define LT_IPC_PPCCTRL_COMPAT (LT_REG_BASE + 0x004)
#define LT_IPC_ARMMSG_COMPAT (LT_REG_BASE + 0x008)
#define LT_IPC_ARMCTRL_COMPAT (LT_REG_BASE + 0x00C)
#define LT_TIMER (LT_REG_BASE + 0x010)
#define LT_ALARM (LT_REG_BASE + 0x014)
#define LT_INTSR_PPC_COMPAT (LT_REG_BASE + 0x030)
#define LT_INTMR_PPC_COMPAT (LT_REG_BASE + 0x034)
#define LT_INTSR_ARM_COMPAT (LT_REG_BASE + 0x038)
#define LT_INTMR_ARM_COMPAT (LT_REG_BASE + 0x03C)
#define LT_INTMR_ARM2X_COMPAT (LT_REG_BASE + 0x040)
#define LT_UNK044 (LT_REG_BASE + 0x044)
#define LT_AHB_WDG_STATUS (LT_REG_BASE + 0x048)
#define LT_AHB_WDG_CONFIG (LT_REG_BASE + 0x04C)
#define LT_AHB_DMA_STATUS (LT_REG_BASE + 0x050)
#define LT_AHB_CPU_STATUS (LT_REG_BASE + 0x054)
#define LT_ERROR (LT_REG_BASE + 0x058)
#define LT_ERROR_MASK (LT_REG_BASE + 0x05C)
#define LT_MEMIRR (LT_REG_BASE + 0x060)
#define LT_AHBPROT (LT_REG_BASE + 0x064)
#define LT_UNK068 (LT_REG_BASE + 0x068)
#define LT_UNK06C (LT_REG_BASE + 0x06C)
#define LT_EXICTRL (LT_REG_BASE + 0x070)
#define LT_UNK074 (LT_REG_BASE + 0x074)
#define LT_UNK088 (LT_REG_BASE + 0x088)
#define LT_GPIOE_OUT (LT_REG_BASE + 0x0C0)
#define LT_GPIOE_DIR (LT_REG_BASE + 0x0C4)
#define LT_GPIOE_IN (LT_REG_BASE + 0x0C8)
#define LT_GPIOE_INTLVL (LT_REG_BASE + 0x0CC)
#define LT_GPIOE_INTFLAG (LT_REG_BASE + 0x0D0)
#define LT_GPIOE_INTMASK (LT_REG_BASE + 0x0D4)
#define LT_GPIOE_INMIR (LT_REG_BASE + 0x0D8)
#define LT_GPIO_ENABLE (LT_REG_BASE + 0x0DC)
#define LT_GPIO_OUT (LT_REG_BASE + 0x0E0)
#define LT_GPIO_DIR (LT_REG_BASE + 0x0E4)
#define LT_GPIO_IN (LT_REG_BASE + 0x0E8)
#define LT_GPIO_INTLVL (LT_REG_BASE + 0x0EC)
#define LT_GPIO_INTFLAG (LT_REG_BASE + 0x0F0)
#define LT_GPIO_INTMASK (LT_REG_BASE + 0x0F4)
#define LT_GPIO_INMIR (LT_REG_BASE + 0x0F8)
#define LT_GPIO_OWNER (LT_REG_BASE + 0x0FC)
#define LT_AHB_UNK100 (LT_REG_BASE + 0x100)
#define LT_AHB_UNK104 (LT_REG_BASE + 0x104)
#define LT_AHB_UNK108 (LT_REG_BASE + 0x108)
#define LT_AHB_UNK10C (LT_REG_BASE + 0x10C)
#define LT_AHB_UNK110 (LT_REG_BASE + 0x110)
#define LT_AHB_UNK114 (LT_REG_BASE + 0x114)
#define LT_AHB_UNK118 (LT_REG_BASE + 0x118)
#define LT_AHB_UNK11C (LT_REG_BASE + 0x11C)
#define LT_AHB_UNK120 (LT_REG_BASE + 0x120)
#define LT_AHB_UNK124 (LT_REG_BASE + 0x124)
#define LT_AHB_UNK130 (LT_REG_BASE + 0x130)
#define LT_AHB_UNK134 (LT_REG_BASE + 0x134)
#define LT_AHB_UNK138 (LT_REG_BASE + 0x138)
#define LT_ARB_CFG (LT_REG_BASE + 0x140)
#define LT_DIFLAGS (LT_REG_BASE + 0x180)
#define LT_RESETS_AHB (LT_REG_BASE + 0x184)
#define LT_COMPAT_MEMCTRL_WORKAROUND (LT_REG_BASE + 0x188)
#define LT_BOOT0 (LT_REG_BASE + 0x18C)
#define LT_CLOCKINFO (LT_REG_BASE + 0x190)
#define LT_RESETS_COMPAT (LT_REG_BASE + 0x194)
#define LT_CLOCKGATE_COMPAT (LT_REG_BASE + 0x198)
#define LT_SATA_UNK1A8 (LT_REG_BASE + 0x1A8)
#define LT_SATA_UNK1C8 (LT_REG_BASE + 0x1C8)
#define LT_SATA_UNK1CC (LT_REG_BASE + 0x1CC)
#define LT_SATA_UNK1D0 (LT_REG_BASE + 0x1D0)
#define LT_UNK1D8 (LT_REG_BASE + 0x1D8)
#define LT_IOPOWER (LT_REG_BASE + 0x1DC)
#define LT_IOSTRENGTH_CTRL0 (LT_REG_BASE + 0x1E0)
#define LT_IOSTRENGTH_CTRL1 (LT_REG_BASE + 0x1E4)
#define LT_ACRCLK_STRENGTH_CTRL (LT_REG_BASE + 0x1E8)
#define LT_OTPCMD (LT_REG_BASE + 0x1EC)
#define LT_OTPDATA (LT_REG_BASE + 0x1F0)
#define LT_UNK204 (LT_REG_BASE + 0x204)
#define LT_ASICREV_ACR (LT_REG_BASE + 0x214)
#define LT_UNK224 (LT_REG_BASE + 0x224)
#define LT_UNK250 (LT_REG_BASE + 0x250)
#define LT_UNK254 (LT_REG_BASE + 0x254)
#define LT_UNK258 (LT_REG_BASE + 0x258)
#define LT_IPC_PPC0_PPCMSG (LT_REG_BASE + 0x400)
#define LT_IPC_PPC0_PPCCTRL (LT_REG_BASE + 0x404)
#define LT_IPC_PPC0_ARMMSG (LT_REG_BASE + 0x408)
#define LT_IPC_PPC0_ARMCTRL (LT_REG_BASE + 0x40C)
#define LT_IPC_PPC1_PPCMSG (LT_REG_BASE + 0x410)
#define LT_IPC_PPC1_PPCCTRL (LT_REG_BASE + 0x414)
#define LT_IPC_PPC1_ARMMSG (LT_REG_BASE + 0x418)
#define LT_IPC_PPC1_ARMCTRL (LT_REG_BASE + 0x41C)
#define LT_IPC_PPC2_PPCMSG (LT_REG_BASE + 0x420)
#define LT_IPC_PPC2_PPCCTRL (LT_REG_BASE + 0x424)
#define LT_IPC_PPC2_ARMMSG (LT_REG_BASE + 0x428)
#define LT_IPC_PPC2_ARMCTRL (LT_REG_BASE + 0x42C)
#define LT_INTSR_AHBALL_PPC0 (LT_REG_BASE + 0x440)
#define LT_INTSR_AHBLT_PPC0 (LT_REG_BASE + 0x444)
#define LT_INTMR_AHBALL_PPC0 (LT_REG_BASE + 0x448)
#define LT_INTMR_AHBLT_PPC0 (LT_REG_BASE + 0x44C)
#define LT_INTSR_AHBALL_PPC1 (LT_REG_BASE + 0x450)
#define LT_INTSR_AHBLT_PPC1 (LT_REG_BASE + 0x454)
#define LT_INTMR_AHBALL_PPC1 (LT_REG_BASE + 0x458)
#define LT_INTMR_AHBLT_PPC1 (LT_REG_BASE + 0x45C)
#define LT_INTSR_AHBALL_PPC2 (LT_REG_BASE + 0x460)
#define LT_INTSR_AHBLT_PPC2 (LT_REG_BASE + 0x464)
#define LT_INTMR_AHBALL_PPC2 (LT_REG_BASE + 0x468)
#define LT_INTMR_AHBLT_PPC2 (LT_REG_BASE + 0x46C)
#define LT_INTSR_AHBALL_ARM (LT_REG_BASE + 0x470)
#define LT_INTSR_AHBLT_ARM (LT_REG_BASE + 0x474)
#define LT_INTMR_AHBALL_ARM (LT_REG_BASE + 0x478)
#define LT_INTMR_AHBLT_ARM (LT_REG_BASE + 0x47C)
#define LT_INTMR_AHBALL_ARM2X (LT_REG_BASE + 0x480)
#define LT_INTMR_AHBLT_ARM2X (LT_REG_BASE + 0x484)
#define LT_AHB2_WDG_STATUS (LT_REG_BASE + 0x4A0)
#define LT_AHB2_DMA_STATUS (LT_REG_BASE + 0x4A4)
#define LT_AHB2_CPU_STATUS (LT_REG_BASE + 0x4A8)
#define LT_UNK4C8 (LT_REG_BASE + 0x4C8)
#define LT_UNK4CC (LT_REG_BASE + 0x4CC)
#define LT_UNK4D0 (LT_REG_BASE + 0x4D0)
#define LT_UNK4D4 (LT_REG_BASE + 0x4D4)
#define LT_UNK4DC (LT_REG_BASE + 0x4DC)
#define LT_UNK4E0 (LT_REG_BASE + 0x4E0)
#define LT_UNK4E4 (LT_REG_BASE + 0x4E4)
#define LT_UNK500 (LT_REG_BASE + 0x500)
#define LT_UNK504 (LT_REG_BASE + 0x504)
#define LT_OTPPROT (LT_REG_BASE + 0x510)
#define LT_SYSPROT (LT_REG_BASE + 0x514)
#define LT_GPIOE2_OUT (LT_REG_BASE + 0x520)
#define LT_GPIOE2_DIR (LT_REG_BASE + 0x524)
#define LT_GPIOE2_IN (LT_REG_BASE + 0x528)
#define LT_GPIOE2_INTLVL (LT_REG_BASE + 0x52C)
#define LT_GPIOE2_INTFLAG (LT_REG_BASE + 0x530)
#define LT_GPIOE2_INTMASK (LT_REG_BASE + 0x534)
#define LT_GPIOE2_INMIR (LT_REG_BASE + 0x538)
#define LT_GPIO2_ENABLE (LT_REG_BASE + 0x53C)
#define LT_GPIO2_OUT (LT_REG_BASE + 0x540)
#define LT_GPIO2_DIR (LT_REG_BASE + 0x544)
#define LT_GPIO2_IN (LT_REG_BASE + 0x548)
#define LT_GPIO2_INTLVL (LT_REG_BASE + 0x54C)
#define LT_GPIO2_INTFLAG (LT_REG_BASE + 0x550)
#define LT_GPIO2_INTMASK (LT_REG_BASE + 0x554)
#define LT_GPIO2_INMIR (LT_REG_BASE + 0x558)
#define LT_GPIO2_OWNER (LT_REG_BASE + 0x55C)
#define LT_I2C_CLOCK (LT_REG_BASE + 0x570)
#define LT_I2C_INOUT_DATA (LT_REG_BASE + 0x574)
#define LT_I2C_INOUT_CTRL (LT_REG_BASE + 0x578)
#define LT_I2C_INOUT_SIZE (LT_REG_BASE + 0x57C)
#define LT_I2C_INT_MASK (LT_REG_BASE + 0x580)
#define LT_I2C_INT_STATE (LT_REG_BASE + 0x584)
#define LT_ASICREV_CCR (LT_REG_BASE + 0x5A0)
#define LT_DEBUG (LT_REG_BASE + 0x5A4)
#define LT_COMPAT_MEMCTRL_STATE (LT_REG_BASE + 0x5B0)
#define LT_COMPAT_AHB_STATE (LT_REG_BASE + 0x5B4)
#define LT_COMPAT_STEREO_OUT_SELECT (LT_REG_BASE + 0x5B8)
#define LT_IOP2X (LT_REG_BASE + 0x5BC)
#define LT_UNK5C0 (LT_REG_BASE + 0x5C0)
#define LT_IOSTRENGTH_CTRL2 (LT_REG_BASE + 0x5C8)
#define LT_UNK5CC (LT_REG_BASE + 0x5CC)
#define LT_RESETS (LT_REG_BASE + 0x5E0)
#define LT_RESETS_AHMN (LT_REG_BASE + 0x5E4)
#define LT_CLOCKGATE (LT_REG_BASE + 0x5E8)
#define LT_SYSPLL_CFG (LT_REG_BASE + 0x5EC)
#define LT_ABIF_CPLTL_OFFSET (LT_REG_BASE + 0x620)
#define LT_ABIF_CPLTL_DATA (LT_REG_BASE + 0x624)
#define LT_UNK628 (LT_REG_BASE + 0x628)
#define LT_60XE_CFG (LT_REG_BASE + 0x640)
#define LT_UNK660 (LT_REG_BASE + 0x660)
#define LT_UNK640 (LT_REG_BASE + 0x640)
#define LT_DCCMPT (LT_REG_BASE + 0x708)
/*
* NAND registers.
* http://wiiubrew.org/wiki/Hardware/NAND_Interface
*/
#define NAND_REG_BASE (0x0D010000)
#define NAND_CTRL (NAND_REG_BASE + 0x000)
#define NAND_CONF (NAND_REG_BASE + 0x004)
#define NAND_ADDR0 (NAND_REG_BASE + 0x008)
#define NAND_ADDR1 (NAND_REG_BASE + 0x00C)
#define NAND_DATA (NAND_REG_BASE + 0x010)
#define NAND_ECC (NAND_REG_BASE + 0x014)
#define NAND_BANK (NAND_REG_BASE + 0x018)
#define NAND_UNK1 (NAND_REG_BASE + 0x01C)
#define NAND_BANK_CTRL (NAND_REG_BASE + 0x030)
#define NAND_UNK3 (NAND_REG_BASE + 0x040)
/*
* AES registers.
* http://wiiubrew.org/wiki/Hardware/AES_Engine
*/
#define AES_REG_BASE (0x0D020000)
#define AES_CTRL (AES_REG_BASE + 0x000)
#define AES_SRC (AES_REG_BASE + 0x004)
#define AES_DEST (AES_REG_BASE + 0x008)
#define AES_KEY (AES_REG_BASE + 0x00C)
#define AES_IV (AES_REG_BASE + 0x010)
/*
* SHA-1 registers.
* http://wiiubrew.org/wiki/Hardware/SHA-1_Engine
*/
#define SHA_REG_BASE (0x0D030000)
#define SHA_CTRL (SHA_REG_BASE + 0x000)
#define SHA_SRC (SHA_REG_BASE + 0x004)
#define SHA_H0 (SHA_REG_BASE + 0x008)
#define SHA_H1 (SHA_REG_BASE + 0x00C)
#define SHA_H2 (SHA_REG_BASE + 0x010)
#define SHA_H3 (SHA_REG_BASE + 0x014)
#define SHA_H4 (SHA_REG_BASE + 0x018)
/*
* SD Host Controller registers.
* http://wiiubrew.org/wiki/Hardware/SD_Host_Controller
*/
#define SD0_REG_BASE (0x0D070000)
#define SD1_REG_BASE (0x0D080000)
#define SD2_REG_BASE (0x0D100000)
#define SD3_REG_BASE (0x0D110000)
/*
* OHCI registers.
* http://wiiubrew.org/wiki/Hardware/USB_Host_Controller
*/
#define OHCI0_REG_BASE (0x0D050000)
#define OHCI1_REG_BASE (0x0D060000)
#define OHCI10_REG_BASE (0x0D130000)
#define OHCI20_REG_BASE (0x0D150000)
/*
* EHCI registers.
* http://wiiubrew.org/wiki/Hardware/USB_Host_Controller
*/
#define EHCI0_REG_BASE (0x0D040000)
#define EHCI1_REG_BASE (0x0D120000)
#define EHCI2_REG_BASE (0x0D140000)
/*
* EXI registers.
* http://wiiubrew.org/wiki/Hardware/Legacy#External_Interface
*/
#define EXI_REG_BASE (0x0D806800)
#define EXI0_REG_BASE (EXI_REG_BASE + 0x000)
#define EXI1_REG_BASE (EXI_REG_BASE + 0x014)
#define EXI2_REG_BASE (EXI_REG_BASE + 0x028)
#define EXIBOOT_REG_BASE (EXI_REG_BASE + 0x040)
#define EXI0_CSR (EXI0_REG_BASE + 0x000)
#define EXI0_MAR (EXI0_REG_BASE + 0x004)
#define EXI0_LENGTH (EXI0_REG_BASE + 0x008)
#define EXI0_CR (EXI0_REG_BASE + 0x00C)
#define EXI0_DATA (EXI0_REG_BASE + 0x010)
#define EXI1_CSR (EXI1_REG_BASE + 0x000)
#define EXI1_MAR (EXI1_REG_BASE + 0x004)
#define EXI1_LENGTH (EXI1_REG_BASE + 0x008)
#define EXI1_CR (EXI1_REG_BASE + 0x00C)
#define EXI1_DATA (EXI1_REG_BASE + 0x010)
#define EXI2_CSR (EXI2_REG_BASE + 0x000)
#define EXI2_MAR (EXI2_REG_BASE + 0x004)
#define EXI2_LENGTH (EXI2_REG_BASE + 0x008)
#define EXI2_CR (EXI2_REG_BASE + 0x00C)
#define EXI2_DATA (EXI2_REG_BASE + 0x010)
/*
* Memory Controller registers.
* http://wiiubrew.org/wiki/Hardware/Memory_Controller
*/
#define MEM_REG_BASE (0x0D8B4000)
#define MEM_PROT (MEM_REG_BASE + 0x20A)
#define MEM_PROT_START (MEM_REG_BASE + 0x20C)
#define MEM_PROT_END (MEM_REG_BASE + 0x20E)
#define MEM_REFRESH_FLAG (MEM_REG_BASE + 0x226)
#define MEM_FLUSH_MASK (MEM_REG_BASE + 0x228)
#define MEM_FLUSH_ACK (MEM_REG_BASE + 0x22A)
#define MEM_SEQ_REG_VAL (MEM_REG_BASE + 0x2C4)
#define MEM_SEQ_REG_ADDR (MEM_REG_BASE + 0x2C6)
#define MEM_SEQ0_REG_VAL (MEM_REG_BASE + 0x300)
#define MEM_SEQ0_REG_ADDR (MEM_REG_BASE + 0x302)
/*
* AHMN registers.
* http://wiiubrew.org/wiki/Hardware/XN_Controller
*/
#define AHMN_REG_BASE (0x0D8B0800)
#define AHMN_MEM0_CONFIG (AHMN_REG_BASE + 0x000)
#define AHMN_MEM1_CONFIG (AHMN_REG_BASE + 0x004)
#define AHMN_MEM2_CONFIG (AHMN_REG_BASE + 0x008)
#define AHMN_RDBI_MASK (AHMN_REG_BASE + 0x00C)
#define AHMN_ERROR_MASK (AHMN_REG_BASE + 0x020)
#define AHMN_ERROR (AHMN_REG_BASE + 0x024)
#define AHMN_UNK40 (AHMN_REG_BASE + 0x040)
#define AHMN_UNK44 (AHMN_REG_BASE + 0x044)
#define AHMN_TRANSFER_STATE (AHMN_REG_BASE + 0x050)
#define AHMN_WORKAROUND (AHMN_REG_BASE + 0x054)
#define AHMN_MEM0 (AHMN_REG_BASE + 0x100)
#define AHMN_MEM1 (AHMN_REG_BASE + 0x200)
#define AHMN_MEM2 (AHMN_REG_BASE + 0x400)
#endif

View File

@ -1,106 +0,0 @@
/*
mini - a Free Software replacement for the Nintendo/BroadOn IOS.
linker script
Copyright (C) 2008, 2009 Hector Martin "marcan" <marcan@marcansoft.com>
# This code is licensed to you under the terms of the GNU GPL, version 2;
# see file COPYING or http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt
*/
OUTPUT_FORMAT("elf32-bigarm", "elf32-bigarm", "elf32-bigarm")
OUTPUT_ARCH(arm)
EXTERN(_start)
ENTRY(_start)
__stack_size = 0x80000;
__irqstack_size = 0x40000;
__excstack_size = 0x40000;
MEMORY {
sram0 : ORIGIN = 0xffff0000, LENGTH = 64K
mem2 : ORIGIN = 0x10100000, LENGTH = 60M
}
SECTIONS
{
.init :
{
*(.init)
*(.sram.text)
. = ALIGN(4);
} >sram0
.text :
{
*(.text*)
*(.text.*)
*(.gnu.warning)
*(.gnu.linkonce.t*)
*(.glue_7)
*(.glue_7t)
. = ALIGN(4);
} >mem2
.rodata :
{
*(.rodata)
*all.rodata*(*)
*(.roda)
*(.rodata.*)
*(.gnu.linkonce.r*)
. = ALIGN(4);
} >mem2
.data :
{
*(.data)
*(.data.*)
*(.gnu.linkonce.d*)
. = ALIGN(4);
} >mem2
.bss :
{
__bss_start = . ;
*(.dynbss)
*(.gnu.linkonce.b*)
*(.bss*)
*(COMMON)
. = ALIGN(4);
__bss_end = . ;
} >mem2
.stack :
{
. = ALIGN(16);
__stack_end = .;
. = . +__stack_size;
. = ALIGN(16);
__stack_addr = .;
__irqstack_end = .;
. = . +__irqstack_size;
. = ALIGN(16);
__irqstack_addr = .;
__excstack_end = .;
. = . +__excstack_size;
. = ALIGN(16);
__excstack_addr = .;
. = ALIGN(4);
} >mem2
.heap :
{
__end__ = .;
__heap_start__ = .;
__heap_end__ = (ORIGIN(mem2) + LENGTH(mem2));
. = __heap_end__;
} >mem2
/DISCARD/ :
{
*(.ARM.exidx*)
*(.ARM.extab*)
}
}

View File

@ -1,4 +0,0 @@
%rename link old_link
*link:
%(old_link) -T ../stage2/link.ld%s

View File

@ -1,84 +0,0 @@
#ifdef LOLSERIAL_DEBUG
#include "lolserial.h"
#include "gpio.h"
#include "utils.h"
#include "latte.h"
#include <sys/iosupport.h>
#include <string.h>
#define LOLSERIAL_WAIT_TICKS 200
#if 1
#define LOLSERIAL_PIN GP_SENSORBAR
#else
#define LOLSERIAL_PIN GP_DEBUG0
#endif
static int enable = 1;
static char suspend_buf[4096];
static int suspend_len = 0;
/* lolserial string output, now not in assembly... */
static void lolserial_lprint(const char *str, int len)
{
/* setup output pin */
clear32(LT_GPIO_OWNER, LOLSERIAL_PIN);
set32(LT_GPIO_ENABLE, LOLSERIAL_PIN);
set32(LT_GPIO_DIR, LOLSERIAL_PIN);
set32(LT_GPIO_OUT, LOLSERIAL_PIN);
/* loop until null terminator or string end */
for (const char *end = str + len; *str && (str != end); str++) {
for (u32 bits = 0x200 | (*str << 1); bits; bits >>= 1) {
/* set bit value */
mask32(LT_GPIO_OUT, LOLSERIAL_PIN, (bits & 1) ? LOLSERIAL_PIN : 0);
/* wait ticks for bit */
u32 now = read32(LT_TIMER), then = now + LOLSERIAL_WAIT_TICKS;
for (; then < now; now = read32(LT_TIMER)); /* wait overflow */
for (; now < then; now = read32(LT_TIMER)); /* wait */
}
}
}
/* lolserial is slow, for timing critical tasks it might change
* the outcome; as a workaround, output can be suspended and
* printed out at a later point in time */
void lolserial_suspend(void)
{
memset(suspend_buf, 0, sizeof(suspend_buf));
suspend_len = 0;
enable = 0;
}
void lolserial_resume(void)
{
enable = 1;
lolserial_lprint(suspend_buf, suspend_len);
}
/* devoptab output function */
static ssize_t lolserial_write(struct _reent *r, void *fd, const char *ptr, size_t len)
{
if (enable) {
lolserial_lprint(ptr, len);
} else {
for(size_t i = 0; (i < len) && (suspend_len < sizeof(suspend_buf)); i++)
suspend_buf[suspend_len++] = ptr[i];
}
return len;
}
/* register lolserial devoptab */
void lolserial_init() {
static devoptab_t lolserial_dotab = {
.name = "lolserial",
.write_r = &lolserial_write,
};
devoptab_list[STD_OUT] = &lolserial_dotab;
devoptab_list[STD_ERR] = &lolserial_dotab;
}
#endif /* LOLSERIAL_DEBUG */

View File

@ -1,19 +0,0 @@
#ifndef __LOLSERIAL_H__
#define __LOLSERIAL_H__
#ifdef LOLSERIAL_DEBUG
void lolserial_init();
void lolserial_suspend(void);
void lolserial_resume(void);
#else
#define lolserial_init()
#define lolserial_suspend()
#define lolserial_resume()
#endif /* LOLSERIAL_DEBUG */
#endif /* __LOLSERIAL_H__ */

View File

@ -1,149 +0,0 @@
/*
* ISFSHAX
*
* Copyright (C) 2021 rw-r-r-0644 <rwrr0644@gmail.com>
*
* Based on code from Minute and Mini:
*
* Copyright (C) 2017 Ash Logan <quarktheawesome@gmail.com>
* Copyright (C) 2016 SALT
* Copyright (C) 2016 Daz Jones <daz@dazzozo.com>
*
* Copyright (C) 2008, 2009 Haxx Enterprises <bushing@gmail.com>
* Copyright (C) 2008, 2009 Sven Peter <svenpeter@gmail.com>
* Copyright (C) 2008, 2009 Hector Martin "marcan" <marcan@marcansoft.com>
* Copyright (C) 2009 Andre Heider "dhewg" <dhewg@wiibrew.org>
* Copyright (C) 2009 John Kelley <wiidev@kelley.ca>
*
* This code is licensed to you under the terms of the GNU GPL, version 2;
* see file COPYING or http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt
*/
#include <stdlib.h>
#include "memory.h"
#include "irq.h"
#include "crypto.h"
#include "smc.h"
#include "latte.h"
#include "utils.h"
#include "isfs/isfshax.h"
#include "sdcard.h"
#include "fatfs/ff.h"
#include "nand.h"
#include "isfs/isfs.h"
#include "ancast.h"
#include "debug.h"
#include "lolserial.h"
u32 load_payload_sd(void)
{
static FATFS fatfs;
UINT btr, br;
FRESULT res;
FIL file;
u32 vector = 0;
ancast_iop_clear((u8*)ANCAST_ADDRESS_IOP);
sdcard_init();
res = f_mount(&fatfs, "0:", 1);
if (res)
goto error_mount;
res = f_open(&file, "isfshax.bin", FA_READ);
if (res)
goto error_open;
btr = f_size(&file);
if (!btr)
goto error_read;
res = f_read(&file, (u8*)ANCAST_ADDRESS_IOP, btr, &br);
if (res || (btr != br))
goto error_read;
vector = ancast_iop_load((u8*)ANCAST_ADDRESS_IOP, btr);
error_read:
f_close(&file);
error_open:
f_mount(0, "0:", 0);
error_mount:
sdcard_exit();
return vector;
}
u32 load_payload_nand(void)
{
isfs_file file;
size_t btr, br;
int res;
u32 vector = 0;
ancast_iop_clear((u8*)ANCAST_ADDRESS_IOP);
res = isfs_init();
if (res)
return vector;
res = isfs_open(&file, "slc:/sys/isfshax.bin");
if (res)
goto error_open;
btr = file.fst->size;
if (!btr)
goto error_read;
res = isfs_read(&file, (u8*)ANCAST_ADDRESS_IOP, btr, &br);
if (res || (btr != br))
goto error_read;
vector = ancast_iop_load((u8*)ANCAST_ADDRESS_IOP, btr);
error_read:
isfs_close(&file);
error_open:
isfs_fini();
return vector;
}
u32 _main(void)
{
u32 vector = 0;
lolserial_init();
DEBUG("isfshax start\n");
//mem_initialize();
irq_initialize();
crypto_read_otp();
nand_initialize();
/* repair isfshax superblocks ecc errors, if present */
DEBUG("isfshax_refresh\n");
isfshax_refresh();
/* attempt to load the payload from SD, then NAND */
DEBUG("load_payload_sd\n");
lolserial_suspend();
vector = load_payload_sd();
lolserial_resume();
if (!vector) {
DEBUG("load_payload_nand\n");
lolserial_suspend();
vector = load_payload_nand();
lolserial_resume();
}
DEBUG("vector: %08lX\n", vector);
nand_deinitialize();
irq_shutdown();
//mem_shutdown();
/* failed to load the payload from SD or NAND -> shutdown */
if (!vector)
smc_shutdown(false);
return vector;
}

View File

@ -1,400 +0,0 @@
/*
* minute - a port of the "mini" IOS replacement for the Wii U.
*
* Copyright (C) 2016 SALT
* Copyright (C) 2016 Daz Jones <daz@dazzozo.com>
*
* Copyright (C) 2008, 2009 Hector Martin "marcan" <marcan@marcansoft.com>
*
* This code is licensed to you under the terms of the GNU GPL, version 2;
* see file COPYING or http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt
*/
#include "types.h"
#include "memory.h"
#include "utils.h"
#include "latte.h"
#include "irq.h"
#include "debug.h"
#include "malloc.h"
void _dc_inval_entries(void *start, int count);
void _dc_flush_entries(const void *start, int count);
void _dc_flush(void);
void _ic_inval(void);
void _drain_write_buffer(void);
#ifndef LOADER
static u32 *__page_table;
void _dc_inval(void);
void _tlb_inval(void);
#endif
#define LINESIZE 0x20
#define CACHESIZE 0x4000
#define CR_MMU (1 << 0)
#define CR_DCACHE (1 << 2)
#define CR_ICACHE (1 << 12)
// this is ripped from IOS, because no one can figure out just WTF this thing is doing
void _ahb_flush_to(enum rb_client dev) {
u32 mask;
switch(dev) {
case RB_IOD: mask = 0x8000; break;
case RB_IOI: mask = 0x4000; break;
case RB_AIM: mask = 0x0001; break;
case RB_FLA: mask = 0x0002; break;
case RB_AES: mask = 0x0004; break;
case RB_SHA: mask = 0x0008; break;
case RB_EHCI: mask = 0x0010; break;
case RB_OHCI0: mask = 0x0020; break;
case RB_OHCI1: mask = 0x0040; break;
case RB_SD0: mask = 0x0080; break;
case RB_SD1: mask = 0x0100; break;
default:
// ahb_flush_to() does this now
//DEBUG("_ahb_flush_to(%d): Invalid device\n", dev);
return;
}
//NOTE: 0xd8b000x, not 0xd8b400x!
if(read32(0xd8b0008) & mask) {
return;
}
switch(dev) {
case RB_FLA:
case RB_AES:
case RB_SHA:
case RB_EHCI:
case RB_OHCI0:
case RB_OHCI1:
case RB_SD0:
case RB_SD1:
while((read32(LT_BOOT0) & 0xF) == 9)
set32(LT_COMPAT_MEMCTRL_WORKAROUND, 0x10000);
clear32(LT_COMPAT_MEMCTRL_WORKAROUND, 0x10000);
set32(LT_COMPAT_MEMCTRL_WORKAROUND, 0x2000000);
mask32(LT_AHB_UNK124, 0x7C0, 0x280);
set32(LT_AHB_UNK134, 0x400);
while((read32(LT_BOOT0) & 0xF) != 9);
set32(LT_AHB_UNK100, 0x400);
set32(LT_AHB_UNK104, 0x400);
set32(LT_AHB_UNK108, 0x400);
set32(LT_AHB_UNK10C, 0x400);
set32(LT_AHB_UNK110, 0x400);
set32(LT_AHB_UNK114, 0x400);
set32(LT_AHB_UNK118, 0x400);
set32(LT_AHB_UNK11C, 0x400);
set32(LT_AHB_UNK120, 0x400);
clear32(0xd8b0008, mask);
set32(0xd8b0008, mask);
clear32(LT_AHB_UNK134, 0x400);
clear32(LT_AHB_UNK100, 0x400);
clear32(LT_AHB_UNK104, 0x400);
clear32(LT_AHB_UNK108, 0x400);
clear32(LT_AHB_UNK10C, 0x400);
clear32(LT_AHB_UNK110, 0x400);
clear32(LT_AHB_UNK114, 0x400);
clear32(LT_AHB_UNK118, 0x400);
clear32(LT_AHB_UNK11C, 0x400);
clear32(LT_AHB_UNK120, 0x400);
clear32(LT_COMPAT_MEMCTRL_WORKAROUND, 0x2000000);
mask32(LT_AHB_UNK124, 0x7C0, 0xC0);
break;
case RB_IOD:
case RB_IOI:
set32(0xd8b0008, mask);
break;
default:
break;
}
}
// invalidate device and then starlet
void ahb_flush_to(enum rb_client dev)
{
u32 mask;
switch(dev) {
case RB_IOD: mask = 0x8000; break;
case RB_IOI: mask = 0x4000; break;
case RB_AIM: mask = 0x0001; break;
case RB_FLA: mask = 0x0002; break;
case RB_AES: mask = 0x0004; break;
case RB_SHA: mask = 0x0008; break;
case RB_EHCI: mask = 0x0010; break;
case RB_OHCI0: mask = 0x0020; break;
case RB_OHCI1: mask = 0x0040; break;
case RB_SD0: mask = 0x0080; break;
case RB_SD1: mask = 0x0100; break;
case RB_SD2: mask = 0x10000; break;
case RB_SD3: mask = 0x20000; break;
case RB_EHC1: mask = 0x40000; break;
case RB_OHCI10: mask = 0x80000; break;
case RB_EHC2: mask = 0x100000; break;
case RB_OHCI20: mask = 0x200000; break;
case RB_SATA: mask = 0x400000; break;
case RB_AESS: mask = 0x800000; break;
case RB_SHAS: mask = 0x1000000; break;
default:
DEBUG("ahb_flush_to(%d): Invalid device\n", dev);
return;
}
u32 cookie = irq_kill();
write32(AHMN_RDBI_MASK, mask);
_ahb_flush_to(dev);
if(dev != RB_IOD)
_ahb_flush_to(RB_IOD);
irq_restore(cookie);
}
// flush device and also invalidate memory
void ahb_flush_from(enum wb_client dev)
{
u32 cookie = irq_kill();
u16 req = 0;
bool done = false;
int i;
switch(dev)
{
case WB_IOD:
req = 0b0001;
break;
case WB_AIM:
case WB_EHCI:
case WB_EHC1:
case WB_EHC2:
case WB_SATA:
case WB_DMAB:
req = 0b0100;
break;
case WB_FLA:
case WB_OHCI0:
case WB_OHCI1:
case WB_SD0:
case WB_SD1:
case WB_SD2:
case WB_SD3:
case WB_OHCI10:
case WB_OHCI20:
case WB_DMAC:
req = 0b1000;
break;
case WB_AES:
case WB_SHA:
case WB_AESS:
case WB_SHAS:
case WB_DMAA:
req = 0b0010;
break;
case WB_ALL:
req = 0b1111;
break;
default:
DEBUG("ahb_flush(%d): Invalid device\n", dev);
goto done;
}
write16(MEM_FLUSH_MASK, req);
for(i = 0; i < 1000000; i++) {
if(!(read16(MEM_FLUSH_MASK) & req)) {
done = true;
break;
}
udelay(1);
}
if(!done) {
DEBUG("ahb_flush(%d): Flush (0x%x) did not ack!\n", dev, req);
}
done:
irq_restore(cookie);
}
void dc_flushrange(const void *start, u32 size)
{
u32 cookie = irq_kill();
if(size > 0x4000) {
_dc_flush();
} else {
void *end = ALIGN_FORWARD(((u8*)start) + size, LINESIZE);
start = ALIGN_BACKWARD(start, LINESIZE);
_dc_flush_entries(start, (end - start) / LINESIZE);
}
_drain_write_buffer();
ahb_flush_from(WB_AIM);
irq_restore(cookie);
}
void dc_invalidaterange(void *start, u32 size)
{
u32 cookie = irq_kill();
void *end = ALIGN_FORWARD(((u8*)start) + size, LINESIZE);
start = ALIGN_BACKWARD(start, LINESIZE);
_dc_inval_entries(start, (end - start) / LINESIZE);
ahb_flush_to(RB_IOD);
irq_restore(cookie);
}
void dc_flushall(void)
{
u32 cookie = irq_kill();
_dc_flush();
_drain_write_buffer();
ahb_flush_from(WB_AIM);
irq_restore(cookie);
}
void ic_invalidateall(void)
{
u32 cookie = irq_kill();
_ic_inval();
ahb_flush_to(RB_IOD);
irq_restore(cookie);
}
void mem_protect(int enable, void *start, void *end)
{
write16(MEM_PROT, enable?1:0);
write16(MEM_PROT_START, (((u32)start) & 0xFFFFFFF) >> 12);
write16(MEM_PROT_END, (((u32)end) & 0xFFFFFFF) >> 12);
udelay(10);
}
void mem_setswap(int enable)
{
u32 d = read32(LT_MEMIRR);
if((d & 0x20) && !enable)
write32(LT_MEMIRR, d & ~0x20);
if((!(d & 0x20)) && enable)
write32(LT_MEMIRR, d | 0x20);
}
#ifndef LOADER
u32 dma_addr(void *p)
{
u32 addr = (u32)p;
switch(addr>>20) {
case 0xfff:
case 0x0d4:
case 0x0dc:
if(read32(LT_MEMIRR) & 0x20) {
addr ^= 0x10000;
}
addr &= 0x0001FFFF;
addr |= 0x0d400000;
break;
}
//DEBUG("DMA to %p: address %08x\n", p, addr);
return addr;
}
#define SECTION 0x012
#define NONBUFFERABLE 0x000
#define BUFFERABLE 0x004
#define WRITETHROUGH_CACHE 0x008
#define WRITEBACK_CACHE 0x00C
#define DOMAIN(x) ((x)<<5)
#define AP_ROM 0x000
#define AP_NOUSER 0x400
#define AP_ROUSER 0x800
#define AP_RWUSER 0xC00
// from, to, size: units of 1MB
void map_section(u32 from, u32 to, u32 size, u32 attributes)
{
attributes |= SECTION;
while(size--) {
__page_table[from++] = (to++<<20) | attributes;
}
}
//#define NO_CACHES
void mem_initialize(void)
{
u32 cr;
u32 cookie = irq_kill();
DEBUG("MEM: cleaning up\n");
_ic_inval();
_dc_inval();
_tlb_inval();
DEBUG("MEM: unprotecting memory\n");
mem_protect(0, NULL, NULL);
DEBUG("MEM: configuring heap\n");
extern char* fake_heap_start;
extern char* fake_heap_end;
extern char heap_start __asm__("__heap_start__");
extern char heap_end __asm__("__heap_end__");
fake_heap_start = &heap_start;
fake_heap_end = &heap_end;
DEBUG("MEM: mapping sections\n");
__page_table = (u32 *)memalign(16384, 16384);
memset32(__page_table, 0, sizeof(__page_table));
map_section(0x080, 0x080, 0x003, WRITEBACK_CACHE | DOMAIN(0) | AP_RWUSER); // MEM0
map_section(0x000, 0x000, 0x020, WRITEBACK_CACHE | DOMAIN(0) | AP_RWUSER); // MEM1
map_section(0x100, 0x100, 0xC00, WRITEBACK_CACHE | DOMAIN(0) | AP_RWUSER); // MEM2
map_section(0xFFF, 0xFFF, 0x001, WRITEBACK_CACHE | DOMAIN(0) | AP_RWUSER); // SRAM
map_section(0x0D0, 0x0D0, 0x010, NONBUFFERABLE | DOMAIN(0) | AP_RWUSER); // MMIO
set_dacr(0xFFFFFFFF); //manager access for all domains, ignore AP
set_ttbr((u32)__page_table); //configure translation table
_drain_write_buffer();
cr = get_cr();
#ifndef NO_CACHES
DEBUG("MEM: enabling caches\n");
cr |= CR_DCACHE | CR_ICACHE;
set_cr(cr);
DEBUG("MEM: enabling MMU\n");
cr |= CR_MMU;
set_cr(cr);
#endif
DEBUG("MEM: init done\n");
irq_restore(cookie);
}
void mem_shutdown(void)
{
u32 cookie = irq_kill();
_dc_flush();
_drain_write_buffer();
u32 cr = get_cr();
cr &= ~(CR_MMU | CR_DCACHE | CR_ICACHE); //disable ICACHE, DCACHE, MMU
set_cr(cr);
_ic_inval();
_dc_inval();
_tlb_inval();
irq_restore(cookie);
}
#endif

View File

@ -1,156 +0,0 @@
/*
* minute - a port of the "mini" IOS replacement for the Wii U.
*
* Copyright (C) 2008, 2009 Hector Martin "marcan" <marcan@marcansoft.com>
*
* This code is licensed to you under the terms of the GNU GPL, version 2;
* see file COPYING or http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt
*/
#ifndef __MEMORY_H__
#define __MEMORY_H__
#include "types.h"
#define ALIGN_FORWARD(x,align) \
((__typeof__(x))((((u32)(x)) + (align) - 1) & (~(align-1))))
#define ALIGN_BACKWARD(x,align) \
((__typeof__(x))(((u32)(x)) & (~(align-1))))
enum rb_client {
RB_IOD = 0,
RB_IOI = 1,
RB_AIM = 2,
RB_FLA = 3,
RB_AES = 4,
RB_SHA = 5,
RB_EHCI = 6,
RB_OHCI0 = 7,
RB_OHCI1 = 8,
RB_SD0 = 9,
RB_SD1 = 10,
RB_SD2 = 11,
RB_SD3 = 12,
RB_EHC1 = 13,
RB_OHCI10 = 14,
RB_EHC2 = 15,
RB_OHCI20 = 16,
RB_SATA = 17,
RB_AESS = 18,
RB_SHAS = 19
};
enum wb_client {
WB_IOD = 0,
WB_AIM = 1,
WB_FLA = 2,
WB_AES = 3,
WB_SHA = 4,
WB_EHCI = 5,
WB_OHCI0 = 6,
WB_OHCI1 = 7,
WB_SD0 = 8,
WB_SD1 = 9,
WB_SD2 = 10,
WB_SD3 = 11,
WB_EHC1 = 12,
WB_OHCI10 = 13,
WB_EHC2 = 14,
WB_OHCI20 = 15,
WB_SATA = 16,
WB_AESS = 17,
WB_SHAS = 18,
WB_DMAA = 19,
WB_DMAB = 20,
WB_DMAC = 21,
WB_ALL = 22
};
void dc_flushrange(const void *start, u32 size);
void dc_invalidaterange(void *start, u32 size);
void dc_flushall(void);
void ic_invalidateall(void);
void ahb_flush_from(enum wb_client dev);
void ahb_flush_to(enum rb_client dev);
void mem_protect(int enable, void *start, void *end);
void mem_setswap(int enable);
void mem_initialize(void);
void mem_shutdown(void);
u32 dma_addr(void *);
static inline u32 get_cr(void)
{
u32 data;
__asm__ volatile ( "mrc\tp15, 0, %0, c1, c0, 0" : "=r" (data) );
return data;
}
static inline u32 get_ttbr(void)
{
u32 data;
__asm__ volatile ( "mrc\tp15, 0, %0, c2, c0, 0" : "=r" (data) );
return data;
}
static inline u32 get_dacr(void)
{
u32 data;
__asm__ volatile ( "mrc\tp15, 0, %0, c3, c0, 0" : "=r" (data) );
return data;
}
static inline void set_cr(u32 data)
{
__asm__ volatile ( "mcr\tp15, 0, %0, c1, c0, 0" :: "r" (data) );
}
static inline void set_ttbr(u32 data)
{
__asm__ volatile ( "mcr\tp15, 0, %0, c2, c0, 0" :: "r" (data) );
}
static inline void set_dacr(u32 data)
{
__asm__ volatile ( "mcr\tp15, 0, %0, c3, c0, 0" :: "r" (data) );
}
static inline u32 get_dfsr(void)
{
u32 data;
__asm__ volatile ( "mrc\tp15, 0, %0, c5, c0, 0" : "=r" (data) );
return data;
}
static inline u32 get_ifsr(void)
{
u32 data;
__asm__ volatile ( "mrc\tp15, 0, %0, c5, c0, 1" : "=r" (data) );
return data;
}
static inline u32 get_far(void)
{
u32 data;
__asm__ volatile ( "mrc\tp15, 0, %0, c6, c0, 0" : "=r" (data) );
return data;
}
void _ahb_flush_to(enum rb_client dev);
static inline void dc_inval_block_fast(void *block)
{
__asm__ volatile ( "mcr\tp15, 0, %0, c7, c6, 1" :: "r" (block) );
_ahb_flush_to(RB_IOD); //TODO: check if really needed and if not, remove
}
static inline void dc_flush_block_fast(void *block)
{
__asm__ volatile ( "mcr\tp15, 0, %0, c7, c10, 1" :: "r" (block) );
__asm__ volatile ( "mcr\tp15, 0, %0, c7, c10, 4" :: "r" (0) );
ahb_flush_from(WB_AIM); //TODO: check if really needed and if not, remove
}
#endif

View File

@ -1,59 +0,0 @@
/*
* minute - a port of the "mini" IOS replacement for the Wii U.
*
* Copyright (C) 2008, 2009 Hector Martin "marcan" <marcan@marcansoft.com>
*
* This code is licensed to you under the terms of the GNU GPL, version 2;
* see file COPYING or http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt
*/
.arm
.globl _dc_inval_entries
.globl _dc_flush_entries
.globl _dc_flush
.globl _dc_inval
.globl _ic_inval
.globl _drain_write_buffer
.globl _tlb_inval
.section .sram.text
_dc_inval_entries:
mcr p15, 0, r0, c7, c6, 1
add r0, #0x20
subs r1, #1
bne _dc_inval_entries
bx lr
_dc_flush_entries:
mcr p15, 0, r0, c7, c10, 1
add r0, #0x20
subs r1, #1
bne _dc_flush_entries
bx lr
_dc_flush:
mrc p15, 0, pc, c7, c10, 3
bne _dc_flush
bx lr
_dc_inval:
mov r0, #0
mcr p15, 0, r0, c7, c6, 0
bx lr
_ic_inval:
mov r0, #0
mcr p15, 0, r0, c7, c5, 0
bx lr
_drain_write_buffer:
mov r0, #0
mcr p15, 0, r0, c7, c10, 4
bx lr
_tlb_inval:
mov r0, #0
mcr p15, 0, r0, c8, c7
bx lr

View File

@ -1,456 +0,0 @@
/*
* minute - a port of the "mini" IOS replacement for the Wii U.
*
* Copyright (C) 2021 rw-r-r-0644
* Copyright (C) 2016 SALT
* Copyright (C) 2016 Daz Jones <daz@dazzozo.com>
*
* Copyright (C) 2008, 2009 Haxx Enterprises <bushing@gmail.com>
* Copyright (C) 2008, 2009 Sven Peter <svenpeter@gmail.com>
* Copyright (C) 2008, 2009 Hector Martin "marcan" <marcan@marcansoft.com>
*
* This code is licensed to you under the terms of the GNU GPL, version 2;
* see file COPYING or http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt
*/
#include "nand.h"
#include "utils.h"
#include "types.h"
#include "latte.h"
#include "memory.h"
#include "irq.h"
#include "crypto.h"
#include "debug.h"
#include <string.h>
/* ECC definitions */
#define ECC_SIZE 0x10
#define ECC_STOR_OFFS 0x30
#define ECC_CALC_OFFS 0x40
/* required buffers sizes */
#define SPARE_BUF_SIZE (SPARE_SIZE + ECC_SIZE + 0x10)
#define STATUS_BUF_SIZE 0x40
/* NAND chip commands */
#define CMD_CHIPID 0x90
#define CMD_RESET 0xff
#define CMD_GET_STATUS 0x70
#define CMD_ERASE_SETUP 0x60
#define CMD_ERASE 0xd0
#define CMD_SERIALDATA_IN 0x80
#define CMD_RANDOMDATA_IN 0x85
#define CMD_PROGRAM 0x10
#define CMD_READ_SETUP 0x00
#define CMD_READ 0x30
/* NAND_CTRL definitions */
#define CTRL_FL_EXEC (0x80000000)
#define CTRL_FL_ERR (0x20000000)
#define CTRL_FL_IRQ (0x40000000)
#define CTRL_FL_WAIT (0x00008000)
#define CTRL_FL_WR (0x00004000)
#define CTRL_FL_RD (0x00002000)
#define CTRL_FL_ECC (0x00001000)
#define CTRL_CMD(cmd) (0x00ff0000 & (cmd << 16))
#define CTRL_ADDR(addr) (0x1f000000 & (addr << 24))
#define CTRL_SIZE(size) (0x00000fff & (size))
/* NAND_CONF definitions */
#define CONF_FL_WP (0x80000000) /* bsp:fla clears this flag when writing */
#define CONF_FL_EN (0x08000000) /* enable nand controller */
#define CONF_ATTR_INIT (0x743e3eff) /* initial nand config */
#define CONF_ATTR_NORMAL (0x550f1eff) /* normal nand config */
/* NAND_BANK definitions */
#define BANK_FL_4 (0x00000004) /* set by bsp:fla for revisions after latte A2X */
#if NAND_WRITE_ENABLED
static u8 nand_status_buf[STATUS_BUF_SIZE] ALIGNED(NAND_DATA_ALIGN);
#endif
static u8 nand_spare_buf[SPARE_BUF_SIZE] ALIGNED(NAND_DATA_ALIGN);
static u32 nand_enabled_banks = BANK_SLC;
static int irq_flag = 0;
int nand_error(const char *error)
{
DEBUG("nand: %s\n", error);
nand_initialize();
return -1;
}
void nand_irq(void)
{
ahb_flush_from(WB_FLA);
ahb_flush_to(RB_IOD);
irq_flag = 1;
}
void nand_irq_clear_and_enable(void)
{
irq_flag = 0;
irq_enable(IRQ_NAND);
}
void nand_wait_irq(void)
{
while(!irq_flag) {
u32 cookie = irq_kill();
if (!irq_flag) {
irq_wait();
}
irq_restore(cookie);
}
}
void nand_enable_banks(u32 bank)
{
nand_enabled_banks = bank & 3;
}
void nand_set_config(int write_enable)
{
u32 conf, bank;
write32(NAND_CTRL, 0);
write32(NAND_CONF, 0);
/* set nand config */
conf = (write_enable ? 0 : CONF_FL_WP)
| (CONF_FL_EN)
| (CONF_ATTR_NORMAL);
write32(NAND_CONF, conf);
/* set nand bank */
bank = BANK_FL_4
| nand_enabled_banks;
write32(NAND_BANK, bank);
}
#if NAND_WRITE_ENABLED
int nand_erase_block(u32 blockno)
{
if (blockno > BLOCK_COUNT) {
return nand_error("invalid block number");
}
/* clear write protection */
nand_set_config(1);
/* erase setup */
write32(NAND_CTRL, 0);
write32(NAND_ADDR0, 0);
write32(NAND_ADDR1, blockno * BLOCK_PAGES);
write32(NAND_CTRL,
CTRL_FL_EXEC |
CTRL_CMD(CMD_ERASE_SETUP) |
CTRL_ADDR(0x1c));
while(read32(NAND_CTRL) & CTRL_FL_EXEC);
write32(NAND_CTRL, 0);
nand_irq_clear_and_enable();
/* erase */
write32(NAND_CTRL,
CTRL_FL_EXEC |
CTRL_FL_IRQ |
CTRL_CMD(CMD_ERASE) |
CTRL_FL_WAIT);
nand_wait_irq();
/* set write protection */
nand_set_config(0);
/* get status */
*nand_status_buf = 1;
dc_flushrange(nand_status_buf, STATUS_BUF_SIZE);
write32(NAND_DATA, dma_addr(nand_status_buf));
write32(NAND_CTRL,
CTRL_FL_EXEC |
CTRL_CMD(CMD_GET_STATUS) |
CTRL_FL_RD |
CTRL_SIZE(STATUS_BUF_SIZE));
while(read32(NAND_CTRL) & CTRL_FL_EXEC);
ahb_flush_from(WB_FLA);
dc_invalidaterange(nand_status_buf, STATUS_BUF_SIZE);
/* check failure */
if (*nand_status_buf & 1) {
return nand_error("erase command failed");
}
return 0;
}
int nand_write_page(u32 pageno, void *data, void *spare)
{
if (pageno > PAGE_COUNT) {
return nand_error("invalid page number");
}
if ((u32)data & (NAND_DATA_ALIGN - 1)) {
return nand_error("unaligned page buffer");
}
dc_flushrange(data, PAGE_SIZE);
ahb_flush_to(RB_FLA);
dc_invalidaterange(nand_spare_buf + ECC_CALC_OFFS, ECC_SIZE);
/* clear write protection */
nand_set_config(1);
/* send page content and calc ecc */
write32(NAND_CTRL, 0);
write32(NAND_ADDR0, 0);
write32(NAND_ADDR1, pageno);
write32(NAND_DATA, dma_addr(data));
write32(NAND_ECC, dma_addr(nand_spare_buf));
write32(NAND_CTRL,
CTRL_FL_EXEC |
CTRL_ADDR(0x1f) |
CTRL_CMD(CMD_SERIALDATA_IN) |
CTRL_FL_WR |
CTRL_FL_ECC |
CTRL_SIZE(PAGE_SIZE));
while(read32(NAND_CTRL) & CTRL_FL_EXEC);
if (read32(NAND_CTRL) & CTRL_FL_ERR) {
nand_error("error executing data input command");
}
/* prepare page spare */
ahb_flush_from(WB_FLA);
if (spare) {
memcpy(nand_spare_buf, spare, SPARE_SIZE);
} else {
memset(nand_spare_buf, 0, SPARE_SIZE);
}
nand_spare_buf[0] = 0xff;
memcpy(nand_spare_buf + ECC_STOR_OFFS, nand_spare_buf + ECC_CALC_OFFS, ECC_SIZE);
dc_flushrange(nand_spare_buf, SPARE_SIZE);
/* setup irq */
write32(NAND_CTRL, 0);
nand_irq_clear_and_enable();
/* send spare content */
write32(NAND_ADDR0, PAGE_SIZE);
write32(NAND_ADDR1, 0);
write32(NAND_DATA, dma_addr(nand_spare_buf));
write32(NAND_ECC, 0);
write32(NAND_CTRL,
CTRL_FL_EXEC |
CTRL_ADDR(0x3) |
CTRL_CMD(CMD_RANDOMDATA_IN) |
CTRL_FL_WR |
CTRL_SIZE(SPARE_SIZE));
while(read32(NAND_CTRL) & CTRL_FL_EXEC);
if (read32(NAND_CTRL) & CTRL_FL_ERR) {
nand_error("error executing random data input command");
}
/* program page */
write32(NAND_CTRL, 0);
write32(NAND_CTRL,
CTRL_FL_EXEC |
CTRL_FL_IRQ |
CTRL_CMD(CMD_PROGRAM) |
CTRL_FL_WAIT);
nand_wait_irq();
/* set write protection */
nand_set_config(0);
/* get status */
*nand_status_buf = 1;
dc_flushrange(nand_status_buf, STATUS_BUF_SIZE);
write32(NAND_DATA, dma_addr(nand_status_buf));
write32(NAND_CTRL,
CTRL_FL_EXEC |
CTRL_CMD(CMD_GET_STATUS) |
CTRL_FL_RD |
CTRL_SIZE(STATUS_BUF_SIZE));
while(read32(NAND_CTRL) & CTRL_FL_EXEC);
ahb_flush_from(WB_FLA);
dc_invalidaterange(nand_status_buf, STATUS_BUF_SIZE);
/* check failure */
if (*nand_status_buf & 1) {
return nand_error("page program command failed");
}
return 0;
}
#endif
int nand_ecc_correct(u8 *data, u32 *ecc_save, u32 *ecc_calc, u32 size)
{
u32 syndrome;
u16 odd, even;
/* check if the page contain ecc errors */
if (!memcmp(ecc_save, ecc_calc, size)) {
return 0;
}
/* correct ecc errors */
for (int i = 0; i < (size / 4); i++) {
if (ecc_save[i] == ecc_calc[i]) {
continue;
}
/* don't try to correct unformatted pages */
if (ecc_save[i] == 0xffffffff) {
continue;
}
/* calculate ecc syndrome */
syndrome = (ecc_save[i] ^ ecc_calc[i]) & 0x0fff0fff;
if ((syndrome & (syndrome - 1)) == 0) {
continue;
}
/* extract odd and even halves */
odd = syndrome >> 16;
even = syndrome;
/* uncorrectable error */
if ((odd ^ even) != 0xfff) {
return -1;
}
/* fix the bad bit */
data[i * 0x200 + (odd >> 3)] ^= 1 << (odd & 7);
}
return 1;
}
int nand_read_page(u32 pageno, void *data, void *spare)
{
int res = 0;
if (pageno > PAGE_COUNT) {
return nand_error("invalid page number");
}
if ((u32)data & (NAND_DATA_ALIGN - 1)) {
return nand_error("unaligned page buffer");
}
/* set nand config */
nand_set_config(0);
/* prepare for reading */
write32(NAND_CTRL, 0);
write32(NAND_ADDR0, 0);
write32(NAND_ADDR1, pageno);
write32(NAND_CTRL,
CTRL_FL_EXEC |
CTRL_ADDR(0x1f) |
CTRL_CMD(CMD_READ_SETUP));
while(read32(NAND_CTRL) & CTRL_FL_EXEC);
/* read page and spare */
dc_invalidaterange(data, PAGE_SIZE);
dc_invalidaterange(nand_spare_buf, SPARE_BUF_SIZE);
write32(NAND_CTRL, 0);
write32(NAND_DATA, dma_addr(data));
write32(NAND_ECC, dma_addr(nand_spare_buf));
nand_irq_clear_and_enable();
write32(NAND_CTRL,
CTRL_FL_EXEC |
CTRL_FL_IRQ |
CTRL_CMD(CMD_READ) |
CTRL_FL_WAIT |
CTRL_FL_RD |
CTRL_FL_ECC |
CTRL_SIZE(PAGE_SIZE + SPARE_SIZE));
nand_wait_irq();
if (read32(NAND_CTRL) & CTRL_FL_ERR) {
return nand_error("error executing page read command");
}
write32(NAND_CTRL, 0);
ahb_flush_from(WB_FLA);
/* correct ecc errors */
res = nand_ecc_correct(data,
(u32*)(nand_spare_buf + ECC_STOR_OFFS),
(u32*)(nand_spare_buf + ECC_CALC_OFFS),
ECC_SIZE);
if (res < 0) {
return nand_error("uncorrectable ecc error");
}
/* copy spare from internal buffer */
if (spare) {
memcpy(spare, nand_spare_buf, SPARE_SIZE);
}
return res;
}
void nand_deinitialize(void)
{
/* shutdown nand banks */
write32(NAND_BANK_CTRL, 0);
while(read32(NAND_BANK_CTRL) & (1 << 31));
write32(NAND_BANK_CTRL, 0);
for (int i = 0; i < 0xc0; i += 0x18) {
write32(NAND_REG_BASE + 0x40 + i, 0);
write32(NAND_REG_BASE + 0x44 + i, 0);
write32(NAND_REG_BASE + 0x48 + i, 0);
write32(NAND_REG_BASE + 0x4c + i, 0);
write32(NAND_REG_BASE + 0x50 + i, 0);
write32(NAND_REG_BASE + 0x54 + i, 0);
}
/* shutdown main nand bank */
write32(NAND_CTRL, 0);
while(read32(NAND_CTRL) & (1 << 31));
write32(NAND_CTRL, 0);
/* write init config */
write32(NAND_CONF, CONF_ATTR_INIT);
write32(NAND_BANK, 1);
}
void nand_initialize(void)
{
for (int i = 0; i < 2; i++) {
/* shutdown nand interface */
nand_deinitialize();
/* set nand init config and enable */
write32(NAND_CONF,
CONF_FL_EN |
CONF_ATTR_INIT);
/* set nand bank */
write32(NAND_BANK,
BANK_FL_4 | // ???
(i ? 3 : 1)); // ???
/* reset nand chip */
write32(NAND_CTRL,
CTRL_FL_EXEC |
CTRL_CMD(CMD_RESET) |
CTRL_FL_WAIT);
while(read32(NAND_CTRL) & CTRL_FL_EXEC);
write32(NAND_CTRL, 0);
}
/* set normal nand config */
nand_set_config(0);
}

View File

@ -1,66 +0,0 @@
/*
* minute - a port of the "mini" IOS replacement for the Wii U.
*
* Copyright (C) 2021 rw-r-r-0644
* Copyright (C) 2016 SALT
* Copyright (C) 2016 Daz Jones <daz@dazzozo.com>
*
* Copyright (C) 2008, 2009 Hector Martin "marcan" <marcan@marcansoft.com>
* Copyright (C) 2008, 2009 Sven Peter <svenpeter@gmail.com>
*
* This code is licensed to you under the terms of the GNU GPL, version 2;
* see file COPYING or http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt
*/
#ifndef __NAND_H__
#define __NAND_H__
#include "types.h"
#define NAND_WRITE_ENABLED 1
#define NAND_DATA_ALIGN 128
/* nand structure definitions */
#define PAGE_SIZE 0x800
#define PAGE_COUNT 0x40000
#define SPARE_SIZE 0x40
#define CLUSTER_PAGES 8
#define CLUSTER_SIZE (PAGE_SIZE * CLUSTER_PAGES)
#define CLUSTER_COUNT (PAGE_COUNT / CLUSTER_PAGES)
#define BLOCK_CLUSTERS 8
#define BLOCK_PAGES 0x40
#define BLOCK_SIZE (CLUSTER_SIZE * BLOCK_CLUSTERS)
#define BLOCK_COUNT 0x1000
/* nand banks */
#define BANK_SLCCMPT 1
#define BANK_SLC 2
/* initialize nand */
void nand_initialize(void);
/* shutdown nand interface */
void nand_deinitialize(void);
/* read page and spare */
int nand_read_page(u32 pageno, void *data, void *spare);
#if NAND_WRITE_ENABLED
/* write page and spare */
int nand_write_page(u32 pageno, void *data, void *spare);
/* erase a block of pages */
int nand_erase_block(u32 blockno);
#endif
/* set enabled nand banks */
void nand_enable_banks(u32 bank);
/* nand irq handler */
void nand_irq(void);
#endif

View File

@ -1,713 +0,0 @@
/*
* minute - a port of the "mini" IOS replacement for the Wii U.
*
* Copyright (C) 2016 SALT
* Copyright (C) 2016 Daz Jones <daz@dazzozo.com>
*
* Copyright (C) 2008, 2009 Sven Peter <svenpeter@gmail.com>
*
* This code is licensed to you under the terms of the GNU GPL, version 2;
* see file COPYING or http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt
*/
#include "bsdtypes.h"
#include "utils.h"
#include "memory.h"
#include "latte.h"
#include "sdhc.h"
#include "sdcard.h"
#include <string.h>
#include "debug.h"
#include "gpio.h"
#ifdef CAN_HAZ_IRQ
#include "irq.h"
#endif
//#define SDCARD_DEBUG
#ifdef SDCARD_DEBUG
static int sdcarddebug = 2;
#define DPRINTF(n,s) do { if ((n) <= sdcarddebug) DEBUG(s); } while (0)
#else
#define DPRINTF(n,s) do {} while(0)
#endif
static struct sdhc_host sdcard_host;
struct sdcard_ctx {
sdmmc_chipset_handle_t handle;
int inserted;
int sdhc_blockmode;
int selected;
int new_card; // set to 1 everytime a new card is inserted
u32 num_sectors;
u16 rca;
};
static struct sdcard_ctx card;
void sdcard_attach(sdmmc_chipset_handle_t handle)
{
memset(&card, 0, sizeof(card));
card.handle = handle;
DPRINTF(0, ("sdcard: attached new SD/MMC card\n"));
sdhc_host_reset(card.handle);
if (sdhc_card_detect(card.handle)) {
DPRINTF(1, ("card is inserted. starting init sequence.\n"));
sdcard_needs_discover();
}
}
void sdcard_abort(void) {
struct sdmmc_command cmd;
DEBUG("sdcard: abortion kthx\n");
memset(&cmd, 0, sizeof(cmd));
cmd.c_opcode = MMC_STOP_TRANSMISSION;
cmd.c_arg = 0;
cmd.c_flags = SCF_RSP_R1B;
sdhc_exec_command(card.handle, &cmd);
}
void sdcard_needs_discover(void)
{
struct sdmmc_command cmd;
u32 ocr = card.handle->ocr;
DPRINTF(0, ("sdcard: card needs discovery.\n"));
sdhc_host_reset(card.handle);
card.new_card = 1;
if (!sdhc_card_detect(card.handle)) {
DPRINTF(1, ("sdcard: card (no longer?) inserted.\n"));
card.inserted = 0;
return;
}
DPRINTF(1, ("sdcard: enabling power\n"));
if (sdhc_bus_power(card.handle, ocr) != 0) {
DEBUG("sdcard: powerup failed for card\n");
goto out;
}
DPRINTF(1, ("sdcard: enabling clock\n"));
if (sdhc_bus_clock(card.handle, SDMMC_SDCLK_25MHZ, SDMMC_TIMING_LEGACY) != 0) {
DEBUG("sdcard: could not enable clock for card\n");
goto out_power;
}
sdhc_bus_width(card.handle, 1);
DPRINTF(1, ("sdcard: sending GO_IDLE_STATE\n"));
memset(&cmd, 0, sizeof(cmd));
cmd.c_opcode = MMC_GO_IDLE_STATE;
cmd.c_flags = SCF_RSP_R0;
sdhc_exec_command(card.handle, &cmd);
if (cmd.c_error) {
DEBUG("sdcard: GO_IDLE_STATE failed with %d\n", cmd.c_error);
goto out_clock;
}
DPRINTF(2, ("sdcard: GO_IDLE_STATE response: %x\n", MMC_R1(cmd.c_resp)));
DPRINTF(1, ("sdcard: sending SEND_IF_COND\n"));
memset(&cmd, 0, sizeof(cmd));
cmd.c_opcode = SD_SEND_IF_COND;
cmd.c_arg = 0x1aa;
cmd.c_flags = SCF_RSP_R7;
cmd.c_timeout = 100;
sdhc_exec_command(card.handle, &cmd);
if (cmd.c_error || (cmd.c_resp[0] & 0xff) != 0xaa)
ocr &= ~SD_OCR_SDHC_CAP;
else
ocr |= SD_OCR_SDHC_CAP;
DPRINTF(2, ("sdcard: SEND_IF_COND ocr: %x\n", ocr));
int tries;
for (tries = 100; tries > 0; tries--) {
udelay(100000);
memset(&cmd, 0, sizeof(cmd));
cmd.c_opcode = MMC_APP_CMD;
cmd.c_arg = 0;
cmd.c_flags = SCF_RSP_R1;
sdhc_exec_command(card.handle, &cmd);
if (cmd.c_error) {
DEBUG("sdcard: MMC_APP_CMD failed with %d\n", cmd.c_error);
goto out_clock;
}
memset(&cmd, 0, sizeof(cmd));
cmd.c_opcode = SD_APP_OP_COND;
cmd.c_arg = ocr;
cmd.c_flags = SCF_RSP_R3;
sdhc_exec_command(card.handle, &cmd);
if (cmd.c_error) {
DEBUG("sdcard: SD_APP_OP_COND failed with %d\n", cmd.c_error);
goto out_clock;
}
DPRINTF(3, ("sdcard: response for SEND_IF_COND: %08x\n",
MMC_R1(cmd.c_resp)));
if (ISSET(MMC_R1(cmd.c_resp), MMC_OCR_MEM_READY))
break;
}
if (!ISSET(cmd.c_resp[0], MMC_OCR_MEM_READY)) {
DEBUG("sdcard: card failed to powerup.\n");
goto out_power;
}
if (ISSET(MMC_R1(cmd.c_resp), SD_OCR_SDHC_CAP))
card.sdhc_blockmode = 1;
else
card.sdhc_blockmode = 0;
DPRINTF(2, ("sdcard: SDHC: %d\n", card.sdhc_blockmode));
u8 *resp;
u32 *resp32;
DPRINTF(2, ("sdcard: MMC_ALL_SEND_CID\n"));
memset(&cmd, 0, sizeof(cmd));
cmd.c_opcode = MMC_ALL_SEND_CID;
cmd.c_arg = 0;
cmd.c_flags = SCF_RSP_R2;
sdhc_exec_command(card.handle, &cmd);
if (cmd.c_error) {
DEBUG("sdcard: MMC_ALL_SEND_CID failed with %d\n", cmd.c_error);
goto out_clock;
}
resp = (u8 *)cmd.c_resp;
resp32 = (u32 *)cmd.c_resp;
DEBUG("CID: %08lX%08lX%08lX%08lX\n", resp32[0], resp32[1], resp32[2], resp32[3]);
DEBUG("CID: mid=%02x name='%c%c%c%c%c%c%c' prv=%d.%d psn=%02x%02x%02x%02x mdt=%d/%d\n", resp[14],
resp[13],resp[12],resp[11],resp[10],resp[9],resp[8],resp[7], resp[6], resp[5] >> 4, resp[5] & 0xf,
resp[4], resp[3], resp[2], resp[0] & 0xf, 2000 + (resp[0] >> 4));
DPRINTF(2, ("sdcard: SD_SEND_RELATIVE_ADDRESS\n"));
memset(&cmd, 0, sizeof(cmd));
cmd.c_opcode = SD_SEND_RELATIVE_ADDR;
cmd.c_arg = 0;
cmd.c_flags = SCF_RSP_R6;
sdhc_exec_command(card.handle, &cmd);
if (cmd.c_error) {
DEBUG("sdcard: SD_SEND_RCA failed with %d\n", cmd.c_error);
goto out_clock;
}
card.rca = MMC_R1(cmd.c_resp)>>16;
DPRINTF(2, ("sdcard: rca: %08x\n", card.rca));
card.selected = 0;
card.inserted = 1;
memset(&cmd, 0, sizeof(cmd));
cmd.c_opcode = MMC_SEND_CSD;
cmd.c_arg = ((u32)card.rca)<<16;
cmd.c_flags = SCF_RSP_R2;
sdhc_exec_command(card.handle, &cmd);
if (cmd.c_error) {
DEBUG("sdcard: MMC_SEND_CSD failed with %d\n", cmd.c_error);
goto out_power;
}
resp = (u8 *)cmd.c_resp;
resp32 = (u32 *)cmd.c_resp;
DEBUG("CSD: %08lX%08lX%08lX%08lX\n", resp32[0], resp32[1], resp32[2], resp32[3]);
if (resp[13] == 0xe) { // sdhc
unsigned int c_size = resp[7] << 16 | resp[6] << 8 | resp[5];
DEBUG("sdcard: sdhc mode, c_size=%u, card size = %uk\n", c_size, (c_size + 1)* 512);
card.num_sectors = (c_size + 1) * 1024; // number of 512-byte sectors
}
else {
unsigned int taac, nsac, read_bl_len, c_size, c_size_mult;
taac = resp[13];
nsac = resp[12];
read_bl_len = resp[9] & 0xF;
c_size = (resp[8] & 3) << 10;
c_size |= (resp[7] << 2);
c_size |= (resp[6] >> 6);
c_size_mult = (resp[5] & 3) << 1;
c_size_mult |= resp[4] >> 7;
DEBUG("taac=%u nsac=%u read_bl_len=%u c_size=%u c_size_mult=%u card size=%u bytes\n",
taac, nsac, read_bl_len, c_size, c_size_mult, (c_size + 1) * (4 << c_size_mult) * (1 << read_bl_len));
card.num_sectors = (c_size + 1) * (4 << c_size_mult) * (1 << read_bl_len) / 512;
}
sdcard_select();
DPRINTF(2, ("mlc: MMC_SEND_STATUS\n"));
memset(&cmd, 0, sizeof(cmd));
cmd.c_opcode = MMC_SEND_STATUS;
cmd.c_arg = ((u32)card.rca)<<16;
cmd.c_flags = SCF_RSP_R1;
sdhc_exec_command(card.handle, &cmd);
if (cmd.c_error) {
DEBUG("mlc: MMC_SEND_STATUS failed with %d\n", cmd.c_error);
card.inserted = card.selected = 0;
goto out_clock;
}
DPRINTF(2, ("sdcard: MMC_SET_BLOCKLEN\n"));
memset(&cmd, 0, sizeof(cmd));
cmd.c_opcode = MMC_SET_BLOCKLEN;
cmd.c_arg = SDMMC_DEFAULT_BLOCKLEN;
cmd.c_flags = SCF_RSP_R1;
sdhc_exec_command(card.handle, &cmd);
if (cmd.c_error) {
DEBUG("sdcard: MMC_SET_BLOCKLEN failed with %d\n", cmd.c_error);
card.inserted = card.selected = 0;
goto out_clock;
}
DPRINTF(2, ("sdcard: MMC_APP_CMD\n"));
memset(&cmd, 0, sizeof(cmd));
cmd.c_opcode = MMC_APP_CMD;
cmd.c_arg = ((u32)card.rca)<<16;
cmd.c_flags = SCF_RSP_R1;
sdhc_exec_command(card.handle, &cmd);
if (cmd.c_error) {
DEBUG("sdcard: MMC_APP_CMD failed with %d\n", cmd.c_error);
card.inserted = card.selected = 0;
goto out_clock;
}
DPRINTF(2, ("sdcard: SD_APP_SET_BUS_WIDTH\n"));
memset(&cmd, 0, sizeof(cmd));
cmd.c_opcode = SD_APP_SET_BUS_WIDTH;
cmd.c_arg = SD_ARG_BUS_WIDTH_4;
cmd.c_flags = SCF_RSP_R1;
sdhc_exec_command(card.handle, &cmd);
if (cmd.c_error) {
DEBUG("sdcard: SD_APP_SET_BUS_WIDTH failed with %d\n", cmd.c_error);
card.inserted = card.selected = 0;
goto out_clock;
}
sdhc_bus_width(card.handle, 4);
DPRINTF(1, ("sdcard: enabling clock\n"));
if (sdhc_bus_clock(card.handle, SDMMC_SDCLK_25MHZ, SDMMC_TIMING_LEGACY) != 0) {
DEBUG("sdcard: could not enable clock for card\n");
goto out_power;
}
return;
out_clock:
sdhc_bus_width(card.handle, 1);
sdhc_bus_clock(card.handle, SDMMC_SDCLK_OFF, SDMMC_TIMING_LEGACY);
out_power:
sdhc_bus_power(card.handle, 0);
out:
return;
}
int sdcard_select(void)
{
struct sdmmc_command cmd;
DPRINTF(2, ("sdcard: MMC_SELECT_CARD\n"));
memset(&cmd, 0, sizeof(cmd));
cmd.c_opcode = MMC_SELECT_CARD;
cmd.c_arg = ((u32)card.rca)<<16;
cmd.c_flags = SCF_RSP_R1B;
sdhc_exec_command(card.handle, &cmd);
DEBUG("%s: resp=%lx\n", __FUNCTION__, MMC_R1(cmd.c_resp));
// sdhc_dump_regs(card.handle);
// DEBUG("present state = %x\n", HREAD4(hp, SDHC_PRESENT_STATE));
if (cmd.c_error) {
DEBUG("sdcard: MMC_SELECT card failed with %d.\n", cmd.c_error);
return -1;
}
card.selected = 1;
return 0;
}
int sdcard_check_card(void)
{
if (card.inserted == 0)
return SDMMC_NO_CARD;
if (card.new_card == 1)
return SDMMC_NEW_CARD;
return SDMMC_INSERTED;
}
int sdcard_ack_card(void)
{
if (card.new_card == 1) {
card.new_card = 0;
return 0;
}
return -1;
}
int sdcard_start_read(u32 blk_start, u32 blk_count, void *data, struct sdmmc_command* cmdbuf)
{
// DEBUG("%s(%u, %u, %p)\n", __FUNCTION__, blk_start, blk_count, data);
if (card.inserted == 0) {
DEBUG("sdcard: READ: no card inserted.\n");
return -1;
}
if (card.selected == 0) {
if (sdcard_select() < 0) {
DEBUG("sdcard: READ: cannot select card.\n");
return -1;
}
}
if (card.new_card == 1) {
DEBUG("sdcard: new card inserted but not acknowledged yet.\n");
return -1;
}
memset(cmdbuf, 0, sizeof(struct sdmmc_command));
if(blk_count > 1) {
DPRINTF(2, ("sdcard: MMC_READ_BLOCK_MULTIPLE\n"));
cmdbuf->c_opcode = MMC_READ_BLOCK_MULTIPLE;
} else {
DPRINTF(2, ("sdcard: MMC_READ_BLOCK_SINGLE\n"));
cmdbuf->c_opcode = MMC_READ_BLOCK_SINGLE;
}
if (card.sdhc_blockmode)
cmdbuf->c_arg = blk_start;
else
cmdbuf->c_arg = blk_start * SDMMC_DEFAULT_BLOCKLEN;
cmdbuf->c_data = data;
cmdbuf->c_datalen = blk_count * SDMMC_DEFAULT_BLOCKLEN;
cmdbuf->c_blklen = SDMMC_DEFAULT_BLOCKLEN;
cmdbuf->c_flags = SCF_RSP_R1 | SCF_CMD_READ;
sdhc_async_command(card.handle, cmdbuf);
if (cmdbuf->c_error) {
DEBUG("sdcard: MMC_READ_BLOCK_%s failed with %d\n", blk_count > 1 ? "MULTIPLE" : "SINGLE", cmdbuf->c_error);
return -1;
}
if(blk_count > 1)
DPRINTF(2, ("sdcard: async MMC_READ_BLOCK_MULTIPLE started\n"));
else
DPRINTF(2, ("sdcard: async MMC_READ_BLOCK_SINGLE started\n"));
return 0;
}
int sdcard_end_read(struct sdmmc_command* cmdbuf)
{
// DEBUG("%s(%u, %u, %p)\n", __FUNCTION__, blk_start, blk_count, data);
if (card.inserted == 0) {
DEBUG("sdcard: READ: no card inserted.\n");
return -1;
}
if (card.selected == 0) {
if (sdcard_select() < 0) {
DEBUG("sdcard: READ: cannot select card.\n");
return -1;
}
}
if (card.new_card == 1) {
DEBUG("sdcard: new card inserted but not acknowledged yet.\n");
return -1;
}
sdhc_async_response(card.handle, cmdbuf);
if (cmdbuf->c_error) {
DEBUG("sdcard: MMC_READ_BLOCK_%s failed with %d\n", cmdbuf->c_opcode == MMC_READ_BLOCK_MULTIPLE ? "MULTIPLE" : "SINGLE", cmdbuf->c_error);
return -1;
}
if(cmdbuf->c_opcode == MMC_READ_BLOCK_MULTIPLE)
DPRINTF(2, ("sdcard: async MMC_READ_BLOCK_MULTIPLE finished\n"));
else
DPRINTF(2, ("sdcard: async MMC_READ_BLOCK_SINGLE finished\n"));
return 0;
}
int sdcard_read(u32 blk_start, u32 blk_count, void *data)
{
struct sdmmc_command cmd;
// DEBUG("%s(%u, %u, %p)\n", __FUNCTION__, blk_start, blk_count, data);
if (card.inserted == 0) {
DEBUG("sdcard: READ: no card inserted.\n");
return -1;
}
if (card.selected == 0) {
if (sdcard_select() < 0) {
DEBUG("sdcard: READ: cannot select card.\n");
return -1;
}
}
if (card.new_card == 1) {
DEBUG("sdcard: new card inserted but not acknowledged yet.\n");
return -1;
}
memset(&cmd, 0, sizeof(cmd));
if(blk_count > 1) {
DPRINTF(2, ("sdcard: MMC_READ_BLOCK_MULTIPLE\n"));
cmd.c_opcode = MMC_READ_BLOCK_MULTIPLE;
} else {
DPRINTF(2, ("sdcard: MMC_READ_BLOCK_SINGLE\n"));
cmd.c_opcode = MMC_READ_BLOCK_SINGLE;
}
if (card.sdhc_blockmode)
cmd.c_arg = blk_start;
else
cmd.c_arg = blk_start * SDMMC_DEFAULT_BLOCKLEN;
cmd.c_data = data;
cmd.c_datalen = blk_count * SDMMC_DEFAULT_BLOCKLEN;
cmd.c_blklen = SDMMC_DEFAULT_BLOCKLEN;
cmd.c_flags = SCF_RSP_R1 | SCF_CMD_READ;
sdhc_exec_command(card.handle, &cmd);
if (cmd.c_error) {
DEBUG("sdcard: MMC_READ_BLOCK_%s failed with %d\n", blk_count > 1 ? "MULTIPLE" : "SINGLE", cmd.c_error);
return -1;
}
if(blk_count > 1)
DPRINTF(2, ("sdcard: MMC_READ_BLOCK_MULTIPLE done\n"));
else
DPRINTF(2, ("sdcard: MMC_READ_BLOCK_SINGLE done\n"));
return 0;
}
#ifndef LOADER
int sdcard_start_write(u32 blk_start, u32 blk_count, void *data, struct sdmmc_command* cmdbuf)
{
if (card.inserted == 0) {
DEBUG("sdcard: WRITE: no card inserted.\n");
return -1;
}
if (card.selected == 0) {
if (sdcard_select() < 0) {
DEBUG("sdcard: WRITE: cannot select card.\n");
return -1;
}
}
if (card.new_card == 1) {
DEBUG("sdcard: new card inserted but not acknowledged yet.\n");
return -1;
}
memset(cmdbuf, 0, sizeof(struct sdmmc_command));
if(blk_count > 1) {
DPRINTF(2, ("sdcard: MMC_WRITE_BLOCK_MULTIPLE\n"));
cmdbuf->c_opcode = MMC_WRITE_BLOCK_MULTIPLE;
} else {
DPRINTF(2, ("sdcard: MMC_WRITE_BLOCK_SINGLE\n"));
cmdbuf->c_opcode = MMC_WRITE_BLOCK_SINGLE;
}
if (card.sdhc_blockmode)
cmdbuf->c_arg = blk_start;
else
cmdbuf->c_arg = blk_start * SDMMC_DEFAULT_BLOCKLEN;
cmdbuf->c_data = data;
cmdbuf->c_datalen = blk_count * SDMMC_DEFAULT_BLOCKLEN;
cmdbuf->c_blklen = SDMMC_DEFAULT_BLOCKLEN;
cmdbuf->c_flags = SCF_RSP_R1;
sdhc_async_command(card.handle, cmdbuf);
if (cmdbuf->c_error) {
DEBUG("sdcard: MMC_WRITE_BLOCK_%s failed with %d\n", blk_count > 1 ? "MULTIPLE" : "SINGLE", cmdbuf->c_error);
return -1;
}
if(blk_count > 1)
DPRINTF(2, ("sdcard: async MMC_WRITE_BLOCK_MULTIPLE started\n"));
else
DPRINTF(2, ("sdcard: async MMC_WRITE_BLOCK_SINGLE started\n"));
return 0;
}
int sdcard_end_write(struct sdmmc_command* cmdbuf)
{
if (card.inserted == 0) {
DEBUG("sdcard: WRITE: no card inserted.\n");
return -1;
}
if (card.selected == 0) {
if (sdcard_select() < 0) {
DEBUG("sdcard: WRITE: cannot select card.\n");
return -1;
}
}
if (card.new_card == 1) {
DEBUG("sdcard: new card inserted but not acknowledged yet.\n");
return -1;
}
sdhc_async_response(card.handle, cmdbuf);
if (cmdbuf->c_error) {
DEBUG("sdcard: MMC_WRITE_BLOCK_%s failed with %d\n", cmdbuf->c_opcode == MMC_WRITE_BLOCK_MULTIPLE ? "MULTIPLE" : "SINGLE", cmdbuf->c_error);
return -1;
}
if(cmdbuf->c_opcode == MMC_WRITE_BLOCK_MULTIPLE)
DPRINTF(2, ("sdcard: async MMC_WRITE_BLOCK_MULTIPLE finished\n"));
else
DPRINTF(2, ("sdcard: async MMC_WRITE_BLOCK_SINGLE finished\n"));
return 0;
}
int sdcard_write(u32 blk_start, u32 blk_count, void *data)
{
struct sdmmc_command cmd;
if (card.inserted == 0) {
DEBUG("sdcard: WRITE: no card inserted.\n");
return -1;
}
if (card.selected == 0) {
if (sdcard_select() < 0) {
DEBUG("sdcard: WRITE: cannot select card.\n");
return -1;
}
}
if (card.new_card == 1) {
DEBUG("sdcard: new card inserted but not acknowledged yet.\n");
return -1;
}
memset(&cmd, 0, sizeof(cmd));
if(blk_count > 1) {
DPRINTF(2, ("sdcard: MMC_WRITE_BLOCK_MULTIPLE\n"));
cmd.c_opcode = MMC_WRITE_BLOCK_MULTIPLE;
} else {
DPRINTF(2, ("sdcard: MMC_WRITE_BLOCK_SINGLE\n"));
cmd.c_opcode = MMC_WRITE_BLOCK_SINGLE;
}
if (card.sdhc_blockmode)
cmd.c_arg = blk_start;
else
cmd.c_arg = blk_start * SDMMC_DEFAULT_BLOCKLEN;
cmd.c_data = data;
cmd.c_datalen = blk_count * SDMMC_DEFAULT_BLOCKLEN;
cmd.c_blklen = SDMMC_DEFAULT_BLOCKLEN;
cmd.c_flags = SCF_RSP_R1;
sdhc_exec_command(card.handle, &cmd);
if (cmd.c_error) {
DEBUG("sdcard: MMC_WRITE_BLOCK_%s failed with %d\n", blk_count > 1 ? "MULTIPLE" : "SINGLE", cmd.c_error);
return -1;
}
if(blk_count > 1)
DPRINTF(2, ("sdcard: MMC_WRITE_BLOCK_MULTIPLE done\n"));
else
DPRINTF(2, ("sdcard: MMC_WRITE_BLOCK_SINGLE done\n"));
return 0;
}
int sdcard_wait_data(void)
{
struct sdmmc_command cmd;
do
{
DPRINTF(2, ("sdcard: MMC_SEND_STATUS\n"));
memset(&cmd, 0, sizeof(cmd));
cmd.c_opcode = MMC_SEND_STATUS;
cmd.c_arg = ((u32)card.rca)<<16;
cmd.c_flags = SCF_RSP_R1;
sdhc_exec_command(card.handle, &cmd);
if (cmd.c_error) {
DEBUG("sdcard: MMC_SEND_STATUS failed with %d\n", cmd.c_error);
return -1;
}
} while (!ISSET(MMC_R1(cmd.c_resp), MMC_R1_READY_FOR_DATA));
return 0;
}
int sdcard_get_sectors(void)
{
if (card.inserted == 0) {
DEBUG("sdcard: READ: no card inserted.\n");
return -1;
}
if (card.new_card == 1) {
DEBUG("sdcard: new card inserted but not acknowledged yet.\n");
return -1;
}
// sdhc_error(sdhci->reg_base, "num sectors = %u", sdhci->num_sectors);
return card.num_sectors;
}
void sdcard_irq(void)
{
sdhc_intr(&sdcard_host);
}
void sdcard_init(void)
{
struct sdhc_host_params params = {
.attach = &sdcard_attach,
.abort = &sdcard_abort,
.rb = RB_SD0,
.wb = WB_SD0,
};
clear32(LT_GPIO_INTMASK, GP_SDSLOT0_PWR);
set32(LT_GPIO_DIR, GP_SDSLOT0_PWR);
set32(LT_GPIO_ENABLE, GP_SDSLOT0_PWR);
clear32(LT_GPIO_OUT, GP_SDSLOT0_PWR);
udelay(100);
#ifdef CAN_HAZ_IRQ
irq_enable(IRQ_SD0);
#endif
sdhc_host_found(&sdcard_host, &params, 0, SD0_REG_BASE, 1);
}
void sdcard_exit(void)
{
#ifdef CAN_HAZ_IRQ
irq_disable(IRQ_SD0);
#endif
sdhc_shutdown(&sdcard_host);
#ifdef CAN_HAZ_IRQ
irq_disable(IRQ_SD0);
#endif
}
#endif

View File

@ -1,41 +0,0 @@
/*
* minute - a port of the "mini" IOS replacement for the Wii U.
*
* Copyright (C) 2016 SALT
* Copyright (C) 2016 Daz Jones <daz@dazzozo.com>
*
* Copyright (C) 2008, 2009 Sven Peter <svenpeter@gmail.com>
*
* This code is licensed to you under the terms of the GNU GPL, version 2;
* see file COPYING or http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt
*/
#ifndef __SDCARD_H__
#define __SDCARD_H__
#include "bsdtypes.h"
#include "sdmmc.h"
void sdcard_init(void);
void sdcard_exit(void);
void sdcard_irq(void);
void sdcard_attach(sdmmc_chipset_handle_t handle);
void sdcard_needs_discover(void);
int sdcard_wait_data(void);
int sdcard_select(void);
int sdcard_check_card(void);
int sdcard_ack_card(void);
int sdcard_get_sectors(void);
int sdcard_read(u32 blk_start, u32 blk_count, void *data);
int sdcard_write(u32 blk_start, u32 blk_count, void *data);
int sdcard_start_read(u32 blk_start, u32 blk_count, void *data, struct sdmmc_command* cmdbuf);
int sdcard_end_read(struct sdmmc_command* cmdbuf);
int sdcard_start_write(u32 blk_start, u32 blk_count, void *data, struct sdmmc_command* cmdbuf);
int sdcard_end_write(struct sdmmc_command* cmdbuf);
#endif

View File

@ -1,903 +0,0 @@
/*
* Copyright (c) 2006 Uwe Stuehler <uwe@openbsd.org>
* Copyright (c) 2009 Sven Peter <svenpeter@gmail.com>
* Copyright (c) 2016 Daz Jones <daz@dazzozo.com>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
/*
* SD Host Controller driver based on the SD Host Controller Standard
* Simplified Specification Version 1.00 (www.sdcard.com).
*/
#include "bsdtypes.h"
#include "memory.h"
#include "utils.h"
#include "sdmmc.h"
#include "sdhc.h"
#include <string.h>
#include "debug.h"
#ifdef CAN_HAZ_IRQ
#include "irq.h"
#endif
//#define SDHC_DEBUG
#define SDHC_COMMAND_TIMEOUT 500
#define SDHC_TRANSFER_TIMEOUT 5000
#define sdhc_wait_intr(a,b,c) sdhc_wait_intr_debug(__func__, __LINE__, a, b, c)
static inline u32 bus_space_read_4(bus_space_handle_t ioh, u32 reg)
{
return read32(ioh + reg);
}
static inline u16 bus_space_read_2(bus_space_handle_t ioh, u32 reg)
{
if(reg & 3)
return (read32((ioh + reg) & ~3) & 0xffff0000) >> 16;
else
return (read32(ioh + reg) & 0xffff);
}
static inline u8 bus_space_read_1(bus_space_handle_t ioh, u32 reg)
{
u32 mask;
u32 addr;
u8 shift;
shift = (reg & 3) * 8;
mask = (0xFF << shift);
addr = ioh + reg;
return (read32(addr & ~3) & mask) >> shift;
}
static inline void bus_space_write_4(bus_space_handle_t ioh, u32 r, u32 v)
{
write32(ioh + r, v);
}
static inline void bus_space_write_2(bus_space_handle_t ioh, u32 r, u16 v)
{
if(r & 3)
mask32((ioh + r) & ~3, 0xffff0000, v << 16);
else
mask32((ioh + r), 0xffff, ((u32)v));
}
static inline void bus_space_write_1(bus_space_handle_t ioh, u32 r, u8 v)
{
u32 mask;
u32 addr;
u8 shift;
shift = (r & 3) * 8;
mask = (0xFF << shift);
addr = ioh + r;
mask32(addr & ~3, mask, v << shift);
}
/* flag values */
#define SHF_USE_DMA 0x0001
#define HREAD1(hp, reg) \
(bus_space_read_1((hp)->ioh, (reg)))
#define HREAD2(hp, reg) \
(bus_space_read_2((hp)->ioh, (reg)))
#define HREAD4(hp, reg) \
(bus_space_read_4((hp)->ioh, (reg)))
#define HWRITE1(hp, reg, val) \
bus_space_write_1((hp)->ioh, (reg), (val))
#define HWRITE2(hp, reg, val) \
bus_space_write_2((hp)->ioh, (reg), (val))
#define HWRITE4(hp, reg, val) \
bus_space_write_4((hp)->ioh, (reg), (val))
#define HCLR1(hp, reg, bits) \
HWRITE1((hp), (reg), HREAD1((hp), (reg)) & ~(bits))
#define HCLR2(hp, reg, bits) \
HWRITE2((hp), (reg), HREAD2((hp), (reg)) & ~(bits))
#define HSET1(hp, reg, bits) \
HWRITE1((hp), (reg), HREAD1((hp), (reg)) | (bits))
#define HSET2(hp, reg, bits) \
HWRITE2((hp), (reg), HREAD2((hp), (reg)) | (bits))
int sdhc_start_command(struct sdhc_host *, struct sdmmc_command *);
int sdhc_wait_state(struct sdhc_host *, u_int32_t, u_int32_t);
int sdhc_soft_reset(struct sdhc_host *, int);
void sdhc_reset_intr_status(struct sdhc_host *hp);
int sdhc_wait_intr_debug(const char *func, int line, struct sdhc_host *, int, int);
void sdhc_transfer_data(struct sdhc_host *, struct sdmmc_command *);
void sdhc_read_data(struct sdhc_host *, u_char *, int);
void sdhc_write_data(struct sdhc_host *, u_char *, int);
#ifdef SDHC_DEBUG
int sdhcdebug = 3;
#define DPRINTF(n,s) do { if ((n) <= sdhcdebug) printf s; } while (0)
void sdhc_dump_regs(struct sdhc_host *);
#else
#define DPRINTF(n,s) do {} while(0)
#endif
/*
* Called by attachment driver. For each SD card slot there is one SD
* host controller standard register set. (1.3)
*/
int
sdhc_host_found(struct sdhc_host *hp, struct sdhc_host_params *pa, bus_space_tag_t iot, bus_space_handle_t ioh, int usedma)
{
u_int32_t caps;
int error = 1;
int max_clock;
#ifdef SDHC_DEBUG
u_int16_t version;
version = HREAD2(hp, SDHC_HOST_CTL_VERSION);
DEBUG("sdhc: SD Host Specification/Vendor Version ");
switch(SDHC_SPEC_VERSION(version)) {
case 0x00:
DEBUG("1.0/%u\n", SDHC_VENDOR_VERSION(version));
break;
default:
DEBUG(">1.0/%u\n", SDHC_VENDOR_VERSION(version));
break;
}
#endif
memset(hp, 0, sizeof(struct sdhc_host));
/* Fill in the new host structure. */
hp->iot = iot;
hp->ioh = ioh;
hp->data_command = 0;
memcpy(&hp->pa, pa, sizeof(struct sdhc_host_params));
/* Store specification version. */
hp->version = HREAD2(hp, SDHC_HOST_CTL_VERSION);
/*
* Reset the host controller and enable interrupts.
*/
(void)sdhc_host_reset(hp);
/* Determine host capabilities. */
caps = HREAD4(hp, SDHC_CAPABILITIES);
/* Use DMA if the host system and the controller support it. */
if (usedma && ISSET(caps, SDHC_DMA_SUPPORT))
SET(hp->flags, SHF_USE_DMA);
/*
* Determine the base clock frequency. (2.2.24)
*/
if (SDHC_SPEC_VERSION(hp->version) >= SDHC_SPEC_V3) {
/* SDHC 3.0 supports 10-255 MHz. */
max_clock = 255000;
if (SDHC_BASE_FREQ_KHZ_V3(caps) != 0)
hp->clkbase = SDHC_BASE_FREQ_KHZ_V3(caps);
} else {
/* SDHC 1.0/2.0 supports only 10-63 MHz. */
max_clock = 63000;
if (SDHC_BASE_FREQ_KHZ(caps) != 0)
hp->clkbase = SDHC_BASE_FREQ_KHZ(caps);
}
if (hp->clkbase == 0) {
/* The attachment driver must tell us. */
DEBUG("sdhc: base clock frequency unknown\n");
goto err;
} else if (hp->clkbase < 10000 || hp->clkbase > max_clock) {
DEBUG("sdhc: base clock frequency out of range: %u MHz\n",
hp->clkbase / 1000);
goto err;
}
DEBUG("sdhc: SDHC %d.0, %d MHz base clock\n",
SDHC_SPEC_VERSION(hp->version) + 1, hp->clkbase / 1000);
/*
* Determine SD bus voltage levels supported by the controller.
*/
if (ISSET(caps, SDHC_VOLTAGE_SUPP_1_8V))
SET(hp->ocr, MMC_OCR_1_9V_2_0V);
if (ISSET(caps, SDHC_VOLTAGE_SUPP_3_0V))
SET(hp->ocr, MMC_OCR_2_9V_3_0V | MMC_OCR_3_0V_3_1V);
if (ISSET(caps, SDHC_VOLTAGE_SUPP_3_3V))
SET(hp->ocr, MMC_OCR_3_2V_3_3V | MMC_OCR_3_3V_3_4V);
/*
* Attach the generic SD/MMC bus driver. (The bus driver must
* not invoke any chipset functions before it is attached.)
*/
hp->pa.attach(hp);
return 0;
err:
return (error);
}
#ifndef LOADER
/*
* Shutdown hook established by or called from attachment driver.
*/
void
sdhc_shutdown(struct sdhc_host *hp)
{
/* XXX chip locks up if we don't disable it before reboot. */
(void)sdhc_host_reset(hp);
}
#endif
/*
* Reset the host controller. Called during initialization, when
* cards are removed, upon resume, and during error recovery.
*/
int
sdhc_host_reset(struct sdhc_host *hp)
{
u_int16_t imask;
int error;
/* Disable all interrupts. */
HWRITE2(hp, SDHC_NINTR_SIGNAL_EN, 0);
/*
* Reset the entire host controller and wait up to 100ms for
* the controller to clear the reset bit.
*/
if ((error = sdhc_soft_reset(hp, SDHC_RESET_ALL)) != 0) {
return (error);
}
/* Set data timeout counter value to max for now. */
HWRITE1(hp, SDHC_TIMEOUT_CTL, SDHC_TIMEOUT_MAX);
/* Enable interrupts. */
imask =
#ifndef LOADER
SDHC_CARD_REMOVAL | SDHC_CARD_INSERTION |
#endif
SDHC_BUFFER_READ_READY | SDHC_BUFFER_WRITE_READY |
SDHC_DMA_INTERRUPT | SDHC_BLOCK_GAP_EVENT |
SDHC_TRANSFER_COMPLETE | SDHC_COMMAND_COMPLETE;
HWRITE2(hp, SDHC_NINTR_STATUS_EN, imask);
HWRITE2(hp, SDHC_EINTR_STATUS_EN, SDHC_EINTR_STATUS_MASK);
HWRITE2(hp, SDHC_NINTR_SIGNAL_EN, imask);
HWRITE2(hp, SDHC_EINTR_SIGNAL_EN, SDHC_EINTR_SIGNAL_MASK);
return 0;
}
/*
* Return non-zero if the card is currently inserted.
*/
int
sdhc_card_detect(struct sdhc_host *hp)
{
return ISSET(HREAD4(hp, SDHC_PRESENT_STATE), SDHC_CARD_INSERTED) ?
1 : 0;
}
/*
* Set or change SD bus voltage and enable or disable SD bus power.
* Return zero on success.
*/
int
sdhc_bus_power(struct sdhc_host *hp, u_int32_t ocr)
{
u_int8_t vdd;
DEBUG("sdhc_bus_power(0x%lx)\n", ocr);
/* Disable bus power before voltage change. */
HWRITE1(hp, SDHC_POWER_CTL, 0);
/* If power is disabled, reset the host and return now. */
if (ocr == 0) {
(void)sdhc_host_reset(hp);
return 0;
}
/*
* Select the maximum voltage according to capabilities.
*/
ocr &= hp->ocr;
if (ISSET(ocr, MMC_OCR_3_2V_3_3V|MMC_OCR_3_3V_3_4V))
vdd = SDHC_VOLTAGE_3_3V;
else if (ISSET(ocr, MMC_OCR_2_9V_3_0V|MMC_OCR_3_0V_3_1V))
vdd = SDHC_VOLTAGE_3_0V;
else if (ISSET(ocr, MMC_OCR_1_9V_2_0V))
vdd = SDHC_VOLTAGE_1_8V;
else {
/* Unsupported voltage level requested. */
return EINVAL;
}
/*
* Enable bus power. Wait at least 1 ms (or 74 clocks) plus
* voltage ramp until power rises.
*/
HWRITE1(hp, SDHC_POWER_CTL, (vdd << SDHC_VOLTAGE_SHIFT) |
SDHC_BUS_POWER);
udelay(10000);
/*
* The host system may not power the bus due to battery low,
* etc. In that case, the host controller should clear the
* bus power bit.
*/
if (!ISSET(HREAD1(hp, SDHC_POWER_CTL), SDHC_BUS_POWER)) {
DEBUG("Host controller failed to enable bus power\n");
return ENXIO;
}
return 0;
}
/*
* Return the smallest possible base clock frequency divisor value
* for the CLOCK_CTL register to produce `freq' (KHz).
*/
static int
sdhc_clock_divisor(struct sdhc_host *hp, u_int freq)
{
int max_div = 256;
int div;
if (SDHC_SPEC_VERSION(hp->version) >= SDHC_SPEC_V3)
max_div = 2046;
for (div = 1; div <= max_div; div *= 2)
if ((hp->clkbase / div) <= freq)
return (div / 2);
/* No divisor found. */
return -1;
}
/*
* Set or change SDCLK frequency or disable the SD clock.
* Return zero on success.
*/
int
sdhc_bus_clock(struct sdhc_host *hp, int freq, int timing)
{
int div;
int timo;
int sdclk;
DEBUG("%s(%d, %d)\n", __FUNCTION__, freq, timing);
#ifdef DIAGNOSTIC
/* Must not stop the clock if commands are in progress. */
if (ISSET(HREAD4(hp, SDHC_PRESENT_STATE), SDHC_CMD_INHIBIT_MASK) &&
sdhc_card_detect(hp))
DEBUG("sdhc_sdclk_frequency_select: command in progress\n");
#endif
/* Stop SD clock before changing the frequency. */
HWRITE2(hp, SDHC_CLOCK_CTL, 0);
if (freq == SDMMC_SDCLK_OFF)
return 0;
if (timing == SDMMC_TIMING_LEGACY)
HCLR1(hp, SDHC_HOST_CTL, SDHC_HIGH_SPEED);
else
HSET1(hp, SDHC_HOST_CTL, SDHC_HIGH_SPEED);
/* Set the minimum base clock frequency divisor. */
if ((div = sdhc_clock_divisor(hp, freq)) < 0) {
/* Invalid base clock frequency or `freq' value. */
return EINVAL;
}
if (SDHC_SPEC_VERSION(hp->version) >= SDHC_SPEC_V3)
sdclk = SDHC_SDCLK_DIV_V3(div);
else
sdclk = SDHC_SDCLK_DIV(div);
HWRITE2(hp, SDHC_CLOCK_CTL, sdclk);
/* Start internal clock. Wait 10ms for stabilization. */
HSET2(hp, SDHC_CLOCK_CTL, SDHC_INTCLK_ENABLE);
for (timo = 1000; timo > 0; timo--) {
if (ISSET(HREAD2(hp, SDHC_CLOCK_CTL), SDHC_INTCLK_STABLE))
break;
udelay(10);
}
if (timo == 0) {
DEBUG("sdhc: internal clock never stabilized\n");
return ETIMEDOUT;
}
/* Enable SD clock. */
HSET2(hp, SDHC_CLOCK_CTL, SDHC_SDCLK_ENABLE);
return 0;
}
int
sdhc_bus_width(struct sdhc_host *hp, int width)
{
int reg;
DEBUG("%s(%d)\n", __FUNCTION__, width);
if (width != 1 && width != 4 && width != 8)
return EINVAL;
reg = HREAD1(hp, SDHC_HOST_CTL);
reg &= ~(SDHC_4BIT_MODE | SDHC_8BIT_MODE);
if (width == 4) {
reg |= SDHC_4BIT_MODE;
} else if (width == 8) {
reg |= SDHC_8BIT_MODE;
}
HWRITE1(hp, SDHC_HOST_CTL, reg);
return 0;
}
void
sdhc_card_intr_mask(struct sdhc_host *hp, int enable)
{
if (enable) {
HSET2(hp, SDHC_NINTR_STATUS_EN, SDHC_CARD_INTERRUPT);
HSET2(hp, SDHC_NINTR_SIGNAL_EN, SDHC_CARD_INTERRUPT);
} else {
HCLR2(hp, SDHC_NINTR_SIGNAL_EN, SDHC_CARD_INTERRUPT);
HCLR2(hp, SDHC_NINTR_STATUS_EN, SDHC_CARD_INTERRUPT);
}
}
void
sdhc_card_intr_ack(struct sdhc_host *hp)
{
HSET2(hp, SDHC_NINTR_STATUS_EN, SDHC_CARD_INTERRUPT);
}
int
sdhc_wait_state(struct sdhc_host *hp, u_int32_t mask, u_int32_t value)
{
u_int32_t state;
int timeout;
for (timeout = 500; timeout > 0; timeout--) {
if (((state = HREAD4(hp, SDHC_PRESENT_STATE)) & mask)
== value)
return 0;
udelay(10000);
}
DPRINTF(0,("sdhc: timeout waiting for %x (state=%d)\n", value, state));
return ETIMEDOUT;
}
void
sdhc_exec_command(struct sdhc_host *hp, struct sdmmc_command *cmd)
{
int error;
if (cmd->c_datalen > 0)
hp->data_command = 1;
if (cmd->c_timeout == 0) {
if (cmd->c_datalen > 0)
cmd->c_timeout = SDHC_TRANSFER_TIMEOUT;
else
cmd->c_timeout = SDHC_COMMAND_TIMEOUT;
}
hp->intr_status = 0;
/*
* Start the MMC command, or mark `cmd' as failed and return.
*/
error = sdhc_start_command(hp, cmd);
if (error != 0) {
cmd->c_error = error;
SET(cmd->c_flags, SCF_ITSDONE);
hp->data_command = 0;
return;
}
/*
* Wait until the command phase is done, or until the command
* is marked done for any other reason.
*/
int status = sdhc_wait_intr(hp, SDHC_COMMAND_COMPLETE, cmd->c_timeout);
if (!ISSET(status, SDHC_COMMAND_COMPLETE)) {
cmd->c_error = ETIMEDOUT;
DEBUG("timeout dump: error_intr: 0x%x intr: 0x%x\n", hp->intr_error_status, hp->intr_status);
// sdhc_dump_regs(hp);
SET(cmd->c_flags, SCF_ITSDONE);
hp->data_command = 0;
return;
}
// DEBUG("command_complete, continuing...\n");
/*
* The host controller removes bits [0:7] from the response
* data (CRC) and we pass the data up unchanged to the bus
* driver (without padding).
*/
if (cmd->c_error == 0 && ISSET(cmd->c_flags, SCF_RSP_PRESENT)) {
if (ISSET(cmd->c_flags, SCF_RSP_136)) {
u_char *p = (u_char *)cmd->c_resp;
int i;
for (i = 0; i < 15; i++)
*p++ = HREAD1(hp, SDHC_RESPONSE + i);
} else
cmd->c_resp[0] = HREAD4(hp, SDHC_RESPONSE);
}
/*
* If the command has data to transfer in any direction,
* execute the transfer now.
*/
if (cmd->c_error == 0 && cmd->c_datalen > 0)
sdhc_transfer_data(hp, cmd);
DPRINTF(1,("sdhc: cmd %u done (flags=%#x error=%d prev state=%d)\n",
cmd->c_opcode, cmd->c_flags, cmd->c_error, (cmd->c_resp[0] >> 9) & 15));
SET(cmd->c_flags, SCF_ITSDONE);
hp->data_command = 0;
}
int
sdhc_start_command(struct sdhc_host *hp, struct sdmmc_command *cmd)
{
u_int16_t blksize = 0;
u_int16_t blkcount = 0;
u_int16_t mode;
u_int16_t command;
int error;
DPRINTF(1,("sdhc: start cmd %u arg=%#x data=%p dlen=%d flags=%#x\n",
cmd->c_opcode, cmd->c_arg, cmd->c_data, cmd->c_datalen, cmd->c_flags));
/*
* The maximum block length for commands should be the minimum
* of the host buffer size and the card buffer size. (1.7.2)
*/
/* Fragment the data into proper blocks. */
if (cmd->c_datalen > 0) {
blksize = MIN(cmd->c_datalen, cmd->c_blklen);
blkcount = cmd->c_datalen / blksize;
if (cmd->c_datalen % blksize > 0) {
/* XXX: Split this command. (1.7.4) */
DEBUG("sdhc: data not a multiple of %d bytes\n", blksize);
return EINVAL;
}
}
/* Check limit imposed by 9-bit block count. (1.7.2) */
if (blkcount > SDHC_BLOCK_COUNT_MAX) {
DEBUG("sdhc: too much data\n");
return EINVAL;
}
/* Prepare transfer mode register value. (2.2.5) */
mode = 0;
if (ISSET(cmd->c_flags, SCF_CMD_READ))
mode |= SDHC_READ_MODE;
if (blkcount > 0) {
mode |= SDHC_BLOCK_COUNT_ENABLE;
if (blkcount > 1) {
mode |= SDHC_MULTI_BLOCK_MODE;
/* XXX only for memory commands? */
mode |= SDHC_AUTO_CMD12_ENABLE;
}
}
if (ISSET(hp->flags, SHF_USE_DMA))
mode |= SDHC_DMA_ENABLE;
/*
* Prepare command register value. (2.2.6)
*/
command = (cmd->c_opcode & SDHC_COMMAND_INDEX_MASK) <<
SDHC_COMMAND_INDEX_SHIFT;
if (ISSET(cmd->c_flags, SCF_RSP_CRC))
command |= SDHC_CRC_CHECK_ENABLE;
if (ISSET(cmd->c_flags, SCF_RSP_IDX))
command |= SDHC_INDEX_CHECK_ENABLE;
if (cmd->c_data != NULL)
command |= SDHC_DATA_PRESENT_SELECT;
if (!ISSET(cmd->c_flags, SCF_RSP_PRESENT))
command |= SDHC_NO_RESPONSE;
else if (ISSET(cmd->c_flags, SCF_RSP_136))
command |= SDHC_RESP_LEN_136;
else if (ISSET(cmd->c_flags, SCF_RSP_BSY))
command |= SDHC_RESP_LEN_48_CHK_BUSY;
else
command |= SDHC_RESP_LEN_48;
/* Wait until command and data inhibit bits are clear. (1.5) */
if ((error = sdhc_wait_state(hp, SDHC_CMD_INHIBIT_MASK, 0)) != 0)
return error;
if (ISSET(hp->flags, SHF_USE_DMA) && cmd->c_datalen > 0) {
cmd->c_resid = blkcount;
cmd->c_buf = cmd->c_data;
if (ISSET(cmd->c_flags, SCF_CMD_READ) == 0) {
dc_flushrange(cmd->c_data, cmd->c_datalen);
ahb_flush_to(hp->pa.rb);
}
HWRITE4(hp, SDHC_DMA_ADDR, (u32)cmd->c_data);
}
DPRINTF(1,("sdhc: cmd=%#x mode=%#x blksize=%d blkcount=%d\n",
command, mode, blksize, blkcount));
/*
* Start a CPU data transfer. Writing to the high order byte
* of the SDHC_COMMAND register triggers the SD command. (1.5)
*/
// HWRITE2(hp, SDHC_TRANSFER_MODE, mode);
HWRITE2(hp, SDHC_BLOCK_SIZE, blksize | 7 << 12);
HWRITE2(hp, SDHC_BLOCK_COUNT, blkcount);
HWRITE4(hp, SDHC_ARGUMENT, cmd->c_arg);
// http://wiibrew.org/wiki/Reversed_Little_Endian
// HWRITE2(hp, SDHC_COMMAND, command);
HWRITE4(hp, SDHC_TRANSFER_MODE, ((u32)command << 16) | mode);
return 0;
}
void
sdhc_transfer_data(struct sdhc_host *hp, struct sdmmc_command *cmd)
{
int error;
int status;
error = 0;
DPRINTF(1,("resp=%#x datalen=%d\n", MMC_R1(cmd->c_resp), cmd->c_datalen));
if (ISSET(hp->flags, SHF_USE_DMA)) {
for(;;) {
status = sdhc_wait_intr(hp, SDHC_TRANSFER_COMPLETE |
SDHC_DMA_INTERRUPT,
SDHC_TRANSFER_TIMEOUT);
if (!status) {
DEBUG("DMA timeout %08x\n", status);
error = ETIMEDOUT;
break;
}
if (ISSET(status, SDHC_TRANSFER_COMPLETE)) {
// DEBUG("got a TRANSFER_COMPLETE: %08x\n", status);
break;
}
}
} else
DEBUG("fail.\n");
#ifdef SDHC_DEBUG
/* XXX I forgot why I wanted to know when this happens :-( */
if ((cmd->c_opcode == 52 || cmd->c_opcode == 53) &&
ISSET(MMC_R1(cmd->c_resp), 0xcb00))
DEBUG("sdhc: CMD52/53 error response flags %#x\n",
MMC_R1(cmd->c_resp) & 0xff00);
#endif
if (ISSET(cmd->c_flags, SCF_CMD_READ)) {
ahb_flush_from(hp->pa.wb);
dc_invalidaterange(cmd->c_data, cmd->c_datalen);
}
if (error != 0)
cmd->c_error = error;
SET(cmd->c_flags, SCF_ITSDONE);
DPRINTF(1,("sdhc: data transfer done (error=%d)\n", cmd->c_error));
return;
}
/* Prepare for another command. */
int
sdhc_soft_reset(struct sdhc_host *hp, int mask)
{
int timo;
DPRINTF(1,("sdhc: software reset reg=%#x\n", mask));
HWRITE1(hp, SDHC_SOFTWARE_RESET, mask);
for (timo = 10; timo > 0; timo--) {
if (!ISSET(HREAD1(hp, SDHC_SOFTWARE_RESET), mask))
break;
udelay(10000);
HWRITE1(hp, SDHC_SOFTWARE_RESET, 0);
}
if (timo == 0) {
DPRINTF(1,("sdhc: timeout reg=%#x\n", HREAD1(hp, SDHC_SOFTWARE_RESET)));
HWRITE1(hp, SDHC_SOFTWARE_RESET, 0);
return (ETIMEDOUT);
}
return (0);
}
int
sdhc_wait_intr_debug(const char *funcname, int line, struct sdhc_host *hp, int mask, int timo)
{
(void) funcname;
(void) line;
int status;
mask |= SDHC_ERROR_INTERRUPT;
mask |= SDHC_ERROR_TIMEOUT;
status = hp->intr_status & mask;
for (; timo > 0; timo--) {
#ifdef CAN_HAZ_IRQ
if((get_cpsr() & 0b11111) == 0b10010)
#endif
sdhc_intr(hp); // seems backwards but ok
if (hp->intr_status != 0) {
status = hp->intr_status & mask;
break;
}
udelay(1000);
}
if (timo == 0) {
status |= SDHC_ERROR_TIMEOUT;
}
hp->intr_status &= ~status;
DPRINTF(2,("sdhc: funcname=%s, line=%d, timo=%d status=%#x intr status=%#x error %#x\n",
funcname, line, timo, status, hp->intr_status, hp->intr_error_status));
/* Command timeout has higher priority than command complete. */
if (ISSET(status, SDHC_ERROR_INTERRUPT)) {
DEBUG("resetting due to error interrupt\n");
// sdhc_dump_regs(hp);
hp->intr_error_status = 0;
(void)sdhc_soft_reset(hp, SDHC_RESET_DAT|SDHC_RESET_CMD);
status = 0;
}
/* Command timeout has higher priority than command complete. */
if (ISSET(status, SDHC_ERROR_TIMEOUT)) {
DEBUG("resetting due to timeout\n");
// sdhc_dump_regs(hp);
hp->intr_error_status = 0;
(void)sdhc_soft_reset(hp, SDHC_RESET_DAT|SDHC_RESET_CMD);
status = 0;
}
return status;
}
/*
* Established by attachment driver at interrupt priority IPL_SDMMC.
*/
int
sdhc_intr(struct sdhc_host *hp)
{
u_int16_t status;
u_int16_t error;
u_int16_t signal;
DPRINTF(1,("sdhc_intr():\n"));
// sdhc_dump_regs(hp);
/* Find out which interrupts are pending. */
status = HREAD2(hp, SDHC_NINTR_STATUS);
if (!ISSET(status, SDHC_NINTR_STATUS_MASK)) {
DPRINTF(1, ("unknown interrupt\n"));
return 0;
}
error = HREAD2(hp, SDHC_EINTR_STATUS);
signal = HREAD2(hp, SDHC_EINTR_SIGNAL_EN);
/* Acknowledge the interrupts we are about to handle. */
HWRITE2(hp, SDHC_NINTR_STATUS, status);
DPRINTF(2,("sdhc: interrupt status=%d\n", status));
/* Service error interrupts. */
if (ISSET(status, SDHC_ERROR_INTERRUPT)) {
/* Acknowledge error interrupts. */
HWRITE2(hp, SDHC_EINTR_SIGNAL_EN, 0);
(void)sdhc_soft_reset(hp, SDHC_RESET_DAT|SDHC_RESET_CMD);
if (hp->data_command == 1) {
hp->data_command = 0;
hp->pa.abort();
}
HWRITE2(hp, SDHC_EINTR_STATUS, error);
HWRITE2(hp, SDHC_EINTR_SIGNAL_EN, signal);
DPRINTF(2,("sdhc: error interrupt, status=0x%x, signal=0x%x\n", error, signal));
if (ISSET(error, SDHC_CMD_TIMEOUT_ERROR|
SDHC_DATA_TIMEOUT_ERROR)) {
hp->intr_error_status |= error;
hp->intr_status |= status;
}
}
/*
* Wake up the blocking process to service command
* related interrupt(s).
*/
if (ISSET(status, SDHC_BUFFER_READ_READY|
SDHC_BUFFER_WRITE_READY|SDHC_COMMAND_COMPLETE|
SDHC_TRANSFER_COMPLETE)) {
hp->intr_status |= status;
}
if (ISSET(status, SDHC_DMA_INTERRUPT)) {
DPRINTF(2,("sdhc: dma left:%#x\n", HREAD2(hp, SDHC_BLOCK_COUNT)));
// this works because our virtual memory
// addresses are equal to the physical memory
// addresses and because we require the target
// buffer to be contiguous
HWRITE4(hp, SDHC_DMA_ADDR, HREAD4(hp, SDHC_DMA_ADDR));
}
/* Service SD card interrupts. */
if (ISSET(status, SDHC_CARD_INTERRUPT)) {
DPRINTF(0,("sdhc: card interrupt\n"));
HCLR2(hp, SDHC_NINTR_STATUS_EN, SDHC_CARD_INTERRUPT);
}
/*
* Wake up the sdmmc event thread to scan for cards.
*/
if (ISSET(status, SDHC_CARD_REMOVAL|SDHC_CARD_INSERTION))
hp->pa.attach(hp);
return 1;
}
#ifdef SDHC_DEBUG
void
sdhc_dump_regs(struct sdhc_host *hp)
{
DEBUG("0x%02x PRESENT_STATE: %x\n", SDHC_PRESENT_STATE,
HREAD4(hp, SDHC_PRESENT_STATE));
DEBUG("0x%02x POWER_CTL: %x\n", SDHC_POWER_CTL,
HREAD1(hp, SDHC_POWER_CTL));
DEBUG("0x%02x NINTR_STATUS: %x\n", SDHC_NINTR_STATUS,
HREAD2(hp, SDHC_NINTR_STATUS));
DEBUG("0x%02x EINTR_STATUS: %x\n", SDHC_EINTR_STATUS,
HREAD2(hp, SDHC_EINTR_STATUS));
DEBUG("0x%02x NINTR_STATUS_EN: %x\n", SDHC_NINTR_STATUS_EN,
HREAD2(hp, SDHC_NINTR_STATUS_EN));
DEBUG("0x%02x EINTR_STATUS_EN: %x\n", SDHC_EINTR_STATUS_EN,
HREAD2(hp, SDHC_EINTR_STATUS_EN));
DEBUG("0x%02x NINTR_SIGNAL_EN: %x\n", SDHC_NINTR_SIGNAL_EN,
HREAD2(hp, SDHC_NINTR_SIGNAL_EN));
DEBUG("0x%02x EINTR_SIGNAL_EN: %x\n", SDHC_EINTR_SIGNAL_EN,
HREAD2(hp, SDHC_EINTR_SIGNAL_EN));
DEBUG("0x%02x CAPABILITIES: %x\n", SDHC_CAPABILITIES,
HREAD4(hp, SDHC_CAPABILITIES));
DEBUG("0x%02x MAX_CAPABILITIES: %x\n", SDHC_MAX_CAPABILITIES,
HREAD4(hp, SDHC_MAX_CAPABILITIES));
}
#endif

View File

@ -1,233 +0,0 @@
/* $OpenBSD: sdhcvar.h,v 1.3 2007/09/06 08:01:01 jsg Exp $ */
/*
* Copyright (c) 2006 Uwe Stuehler <uwe@openbsd.org>
* Copyright (c) 2009 Sven Peter <svenpeter@gmail.com>
* Copyright (c) 2016 Daz Jones <daz@dazzozo.com>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#ifndef _SDHCVAR_H_
#define _SDHCVAR_H_
#include "bsdtypes.h"
#include "memory.h"
#include "sdmmc.h"
struct sdhc_host_params {
void (*attach)();
void (*abort)();
enum rb_client rb;
enum wb_client wb;
};
struct sdhc_host {
bus_space_tag_t iot; /* host register set tag */
bus_space_handle_t ioh; /* host register set handle */
u_int16_t version; /* specification version */
u_int clkbase; /* base clock frequency in KHz */
int flags; /* flags for this host */
u_int32_t ocr; /* OCR value from capabilities */
u_int8_t regs[14]; /* host controller state */
volatile u_int16_t intr_status; /* soft interrupt status */
volatile u_int16_t intr_error_status; /* soft error status */
int data_command;
struct sdhc_host_params pa;
};
/* Host controller functions called by the attachment driver. */
int sdhc_host_found(struct sdhc_host *, struct sdhc_host_params *, bus_space_tag_t, bus_space_handle_t, int);
void sdhc_power(int, void *);
void sdhc_shutdown(struct sdhc_host *);
int sdhc_intr(struct sdhc_host *);
/* Host standard register set */
#define SDHC_DMA_ADDR 0x00
#define SDHC_BLOCK_SIZE 0x04
#define SDHC_BLOCK_COUNT 0x06
#define SDHC_BLOCK_COUNT_MAX 512
#define SDHC_ARGUMENT 0x08
#define SDHC_TRANSFER_MODE 0x0c
#define SDHC_MULTI_BLOCK_MODE (1<<5)
#define SDHC_READ_MODE (1<<4)
#define SDHC_AUTO_CMD12_ENABLE (1<<2)
#define SDHC_BLOCK_COUNT_ENABLE (1<<1)
#define SDHC_DMA_ENABLE (1<<0)
#define SDHC_COMMAND 0x0e
/* 14-15 reserved */
#define SDHC_COMMAND_INDEX_SHIFT 8
#define SDHC_COMMAND_INDEX_MASK 0x3f
#define SDHC_COMMAND_TYPE_ABORT (3<<6)
#define SDHC_COMMAND_TYPE_RESUME (2<<6)
#define SDHC_COMMAND_TYPE_SUSPEND (1<<6)
#define SDHC_COMMAND_TYPE_NORMAL (0<<6)
#define SDHC_DATA_PRESENT_SELECT (1<<5)
#define SDHC_INDEX_CHECK_ENABLE (1<<4)
#define SDHC_CRC_CHECK_ENABLE (1<<3)
/* 2 reserved */
#define SDHC_RESP_LEN_48_CHK_BUSY (3<<0)
#define SDHC_RESP_LEN_48 (2<<0)
#define SDHC_RESP_LEN_136 (1<<0)
#define SDHC_NO_RESPONSE (0<<0)
#define SDHC_RESPONSE 0x10 /* - 0x1f */
#define SDHC_DATA 0x20
#define SDHC_PRESENT_STATE 0x24
/* 25-31 reserved */
#define SDHC_CMD_LINE_SIGNAL_LEVEL (1<<24)
#define SDHC_DAT3_LINE_LEVEL (1<<23)
#define SDHC_DAT2_LINE_LEVEL (1<<22)
#define SDHC_DAT1_LINE_LEVEL (1<<21)
#define SDHC_DAT0_LINE_LEVEL (1<<20)
#define SDHC_WRITE_PROTECT_SWITCH (1<<19)
#define SDHC_CARD_DETECT_PIN_LEVEL (1<<18)
#define SDHC_CARD_STATE_STABLE (1<<17)
#define SDHC_CARD_INSERTED (1<<16)
/* 12-15 reserved */
#define SDHC_BUFFER_READ_ENABLE (1<<11)
#define SDHC_BUFFER_WRITE_ENABLE (1<<10)
#define SDHC_READ_TRANSFER_ACTIVE (1<<9)
#define SDHC_WRITE_TRANSFER_ACTIVE (1<<8)
/* 3-7 reserved */
#define SDHC_DAT_ACTIVE (1<<2)
#define SDHC_CMD_INHIBIT_DAT (1<<1)
#define SDHC_CMD_INHIBIT_CMD (1<<0)
#define SDHC_CMD_INHIBIT_MASK 0x0003
#define SDHC_HOST_CTL 0x28
#define SDHC_8BIT_MODE (1<<5)
#define SDHC_HIGH_SPEED (1<<2)
#define SDHC_4BIT_MODE (1<<1)
#define SDHC_LED_ON (1<<0)
#define SDHC_POWER_CTL 0x29
#define SDHC_VOLTAGE_SHIFT 1
#define SDHC_VOLTAGE_MASK 0x07
#define SDHC_VOLTAGE_3_3V 0x07
#define SDHC_VOLTAGE_3_0V 0x06
#define SDHC_VOLTAGE_1_8V 0x05
#define SDHC_BUS_POWER (1<<0)
#define SDHC_BLOCK_GAP_CTL 0x2a
#define SDHC_WAKEUP_CTL 0x2b
#define SDHC_CLOCK_CTL 0x2c
#define SDHC_SDCLK_DIV_SHIFT 8
#define SDHC_SDCLK_DIV_MASK 0xff
#define SDHC_SDCLK_DIV_RSHIFT_V3 2
#define SDHC_SDCLK_DIV_MASK_V3 0x300
#define SDHC_SDCLK_ENABLE (1<<2)
#define SDHC_INTCLK_STABLE (1<<1)
#define SDHC_INTCLK_ENABLE (1<<0)
#define SDHC_TIMEOUT_CTL 0x2e
#define SDHC_TIMEOUT_MAX 0x0e
#define SDHC_SOFTWARE_RESET 0x2f
#define SDHC_RESET_MASK 0x5
#define SDHC_RESET_DAT (1<<2)
#define SDHC_RESET_CMD (1<<1)
#define SDHC_RESET_ALL (1<<0)
#define SDHC_NINTR_STATUS 0x30
#define SDHC_ERROR_INTERRUPT (1<<15)
#define SDHC_ERROR_TIMEOUT (1<<14)
#define SDHC_CARD_INTERRUPT (1<<8)
#define SDHC_CARD_REMOVAL (1<<7)
#define SDHC_CARD_INSERTION (1<<6)
#define SDHC_BUFFER_READ_READY (1<<5)
#define SDHC_BUFFER_WRITE_READY (1<<4)
#define SDHC_DMA_INTERRUPT (1<<3)
#define SDHC_BLOCK_GAP_EVENT (1<<2)
#define SDHC_TRANSFER_COMPLETE (1<<1)
#define SDHC_COMMAND_COMPLETE (1<<0)
#define SDHC_NINTR_STATUS_MASK 0x81ff
#define SDHC_EINTR_STATUS 0x32
#define SDHC_ADMA_ERROR (1<<9)
#define SDHC_AUTO_CMD12_ERROR (1<<8)
#define SDHC_CURRENT_LIMIT_ERROR (1<<7)
#define SDHC_DATA_END_BIT_ERROR (1<<6)
#define SDHC_DATA_CRC_ERROR (1<<5)
#define SDHC_DATA_TIMEOUT_ERROR (1<<4)
#define SDHC_DATA_ERROR 0x70
#define SDHC_CMD_INDEX_ERROR (1<<3)
#define SDHC_CMD_END_BIT_ERROR (1<<2)
#define SDHC_CMD_CRC_ERROR (1<<1)
#define SDHC_CMD_TIMEOUT_ERROR (1<<0)
#define SDHC_CMD_ERROR 0x0f
#define SDHC_EINTR_STATUS_MASK 0x03ff /* excluding vendor signals */
#define SDHC_NINTR_STATUS_EN 0x34
#define SDHC_EINTR_STATUS_EN 0x36
#define SDHC_NINTR_SIGNAL_EN 0x38
#define SDHC_NINTR_SIGNAL_MASK 0x01ff
#define SDHC_EINTR_SIGNAL_EN 0x3a
#define SDHC_EINTR_SIGNAL_MASK 0x03ff /* excluding vendor signals */
#define SDHC_CMD12_ERROR_STATUS 0x3c
#define SDHC_CAPABILITIES 0x40
#define SDHC_VOLTAGE_SUPP_1_8V (1<<26)
#define SDHC_VOLTAGE_SUPP_3_0V (1<<25)
#define SDHC_VOLTAGE_SUPP_3_3V (1<<24)
#define SDHC_DMA_SUPPORT (1<<22)
#define SDHC_HIGH_SPEED_SUPP (1<<21)
#define SDHC_BASE_FREQ_SHIFT 8
#define SDHC_BASE_FREQ_MASK 0x3f
#define SDHC_BASE_FREQ_MASK_V3 0xff
#define SDHC_TIMEOUT_FREQ_UNIT (1<<7) /* 0=KHz, 1=MHz */
#define SDHC_TIMEOUT_FREQ_SHIFT 0
#define SDHC_TIMEOUT_FREQ_MASK 0x1f
#define SDHC_MAX_CAPABILITIES 0x48
#define SDHC_SLOT_INTR_STATUS 0xfc
#define SDHC_HOST_CTL_VERSION 0xfe
#define SDHC_SPEC_VERS_SHIFT 0
#define SDHC_SPEC_VERS_MASK 0xff
#define SDHC_VENDOR_VERS_SHIFT 8
#define SDHC_VENDOR_VERS_MASK 0xff
#define SDHC_SPEC_V1 0
#define SDHC_SPEC_V2 1
#define SDHC_SPEC_V3 2
/* SDHC_CLOCK_CTL encoding */
#define SDHC_SDCLK_DIV(div) \
(((div) & SDHC_SDCLK_DIV_MASK) << SDHC_SDCLK_DIV_SHIFT)
#define SDHC_SDCLK_DIV_V3(div) \
(SDHC_SDCLK_DIV(div) | \
(((div) & SDHC_SDCLK_DIV_MASK_V3) >> SDHC_SDCLK_DIV_RSHIFT_V3))
/* SDHC_CAPABILITIES decoding */
#define SDHC_BASE_FREQ_KHZ(cap) \
((((cap) >> SDHC_BASE_FREQ_SHIFT) & SDHC_BASE_FREQ_MASK) * 1000)
#define SDHC_BASE_FREQ_KHZ_V3(cap) \
((((cap) >> SDHC_BASE_FREQ_SHIFT) & SDHC_BASE_FREQ_MASK_V3) * 1000)
#define SDHC_TIMEOUT_FREQ(cap) \
(((cap) >> SDHC_TIMEOUT_FREQ_SHIFT) & SDHC_TIMEOUT_FREQ_MASK)
#define SDHC_TIMEOUT_FREQ_KHZ(cap) \
(((cap) & SDHC_TIMEOUT_FREQ_UNIT) ? \
SDHC_TIMEOUT_FREQ(cap) * 1000: \
SDHC_TIMEOUT_FREQ(cap))
/* SDHC_HOST_CTL_VERSION decoding */
#define SDHC_SPEC_VERSION(hcv) \
(((hcv) >> SDHC_SPEC_VERS_SHIFT) & SDHC_SPEC_VERS_MASK)
#define SDHC_VENDOR_VERSION(hcv) \
(((hcv) >> SDHC_VENDOR_VERS_SHIFT) & SDHC_VENDOR_VERS_MASK)
struct sdmmc_command;
int sdhc_host_reset(struct sdhc_host *hp);
int sdhc_card_detect(struct sdhc_host *hp);
int sdhc_bus_power(struct sdhc_host *hp, u_int32_t);
int sdhc_bus_clock(struct sdhc_host *hp, int, int);
int sdhc_bus_width(struct sdhc_host *hp, int);
void sdhc_card_intr_mask(struct sdhc_host *hp, int);
void sdhc_card_intr_ack(struct sdhc_host *hp);
void sdhc_exec_command(struct sdhc_host *hp, struct sdmmc_command *);
void sdhc_async_command(struct sdhc_host *hp, struct sdmmc_command *);
void sdhc_async_response(struct sdhc_host *hp, struct sdmmc_command *);
#endif

View File

@ -1,372 +0,0 @@
/*
* minute - a port of the "mini" IOS replacement for the Wii U.
*
* Copyright (C) 2016 SALT
* Copyright (C) 2016 Daz Jones <daz@dazzozo.com>
*
* Copyright (C) 2008, 2009 Sven Peter <svenpeter@gmail.com>
*
* This code is licensed to you under the terms of the GNU GPL, version 2;
* see file COPYING or http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt
*/
#ifndef __SDMMC_H__
#define __SDMMC_H__
#include "bsdtypes.h"
struct sdmmc_command;
typedef struct sdhc_host * sdmmc_chipset_handle_t;
/* clock frequencies for sdmmc_chip_bus_clock() */
#define SDMMC_SDCLK_OFF 0
#define SDMMC_SDCLK_400KHZ 400
#define SDMMC_SDCLK_25MHZ 25000
#define SDMMC_TIMING_LEGACY 0
#define SDMMC_TIMING_HIGHSPEED 1
struct sdmmc_csd {
int csdver; /* CSD structure format */
int mmcver; /* MMC version (for CID format) */
int capacity; /* total number of sectors */
int sector_size; /* sector size in bytes */
int read_bl_len; /* block length for reads */
/* ... */
};
struct sdmmc_cid {
int mid; /* manufacturer identification number */
int oid; /* OEM/product identification number */
char pnm[8]; /* product name (MMC v1 has the longest) */
int rev; /* product revision */
int psn; /* product serial number */
int mdt; /* manufacturing date */
};
typedef u_int32_t sdmmc_response[4];
struct sdmmc_softc;
struct sdmmc_task {
void (*func)(void *arg);
void *arg;
int onqueue;
struct sdmmc_softc *sc;
};
#define sdmmc_init_task(xtask, xfunc, xarg) do { \
(xtask)->func = (xfunc); \
(xtask)->arg = (xarg); \
(xtask)->onqueue = 0; \
(xtask)->sc = NULL; \
} while (0)
#define sdmmc_task_pending(xtask) ((xtask)->onqueue)
struct sdmmc_command {
// struct sdmmc_task c_task; /* task queue entry */
u_int16_t c_opcode; /* SD or MMC command index */
u_int32_t c_arg; /* SD/MMC command argument */
sdmmc_response c_resp; /* response buffer */
void *c_data; /* buffer to send or read into */
int c_datalen; /* length of data buffer */
int c_blklen; /* block length */
int c_flags; /* see below */
#define SCF_ITSDONE 0x0001 /* command is complete */
#define SCF_CMD(flags) ((flags) & 0x00f0)
#define SCF_CMD_AC 0x0000
#define SCF_CMD_ADTC 0x0010
#define SCF_CMD_BC 0x0020
#define SCF_CMD_BCR 0x0030
#define SCF_CMD_READ 0x0040 /* read command (data expected) */
#define SCF_RSP_BSY 0x0100
#define SCF_RSP_136 0x0200
#define SCF_RSP_CRC 0x0400
#define SCF_RSP_IDX 0x0800
#define SCF_RSP_PRESENT 0x1000
/* response types */
#define SCF_RSP_R0 0 /* none */
#define SCF_RSP_R1 (SCF_RSP_PRESENT|SCF_RSP_CRC|SCF_RSP_IDX)
#define SCF_RSP_R1B (SCF_RSP_PRESENT|SCF_RSP_CRC|SCF_RSP_IDX|SCF_RSP_BSY)
#define SCF_RSP_R2 (SCF_RSP_PRESENT|SCF_RSP_CRC|SCF_RSP_136)
#define SCF_RSP_R3 (SCF_RSP_PRESENT)
#define SCF_RSP_R4 (SCF_RSP_PRESENT)
#define SCF_RSP_R5 (SCF_RSP_PRESENT|SCF_RSP_CRC|SCF_RSP_IDX)
#define SCF_RSP_R5B (SCF_RSP_PRESENT|SCF_RSP_CRC|SCF_RSP_IDX|SCF_RSP_BSY)
#define SCF_RSP_R6 (SCF_RSP_PRESENT|SCF_RSP_CRC|SCF_RSP_IDX)
#define SCF_RSP_R7 (SCF_RSP_PRESENT|SCF_RSP_CRC|SCF_RSP_IDX)
int c_error; /* errno value on completion */
int c_timeout;
/* Host controller owned fields for data xfer in progress */
int c_resid; /* remaining I/O */
u_char *c_buf; /* remaining data */
};
/*
* Decoded PC Card 16 based Card Information Structure (CIS),
* per card (function 0) and per function (1 and greater).
*/
struct sdmmc_cis {
u_int16_t manufacturer;
#define SDMMC_VENDOR_INVALID 0xffff
u_int16_t product;
#define SDMMC_PRODUCT_INVALID 0xffff
u_int8_t function;
#define SDMMC_FUNCTION_INVALID 0xff
u_char cis1_major;
u_char cis1_minor;
char cis1_info_buf[256];
char *cis1_info[4];
};
/*
* Structure describing either an SD card I/O function or a SD/MMC
* memory card from a "stack of cards" that responded to CMD2. For a
* combo card with one I/O function and one memory card, there will be
* two of these structures allocated. Each card slot has such a list
* of sdmmc_function structures.
*/
struct sdmmc_function {
/* common members */
u_int16_t rca; /* relative card address */
int flags;
#define SFF_ERROR 0x0001 /* function is poo; ignore it */
#define SFF_SDHC 0x0002 /* SD High Capacity card */
/* SD card I/O function members */
int number; /* I/O function number or -1 */
struct sdmmc_cis cis; /* decoded CIS */
/* SD/MMC memory card members */
struct sdmmc_csd csd; /* decoded CSD value */
struct sdmmc_cid cid; /* decoded CID value */
sdmmc_response raw_cid; /* temp. storage for decoding */
};
#define SDMMC_LOCK(sc) lockmgr(&(sc)->sc_lock, LK_EXCLUSIVE, NULL)
#define SDMMC_UNLOCK(sc) lockmgr(&(sc)->sc_lock, LK_RELEASE, NULL)
#define SDMMC_ASSERT_LOCKED(sc) \
KASSERT(lockstatus(&((sc))->sc_lock) == LK_EXCLUSIVE)
#define SDMMC_DEFAULT_CLOCK 25000
#define SDMMC_DEFAULT_BLOCKLEN 512
#define SDMMC_NO_CARD 1
#define SDMMC_NEW_CARD 2
#define SDMMC_INSERTED 3
/* MMC commands */ /* response type */
#define MMC_GO_IDLE_STATE 0 /* R0 */
#define MMC_SEND_OP_COND 1 /* R3 */
#define MMC_ALL_SEND_CID 2 /* R2 */
#define MMC_SET_RELATIVE_ADDR 3 /* R1 */
#define MMC_SWITCH 6 /* R1B */
#define MMC_SELECT_CARD 7 /* R1 */
#define MMC_SEND_EXT_CSD 8 /* R1 */
#define MMC_SEND_CSD 9 /* R2 */
#define MMC_STOP_TRANSMISSION 12 /* R1B */
#define MMC_SEND_STATUS 13 /* R1 */
#define MMC_SET_BLOCKLEN 16 /* R1 */
#define MMC_READ_BLOCK_SINGLE 17 /* R1 */
#define MMC_READ_BLOCK_MULTIPLE 18 /* R1 */
#define MMC_SET_BLOCK_COUNT 23 /* R1 */
#define MMC_WRITE_BLOCK_SINGLE 24 /* R1 */
#define MMC_WRITE_BLOCK_MULTIPLE 25 /* R1 */
#define MMC_APP_CMD 55 /* R1 */
/* SD commands */ /* response type */
#define SD_SEND_RELATIVE_ADDR 3 /* R6 */
#define SD_SWITCH_FUNC 6 /* R1 */
#define SD_SEND_IF_COND 8 /* R7 */
/* SD application commands */ /* response type */
#define SD_APP_SET_BUS_WIDTH 6 /* R1 */
#define SD_APP_OP_COND 41 /* R3 */
/* OCR bits */
#define MMC_OCR_MEM_READY (1<<31) /* memory power-up status bit */
#define MMC_OCR_3_5V_3_6V (1<<23)
#define MMC_OCR_3_4V_3_5V (1<<22)
#define MMC_OCR_3_3V_3_4V (1<<21)
#define MMC_OCR_3_2V_3_3V (1<<20)
#define MMC_OCR_3_1V_3_2V (1<<19)
#define MMC_OCR_3_0V_3_1V (1<<18)
#define MMC_OCR_2_9V_3_0V (1<<17)
#define MMC_OCR_2_8V_2_9V (1<<16)
#define MMC_OCR_2_7V_2_8V (1<<15)
#define MMC_OCR_2_6V_2_7V (1<<14)
#define MMC_OCR_2_5V_2_6V (1<<13)
#define MMC_OCR_2_4V_2_5V (1<<12)
#define MMC_OCR_2_3V_2_4V (1<<11)
#define MMC_OCR_2_2V_2_3V (1<<10)
#define MMC_OCR_2_1V_2_2V (1<<9)
#define MMC_OCR_2_0V_2_1V (1<<8)
#define MMC_OCR_1_9V_2_0V (1<<7)
#define MMC_OCR_1_8V_1_9V (1<<6)
#define MMC_OCR_1_7V_1_8V (1<<5)
#define MMC_OCR_1_6V_1_7V (1<<4)
#define SD_OCR_SDHC_CAP (1<<30)
#define SD_OCR_VOL_MASK 0xFF8000 /* bits 23:15 */
/* R1 response type bits */
#define MMC_R1_READY_FOR_DATA (1<<8) /* ready for next transfer */
#define MMC_R1_APP_CMD (1<<5) /* app. commands supported */
/* 48-bit response decoding (32 bits w/o CRC) */
#define MMC_R1(resp) ((resp)[0])
#define MMC_R3(resp) ((resp)[0])
#define SD_R6(resp) ((resp)[0])
/* RCA argument and response */
#define MMC_ARG_RCA(rca) ((rca) << 16)
#define SD_R6_RCA(resp) (SD_R6((resp)) >> 16)
/* bus width argument */
#define SD_ARG_BUS_WIDTH_1 0
#define SD_ARG_BUS_WIDTH_4 2
/* MMC R2 response (CSD) */
#define MMC_CSD_CSDVER(resp) MMC_RSP_BITS((resp), 126, 2)
#define MMC_CSD_CSDVER_1_0 1
#define MMC_CSD_CSDVER_2_0 2
#define MMC_CSD_MMCVER(resp) MMC_RSP_BITS((resp), 122, 4)
#define MMC_CSD_MMCVER_1_0 0 /* MMC 1.0 - 1.2 */
#define MMC_CSD_MMCVER_1_4 1 /* MMC 1.4 */
#define MMC_CSD_MMCVER_2_0 2 /* MMC 2.0 - 2.2 */
#define MMC_CSD_MMCVER_3_1 3 /* MMC 3.1 - 3.3 */
#define MMC_CSD_MMCVER_4_0 4 /* MMC 4 */
#define MMC_CSD_READ_BL_LEN(resp) MMC_RSP_BITS((resp), 80, 4)
#define MMC_CSD_C_SIZE(resp) MMC_RSP_BITS((resp), 62, 12)
#define MMC_CSD_CAPACITY(resp) ((MMC_CSD_C_SIZE((resp))+1) << \
(MMC_CSD_C_SIZE_MULT((resp))+2))
#define MMC_CSD_C_SIZE_MULT(resp) MMC_RSP_BITS((resp), 47, 3)
/* MMC v1 R2 response (CID) */
#define MMC_CID_MID_V1(resp) MMC_RSP_BITS((resp), 104, 24)
#define MMC_CID_PNM_V1_CPY(resp, pnm) \
do { \
(pnm)[0] = MMC_RSP_BITS((resp), 96, 8); \
(pnm)[1] = MMC_RSP_BITS((resp), 88, 8); \
(pnm)[2] = MMC_RSP_BITS((resp), 80, 8); \
(pnm)[3] = MMC_RSP_BITS((resp), 72, 8); \
(pnm)[4] = MMC_RSP_BITS((resp), 64, 8); \
(pnm)[5] = MMC_RSP_BITS((resp), 56, 8); \
(pnm)[6] = MMC_RSP_BITS((resp), 48, 8); \
(pnm)[7] = '\0'; \
} while (0)
#define MMC_CID_REV_V1(resp) MMC_RSP_BITS((resp), 40, 8)
#define MMC_CID_PSN_V1(resp) MMC_RSP_BITS((resp), 16, 24)
#define MMC_CID_MDT_V1(resp) MMC_RSP_BITS((resp), 8, 8)
/* MMC v2 R2 response (CID) */
#define MMC_CID_MID_V2(resp) MMC_RSP_BITS((resp), 120, 8)
#define MMC_CID_OID_V2(resp) MMC_RSP_BITS((resp), 104, 16)
#define MMC_CID_PNM_V2_CPY(resp, pnm) \
do { \
(pnm)[0] = MMC_RSP_BITS((resp), 96, 8); \
(pnm)[1] = MMC_RSP_BITS((resp), 88, 8); \
(pnm)[2] = MMC_RSP_BITS((resp), 80, 8); \
(pnm)[3] = MMC_RSP_BITS((resp), 72, 8); \
(pnm)[4] = MMC_RSP_BITS((resp), 64, 8); \
(pnm)[5] = MMC_RSP_BITS((resp), 56, 8); \
(pnm)[6] = '\0'; \
} while (0)
#define MMC_CID_PSN_V2(resp) MMC_RSP_BITS((resp), 16, 32)
/* SD R2 response (CSD) */
#define SD_CSD_CSDVER(resp) MMC_RSP_BITS((resp), 126, 2)
#define SD_CSD_CSDVER_1_0 0
#define SD_CSD_CSDVER_2_0 1
#define SD_CSD_TAAC(resp) MMC_RSP_BITS((resp), 112, 8)
#define SD_CSD_TAAC_1_5_MSEC 0x26
#define SD_CSD_NSAC(resp) MMC_RSP_BITS((resp), 104, 8)
#define SD_CSD_SPEED(resp) MMC_RSP_BITS((resp), 96, 8)
#define SD_CSD_SPEED_25_MHZ 0x32
#define SD_CSD_SPEED_50_MHZ 0x5a
#define SD_CSD_CCC(resp) MMC_RSP_BITS((resp), 84, 12)
#define SD_CSD_CCC_ALL 0x5f5
#define SD_CSD_READ_BL_LEN(resp) MMC_RSP_BITS((resp), 80, 4)
#define SD_CSD_READ_BL_PARTIAL(resp) MMC_RSP_BITS((resp), 79, 1)
#define SD_CSD_WRITE_BLK_MISALIGN(resp) MMC_RSP_BITS((resp), 78, 1)
#define SD_CSD_READ_BLK_MISALIGN(resp) MMC_RSP_BITS((resp), 77, 1)
#define SD_CSD_DSR_IMP(resp) MMC_RSP_BITS((resp), 76, 1)
#define SD_CSD_C_SIZE(resp) MMC_RSP_BITS((resp), 62, 12)
#define SD_CSD_CAPACITY(resp) ((SD_CSD_C_SIZE((resp))+1) << \
(SD_CSD_C_SIZE_MULT((resp))+2))
#define SD_CSD_V2_C_SIZE(resp) MMC_RSP_BITS((resp), 48, 22)
#define SD_CSD_V2_CAPACITY(resp) ((SD_CSD_V2_C_SIZE((resp))+1) << 10)
#define SD_CSD_V2_BL_LEN 0x9 /* 512 */
#define SD_CSD_VDD_R_CURR_MIN(resp) MMC_RSP_BITS((resp), 59, 3)
#define SD_CSD_VDD_R_CURR_MAX(resp) MMC_RSP_BITS((resp), 56, 3)
#define SD_CSD_VDD_W_CURR_MIN(resp) MMC_RSP_BITS((resp), 53, 3)
#define SD_CSD_VDD_W_CURR_MAX(resp) MMC_RSP_BITS((resp), 50, 3)
#define SD_CSD_VDD_RW_CURR_100mA 0x7
#define SD_CSD_VDD_RW_CURR_80mA 0x6
#define SD_CSD_C_SIZE_MULT(resp) MMC_RSP_BITS((resp), 47, 3)
#define SD_CSD_ERASE_BLK_EN(resp) MMC_RSP_BITS((resp), 46, 1)
#define SD_CSD_SECTOR_SIZE(resp) MMC_RSP_BITS((resp), 39, 7) /* +1 */
#define SD_CSD_WP_GRP_SIZE(resp) MMC_RSP_BITS((resp), 32, 7) /* +1 */
#define SD_CSD_WP_GRP_ENABLE(resp) MMC_RSP_BITS((resp), 31, 1)
#define SD_CSD_R2W_FACTOR(resp) MMC_RSP_BITS((resp), 26, 3)
#define SD_CSD_WRITE_BL_LEN(resp) MMC_RSP_BITS((resp), 22, 4)
#define SD_CSD_RW_BL_LEN_2G 0xa
#define SD_CSD_RW_BL_LEN_1G 0x9
#define SD_CSD_WRITE_BL_PARTIAL(resp) MMC_RSP_BITS((resp), 21, 1)
#define SD_CSD_FILE_FORMAT_GRP(resp) MMC_RSP_BITS((resp), 15, 1)
#define SD_CSD_COPY(resp) MMC_RSP_BITS((resp), 14, 1)
#define SD_CSD_PERM_WRITE_PROTECT(resp) MMC_RSP_BITS((resp), 13, 1)
#define SD_CSD_TMP_WRITE_PROTECT(resp) MMC_RSP_BITS((resp), 12, 1)
#define SD_CSD_FILE_FORMAT(resp) MMC_RSP_BITS((resp), 10, 2)
/* SD R2 response (CID) */
#define SD_CID_MID(resp) MMC_RSP_BITS((resp), 120, 8)
#define SD_CID_OID(resp) MMC_RSP_BITS((resp), 104, 16)
#define SD_CID_PNM_CPY(resp, pnm) \
do { \
(pnm)[0] = MMC_RSP_BITS((resp), 96, 8); \
(pnm)[1] = MMC_RSP_BITS((resp), 88, 8); \
(pnm)[2] = MMC_RSP_BITS((resp), 80, 8); \
(pnm)[3] = MMC_RSP_BITS((resp), 72, 8); \
(pnm)[4] = MMC_RSP_BITS((resp), 64, 8); \
(pnm)[5] = '\0'; \
} while (0)
#define SD_CID_REV(resp) MMC_RSP_BITS((resp), 56, 8)
#define SD_CID_PSN(resp) MMC_RSP_BITS((resp), 24, 32)
#define SD_CID_MDT(resp) MMC_RSP_BITS((resp), 8, 12)
/* Might be slow, but it should work on big and little endian systems. */
#define MMC_RSP_BITS(resp, start, len) __bitfield((resp), (start)-8, (len))
static __inline int
__bitfield(u_int32_t *src, int start, int len)
{
u_int8_t *sp;
u_int32_t dst, mask;
int shift, bs, bc;
if (start < 0 || len < 0 || len > 32)
return 0;
dst = 0;
mask = len % 32 ? UINT_MAX >> (32 - (len % 32)) : UINT_MAX;
shift = 0;
while (len > 0) {
sp = (u_int8_t *)src + start / 8;
bs = start % 8;
bc = 8 - bs;
if (bc > len)
bc = len;
dst |= (*sp++ >> bs) << shift;
shift += bc;
start += bc;
len -= bc;
}
dst &= mask;
return (int)dst;
}
#endif

View File

@ -1,149 +0,0 @@
/*
SHA-1 in C
By Steve Reid <steve@edmweb.com>
100% Public Domain
Test Vectors (from FIPS PUB 180-1)
"abc"
A9993E36 4706816A BA3E2571 7850C26C 9CD0D89D
"abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq"
84983E44 1C3BD26E BAAE4AA1 F95129E5 E54670F1
A million repetitions of "a"
34AA973C D4C4DAA4 F61EEB2B DBAD2731 6534016F
*/
#include "types.h"
#include "utils.h"
#include <string.h>
#include <stdlib.h>
#include <malloc.h>
#include "sha.h"
#include "irq.h"
#include "memory.h"
#include "latte.h"
//should be divisible by four
#define BLOCKSIZE 32
#define SHA_CMD_FLAG_EXEC (1<<31)
#define SHA_CMD_FLAG_IRQ (1<<30)
#define SHA_CMD_FLAG_ERR (1<<29)
#define SHA_CMD_AREA_BLOCK ((1<<10) - 1)
static void sha_transform(u32 state[SHA_HASH_WORDS], u8 buffer[SHA_BLOCK_SIZE], u32 blocks)
{
if(blocks == 0) return;
/* Copy ctx->state[] to working vars */
write32(SHA_H0, state[0]);
write32(SHA_H1, state[1]);
write32(SHA_H2, state[2]);
write32(SHA_H3, state[3]);
write32(SHA_H4, state[4]);
// assign block to local copy which is 64-byte aligned
u8 *block = memalign(64, SHA_BLOCK_SIZE * blocks);
memcpy(block, buffer, SHA_BLOCK_SIZE * blocks);
// royal flush :)
dc_flushrange(block, SHA_BLOCK_SIZE * blocks);
ahb_flush_to(RB_SHA);
// tell sha1 controller the block source address
write32(SHA_SRC, dma_addr(block));
// tell sha1 controller number of blocks
write32(SHA_CTRL, (read32(SHA_CTRL) & ~(SHA_CMD_AREA_BLOCK)) | (blocks - 1));
// fire up hashing and wait till its finished
write32(SHA_CTRL, read32(SHA_CTRL) | SHA_CMD_FLAG_EXEC);
while (read32(SHA_CTRL) & SHA_CMD_FLAG_EXEC);
// free the aligned data
free(block);
/* Add the working vars back into ctx.state[] */
state[0] = read32(SHA_H0);
state[1] = read32(SHA_H1);
state[2] = read32(SHA_H2);
state[3] = read32(SHA_H3);
state[4] = read32(SHA_H4);
}
void sha_init(sha_ctx* ctx)
{
memset(ctx, 0, sizeof(sha_ctx));
ctx->state[0] = 0x67452301;
ctx->state[1] = 0xEFCDAB89;
ctx->state[2] = 0x98BADCFE;
ctx->state[3] = 0x10325476;
ctx->state[4] = 0xC3D2E1F0;
}
void sha_update(sha_ctx* ctx, const void* inbuf, size_t size)
{
unsigned int i, j;
u8* data = (u8*)inbuf;
j = (ctx->count[0] >> 3) & 63;
if ((ctx->count[0] += size << 3) < (size << 3))
ctx->count[1]++;
ctx->count[1] += (size >> 29);
if ((j + size) > 63) {
memcpy(&ctx->buffer[j], data, (i = 64-j));
sha_transform(ctx->state, ctx->buffer, 1);
// try bigger blocks at once
for ( ; i + 63 + ((BLOCKSIZE-1)*64) < size; i += (64 + (BLOCKSIZE-1)*64)) {
sha_transform(ctx->state, &data[i], BLOCKSIZE);
}
for ( ; i + 63 + (((BLOCKSIZE/2)-1)*64) < size; i += (64 + ((BLOCKSIZE/2)-1)*64)) {
sha_transform(ctx->state, &data[i], BLOCKSIZE/2);
}
for ( ; i + 63 + (((BLOCKSIZE/4)-1)*64) < size; i += (64 + ((BLOCKSIZE/4)-1)*64)) {
sha_transform(ctx->state, &data[i], BLOCKSIZE/4);
}
for ( ; i + 63 < size; i += 64) {
sha_transform(ctx->state, &data[i], 1);
}
j = 0;
}
else i = 0;
memcpy(&ctx->buffer[j], &data[i], size - i);
}
void sha_final(sha_ctx* ctx, void* outbuf)
{
u8 final_count[8];
u8* digest = outbuf;
for (int i = 0; i < 8; i++) {
final_count[i] = ((ctx->count[(i >= 4 ? 0 : 1)] >> ((3-(i & 3)) * 8) ) & 255); /* Endian independent */
}
sha_update(ctx, "\200", 1);
while ((ctx->count[0] & 504) != 448) {
sha_update(ctx, "\0", 1);
}
sha_update(ctx, final_count, sizeof(final_count)); /* Should cause a sha_transform() */
for (int i = 0; i < SHA_HASH_SIZE; i++) {
digest[i] = ((ctx->state[i>>2] >> ((3-(i & 3)) * 8) ) & 255);
}
/* Wipe variables */
memset(ctx->buffer, 0, sizeof(ctx->buffer));
memset(ctx->state, 0, sizeof(ctx->state));
memset(ctx->count, 0, sizeof(ctx->count));
memset(final_count, 0, sizeof(final_count));
sha_transform(ctx->state, ctx->buffer, 1);
}
void sha_hash(const void* inbuf, void* outbuf, size_t size)
{
sha_ctx ctx;
sha_init(&ctx);
sha_update(&ctx, inbuf, size);
sha_final(&ctx, outbuf);
}

View File

@ -1,36 +0,0 @@
/*
* minute - a port of the "mini" IOS replacement for the Wii U.
*
* Copyright (C) 2016 SALT
* Copyright (C) 2016 Daz Jones <daz@dazzozo.com>
*
* This code is licensed to you under the terms of the GNU GPL, version 2;
* see file COPYING or http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt
*/
#ifndef _SHA_H
#define _SHA_H
#include "types.h"
#define SHA_BLOCK_BITS (0x200) // 512
#define SHA_BLOCK_SIZE (SHA_BLOCK_BITS / 8) // 64
#define SHA_BLOCK_WORDS (SHA_BLOCK_SIZE / sizeof(u32)) // 16
#define SHA_HASH_BITS (0xA0) // 160
#define SHA_HASH_SIZE (SHA_HASH_BITS / 8) // 20 (0x14)
#define SHA_HASH_WORDS (SHA_HASH_SIZE / sizeof(u32)) // 5
typedef struct {
u32 state[SHA_HASH_WORDS];
u32 count[2];
u8 buffer[SHA_BLOCK_SIZE];
} sha_ctx;
void sha_init(sha_ctx* ctx);
void sha_update(sha_ctx* ctx, const void* inbuf, size_t size);
void sha_final(sha_ctx* ctx, void* outbuf);
void sha_hash(const void* inbuf, void* outbuf, size_t size);
#endif

View File

@ -1,118 +0,0 @@
/*
* minute - a port of the "mini" IOS replacement for the Wii U.
*
* Copyright (C) 2016 SALT
* Copyright (C) 2016 Daz Jones <daz@dazzozo.com>
*
* This code is licensed to you under the terms of the GNU GPL, version 2;
* see file COPYING or http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt
*/
#include "types.h"
#include "utils.h"
#include "latte.h"
void SRAM_TEXT __attribute__((__noreturn__)) smc_shutdown(bool reset)
{
write16(MEM_FLUSH_MASK, 0b1111);
while(read16(MEM_FLUSH_MASK) & 0b1111);
if(read32(LT_RESETS) & 4) {
write32(LT_ABIF_CPLTL_OFFSET, 0xC0008020);
write32(LT_ABIF_CPLTL_DATA, 0xFFFFFFFF);
write32(LT_ABIF_CPLTL_OFFSET, 0xC0000E60);
write32(LT_ABIF_CPLTL_DATA, 0xFFFFFFDB);
}
write32(LT_RESETS_AHB, 0xFFFFCE71);
write32(LT_RESETS_AHMN, 0xFFFFCD70);
write32(LT_RESETS_COMPAT, 0xFF8FCDEF);
write16(MEM_REFRESH_FLAG, 0);
write16(MEM_SEQ_REG_ADDR, 0x18);
write16(MEM_SEQ_REG_VAL, 1);
write16(MEM_SEQ_REG_ADDR, 0x19);
write16(MEM_SEQ_REG_VAL, 0);
write16(MEM_SEQ_REG_ADDR, 0x1A);
write16(MEM_SEQ_REG_VAL, 1);
write16(MEM_SEQ0_REG_ADDR, 0x18);
write16(MEM_SEQ0_REG_VAL, 1);
write16(MEM_SEQ0_REG_ADDR, 0x19);
write16(MEM_SEQ0_REG_VAL, 0);
write16(MEM_SEQ0_REG_ADDR, 0x1A);
write16(MEM_SEQ0_REG_VAL, 1);
{
write32(EXI0_CSR, 0x108);
write32(EXI0_DATA, 0xA1000100);
write32(EXI0_CR, 0x35);
while(!(read32(EXI0_CSR) & 8));
write32(EXI0_CSR, 0x108);
write32(EXI0_DATA, 0);
write32(EXI0_CR, 0x35);
while(!(read32(EXI0_CSR) & 8));
write32(EXI0_CSR, 0);
}
if(reset) {
{
write32(EXI0_CSR, 0x108);
write32(EXI0_DATA, 0xA1000D00);
write32(EXI0_CR, 0x35);
while(!(read32(EXI0_CSR) & 8));
write32(EXI0_CSR, 0x108);
write32(EXI0_DATA, 0x501);
write32(EXI0_CR, 0x35);
while(!(read32(EXI0_CSR) & 8));
write32(EXI0_CSR, 0);
}
clear32(LT_RESETS, 1);
} else {
{
write32(EXI0_CSR, 0x108);
write32(EXI0_DATA, 0xA1000D00);
write32(EXI0_CR, 0x35);
while(!(read32(EXI0_CSR) & 8));
write32(EXI0_CSR, 0x108);
write32(EXI0_DATA, 0x101);
write32(EXI0_CR, 0x35);
while(!(read32(EXI0_CSR) & 8));
write32(EXI0_CSR, 0);
}
{
write32(EXI0_CSR, 0x108);
write32(EXI0_DATA, 0xA1000D00);
write32(EXI0_CR, 0x35);
while(!(read32(EXI0_CSR) & 8));
write32(EXI0_CSR, 0x108);
write32(EXI0_DATA, 0x10101);
write32(EXI0_CR, 0x35);
while(!(read32(EXI0_CSR) & 8));
write32(EXI0_CSR, 0);
}
}
while(true);
}
void __attribute__((__noreturn__)) smc_power_off(void)
{
smc_shutdown(false);
}
void __attribute__((__noreturn__)) smc_reset(void)
{
smc_shutdown(true);
}

View File

@ -1,20 +0,0 @@
/*
* minute - a port of the "mini" IOS replacement for the Wii U.
*
* Copyright (C) 2016 SALT
* Copyright (C) 2016 Daz Jones <daz@dazzozo.com>
*
* This code is licensed to you under the terms of the GNU GPL, version 2;
* see file COPYING or http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt
*/
#ifndef _SMC_H
#define _SMC_H
#include "types.h"
void __attribute__((__noreturn__)) smc_shutdown(bool reset);
void __attribute__((__noreturn__)) smc_reset(void);
void __attribute__((__noreturn__)) smc_power_off(void);
#endif

View File

@ -1,83 +0,0 @@
/*
* minute - a port of the "mini" IOS replacement for the Wii U.
*
* Copyright (C) 2008, 2009 Hector Martin "marcan" <marcan@marcansoft.com>
*
* This code is licensed to you under the terms of the GNU GPL, version 2;
* see file COPYING or http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt
*/
.arm
.extern _main
.extern __got_start
.extern __got_end
.extern __bss_start
.extern __bss_end
.extern __stack_addr
.globl _start
.extern v_irq
.section .init
_vectors:
_start:
ldr pc, =v_reset
1: b 1b
2: b 2b
3: b 3b
4: b 4b
5: b 5b
ldr pc, =v_irq
6: b 6b
.pool
v_reset:
@ Switch to System mode
msr cpsr_c, #0xdf
@ Get loader base from ELF loader
mov r4, r0
@ Set up a stack
ldr sp, =__stack_addr
@ clear the stack to a marker value
ldr r1, =__stack_end
ldr r2, =__stack_addr
ldr r3, =0xDEADBEEF
stk_loop:
@ check for the end
cmp r1, r2
beq done_stk
@ clear the word and move on
str r3, [r1]
add r1, r1, #4
b stk_loop
done_stk:
@ clear BSS
ldr r1, =__bss_start
ldr r2, =__bss_end
mov r3, #0
bss_loop:
@ check for the end
cmp r1, r2
beq done_bss
@ clear the word and move on
str r3, [r1]
add r1, r1, #4
b bss_loop
done_bss:
@ take the plunge
mov r0, r4
ldr r1, =_main
blx r1
@ _main returned! Go to whatever address it returned...
bx r0
.pool

View File

@ -1,68 +0,0 @@
/*
* minute - a port of the "mini" IOS replacement for the Wii U.
*
* Copyright (C) 2016 SALT
* Copyright (C) 2016 Daz Jones <daz@dazzozo.com>
*
* Copyright (C) 2008, 2009 Hector Martin "marcan" <marcan@marcansoft.com>
*
* This code is licensed to you under the terms of the GNU GPL, version 2;
* see file COPYING or http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt
*/
#ifndef __TYPES_H__
#define __TYPES_H__
#include <inttypes.h>
#include <stddef.h>
#include <stdbool.h>
#include <stdarg.h>
typedef uint8_t u8;
typedef uint16_t u16;
typedef uint32_t u32;
typedef uint64_t u64;
typedef int8_t s8;
typedef int16_t s16;
typedef int32_t s32;
typedef int64_t s64;
typedef volatile u8 vu8;
typedef volatile u16 vu16;
typedef volatile u32 vu32;
typedef volatile u64 vu64;
typedef volatile s8 vs8;
typedef volatile s16 vs16;
typedef volatile s32 vs32;
typedef volatile s64 vs64;
#define NULL ((void *)0)
#define ALWAYS_INLINE __attribute__((always_inline))
#define SRAM_TEXT __attribute__((section(".sram.text")))
#define SRAM_DATA __attribute__((section(".sram.data")))
#define NORETURN __attribute__((__noreturn__))
#define ALIGNED(x) __attribute__((aligned(x)))
#define PACKED __attribute__((packed))
#define STACK_ALIGN(type, name, cnt, alignment) \
u8 _al__##name[((sizeof(type)*(cnt)) + (alignment) + \
(((sizeof(type)*(cnt))%(alignment)) > 0 ? ((alignment) - \
((sizeof(type)*(cnt))%(alignment))) : 0))]; \
type *name = (type*)(((u32)(_al__##name)) + ((alignment) - (( \
(u32)(_al__##name))&((alignment)-1))))
#define INT_MAX ((s32)0x7fffffff)
#define UINT_MAX ((u32)0xffffffff)
//#define LONG_MAX INT_MAX
//#define ULONG_MAX UINT_MAX
//#define LLONG_MAX ((s64)0x7fffffffffffffff)
//#define ULLONG_MAX ((u64)0xffffffffffffffff)
#endif

View File

@ -1,52 +0,0 @@
/*
* minute - a port of the "mini" IOS replacement for the Wii U.
*
* Copyright (C) 2016 SALT
* Copyright (C) 2016 Daz Jones <daz@dazzozo.com>
*
* Copyright (C) 2008, 2009 Hector Martin "marcan" <marcan@marcansoft.com>
*
* This code is licensed to you under the terms of the GNU GPL, version 2;
* see file COPYING or http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt
*/
#include "types.h"
#include "utils.h"
#include "gpio.h"
#include "latte.h"
#include <stdarg.h>
void udelay(u32 d)
{
// should be good to max .2% error
u32 ticks = d * 19 / 10;
if(ticks < 2)
ticks = 2;
u32 now = read32(LT_TIMER);
u32 then = now + ticks;
if(then < now) {
while(read32(LT_TIMER) >= now);
now = read32(LT_TIMER);
}
while(now < then) {
now = read32(LT_TIMER);
}
}
void panic(u8 v)
{
while(true) {
//debug_output(v);
//set32(HW_GPIO1BOUT, GP_SLOTLED);
//udelay(500000);
//debug_output(0);
//clear32(HW_GPIO1BOUT, GP_SLOTLED);
//udelay(500000);
}
}

View File

@ -1,213 +0,0 @@
/*
* minute - a port of the "mini" IOS replacement for the Wii U.
*
* Copyright (C) 2008, 2009 Hector Martin "marcan" <marcan@marcansoft.com>
*
* This code is licensed to you under the terms of the GNU GPL, version 2;
* see file COPYING or http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt
*/
#ifndef __UTILS_H__
#define __UTILS_H__
#include "types.h"
static inline ALWAYS_INLINE u32 read32(u32 addr)
{
u32 data;
__asm__ volatile ("ldr\t%0, [%1]" : "=l" (data) : "l" (addr));
return data;
}
static inline ALWAYS_INLINE void write32(u32 addr, u32 data)
{
__asm__ volatile ("str\t%0, [%1]" : : "l" (data), "l" (addr));
}
static inline ALWAYS_INLINE u32 set32(u32 addr, u32 set)
{
u32 data;
__asm__ volatile (
"ldr\t%0, [%1]\n"
"\torr\t%0, %2\n"
"\tstr\t%0, [%1]"
: "=&l" (data)
: "l" (addr), "l" (set)
);
return data;
}
static inline ALWAYS_INLINE u32 clear32(u32 addr, u32 clear)
{
u32 data;
__asm__ volatile (
"ldr\t%0, [%1]\n"
"\tbic\t%0, %2\n"
"\tstr\t%0, [%1]"
: "=&l" (data)
: "l" (addr), "l" (clear)
);
return data;
}
static inline ALWAYS_INLINE u32 mask32(u32 addr, u32 clear, u32 set)
{
u32 data;
__asm__ volatile (
"ldr\t%0, [%1]\n"
"\tbic\t%0, %3\n"
"\torr\t%0, %2\n"
"\tstr\t%0, [%1]"
: "=&l" (data)
: "l" (addr), "l" (set), "l" (clear)
);
return data;
}
static inline ALWAYS_INLINE u16 read16(u32 addr)
{
u32 data;
__asm__ volatile ("ldrh\t%0, [%1]" : "=l" (data) : "l" (addr));
return data;
}
static inline ALWAYS_INLINE void write16(u32 addr, u16 data)
{
__asm__ volatile ("strh\t%0, [%1]" : : "l" (data), "l" (addr));
}
static inline ALWAYS_INLINE u16 set16(u32 addr, u16 set)
{
u16 data;
__asm__ volatile (
"ldrh\t%0, [%1]\n"
"\torr\t%0, %2\n"
"\tstrh\t%0, [%1]"
: "=&l" (data)
: "l" (addr), "l" (set)
);
return data;
}
static inline ALWAYS_INLINE u16 clear16(u32 addr, u16 clear)
{
u16 data;
__asm__ volatile (
"ldrh\t%0, [%1]\n"
"\tbic\t%0, %2\n"
"\tstrh\t%0, [%1]"
: "=&l" (data)
: "l" (addr), "l" (clear)
);
return data;
}
static inline ALWAYS_INLINE u16 mask16(u32 addr, u16 clear, u16 set)
{
u16 data;
__asm__ volatile (
"ldrh\t%0, [%1]\n"
"\tbic\t%0, %3\n"
"\torr\t%0, %2\n"
"\tstrh\t%0, [%1]"
: "=&l" (data)
: "l" (addr), "l" (set), "l" (clear)
);
return data;
}
static inline ALWAYS_INLINE u8 read8(u32 addr)
{
u32 data;
__asm__ volatile ("ldrb\t%0, [%1]" : "=l" (data) : "l" (addr));
return data;
}
static inline ALWAYS_INLINE void write8(u32 addr, u8 data)
{
__asm__ volatile ("strb\t%0, [%1]" : : "l" (data), "l" (addr));
}
static inline ALWAYS_INLINE u8 set8(u32 addr, u8 set)
{
u8 data;
__asm__ volatile (
"ldrb\t%0, [%1]\n"
"\torr\t%0, %2\n"
"\tstrb\t%0, [%1]"
: "=&l" (data)
: "l" (addr), "l" (set)
);
return data;
}
static inline ALWAYS_INLINE u8 clear8(u32 addr, u8 clear)
{
u8 data;
__asm__ volatile (
"ldrb\t%0, [%1]\n"
"\tbic\t%0, %2\n"
"\tstrb\t%0, [%1]"
: "=&l" (data)
: "l" (addr), "l" (clear)
);
return data;
}
static inline ALWAYS_INLINE u8 mask8(u32 addr, u8 clear, u8 set)
{
u8 data;
__asm__ volatile (
"ldrb\t%0, [%1]\n"
"\tbic\t%0, %3\n"
"\torr\t%0, %2\n"
"\tstrb\t%0, [%1]"
: "=&l" (data)
: "l" (addr), "l" (set), "l" (clear)
);
return data;
}
/*
* These functions are guaranteed to copy by reading from src and writing to dst in <n>-bit units
* If size is not aligned, the remaining bytes are not copied
*/
void memset32(void *dst, u32 value, u32 size);
void memcpy32(void *dst, void *src, u32 size);
void memset16(void *dst, u16 value, u32 size);
void memcpy16(void *dst, void *src, u32 size);
void memset8(void *dst, u8 value, u32 size);
void memcpy8(void *dst, void *src, u32 size);
void udelay(u32 d);
void panic(u8 v);
static inline ALWAYS_INLINE u32 get_cpsr(void)
{
u32 data;
__asm__ volatile ( "mrs\t%0, cpsr" : "=r" (data) );
return data;
}
#define STACK_ALIGN(type, name, cnt, alignment) \
u8 _al__##name[((sizeof(type)*(cnt)) + (alignment) + \
(((sizeof(type)*(cnt))%(alignment)) > 0 ? ((alignment) - \
((sizeof(type)*(cnt))%(alignment))) : 0))]; \
type *name = (type*)(((u32)(_al__##name)) + ((alignment) - (( \
(u32)(_al__##name))&((alignment)-1))))
#define max(a, b) \
({ __typeof__ (a) _a = (a); \
__typeof__ (b) _b = (b); \
_a > _b ? _a : _b; })
#define min(a, b) \
({ __typeof__ (a) _a = (a); \
__typeof__ (b) _b = (b); \
_a < _b ? _a : _b; })
#endif

View File

@ -1,70 +0,0 @@
/*
* minute - a port of the "mini" IOS replacement for the Wii U.
*
* Copyright (C) 2008, 2009 Hector Martin "marcan" <marcan@marcansoft.com>
*
* This code is licensed to you under the terms of the GNU GPL, version 2;
* see file COPYING or http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt
*/
.arm
.globl memcpy32
.globl memcpy16
.globl memcpy8
.globl memset32
.globl memset16
.globl memset8
.section .sram.text
memcpy32:
bics r2, #3
bxeq lr
1: ldr r3, [r1],#4
str r3, [r0],#4
subs r2, #4
bne 1b
bx lr
memset32:
bics r2, #3
bxeq lr
1: str r1, [r0],#4
subs r2, #4
bne 1b
bx lr
memcpy16:
bics r2, #1
bxeq lr
1: ldrh r3, [r1],#2
strh r3, [r0],#2
subs r2, #2
bne 1b
bx lr
memset16:
bics r2, #1
bxeq lr
1: strh r1, [r0],#2
subs r2, #2
bne 1b
bx lr
memcpy8:
cmp r2, #0
bxeq lr
1: ldrb r3, [r1],#1
strb r3, [r0],#1
subs r2, #1
bne 1b
bx lr
memset8:
cmp r2, #0
bxeq lr
1: strb r1, [r0],#1
subs r2, #1
bne 1b
bx lr