MINI interface

76 views
Skip to first unread message

bushing

unread,
May 23, 2009, 5:09:44 AM5/23/09
to bootmii-devel
I guess I might as well kick off discussion here with some code.
We've been meaning to release a "Hello, world!" PPC app for MINI, but
have not yet found the time to do so. So, I'll start posting some
bits of code, and at some point you'll have enough info to write your
own PPC app! Hopefully. :)

If you have any questions about this code (or MINI, or the interaction
between the two, or the design decisions we made, etc), I'd love to
hear them. We put this thing together in a vacuum for about 6 months,
so we could use some fresh insight.

I assume that everyone has already seen our git repo:

http://gitweb.bootmii.org/
git clone git://git.bootmii.org/mini

You can compile that and put it on your SD card as armboot.bin, and
then you can compile your own PPC code and name it ppcboot.elf and it
will run. Simple things like video and GC pad input should work, but
if you want to do anything like accessing SD or NAND, you'll need to
use the IPC interface we've defined for MINI. Having a USBGecko would
be extremely helpful.

Here's what that interface looks like (although it's subject to
change):

// mini_ipc.h
/*
mini_ipc.h -- public PowerPC-side interface to mini. Part of the
BootMii project.

Copyright (C) 2009 Andre Heider "dhewg" <dh...@wiibrew.org>
Copyright (C) 2009 Haxx Enterprises <bus...@gmail.com>
Copyright (C) 2009 John Kelley <wii...@kelley.ca>
Copyright (C) 2008, 2009 Sven Peter <sven...@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 __MINI_IPC_H__
#define __MINI_IPC_H__

#define SDHC_ENOCARD -0x1001
#define SDHC_ESTRANGE -0x1002
#define SDHC_EOVERFLOW -0x1003
#define SDHC_ETIMEDOUT -0x1004
#define SDHC_EINVAL -0x1005
#define SDHC_EIO -0x1006

#define SDMMC_NO_CARD 1
#define SDMMC_NEW_CARD 2
#define SDMMC_INSERTED 3

#define NAND_ECC_OK 0
#define NAND_ECC_CORRECTED 1
#define NAND_ECC_UNCORRECTABLE -1

int sd_get_state(void);
int sd_protected(void);
int sd_mount(void);
int sd_select(void);
int sd_read(u32 start_block, u32 blk_cnt, void *buffer);
int sd_write(u32 start_block, u32 blk_cnt, const void *buffer);
u32 sd_getsize(void);

int ipc_powerpc_boot(const void *addr, u32 len);

#define TMD_BM_MARK(x) ((u16*)&(x->reserved[4]))
// 'BM'
#define TMD_BM_MAGIC 0x424d

typedef struct {
u32 type;
u8 sig[256];
u8 fill[60];
} __attribute__((packed)) sig_rsa2048;

typedef struct {
u32 cid;
u16 index;
u16 type;
u64 size;
u8 hash[20];
} __attribute__((packed)) tmd_content;

typedef struct {
sig_rsa2048 signature;
char issuer[0x40];
u8 version;
u8 ca_crl_version;
u8 signer_crl_version;
u8 fill2;
u64 sys_version;
u64 title_id;
u32 title_type;
u16 group_id;
u16 zero;
u16 region;
u8 ratings[16];
u8 reserved[42];
u32 access_rights;
u16 title_version;
u16 num_contents;
u16 boot_index;
u16 fill3;
tmd_content boot_content;
} __attribute__((packed)) tmd;

u32 boot2_run(u32 hi, u32 lo);
tmd *boot2_tmd(void);

typedef struct
{
u8 boot1_hash[20];
u8 common_key[16];
u32 ng_id;
union { // first two bytes of nand_hmac overlap last two bytes of
ng_priv. no clue why
struct {
u8 ng_priv[30];
u8 _wtf1[18];
};
struct {
u8 _wtf2[28];
u8 nand_hmac[20];
};
};
u8 nand_key[16];
u8 rng_key[16];
u32 unk1;
u32 unk2; // 0x00000007
} __attribute__((packed)) otp_t;

typedef struct
{
u8 boot2version;
u8 unknown1;
u8 unknown2;
u8 pad;
u32 update_tag;
u16 checksum;
} __attribute__((packed)) eep_ctr_t;

typedef struct
{
union {
struct {
u32 ms_key_id;
u32 ca_key_id;
u32 ng_key_id;
u8 ng_sig[60];
eep_ctr_t counters[2];
u8 fill[0x18];
u8 korean_key[16];
};
u8 data[256];
};
} __attribute__((packed)) seeprom_t;

void getotp(otp_t *otp);
void getseeprom(seeprom_t *seeprom);
void getMiniGitVer(char *buf, u16 len);

void aes_reset(void);
void aes_set_key(u8 *key);
void aes_set_iv(u8 *iv);
void aes_decrypt(u8 *src, u8 *dst, u32 blocks, u8 keep_iv);

void nand_reset(void);
u32 nand_getid(void);
u8 nand_status(void);
int nand_read(u32 pageno, void *data, void *ecc);
void nand_write(u32 pageno, void *data, void *ecc);
void nand_erase(u32 pageno);

#endif

// mini_ipc.c
/*
mini_ipc.c -- public PowerPC-side interface to mini. Part of the
BootMii project.

Copyright (C) 2009 Andre Heider "dhewg" <dh...@wiibrew.org>
Copyright (C) 2009 Haxx Enterprises <bus...@gmail.com>
Copyright (C) 2009 John Kelley <wii...@kelley.ca>
Copyright (C) 2008, 2009 Sven Peter <sven...@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 "bootmii_ppc.h"
#include "ipc.h"
#include "mini_ipc.h"
#include "string.h"

int ipc_powerpc_boot(const void *addr, u32 len)
{
ipc_request *req;

sync_after_write(addr, len);
req = ipc_exchange(IPC_PPC_BOOT, 3, 0, virt_to_phys(addr), len);
return req->args[0];
}

u32 boot2_run(u32 hi, u32 lo)
{
ipc_request * req;
req = ipc_exchange(IPC_BOOT2_RUN, 2, hi, lo);
return req->args[0];
}

tmd *boot2_tmd(void)
{
tmd *ret = phys_to_virt(ipc_exchange(IPC_BOOT2_TMD, 0)->args[0]);
sync_before_read(ret, sizeof(tmd));
return ret;
}

void getotp(otp_t *otp)
{
sync_before_read(otp, sizeof(*otp));
ipc_exchange(IPC_KEYS_GETOTP, 1, virt_to_phys(otp));
}

void getMiniGitVer(char *buf, u16 len)
{
if (len < 32)
{
memset((void *)buf, 0, 32);
return;
}
sync_before_read(buf, len);
ipc_exchange(IPC_SYS_GETGITS, 1, virt_to_phys(buf));
}

void getseeprom(seeprom_t *seeprom)
{
sync_before_read(seeprom, sizeof(*seeprom));
ipc_exchange(IPC_KEYS_GETEEP, 1, virt_to_phys(seeprom));
}

void aes_reset(void)
{
ipc_exchange(IPC_AES_RESET, 0);
}

void aes_set_key(u8 *key)
{
u32 *keyptr = (u32 *)key;
ipc_exchange(IPC_AES_SETKEY, 4, keyptr[0], keyptr[1], keyptr[2],
keyptr[3]);
}

void aes_set_iv(u8 *iv)
{
u32 *ivptr = (u32 *)iv;
ipc_exchange(IPC_AES_SETIV, 4, ivptr[0], ivptr[1], ivptr[2], ivptr
[3]);
}

void aes_decrypt(u8 *src, u8 *dst, u32 blocks, u8 keep_iv)
{
sync_after_write(src, (blocks+1)*16);
ipc_exchange(IPC_AES_DECRYPT, 4, virt_to_phys(src), virt_to_phys
(dst), blocks, keep_iv);
sync_before_read(dst, (blocks+1)*16);
}

void nand_reset(void)
{
ipc_exchange(IPC_NAND_RESET, 0);
}

u32 nand_getid(void)
{
static u8 idbuf[64] __attribute__((aligned(64)));

ipc_exchange(IPC_NAND_GETID, 1, virt_to_phys(&idbuf));
sync_before_read(idbuf, 0x40);

return idbuf[0] << 24 | idbuf[1] << 16 | idbuf[2] << 8 | idbuf[3];
}

u8 nand_status(void)
{
static u8 buf[64] __attribute__((aligned(64)));

ipc_exchange(IPC_NAND_STATUS, 1, virt_to_phys(&buf));
sync_before_read(buf, 0x40);

return buf[0];
}

int nand_read(u32 pageno, void *data, void *ecc)
{
if (data)
sync_before_read(data, 0x800);
if (ecc)
sync_before_read(ecc, 0x40);
return ipc_exchange(IPC_NAND_READ, 3, pageno,
(!data ? (u32)-1 : virt_to_phys(data)),
(!ecc ? (u32)-1 : virt_to_phys(ecc)))->args[0];
}

void nand_write(u32 pageno, void *data, void *ecc)
{
if (data)
sync_after_write(data, 0x800);
if (ecc)
sync_after_write(ecc, 0x40);
ipc_exchange(IPC_NAND_WRITE, 3, pageno,
(!data ? (u32)-1 : virt_to_phys(data)),
(!ecc ? (u32)-1 : virt_to_phys(ecc)));
}

void nand_erase(u32 pageno)
{
ipc_exchange(IPC_NAND_ERASE, 1, pageno);
}

int sd_mount(void)
{
return ipc_exchange(IPC_SDMMC_ACK, 0)->args[0];
}

int sd_get_state(void)
{
return ipc_exchange(IPC_SDMMC_STATE, 0)->args[0];
}

int sd_protected(void)
{
// return (ipc_exchange(IPC_SD_GETSTATE, 0)->args[0] &
SDHC_WRITE_PROTECT) == SDHC_WRITE_PROTECT;
return 0;
}

int sd_select(void)
{
return 1;
// return ipc_exchange(IPC_SD_SELECT, 0)->args[0];
}

int sd_read(u32 start_block, u32 blk_cnt, void *buffer)
{
int retval;
sync_before_read(buffer, blk_cnt * 512);
retval = ipc_exchange(IPC_SDMMC_READ, 3, start_block, blk_cnt,
virt_to_phys(buffer))->args[0];
return retval;
}

int sd_write(u32 start_block, u32 blk_cnt, const void *buffer)
{
int retval;
sync_after_write(buffer, blk_cnt * 512);
retval = ipc_exchange(IPC_SDMMC_WRITE, 3, start_block, blk_cnt,
virt_to_phys(buffer))->args[0];

return retval;
}

u32 sd_getsize(void)
{
return ipc_exchange(IPC_SDMMC_SIZE, 0)->args[0];
}
Reply all
Reply to author
Forward
0 new messages