Add miniios

This commit is contained in:
marcan 2008-12-28 14:35:37 +01:00
commit 91836dca85
37 changed files with 6547 additions and 0 deletions

3
.gitignore vendored Normal file
View File

@ -0,0 +1,3 @@
*.d
*.bin

45
Makefile Normal file
View File

@ -0,0 +1,45 @@
CC = arm-eabi-gcc
AS = arm-eabi-as
LD = arm-eabi-gcc
OBJCOPY = arm-eabi-objcopy
CFLAGS = -mbig-endian -fomit-frame-pointer -Os -fpic -Wall -I.
ASFLAGS = -mbig-endian
LDFLAGS = -nostartfiles -mbig-endian -Wl,-T,stub.ld
TARGET = iosboot.bin
ELF = iosboot.elf
OBJECTS = start.o main.o vsprintf.o string.o gecko.o memory.o memory_asm.o \
utils_asm.o utils.o ff.o diskio.o sdhc.o powerpc_elf.o powerpc.o panic.o
$(TARGET) : $(ELF)
@echo "OBJCPY $@"
@$(OBJCOPY) -O binary $< $@
$(ELF) : stub.ld $(OBJECTS)
@echo "LD $@"
@$(LD) $(LDFLAGS) $(OBJECTS) -o $@
%.o : %.S
@echo "AS $@"
@$(AS) $(ASFLAGS) -o $@ $<
%.o : %.c
@echo "CC $@"
@$(CC) $(CFLAGS) -c -o $@ $<
%.d: %.c
@echo "DEP $@"
@set -e; $(CC) -M $(CFLAGS) $< \
| sed 's?\($*\)\.o[ :]*?\1.o $@ : ?g' > $@; \
[ -s $@ ] || rm -f $@
%.d: %.S
@echo "DEP $@"
@touch $@
-include $(OBJECTS:.o=.d)
clean:
-rm -f *.elf *.o *.bin *.d

125
diskio.c Normal file
View File

@ -0,0 +1,125 @@
/*-----------------------------------------------------------------------*/
/* Low level disk I/O module skeleton for FatFs (C)ChaN, 2007 */
/*-----------------------------------------------------------------------*/
/* This is a stub disk I/O module that acts as front end of the existing */
/* disk I/O modules and attach it to FatFs module with common interface. */
/*-----------------------------------------------------------------------*/
#include "diskio.h"
#include "sdhc.h"
#include <string.h>
static sdhci_t sdhci;
static u8 *buffer[512] __attribute__((aligned(32)));
/*-----------------------------------------------------------------------*/
/* Inidialize a Drive */
DSTATUS disk_initialize (
BYTE drv /* Physical drive nmuber (0..) */
)
{
s32 ret;
sd_init(&sdhci, 0);
ret = sd_mount(&sdhci);
if(ret < 0)
return STA_NOINIT;
else
return disk_status(drv);
}
/*-----------------------------------------------------------------------*/
/* Return Disk Status */
DSTATUS disk_status (
BYTE drv /* Physical drive nmuber (0..) */
)
{
if(sd_inserted(&sdhci) == 0)
return STA_NODISK;
return 0;
}
/*-----------------------------------------------------------------------*/
/* Read Sector(s) */
DRESULT disk_read (
BYTE drv, /* Physical drive nmuber (0..) */
BYTE *buff, /* Data buffer to store read data */
DWORD sector, /* Sector address (LBA) */
BYTE count /* Number of sectors to read (1..255) */
)
{
int i;
DRESULT res;
res = RES_OK;
for(i = 0; i < count; i++)
{
if(sd_read(&sdhci, sector + i, 1, buffer) != 0)
{
res = RES_ERROR;
break;
}
memcpy(buff + i * 512, buffer, 512);
}
return res;
}
/*-----------------------------------------------------------------------*/
/* Write Sector(s) */
#if _READONLY == 0
DRESULT disk_write (
BYTE drv, /* Physical drive nmuber (0..) */
const BYTE *buff, /* Data to be written */
DWORD sector, /* Sector address (LBA) */
BYTE count /* Number of sectors to write (1..255) */
)
{
int i;
DRESULT res;
res = RES_OK;
for(i = 0; i < count; i++)
{
memcpy(buffer, buff + i * 512, 512);
if(sd_write(&sdhci, sector + i, 1, buffer) != 0)
{
res = RES_ERROR;
break;
}
}
return res;
}
#endif /* _READONLY */
/*-----------------------------------------------------------------------*/
/* Miscellaneous Functions */
DRESULT disk_ioctl (
BYTE drv, /* Physical drive nmuber (0..) */
BYTE ctrl, /* Control code */
void *buff /* Buffer to send/receive control data */
)
{
if(ctrl == CTRL_SYNC)
return RES_OK;
return RES_PARERR;
}
DWORD get_fattime (void)
{
return 0; // TODO
}

71
diskio.h Normal file
View File

@ -0,0 +1,71 @@
/*-----------------------------------------------------------------------
/ Low level disk interface modlue include file R0.06 (C)ChaN, 2007
/-----------------------------------------------------------------------*/
#ifndef _DISKIO
#define _READONLY 1 /* 1: Read-only mode */
#define _USE_IOCTL 1
#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);
DSTATUS disk_status (BYTE);
DRESULT disk_read (BYTE, BYTE*, DWORD, BYTE);
#if _READONLY == 0
DRESULT disk_write (BYTE, const BYTE*, DWORD, BYTE);
#endif
DRESULT disk_ioctl (BYTE, BYTE, void*);
void disk_timerproc (void);
/* 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() */
/* Generic command */
#define CTRL_SYNC 0 /* Mandatory for read/write configuration */
#define GET_SECTOR_COUNT 1 /* Mandatory for only f_mkfs() */
#define GET_SECTOR_SIZE 2
#define GET_BLOCK_SIZE 3 /* Mandatory for only f_mkfs() */
#define CTRL_POWER 4
#define CTRL_LOCK 5
#define CTRL_EJECT 6
/* MMC/SDC command */
#define MMC_GET_TYPE 10
#define MMC_GET_CSD 11
#define MMC_GET_CID 12
#define MMC_GET_OCR 13
#define MMC_GET_SDSTAT 14
/* ATA/CF command */
#define ATA_GET_REV 20
#define ATA_GET_MODEL 21
#define ATA_GET_SN 22
#define _DISKIO
#endif

44
elf.h Normal file
View File

@ -0,0 +1,44 @@
#ifndef __ELF_H__
#define __ELF_H__
#include "types.h"
#define EI_NIDENT 16
typedef struct {
unsigned char e_ident[EI_NIDENT];
u16 e_type;
u16 e_machine;
u32 e_version;
void *e_entry;
u32 e_phoff;
u32 e_shoff;
u32 e_flags;
u16 e_ehsize;
u16 e_phentsize;
u16 e_phnum;
u16 e_shentsize;
u16 e_shnum;
u16 e_shtrndx;
} Elf32_Ehdr;
typedef struct {
u32 p_type;
u32 p_offset;
void *p_vaddr;
void *p_paddr;
u32 p_filesz;
u32 p_memsz;
u32 p_flags;
u32 p_align;
} Elf32_Phdr;
#define PT_NULL 0
#define PT_LOAD 1
#define PT_DYNAMIC 2
#define PT_INTERP 3
#define PT_NOTE 4
#define PT_SHLIB 5
#define PT_PHDR 6
#endif

2036
ff.c Normal file

File diff suppressed because it is too large Load Diff

339
ff.h Normal file
View File

@ -0,0 +1,339 @@
/*--------------------------------------------------------------------------/
/ FatFs - FAT file system module include file R0.06 (C)ChaN, 2008
/---------------------------------------------------------------------------/
/ FatFs module is an experimenal project to implement FAT file system to
/ cheap microcontrollers. This is a free software and is opened for education,
/ research and development under license policy of following trems.
/
/ Copyright (C) 2008, ChaN, all right reserved.
/
/ * The FatFs module is a free software and there is no warranty.
/ * You can use, modify and/or redistribute it for personal, non-profit or
/ commercial use without any restriction under your responsibility.
/ * Redistributions of source code must retain the above copyright notice.
/
/---------------------------------------------------------------------------*/
#ifndef _FATFS
#define _MCU_ENDIAN 2
/* The _MCU_ENDIAN defines which access method is used to the FAT structure.
/ 1: Enable word access.
/ 2: Disable word access and use byte-by-byte access instead.
/ When the architectural byte order of the MCU is big-endian and/or address
/ miss-aligned access results incorrect behavior, the _MCU_ENDIAN must be set to 2.
/ If it is not the case, it can also be set to 1 for good code efficiency. */
#define _FS_READONLY 1
/* Setting _FS_READONLY to 1 defines read only configuration. This removes
/ writing functions, f_write, f_sync, f_unlink, f_mkdir, f_chmod, f_rename,
/ f_truncate and useless f_getfree. */
#define _FS_MINIMIZE 2
/* The _FS_MINIMIZE option defines minimization level to remove some functions.
/ 0: Full function.
/ 1: f_stat, f_getfree, f_unlink, f_mkdir, f_chmod, f_truncate and f_rename are removed.
/ 2: f_opendir and f_readdir are removed in addition to level 1.
/ 3: f_lseek is removed in addition to level 2. */
#define _USE_STRFUNC 0
/* To enable string functions, set _USE_STRFUNC to 1 or 2. */
#define _USE_MKFS 0
/* When _USE_MKFS is set to 1 and _FS_READONLY is set to 0, f_mkfs function is
/ enabled. */
#define _DRIVES 2
/* Number of logical drives to be used. This affects the size of internal table. */
#define _MULTI_PARTITION 0
/* When _MULTI_PARTITION is set to 0, each logical drive is bound to same
/ physical drive number and can mount only 1st primaly partition. When it is
/ set to 1, each logical drive can mount a partition listed in Drives[]. */
#define _USE_FSINFO 0
/* To enable FSInfo support on FAT32 volume, set _USE_FSINFO to 1. */
#define _USE_SJIS 1
/* When _USE_SJIS is set to 1, Shift-JIS code transparency is enabled, otherwise
/ only US-ASCII(7bit) code can be accepted as file/directory name. */
#define _USE_NTFLAG 1
/* When _USE_NTFLAG is set to 1, upper/lower case of the file name is preserved.
/ Note that the files are always accessed in case insensitive. */
#include "integer.h"
/* Definitions corresponds to multiple sector size (not tested) */
#define S_MAX_SIZ 512U /* Do not change */
#if S_MAX_SIZ > 512U
#define SS(fs) ((fs)->s_size)
#else
#define SS(fs) 512U
#endif
/* File system object structure */
typedef struct _FATFS {
WORD id; /* File system mount ID */
WORD n_rootdir; /* Number of root directory entries */
DWORD winsect; /* Current sector appearing in the win[] */
DWORD sects_fat; /* Sectors per fat */
DWORD max_clust; /* Maximum cluster# + 1 */
DWORD fatbase; /* FAT start sector */
DWORD dirbase; /* Root directory start sector (cluster# for FAT32) */
DWORD database; /* Data start sector */
#if !_FS_READONLY
DWORD last_clust; /* Last allocated cluster */
DWORD free_clust; /* Number of free clusters */
#if _USE_FSINFO
DWORD fsi_sector; /* fsinfo sector */
BYTE fsi_flag; /* fsinfo dirty flag (1:must be written back) */
BYTE pad2;
#endif
#endif
BYTE fs_type; /* FAT sub type */
BYTE csize; /* Number of sectors per cluster */
#if S_MAX_SIZ > 512U
WORD s_size; /* Sector size */
#endif
BYTE n_fats; /* Number of FAT copies */
BYTE drive; /* Physical drive number */
BYTE winflag; /* win[] dirty flag (1:must be written back) */
BYTE pad1;
BYTE win[S_MAX_SIZ]; /* Disk access window for Directory/FAT */
} FATFS;
/* Directory object structure */
typedef struct _DIR {
WORD id; /* Owner file system mount ID */
WORD index; /* Current index */
FATFS* fs; /* Pointer to the owner file system object */
DWORD sclust; /* Start cluster */
DWORD clust; /* Current cluster */
DWORD sect; /* Current sector */
} DIR;
/* File object structure */
typedef struct _FIL {
WORD id; /* Owner file system mount ID */
BYTE flag; /* File status flags */
BYTE csect; /* Sector address in the cluster */
FATFS* fs; /* Pointer to the owner file system object */
DWORD fptr; /* File R/W pointer */
DWORD fsize; /* File size */
DWORD org_clust; /* File start cluster */
DWORD curr_clust; /* Current cluster */
DWORD curr_sect; /* Current sector */
#if _FS_READONLY == 0
DWORD dir_sect; /* Sector containing the directory entry */
BYTE* dir_ptr; /* Ponter to the directory entry in the window */
#endif
BYTE buffer[S_MAX_SIZ]; /* File R/W buffer */
} FIL;
/* File status structure */
typedef struct _FILINFO {
DWORD fsize; /* Size */
WORD fdate; /* Date */
WORD ftime; /* Time */
BYTE fattrib; /* Attribute */
char fname[8+1+3+1]; /* Name (8.3 format) */
} FILINFO;
/* Definitions corresponds to multi partition */
#if _MULTI_PARTITION != 0 /* Multiple partition cfg */
typedef struct _PARTITION {
BYTE pd; /* Physical drive # (0-255) */
BYTE pt; /* Partition # (0-3) */
} PARTITION;
extern
const PARTITION Drives[]; /* Logical drive# to physical location conversion table */
#define LD2PD(drv) (Drives[drv].pd) /* Get physical drive# */
#define LD2PT(drv) (Drives[drv].pt) /* Get partition# */
#else /* Single partition cfg */
#define LD2PD(drv) (drv) /* Physical drive# is equal to logical drive# */
#define LD2PT(drv) 0 /* Always mounts the 1st partition */
#endif
/* File function return code (FRESULT) */
typedef enum {
FR_OK = 0, /* 0 */
FR_NOT_READY, /* 1 */
FR_NO_FILE, /* 2 */
FR_NO_PATH, /* 3 */
FR_INVALID_NAME, /* 4 */
FR_INVALID_DRIVE, /* 5 */
FR_DENIED, /* 6 */
FR_EXIST, /* 7 */
FR_RW_ERROR, /* 8 */
FR_WRITE_PROTECTED, /* 9 */
FR_NOT_ENABLED, /* 10 */
FR_NO_FILESYSTEM, /* 11 */
FR_INVALID_OBJECT, /* 12 */
FR_MKFS_ABORTED /* 13 */
} FRESULT;
/*-----------------------------------------------------*/
/* FatFs module application interface */
FRESULT f_mount (BYTE, FATFS*); /* Mount/Unmount a logical drive */
FRESULT f_open (FIL*, const char*, BYTE); /* Open or create a file */
FRESULT f_read (FIL*, void*, UINT, UINT*); /* Read data from a file */
FRESULT f_write (FIL*, const void*, UINT, UINT*); /* Write data to a file */
FRESULT f_lseek (FIL*, DWORD); /* Move file pointer of a file object */
FRESULT f_close (FIL*); /* Close an open file object */
FRESULT f_opendir (DIR*, const char*); /* Open an existing directory */
FRESULT f_readdir (DIR*, FILINFO*); /* Read a directory item */
FRESULT f_stat (const char*, FILINFO*); /* Get file status */
FRESULT f_getfree (const char*, DWORD*, FATFS**); /* Get number of free clusters on the drive */
FRESULT f_truncate (FIL*); /* Truncate file */
FRESULT f_sync (FIL*); /* Flush cached data of a writing file */
FRESULT f_unlink (const char*); /* Delete an existing file or directory */
FRESULT f_mkdir (const char*); /* Create a new directory */
FRESULT f_chmod (const char*, BYTE, BYTE); /* Change file/dir attriburte */
FRESULT f_utime (const char*, const FILINFO*); /* Change file/dir timestamp */
FRESULT f_rename (const char*, const char*); /* Rename/Move a file or directory */
FRESULT f_mkfs (BYTE, BYTE, WORD); /* Create a file system on the drive */
#if _USE_STRFUNC
#define feof(fp) ((fp)->fptr == (fp)->fsize)
#define EOF -1
int fputc (int, FIL*); /* Put a character to the file */
int fputs (const char*, FIL*); /* Put a string to the file */
int fprintf (FIL*, const char*, ...); /* Put a formatted string to the file */
char* fgets (char*, int, FIL*); /* Get a string from the file */
#endif
/* User defined function to give a current time to fatfs module */
DWORD get_fattime (void); /* 31-25: Year(0-127 org.1980), 24-21: Month(1-12), 20-16: Day(1-31) */
/* 15-11: Hour(0-23), 10-5: Minute(0-59), 4-0: Second(0-29 *2) */
/* File access control and file status flags (FIL.flag) */
#define FA_READ 0x01
#define FA_OPEN_EXISTING 0x00
#if _FS_READONLY == 0
#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
#define FA__ERROR 0x80
/* 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 */
/* Offset of FAT structure members */
#define BS_jmpBoot 0
#define BS_OEMName 3
#define BPB_BytsPerSec 11
#define BPB_SecPerClus 13
#define BPB_RsvdSecCnt 14
#define BPB_NumFATs 16
#define BPB_RootEntCnt 17
#define BPB_TotSec16 19
#define BPB_Media 21
#define BPB_FATSz16 22
#define BPB_SecPerTrk 24
#define BPB_NumHeads 26
#define BPB_HiddSec 28
#define BPB_TotSec32 32
#define BS_55AA 510
#define BS_DrvNum 36
#define BS_BootSig 38
#define BS_VolID 39
#define BS_VolLab 43
#define BS_FilSysType 54
#define BPB_FATSz32 36
#define BPB_ExtFlags 40
#define BPB_FSVer 42
#define BPB_RootClus 44
#define BPB_FSInfo 48
#define BPB_BkBootSec 50
#define BS_DrvNum32 64
#define BS_BootSig32 66
#define BS_VolID32 67
#define BS_VolLab32 71
#define BS_FilSysType32 82
#define FSI_LeadSig 0
#define FSI_StrucSig 484
#define FSI_Free_Count 488
#define FSI_Nxt_Free 492
#define MBR_Table 446
#define DIR_Name 0
#define DIR_Attr 11
#define DIR_NTres 12
#define DIR_CrtTime 14
#define DIR_CrtDate 16
#define DIR_FstClusHI 20
#define DIR_WrtTime 22
#define DIR_WrtDate 24
#define DIR_FstClusLO 26
#define DIR_FileSize 28
/* Multi-byte word access macros */
#if _MCU_ENDIAN == 1 /* Use word access */
#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)
#elif _MCU_ENDIAN == 2 /* Use byte-by-byte access */
#define LD_WORD(ptr) (WORD)(((WORD)*(volatile BYTE*)((ptr)+1)<<8)|(WORD)*(volatile BYTE*)(ptr))
#define LD_DWORD(ptr) (DWORD)(((DWORD)*(volatile BYTE*)((ptr)+3)<<24)|((DWORD)*(volatile BYTE*)((ptr)+2)<<16)|((WORD)*(volatile BYTE*)((ptr)+1)<<8)|*(volatile BYTE*)(ptr))
#define ST_WORD(ptr,val) *(volatile BYTE*)(ptr)=(BYTE)(val); *(volatile BYTE*)((ptr)+1)=(BYTE)((WORD)(val)>>8)
#define ST_DWORD(ptr,val) *(volatile BYTE*)(ptr)=(BYTE)(val); *(volatile BYTE*)((ptr)+1)=(BYTE)((WORD)(val)>>8); *(volatile BYTE*)((ptr)+2)=(BYTE)((DWORD)(val)>>16); *(volatile BYTE*)((ptr)+3)=(BYTE)((DWORD)(val)>>24)
#else
#error Do not forget to set _MCU_ENDIAN properly!
#endif
#define _FATFS
#endif /* _FATFS */

201
gecko.c Normal file
View File

@ -0,0 +1,201 @@
#include "types.h"
#include "start.h"
#include "vsprintf.h"
#include "string.h"
#include "utils.h"
#include "hollywood.h"
// These two don't really seem to be needed
// Maybe only for boot buffer or some PPC stuff
static inline void _gecko_get(void)
{
//set32(HW_EXICTRL, 1);
}
static inline void _gecko_release(void)
{
//clear32(HW_EXICTRL, 1);
}
static u32 _gecko_command(u32 command)
{
u32 i;
// Memory Card Port B (Channel 1, Device 0, Frequency 3 (32Mhz Clock))
write32(EXI1_CSR, 0xd0);
write32(EXI1_DATA, command);
write32(EXI1_CR, 0x19);
i = 1000;
while ((read32(EXI1_CR) & 1) && (i--));
i = read32(EXI1_DATA);
write32(EXI1_CSR, 0);
return i;
}
static u32 _gecko_sendbyte(char sendbyte)
{
u32 i = 0;
i = _gecko_command(0xB0000000 | (sendbyte<<20));
if (i&0x04000000)
return 1; // Return 1 if byte was sent
return 0;
}
static u32 _gecko_recvbyte(char *recvbyte)
{
u32 i = 0;
*recvbyte = 0;
i = _gecko_command(0xA0000000);
if (i&0x08000000) {
// Return 1 if byte was received
*recvbyte = (i>>16)&0xff;
return 1;
}
return 0;
}
static u32 _gecko_checksend(void)
{
u32 i = 0;
i = _gecko_command(0xC0000000);
if (i&0x04000000)
return 1; // Return 1 if safe to send
return 0;
}
static u32 _gecko_checkrecv(void)
{
u32 i = 0;
i = _gecko_command(0xD0000000);
if (i&0x04000000)
return 1; // Return 1 if safe to recv
return 0;
}
void gecko_init(void)
{
write32(EXI0_CSR, 0);
write32(EXI1_CSR, 0);
write32(EXI2_CSR, 0);
write32(EXI0_CSR, 0x2000);
write32(EXI0_CSR, 3<<10);
write32(EXI1_CSR, 3<<10);
}
void gecko_flush(void)
{
char tmp;
while(_gecko_recvbyte(&tmp));
}
int gecko_isalive(void)
{
u32 i = 0;
i = _gecko_command(0x90000000);
if (i&0x04700000)
return 1;
return 0;
}
int gecko_recvbuffer(void *buffer, u32 size)
{
u32 left = size;
char *ptr = (char*)buffer;
_gecko_get();
while(left>0) {
if(!_gecko_recvbyte(ptr))
break;
ptr++;
left--;
}
_gecko_release();
return (size - left);
}
int gecko_sendbuffer(const void *buffer, u32 size)
{
u32 left = size;
char *ptr = (char*)buffer;
_gecko_get();
while(left>0) {
if(!_gecko_sendbyte(*ptr))
break;
ptr++;
left--;
}
_gecko_release();
return (size - left);
}
int gecko_recvbuffer_safe(void *buffer, u32 size)
{
u32 left = size;
char *ptr = (char*)buffer;
_gecko_get();
while(left>0) {
if(_gecko_checkrecv()) {
if(!_gecko_recvbyte(ptr))
break;
ptr++;
left--;
}
}
_gecko_release();
return (size - left);
}
int gecko_sendbuffer_safe(const void *buffer, u32 size)
{
u32 left = size;
char *ptr = (char*)buffer;
if((read32(HW_EXICTRL) & EXICTRL_ENABLE_EXI) == 0)
return left;
_gecko_get();
while(left>0) {
if(_gecko_checksend()) {
if(!_gecko_sendbyte(*ptr))
break;
ptr++;
left--;
}
}
_gecko_release();
return (size - left);
}
int gecko_putchar(int ic)
{
char b = ic;
return gecko_sendbuffer(&b, 1);
}
int gecko_getchar(void)
{
char b;
if(gecko_recvbuffer_safe(&b, 1) != 1)
return -1;
return b;
}
int gecko_puts(const char *s)
{
udelay(10000);
return gecko_sendbuffer(s, strlen(s));
}
int gecko_printf( const char *fmt, ...)
{
va_list args;
char buffer[1024];
int i;
va_start(args, fmt);
i = vsprintf(buffer, fmt, args);
va_end(args);
gecko_puts(buffer);
return i;
}

18
gecko.h Normal file
View File

@ -0,0 +1,18 @@
#ifndef __GECKO_H__
#define __GECKO_H__
#include "types.h"
void gecko_flush(void);
int gecko_isalive(void);
int gecko_recvbuffer(void *buffer, u32 size);
int gecko_sendbuffer(const void *buffer, u32 size);
int gecko_recvbuffer_safe(void *buffer, u32 size);
int gecko_sendbuffer_safe(const void *buffer, u32 size);
int gecko_putchar(int c);
int gecko_getchar(void);
int gecko_puts(const char *s);
int gecko_printf( const char *fmt, ...);
void gecko_init(void);
#endif

258
hollywood.h Normal file
View File

@ -0,0 +1,258 @@
#ifndef __HOLLYWOOD_H__
#define __HOLLYWOOD_H__
/* Hollywood Registers */
#define HW_PPC_REG_BASE 0xd000000
#define HW_REG_BASE 0xd800000
// The PPC can only see the first three IPC registers
#define HW_IPC_PPCMSG (HW_REG_BASE + 0x000) //PPC to ARM
#define HW_IPC_PPCCTRL (HW_REG_BASE + 0x004)
#define HW_IPC_ARMMSG (HW_REG_BASE + 0x008) //ARM to PPC
#define HW_IPC_ARMCTRL (HW_REG_BASE + 0x00c)
// Write one to send a message. Cleared when peer writes one to IPC_CTRL_RECV.
#define IPC_CTRL_SEND 0x01
// Set by peer to acknowledge a message. Write one to clear.
#define IPC_CTRL_SENT 0x02
// Set by peer to send a message. Write one to clear.
#define IPC_CTRL_RECV 0x04
// Write one acknowledge a message. Cleared when peer writes one to IPC_CTRL_SENT.
#define IPC_CTRL_RECVD 0x08
// Enable interrupt when a message is received
#define IPC_CTRL_INT_RECV 0x10
// Enable interrupt when a sent message is acknowledged
#define IPC_CTRL_INT_SENT 0x20
/*
The IPC registers are connected to each other.
Both registers are identical and this works for
both peers. Flag bits are cleared by writing a one
to them.
When Peer A sets this Peer B sees this set
IPC_CTRL_SEND IPC_CTRL_RECV
IPC_CTRL_RECVD IPC_CTRL_SENT
In fact, bit _SEND on Peer A and bit _RECV on peer B are the same bit,
and the same goes for _RECVD and _SENT, except writing one from A _sets_
the bit, and writing one from B _clears_ the bit. The same, of course,
is true for the other pair of bits in the other direction.
The flow, therefore, goes as follows, for a message
from A to B. Steps with the same number can be taken
in any order.
1. Peer A writes the message address to the register
2. Peer A sets IPC_CTRL_SEND
3. Peer B sees IPC_CTRL_RECV
4. Peer B writes one to IPC_CTRL_RECV to clear it (A's IPC_CTRL_SEND is cleared at this point)
4. Peer B reads its message address register
5. Peer B sets IPC_CTRL_RECVD
6. Peer A sees IPC_CTRL_SENT
7. Peer A writes one to IPC_CTRL_SENT to clear it (B's IPC_CTRL_RECVD is cleared at this point)
7. Peer A may now write to the message address register again
The same is true for a message from Peer B to Peer A.
In the particular case of IOS IPC, the PPC is always the "master"
(it sends requests as messages) and the ARM is always the "slave"
(it replies to PPC's requests). IOS can handle up to 16(15?)
simultaneously pending transactions (the PPC can send up to 16(15?)
messages without getting any replies - for example, due to
asynchronous requests or multithreaded execution of blocking
requests)
*/
#define HW_TIMER (HW_REG_BASE + 0x010)
#define HW_ALARM (HW_REG_BASE + 0x014)
// maybe?
#define HW_FIQFLAG (HW_REG_BASE + 0x030)
#define HW_FIQENABLE (HW_REG_BASE + 0x034)
#define HW_IRQFLAG (HW_REG_BASE + 0x038)
#define HW_IRQENABLE (HW_REG_BASE + 0x03c)
#define HW_MEMMIRR (HW_REG_BASE + 0x060)
// something to do with PPCBOOT
// and legacy DI it seems ?!?
#define HW_EXICTRL (HW_REG_BASE + 0x070)
#define EXICTRL_ENABLE_EXI 1
// PPC side of GPIO1 (Starlet can access this too)
// Output state
#define HW_GPIO1BOUT (HW_REG_BASE + 0x0c0)
// Direction (1=output)
#define HW_GPIO1BDIR (HW_REG_BASE + 0x0c4)
// Input state
#define HW_GPIO1BIN (HW_REG_BASE + 0x0c8)
// Interrupt level
#define HW_GPIO1BINTLVL (HW_REG_BASE + 0x0cc)
// Interrupt flags (write 1 to clear)
#define HW_GPIO1BINTFLAG (HW_REG_BASE + 0x0d0)
// Interrupt propagation enable
// Do these interrupts go anywhere???
#define HW_GPIO1BINTENABLE (HW_REG_BASE + 0x0d4)
//??? seems to be a mirror of inputs at some point... power-up state?
#define HW_GPIO1BINMIR (HW_REG_BASE + 0x0d8)
// 0xFFFFFF by default, if cleared disables respective outputs. Top bits non-settable.
#define HW_GPIO1ENABLE (HW_REG_BASE + 0x0dc)
#define HW_GPIO1_SLOT 0x000020
#define HW_GPIO1_DEBUG 0xFF0000
#define HW_GPIO1_DEBUG_SH 16
// Starlet side of GPIO1
// Output state
#define HW_GPIO1OUT (HW_REG_BASE + 0x0e0)
// Direction (1=output)
#define HW_GPIO1DIR (HW_REG_BASE + 0x0e4)
// Input state
#define HW_GPIO1IN (HW_REG_BASE + 0x0e8)
// Interrupt level
#define HW_GPIO1INTLVL (HW_REG_BASE + 0x0ec)
// Interrupt flags (write 1 to clear)
#define HW_GPIO1INTFLAG (HW_REG_BASE + 0x0f0)
// Interrupt propagation enable (interrupts go to main interrupt 0x800)
#define HW_GPIO1INTENABLE (HW_REG_BASE + 0x0f4)
//??? seems to be a mirror of inputs at some point... power-up state?
#define HW_GPIO1INMIR (HW_REG_BASE + 0x0f8)
// Owner of each GPIO bit. If 1, GPIO1B registers assume control. If 0, GPIO1 registers assume control.
#define HW_GPIO1OWNER (HW_REG_BASE + 0x0fc)
// ????
#define HW_DIFLAGS (HW_REG_BASE + 0x180)
#define DIFLAGS_BOOT_CODE 0x100000
// maybe a GPIO???
#define HW_RESETS (HW_REG_BASE + 0x194)
#define HW_GPIO2OUT (HW_REG_BASE + 0x1c8)
#define HW_GPIO2DIR (HW_REG_BASE + 0x1cc)
#define HW_GPIO2IN (HW_REG_BASE + 0x1d0)
#define HW_OTPCMD (HW_REG_BASE + 0x1ec)
#define HW_OTPDATA (HW_REG_BASE + 0x1f0)
/* NAND Registers */
#define NAND_REG_BASE 0xd010000
#define NAND_CMD (NAND_REG_BASE + 0x000)
#define NAND_STATUS NAND_CMD
#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_UNK1 (NAND_REG_BASE + 0x018)
#define NAND_UNK2 (NAND_REG_BASE + 0x01c)
/* AES Registers */
#define AES_REG_BASE 0xd020000
#define AES_CMD (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 */
#define SHA_REG_BASE 0xd030000
#define SHA_CMD (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 */
#define SD_REG_BASE 0xd070000
#define SDHC_SDMA_ADDR (0x000)
#define SDHC_BLOCK_SIZE (0x004)
#define SDHC_BLOCK_COUNT (0x006)
#define SDHC_CMD_ARG (0x008)
#define SDHC_CMD_TRANSFER_MODE (0x00c)
#define SDHC_CMD (0x00e)
#define SDHC_RESPONSE (0x010)
#define SDHC_DATA (0x020)
#define SDHC_PRESENT_STATE (0x024)
#define SDHC_HOST_CONTROL (0x028)
#define SDHC_POWER_CONTROL (0x029)
#define SDHC_BLOCK_GAP_CONTROL (0x02a)
#define SDHC_WAKEUP_CONTROL (0x02b)
#define SDHC_CLOCK_CONTROL (0x02c)
#define SDHC_TIMEOUT_CONTROL (0x02e)
#define SDHC_SOFTWARE_RESET (0x02f)
#define SDHC_NORMAL_INTERRUPT_STATUS (0x030)
#define SDHC_ERROR_INTERRUPT_STATUS (0x032)
#define SDHC_NORMAL_INTERRUPT_ENABLE (0x034)
#define SDHC_ERROR_INTERRUPT_ENABLE (0x036)
#define SDHC_NORMAL_INTERRUPT_SIGNAL_ENABLE (0x038)
#define SDHC_ERROR_INTERRUPT_SIGNAL_ENABLE (0x03a)
#define SDHC_AMCD12_ERROR_STATUS (0x03c)
#define SDHC_CAPABILITIES (0x040)
#define SDHC_MAX_CAPABILITIES (0x048)
#define SDHC_FORCE_ERROR_EVENT_ACMD12 (0x050)
#define SDHC_FORCE_ERROR_EVENT_INTERRUPT (0x052)
#define SDHC_ADMA_ERROR_STATUS (0x054)
#define SDHC_ADMA_SYSTEM_ADDR (0x058)
#define SDHC_SLOT_INTERRUPT_STATUS (0x0fc)
#define SDHC_VERSION (0x0fe)
/* EXI Registers */
#define EXI_REG_BASE 0xd806800
#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 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)
#define EXI_BOOT_BASE (EXI_REG_BASE+0x040)
/* MEMORY CONTROLLER Registers */
#define MEM_REG_BASE 0xd8b4000
#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_FLUSHREQ (MEM_REG_BASE+0x228)
#define MEM_FLUSHACK (MEM_REG_BASE+0x22a)
#endif

30
integer.h Normal file
View File

@ -0,0 +1,30 @@
/*-------------------------------------------*/
/* Integer type definitions for FatFs module */
/*-------------------------------------------*/
#ifndef _INTEGER
/* These types must be 16-bit, 32-bit or larger integer */
typedef int INT;
typedef unsigned int UINT;
/* These types must be 8-bit integer */
typedef signed char CHAR;
typedef unsigned char UCHAR;
typedef unsigned char BYTE;
/* These types must be 16-bit integer */
typedef short SHORT;
typedef unsigned short USHORT;
typedef unsigned short WORD;
/* These types must be 32-bit integer */
typedef long LONG;
typedef unsigned long ULONG;
typedef unsigned long DWORD;
/* Boolean type */
typedef enum { FALSE = 0, TRUE } BOOL;
#define _INTEGER
#endif

208
lcd.c Normal file
View File

@ -0,0 +1,208 @@
#include "types.h"
#include "lcd.h"
#include "start.h"
#include "vsprintf.h"
#include "string.h"
#include "utils.h"
#include "hollywood.h"
void lcdinit(void);
char ddram[0x80];
u8 ddaddr = 0;
u32 chardelay = 0;
#define WIDTH 16
#define HEIGHT 2
u8 linestarts[HEIGHT] = { 0x00, 0x40 };
u8 cx, cy;
// for 4x20
//u8 linestarts[HEIGHT] = { 0x00, 0x40, 0x14, 0x54 };
#define LCD_HOME_CLEAR 0x01
#define LCD_HOME 0x02
#define LCD_ENTRY_MODE 0x04
# define EM_INC 0x02
# define EM_DEC 0x00
# define EM_SHIFT 0x01
#define LCD_DISPLAY_ONOFF 0x08
# define D_DISPLAY 0x04
# define D_CURSOR 0x02
# define D_BLINK 0x01
#define LCD_SHIFT 0x10
# define SH_SHIFT 0x08
# define SH_CURSOR 0x00
# define SH_RIGHT 0x04
# define SH_LEFT 0x00
#define LCD_FUNCTION_SET 0x20
# define FS_8BIT 0x10
# define FS_4BIT 0x00
# define FS_2LINE 0x08
# define FS_1LINE 0x00
# define FS_5X10 0x04
# define FS_5X8 0x00
#define LCD_CGRAM 0x40
#define LCD_DDRAM 0x80
#define LCD_PORT HW_GPIO1OUT
#define LCD_MASK 0x00FC0000
#define LCD_E 0x00040000
#define LCD_RS 0x00080000
#define LCD_DSHIFT 20
static void _lcdnybble(char rs, char n)
{
if(rs)
mask32(LCD_PORT, LCD_MASK, ((n&0xF) << LCD_DSHIFT) | LCD_RS);
else
mask32(LCD_PORT, LCD_MASK, ((n&0xF) << LCD_DSHIFT));
udelay(4);
set32(HW_GPIO1OUT, LCD_E);
udelay(4);
clear32(HW_GPIO1OUT, LCD_E);
udelay(4);
}
static void _lcdcmd(char c)
{
_lcdnybble(0, c>>4);
_lcdnybble(0, c&0x0F);
udelay(50);
}
static void _lcdwrite(char c)
{
_lcdnybble(1, c>>4);
_lcdnybble(1, c&0x0F);
ddram[ddaddr] = c;
ddaddr = (ddaddr+1)&0x7F;
udelay(50);
}
static void _lcdgoto(u8 addr)
{
_lcdcmd(LCD_DDRAM | addr);
ddaddr = addr;
}
static void _lcdgotoxy(u8 x, u8 y)
{
u8 addr = (x + linestarts[y]);
_lcdcmd(LCD_DDRAM | addr);
ddaddr = addr;
}
static void _lcdclear(void)
{
int i;
_lcdcmd(LCD_HOME_CLEAR);
udelay(2000);
for(i=0;i<0x80;i++) {
ddram[i] = ' ';
}
}
static void _lcdscroll(u8 count)
{
int x,y;
_lcdcmd(LCD_HOME_CLEAR);
udelay(2000);
for(y=0;y<(HEIGHT-count);y++) {
_lcdgotoxy(0,y);
for(x=0;x<WIDTH;x++) {
_lcdwrite(ddram[x + linestarts[y+count]]);
}
}
for(;y<HEIGHT;y++) {
for(x=0;x<WIDTH;x++) {
ddram[linestarts[y] + x] = ' ';
}
}
_lcdgoto(linestarts[HEIGHT-1]);
}
void lcd_init(void)
{
cx = cy = 0;
ddaddr = 0;
memset(ddram, ' ', 0x80);
clear32(LCD_PORT, LCD_MASK);
udelay(100000);
_lcdnybble(0, (LCD_FUNCTION_SET | FS_8BIT)>>4);
udelay(10000);
_lcdnybble(0, (LCD_FUNCTION_SET | FS_8BIT)>>4);
udelay(1000);
_lcdnybble(0, (LCD_FUNCTION_SET | FS_8BIT)>>4);
udelay(1000);
_lcdnybble(0, (LCD_FUNCTION_SET | FS_4BIT)>>4);
udelay(1000);
_lcdcmd(LCD_FUNCTION_SET | FS_4BIT | FS_2LINE | FS_5X8);
_lcdcmd(LCD_DISPLAY_ONOFF);
_lcdcmd(LCD_HOME_CLEAR);
udelay(2000);
_lcdcmd(LCD_ENTRY_MODE | EM_INC);
_lcdcmd(LCD_DISPLAY_ONOFF | D_DISPLAY | D_CURSOR);
}
int lcd_putchar(int ic)
{
char c = ic;
// defer newlines to keep last line of LCD full
if(c == '\n') {
cx = 0;
cy++;
if(cy < HEIGHT)
_lcdgotoxy(cx,cy);
} else {
if(cx >= 16) {
cx = 0;
cy++;
if(cy < HEIGHT)
_lcdgotoxy(cx,cy);
}
if(cy >= (2*HEIGHT-1)) {
_lcdclear();
_lcdgoto(linestarts[HEIGHT-1]);
cy = HEIGHT - 1;
cx = 0;
} else if(cy >= HEIGHT) {
_lcdscroll(cy - HEIGHT + 1);
cy = HEIGHT - 1;
cx = 0;
}
_lcdwrite(c);
cx++;
}
return (u8)c;
}
void lcd_setdelay(u32 delay)
{
chardelay = delay;
}
int lcd_puts(const char *s)
{
while(*s) {
lcd_putchar(*s++);
udelay(chardelay);
}
return 0;
}
int lcd_printf( const char *fmt, ...)
{
va_list args;
char buffer[1024];
int i;
va_start(args, fmt);
i = vsprintf(buffer, fmt, args);
va_end(args);
lcd_puts(buffer);
return i;
}

11
lcd.h Normal file
View File

@ -0,0 +1,11 @@
#ifndef __LCD_H__
#define __LCD_H__
#include "types.h"
void lcd_init(void);
int lcd_putchar(int c);
int lcd_puts(const char *s);
void lcd_setdelay(u32 delay);
int lcd_printf( const char *fmt, ...);
#endif

168
main.c Normal file
View File

@ -0,0 +1,168 @@
#include "types.h"
#include "utils.h"
#include "start.h"
#include "hollywood.h"
#include "sdhc.h"
#include "string.h"
#include "memory.h"
#include "elf.h"
#include "gecko.h"
#include "ff.h"
#include "panic.h"
#include "powerpc_elf.h"
typedef struct {
u32 hdrsize;
u32 loadersize;
u32 elfsize;
u32 argument;
} ioshdr;
int dogecko;
void boot2_loadelf(u8 *elf) {
if(dogecko)
gecko_puts("Loading boot2 ELF...\n");
if(memcmp("\x7F" "ELF\x01\x02\x01\x61\x01",elf,9)) {
if(dogecko)
gecko_printf("Invalid ELF header! 0x%02x 0x%02x 0x%02x 0x%02x\n",elf[0], elf[1], elf[2], elf[3]);
panic(0xE3);
}
Elf32_Ehdr *ehdr = (Elf32_Ehdr*)elf;
if(ehdr->e_phoff == 0) {
if(dogecko)
gecko_printf("ELF has no program headers!\n");
panic(0xE4);
}
int count = ehdr->e_phnum;
Elf32_Phdr *phdr = (Elf32_Phdr*)(elf + ehdr->e_phoff);
if(dogecko)
gecko_printf("PHDRS at %p\n",phdr);
while(count--)
{
if(phdr->p_type != PT_LOAD) {
if(dogecko)
gecko_printf("Skipping PHDR of type %d\n",phdr->p_type);
} else {
void *src = elf + phdr->p_offset;
if(dogecko)
gecko_printf("LOAD %p -> %p [0x%x]\n",src, phdr->p_paddr, phdr->p_filesz);
memcpy(phdr->p_paddr, src, phdr->p_filesz);
}
phdr++;
}
if(dogecko)
gecko_puts("Done!\n");
}
#define PPC_BOOT_FILE "/system/ppcboot.elf"
FATFS fatfs;
void turn_stuff_on(void)
{
clear32(HW_GPIO1OUT, 0x10);
udelay(100);
set32(HW_RESETS, 0x7FFFFCF);
}
void reset_audio(u8 flag)
{
// GPIO2IN is probably mislabeled
if(flag)
clear32(HW_DIFLAGS, 0x180);
else
mask32(HW_DIFLAGS, 0x80, 0x100);
clear32(HW_GPIO2IN, 0x80000000);
udelay(2);
clear32(HW_GPIO2IN, 0x40000000);
if(flag) {
clear32(HW_GPIO2IN, 0x10000000);
mask32(HW_GPIO2DIR, 0x7FFFFFF, 0x4B0FFCE);
} else {
mask32(HW_GPIO2DIR, 0x7FFFFFF, 0x4640FC0);
}
udelay(10);
set32(HW_GPIO2IN, 0x40000000);
udelay(500);
set32(HW_GPIO2IN, 0x80000000);
udelay(2);
}
void regs_setup(void)
{
u8 hwood_ver, hwood_hi, hwood_lo;
hwood_ver = read32(0xd800214);
hwood_hi = hwood_ver >> 4; //R0
hwood_lo = hwood_ver & 0xF; //R1
*(u32*)0xFFFF897C = *(u32*)0xFFFF86D0;
set32(HW_EXICTRL, EXICTRL_ENABLE_EXI);
mem_protect(1, (void*)0x13420000, (void*)0x1fffffff);
clear32(HW_EXICTRL, 0x10);
if(hwood_hi == 0)
write32(0xd8b0010, 0);
write32(0xd8b0010, 0);
if(hwood_hi == 1 && hwood_lo == 0)
mask32(0xd800140, 0x0000FFF0, 1);
set32(0xd80018C, 0x400);
set32(0xd80018C, 0x800);
reset_audio(0);
//boot2_sub_FFFF5D08(0);
//boot2_sub_FFFF5C40(hwood_hi);
//boot2_sub_FFFF6AA8();
turn_stuff_on();
// what do these two pokes do? no clue. Not needed but I'm leaving them in anyway.
write32(0xd8001e0, 0x65244A); //?
write32(0xd8001e4, 0x46A024); //?
clear32(HW_GPIO1OWNER, 0x10);
set32(HW_GPIO1DIR, 0x10);
//write32(HW_ALARM,0);
//write32(HW_ALARM,0);
}
void *_main(void *base)
{
FRESULT fres;
int res;
mem_setswap(1);
write32(HW_IRQENABLE, 0);
regs_setup();
//debug_output(0x50);
//debug_output(0x51);
debug_output(0xF8);
gecko_init();
debug_output(0xF9);
gecko_puts("MiniIOS v0.1 loading\n");
fres = f_mount(0, &fatfs);
if(fres != FR_OK) {
gecko_printf("Error %d while trying to mount SD\n", fres);
panic2(0, PANIC_MOUNT);
}
gecko_puts("Trying to boot:" PPC_BOOT_FILE "\n");
res = powerpc_load_file(PPC_BOOT_FILE);
if(res < 0) {
gecko_printf("Failed to boot PPC: %d\n", res);
gecko_puts("Continuing anyway\n");
}
while(1);
}

218
memory.c Normal file
View File

@ -0,0 +1,218 @@
#include "types.h"
#include "start.h"
#include "memory.h"
#include "utils.h"
#include "gecko.h"
#include "hollywood.h"
void _dc_inval_entries(void *start, int count);
void _dc_flush_entries(void *start, int count);
void _dc_flush(void);
void _ic_inval(void);
void _drain_write_buffer(void);
#define LINESIZE 0x20
#define CACHESIZE 0x4000
// TODO: move to hollywood.h once we figure out WTF
#define HW_100 (HW_REG_BASE + 0x100)
#define HW_104 (HW_REG_BASE + 0x104)
#define HW_108 (HW_REG_BASE + 0x108)
#define HW_10c (HW_REG_BASE + 0x10c)
#define HW_110 (HW_REG_BASE + 0x110)
#define HW_114 (HW_REG_BASE + 0x114)
#define HW_118 (HW_REG_BASE + 0x118)
#define HW_11c (HW_REG_BASE + 0x11c)
#define HW_120 (HW_REG_BASE + 0x120)
#define HW_124 (HW_REG_BASE + 0x124)
#define HW_130 (HW_REG_BASE + 0x130)
#define HW_134 (HW_REG_BASE + 0x134)
#define HW_138 (HW_REG_BASE + 0x138)
#define HW_188 (HW_REG_BASE + 0x188)
#define HW_18C (HW_REG_BASE + 0x18c)
#define HW_214 (HW_REG_BASE + 0x214)
// what is this thing doing anyway?
// and why only on reads?
u32 _mc_read32(u32 addr)
{
u32 data;
u32 tmp130 = 0;
// this seems to be a bug workaround
if(!(read32(HW_214) & 0xF0))
{
tmp130 = read32(HW_130);
write32(HW_130, tmp130 | 0x400);
// Dummy reads?
read32(HW_138);
read32(HW_138);
read32(HW_138);
read32(HW_138);
}
data = read32(addr);
read32(HW_214); //???
if(!(read32(HW_214) & 0xF0))
write32(HW_130, tmp130);
return data;
}
void _magic_bullshit(int type) {
u32 mask = 10;
switch(type) {
case 0: mask = 0x8000; break;
case 1: mask = 0x4000; break;
case 2: mask = 0x0001; break;
case 3: mask = 0x0002; break;
case 4: mask = 0x0004; break;
case 5: mask = 0x0008; break;
case 6: mask = 0x0010; break;
case 7: mask = 0x0020; break;
case 8: mask = 0x0040; break;
case 9: mask = 0x0080; break;
case 10: mask = 0x0100; break;
case 11: mask = 0x1000; break;
case 12: mask = 0x0000; break;
}
//NOTE: 0xd8b000x, not 0xd8b400x!
u32 val = _mc_read32(0xd8b0008);
if(val & mask) {
if((type >= 2) && (type <= 10)) {
while((read32(HW_18C) & 0xF) == 9)
set32(HW_188, 0x10000);
clear32(HW_188, 0x10000);
set32(HW_188, 0x2000000);
mask32(HW_124, 0x7c0, 0x280);
set32(HW_134, 0x400);
while((read32(HW_18C) & 0xF) != 9);
set32(HW_100, 0x400);
set32(HW_104, 0x400);
set32(HW_108, 0x400);
set32(HW_10c, 0x400);
set32(HW_110, 0x400);
set32(HW_114, 0x400);
set32(HW_118, 0x400);
set32(HW_11c, 0x400);
set32(HW_120, 0x400);
write32(0xd8b0008, _mc_read32(0xd8b0008) & (~mask));
write32(0xd8b0008, _mc_read32(0xd8b0008) | mask);
clear32(HW_134, 0x400);
clear32(HW_100, 0x400);
clear32(HW_104, 0x400);
clear32(HW_108, 0x400);
clear32(HW_10c, 0x400);
clear32(HW_110, 0x400);
clear32(HW_114, 0x400);
clear32(HW_118, 0x400);
clear32(HW_11c, 0x400);
clear32(HW_120, 0x400);
clear32(HW_188, 0x2000000);
mask32(HW_124, 0x7c0, 0xc0);
} else {
if((type == 11) || (type == 0) || (type == 1)) {
write32(0xd8b0008, val & (~mask));
// wtfux
write32(0xd8b0008, val | mask);
write32(0xd8b0008, val | mask);
write32(0xd8b0008, val | mask);
}
}
}
}
void magic_bullshit(int type)
{
_magic_bullshit(type);
if(type != 0)
_magic_bullshit(0);
}
void ahb_memflush(enum AHBDEV dev)
{
u16 req = 0;
u16 ack;
int i;
switch(dev)
{
case MEMORY:
req = 1;
break;
default:
if((dev >= RAW0) && (dev <= RAWF))
{
req = dev - RAW0;
} else {
gecko_printf("ahb_memflush(0x%x): Invalid device\n", dev);
return;
}
break;
}
write32(MEM_FLUSHREQ, req);
for(i=0;i<1000000;i++) {
ack = read16(MEM_FLUSHACK);
_magic_bullshit(0);
if(ack == req)
break;
}
write32(MEM_FLUSHREQ, 0);
if(i>=1000000) {
gecko_printf("ahb_memflush(%d): Flush (0x%x) did not ack!\n", dev, req);
}
}
void dc_flushrange(void *start, u32 size)
{
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_memflush(MEMORY);
}
void dc_invalidaterange(void *start, u32 size)
{
void *end = ALIGN_FORWARD(((u8*)start) + size, LINESIZE);
start = ALIGN_BACKWARD(start, LINESIZE);
_dc_inval_entries(start, (end - start) / LINESIZE);
//_magic_bullshit(0);
}
void dc_flushall(void)
{
_dc_flush();
_drain_write_buffer();
//ahb_memflush(MEMORY);
}
void ic_invalidateall(void)
{
_ic_inval();
//_magic_bullshit(0);
}
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(HW_MEMMIRR);
if((d & 0x20) && !enable)
write32(HW_MEMMIRR, d & ~0x20);
if((!(d & 0x20)) && enable)
write32(HW_MEMMIRR, d | 0x20);
}

27
memory.h Normal file
View File

@ -0,0 +1,27 @@
#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 AHBDEV {
MEMORY = 0,
RAW0 = 0x100,
RAWF = 0x10F,
};
void dc_flushrange(void *start, u32 size);
void dc_invalidaterange(void *start, u32 size);
void dc_flushall(void);
void ic_invalidateall(void);
void magic_bullshit(int type);
void ahb_memflush(enum AHBDEV dev);
void mem_protect(int enable, void *start, void *end);
void mem_setswap(int enable);
#endif

39
memory_asm.S Normal file
View File

@ -0,0 +1,39 @@
.arm
.globl _dc_inval_entries
.globl _dc_flush_entries
.globl _dc_flush
.globl _ic_inval
.globl _drain_write_buffer
.text
_dc_inval_entries:
mcr p15, 0, r0, c7, c6, 1
add r0, #0x20
subs r1, #1
bgt _dc_inval_entries
bx lr
_dc_flush_entries:
mcr p15, 0, r0, c7, c10, 1
add r0, #0x20
subs r1, #1
bgt _dc_flush_entries
bx lr
_dc_flush:
mrc p15, 0, pc, c7, c10, 3
bne _dc_flush
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

39
panic.c Normal file
View File

@ -0,0 +1,39 @@
#include "types.h"
#include "utils.h"
#include "start.h"
#include "hollywood.h"
#include <stdarg.h>
#define PANIC_ON 200000
#define PANIC_OFF 300000
#define PANIC_INTER 1000000
// figure out a use for mode...
void panic2(int mode, ...)
{
int arg;
va_list ap;
clear32(HW_GPIO1OUT, HW_GPIO1_SLOT);
clear32(HW_GPIO1DIR, HW_GPIO1_SLOT);
clear32(HW_GPIO1OWNER, HW_GPIO1_SLOT);
while(1) {
va_start(ap, mode);
while(1) {
arg = va_arg(ap, int);
if(arg < 0)
break;
set32(HW_GPIO1OUT, HW_GPIO1_SLOT);
udelay(arg * PANIC_ON);
clear32(HW_GPIO1OUT, HW_GPIO1_SLOT);
udelay(PANIC_OFF);
}
va_end(ap);
udelay(PANIC_INTER);
}
}

8
panic.h Normal file
View File

@ -0,0 +1,8 @@
#ifndef __PANIC_H__
#define __PANIC_H__
#define PANIC_MOUNT 1,1,-1
void panic2(int mode, ...) __attribute__ ((noreturn));
#endif

58
powerpc.c Normal file
View File

@ -0,0 +1,58 @@
#include "types.h"
#include "powerpc.h"
#include "hollywood.h"
#include "utils.h"
#include "start.h"
#include "gecko.h"
const u32 stub_default[0x10] = {
0x3c600000,
0x60633400,
0x7c7a03a6,
0x38600000,
0x7c7b03a6,
0x4c000064,
0,
};
void powerpc_upload_stub(const u32 *stub, u32 len)
{
u32 i;
set32(HW_EXICTRL, EXICTRL_ENABLE_EXI);
if(stub == NULL || len == 0)
{
stub = stub_default;
len = sizeof(stub_default) / sizeof(u32);
}
for(i = 0; i < len; i++)
write32(EXI_BOOT_BASE + 4*i, stub[i]);
set32(HW_DIFLAGS, DIFLAGS_BOOT_CODE);
gecko_printf("disabling EXI now...\n");
clear32(HW_EXICTRL, EXICTRL_ENABLE_EXI);
}
void powerpc_hang()
{
clear32(HW_RESETS, 0x30);
udelay(100);
set32(HW_RESETS, 0x20);
udelay(100);
}
void powerpc_reset()
{
write32(0xD800034, 0x40000000);
clear32(HW_RESETS, 0x30);
udelay(100);
set32(HW_RESETS, 0x20);
udelay(100);
set32(HW_RESETS, 0x10);
udelay(100000);
set32(HW_EXICTRL, EXICTRL_ENABLE_EXI);
}

9
powerpc.h Normal file
View File

@ -0,0 +1,9 @@
#ifndef __POWERPC_H__
#define __POWERPC_H__ 1
void ppc_boot_code();
void powerpc_upload_stub(const u32 *stub, u32 len);
void powerpc_hang();
void powerpc_reset();
#endif

89
powerpc_elf.c Normal file
View File

@ -0,0 +1,89 @@
#include "types.h"
#include "powerpc.h"
#include "hollywood.h"
#include "utils.h"
#include "start.h"
#include "gecko.h"
#include "ff.h"
#include "powerpc_elf.h"
#include "elf.h"
#include "string.h"
#define PHDR_MAX 10
Elf32_Ehdr elfhdr;
Elf32_Phdr phdrs[PHDR_MAX];
int powerpc_load_file(const char *path)
{
FIL fd;
u32 read;
FRESULT fres;
fres = f_open(&fd, path, FA_READ);
if(fres != FR_OK)
return -fres;
fres = f_read(&fd, &elfhdr, sizeof(elfhdr), &read);
if(fres != FR_OK)
return -fres;
if(read != sizeof(elfhdr))
return -100;
if(memcmp("\x7F" "ELF\x01\x02\x01\x00\x00",elfhdr.e_ident,9)) {
gecko_printf("Invalid ELF header! 0x%02x 0x%02x 0x%02x 0x%02x\n",elfhdr.e_ident[0], elfhdr.e_ident[1], elfhdr.e_ident[2], elfhdr.e_ident[3]);
return -101;
}
if(elfhdr.e_phoff == 0 || elfhdr.e_phnum == 0) {
gecko_puts("ELF has no program headers!\n");
return -102;
}
if(elfhdr.e_phnum > PHDR_MAX) {
gecko_printf("ELF has too many (%d) program headers!\n", elfhdr.e_phnum);
return -102;
}
fres = f_lseek(&fd, elfhdr.e_phoff);
if(fres != FR_OK)
return -fres;
fres = f_read(&fd, phdrs, sizeof(phdrs[0])*elfhdr.e_phnum, &read);
if(fres != FR_OK)
return -fres;
if(read != sizeof(phdrs[0])*elfhdr.e_phnum)
return -103;
int count = elfhdr.e_phnum;
Elf32_Phdr *phdr = phdrs;
powerpc_hang();
while(count--)
{
if(phdr->p_type != PT_LOAD) {
gecko_printf("Skipping PHDR of type %d\n",phdr->p_type);
} else {
void *dst = phdr->p_paddr;
dst = (void*)((u32)dst & ~0xC0000000);
gecko_printf("LOAD 0x%x -> %p [0x%x]\n", phdr->p_offset, phdr->p_paddr, phdr->p_filesz);
fres = f_lseek(&fd, phdr->p_offset);
if(fres != FR_OK)
return -fres;
fres = f_read(&fd, dst, phdr->p_filesz, &read);
if(fres != FR_OK)
return -fres;
if(read != phdr->p_filesz)
return -104;
}
phdr++;
}
gecko_puts("ELF load done, booting PPC...\n");
powerpc_upload_stub(NULL,0);
powerpc_reset();
gecko_puts("PPC booted!\n");
return 0;
}

6
powerpc_elf.h Normal file
View File

@ -0,0 +1,6 @@
#ifndef __POWERPC_H__
#define __POWERPC_H__ 1
int powerpc_load_file(const char *path);
#endif

1116
sdhc.c Normal file

File diff suppressed because it is too large Load Diff

40
sdhc.h Normal file
View File

@ -0,0 +1,40 @@
#ifndef __SDHC_H__
#define __SDHC_H__
#include "types.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
typedef struct
{
u32 reg_base;
u8 is_sdhc;
u8 is_selected;
u8 is_mounted;
u16 rca;
u32 ocr;
u32 cid;
} sdhci_t;
int sd_init(sdhci_t *sdhci, int slot);
int sd_reset(sdhci_t *sdhci);
int sd_inserted(sdhci_t *sdhci);
int sd_protected(sdhci_t *sdhci);
int sd_mount(sdhci_t *sdhci);
int sd_cmd(sdhci_t *sdhci, u32 cmd, u32 rsp_type, u32 arg, u32 blk_cnt, void *buffer, u32 *response, u8 rlen);
int sd_select(sdhci_t *sdhci);
int sd_read(sdhci_t *sdhci, u32 start_block, u32 blk_cnt, void *buffer);
int sd_write(sdhci_t *sdhci, u32 start_block, u32 blk_cnt, const void *buffer);
u8 __sd_read8(u32 addr);
u16 __sd_read16(u32 addr);
u32 __sd_read32(u32 addr);
#endif

177
start.S Normal file
View File

@ -0,0 +1,177 @@
.arm
.extern _main
.extern __got_start
.extern __got_end
.extern __bss_start
.extern __bss_end
.extern __stack_addr
.globl _start
.globl debug_output
.globl panic
.globl delay
.globl read32, write32
.globl read16, write16
.globl read8, write8
.globl getcpuid
.section .init
_start:
@ Get real address of _start
sub r4, pc, #8
@ Subtract offset to get the address that we were loaded at
ldr r0, =_start
sub r4, r4, r0
@ Output 0x42 to the debug port
mov r0, #0x42
bl debug_output
@ Set up a stack
ldr sp, =__stack_addr
add sp, r4
@ perform boot2v3 memory controller poke
bl memctrl_do_sub_sub_poke
@ Output 0x43 to the debug port
mov r0, #0x43
bl debug_output
@ relocate the GOT entries
ldr r1, =__got_start
add r1, r4
ldr r2, =__got_end
add r2, r4
got_loop:
@ check for the end
cmp r1, r2
beq done_got
@ read the GOT entry
ldr r3, [r1]
@ add our base address
add r3, r4
str r3, [r1]
@ move on
add r1, r1, #4
b got_loop
done_got:
@ clear BSS
ldr r1, =__bss_start
add r1, r4
ldr r2, =__bss_end
add r2, r4
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:
mov r0, #0x44
bl debug_output
@ take the plunge
mov r0, r4
bl _main
@ _main returned! Go to whatever address it returned...
mov pc, r0
memctrl_do_sub_sub_poke:
stmdb sp!, {lr}
ldr r0, =0x163 @ reg_address
mov r1, #0x4C @ address
bl memctrl_sub_poke
ldr r0, =0x163 @ read address back (flush?)
bl memctrl_sub_peek
ldr r0, =0x162 @ reg_data
mov r1, #1 @ data
bl memctrl_sub_poke
ldmia sp!, {pc}
memctrl_sub_poke:
ldr r2, =0xD8B4000
strh r0, [r2, #0x74] @ reg_address <= address
ldrh r0, [r2, #0x74] @ read reg_address back
strh r1, [r2, #0x76] @ reg_data <= data
mov pc, lr
memctrl_sub_peek:
ldr r2, =0xD8B4000
strh r0, [r2, #0x74] @ reg_address <= address
ldrh r0, [r2, #0x74] @ read reg_address back
ldrh r0, [r2, #0x76] @ data <= reg_data
mov pc, lr
.pool
debug_output:
@ load address of port
mov r3, #0xd800000
@ load old value
ldr r2, [r3, #0xe0]
@ clear debug byte
bic r2, r2, #0xFF0000
@ insert new value
and r0, r0, #0xFF
orr r2, r2, r0, LSL #16
@ store back
str r2, [r3, #0xe0]
mov pc, lr
panic:
mov r4, r0
_panic:
mov r0, r4
bl debug_output
ldr r0, =6175000
bl delay
mov r0, #0x00
bl debug_output
ldr r0, =6175000
bl delay
b _panic
@ the speed of this seems to decrease wildly with certain (non-)alignments
@ probably some prefetch buffer / cache / DRAM junk
.balign 64
delay:
cmp r0, #0
moveq pc, lr
1:
subs r0, r0, #1
bne 1b
mov pc, lr
read32:
ldr r0, [r0]
mov pc, lr
write32:
str r1, [r0]
mov pc, lr
read16:
ldrh r0, [r0]
mov pc, lr
write16:
strh r1, [r0]
mov pc, lr
read8:
ldrb r0, [r0]
mov pc, lr
write8:
strb r1, [r0]
mov pc, lr
getcpuid:
mrc p15, 0, r0, c0, c0
mov pc, lr

13
start.h Normal file
View File

@ -0,0 +1,13 @@
#ifndef __START_H__
#define __START_H__
#include "types.h"
void delay(u32 delay);
#define udelay(d) delay(247*(d)/10)
void debug_output(u8 byte);
void panic(u8 code);
#endif

94
string.c Normal file
View File

@ -0,0 +1,94 @@
/*
* linux/lib/string.c
*
* Copyright (C) 1991, 1992 Linus Torvalds
*/
#include "string.h"
size_t strnlen(const char *s, size_t count)
{
const char *sc;
for (sc = s; count-- && *sc != '\0'; ++sc)
/* nothing */;
return sc - s;
}
size_t strlen(const char *s)
{
const char *sc;
for (sc = s; *sc != '\0'; ++sc)
/* nothing */;
return sc - s;
}
char *strncpy(char *dst, const char *src, size_t n)
{
char *ret = dst;
while (n && (*dst++ = *src++))
n--;
while (n--)
*dst++ = 0;
return ret;
}
char *strcpy(char *dst, const char *src)
{
char *ret = dst;
while ((*dst++ = *src++))
;
return ret;
}
int strcmp(const char *p, const char *q)
{
for (;;) {
unsigned char a, b;
a = *p++;
b = *q++;
if (a == 0 || a != b)
return a - b;
}
}
void *memset(void *dst, int x, size_t n)
{
unsigned char *p;
for (p = dst; n; n--)
*p++ = x;
return dst;
}
void *memcpy(void *dst, const void *src, size_t n)
{
unsigned char *p;
const unsigned char *q;
for (p = dst, q = src; n; n--)
*p++ = *q++;
return dst;
}
int memcmp(const void *s1, const void *s2, size_t n)
{
unsigned char *us1 = (unsigned char *) s1;
unsigned char *us2 = (unsigned char *) s2;
while (n-- != 0) {
if (*us1 != *us2)
return (*us1 < *us2) ? -1 : +1;
us1++;
us2++;
}
return 0;
}

15
string.h Normal file
View File

@ -0,0 +1,15 @@
#ifndef _STRING_H_
#define _STRING_H_
#include "types.h"
char *strcpy(char *, const char *);
char *strncpy(char *, const char *, size_t);
int strcmp(const char *, const char *);
size_t strlen(const char *);
size_t strnlen(const char *, size_t);
void *memset(void *, int, size_t);
void *memcpy(void *, const void *, size_t);
int memcmp(const void *s1, const void *s2, size_t n);
#endif

327
stub.c Normal file
View File

@ -0,0 +1,327 @@
#include "types.h"
#include "utils.h"
#include "start.h"
#include "hollywood.h"
#include "sdhc.h"
#include "string.h"
#include "memory.h"
#include "elf.h"
#include "gecko.h"
#include "ff.h"
#include "lcd.h"
void hexline(void *addr, int len)
{
u8 *p = (u8*)addr;
while(len--) {
gecko_printf("%02x",*p++);
}
}
typedef struct {
u32 hdrsize;
u32 loadersize;
u32 elfsize;
u32 argument;
} ioshdr;
int dogecko;
void boot2_loadelf(u8 *elf) {
if(dogecko)
gecko_puts("Loading boot2 ELF...\n");
if(memcmp("\x7F" "ELF\x01\x02\x01\x61\x01",elf,9)) {
if(dogecko)
gecko_printf("Invalid ELF header! 0x%02x 0x%02x 0x%02x 0x%02x\n",elf[0], elf[1], elf[2], elf[3]);
panic(0xE3);
}
Elf32_Ehdr *ehdr = (Elf32_Ehdr*)elf;
if(ehdr->e_phoff == 0) {
if(dogecko)
gecko_printf("ELF has no program headers!\n");
panic(0xE4);
}
int count = ehdr->e_phnum;
Elf32_Phdr *phdr = (Elf32_Phdr*)(elf + ehdr->e_phoff);
if(dogecko)
gecko_printf("PHDRS at %p\n",phdr);
while(count--)
{
if(phdr->p_type != PT_LOAD) {
if(dogecko)
gecko_printf("Skipping PHDR of type %d\n",phdr->p_type);
} else {
void *src = elf + phdr->p_offset;
if(dogecko)
gecko_printf("LOAD %p -> %p [0x%x]\n",src, phdr->p_paddr, phdr->p_filesz);
memcpy(phdr->p_paddr, src, phdr->p_filesz);
}
phdr++;
}
if(dogecko)
gecko_puts("Done!\n");
}
#define BOOT_FILE "/system/iosboot.bin"
FATFS fatfs;
void turn_stuff_on(void)
{
clear32(HW_GPIO1OUT, 0x10);
udelay(100);
set32(HW_RESETS, 0x7FFFFCF);
}
void reset_audio(u8 flag)
{
// GPIO2IN is probably mislabeled
if(flag)
clear32(HW_DIFLAGS, 0x180);
else
mask32(HW_DIFLAGS, 0x80, 0x100);
clear32(HW_GPIO2IN, 0x80000000);
udelay(2);
clear32(HW_GPIO2IN, 0x40000000);
if(flag) {
clear32(HW_GPIO2IN, 0x10000000);
mask32(HW_GPIO2DIR, 0x7FFFFFF, 0x4B0FFCE);
} else {
mask32(HW_GPIO2DIR, 0x7FFFFFF, 0x4640FC0);
}
udelay(10);
set32(HW_GPIO2IN, 0x40000000);
udelay(500);
set32(HW_GPIO2IN, 0x80000000);
udelay(2);
}
void regs_setup(void)
{
u8 hwood_ver, hwood_hi, hwood_lo;
hwood_ver = read32(0xd800214);
hwood_hi = hwood_ver >> 4; //R0
hwood_lo = hwood_ver & 0xF; //R1
*(u32*)0xFFFF897C = *(u32*)0xFFFF86D0;
set32(HW_EXICTRL, EXICTRL_ENABLE_EXI);
mem_protect(1, (void*)0x13420000, (void*)0x1fffffff);
clear32(HW_EXICTRL, 0x10);
if(hwood_hi == 0)
write32(0xd8b0010, 0);
write32(0xd8b0010, 0);
if(hwood_hi == 1 && hwood_lo == 0)
mask32(0xd800140, 0x0000FFF0, 1);
set32(0xd80018C, 0x400);
set32(0xd80018C, 0x800);
reset_audio(0);
//boot2_sub_FFFF5D08(0);
//boot2_sub_FFFF5C40(hwood_hi);
//boot2_sub_FFFF6AA8();
turn_stuff_on();
// what do these two pokes do? no clue. Not needed but I'm leaving them in anyway.
write32(0xd8001e0, 0x65244A); //?
write32(0xd8001e4, 0x46A024); //?
clear32(HW_GPIO1OWNER, 0x10);
set32(HW_GPIO1DIR, 0x10);
//write32(HW_ALARM,0);
//write32(HW_ALARM,0);
}
void hex32(u32 x) {
int i;
u8 b;
for(i=0;i<8;i++) {
b = x >> 28;
if(b > 9)
lcd_putchar(b-10+'a');
else
lcd_putchar(b+'0');
x <<= 4;
}
}
extern void *__end;
void *_main(void *base)
{
FRESULT fres;
ioshdr *hdr = (ioshdr*)base;
ioshdr *iosboot;
u8 *elf;
elf = (u8*) base;
elf += hdr->hdrsize + hdr->loadersize;
dogecko = 1;
debug_output(0xF1);
mem_setswap(1);
write32(HW_IRQENABLE, 0);
clear32(HW_GPIO1DIR, 0x80);
clear32(HW_GPIO1OWNER, 0x80);
udelay(10000);
if(read32(HW_GPIO1IN) & 0x80) {
dogecko = 0;
goto boot2;
}
// NOTE: END DEBUG CRITICAL ZONE
lcd_init();
regs_setup();
//debug_output(0x50);
//debug_output(0x51);
debug_output(0xF8);
gecko_init();
debug_output(0xF9);
lcd_puts("BootMii v0.1\n");
if(dogecko) {
gecko_puts("Hello, world from Starlet again!\n");
gecko_puts("BootMii here, version 0.1\n");
gecko_printf("BOOT2 header (@%p):\n",hdr);
gecko_printf(" Header size: %08x\n", hdr->hdrsize);
gecko_printf(" Loader size: %08x\n", hdr->loadersize);
gecko_printf(" ELF size: %08x\n", hdr->elfsize);
gecko_printf(" Argument: %08x\n", hdr->argument);
gecko_printf("ELF at %p\n",elf);
gecko_puts("Trying to mount SD...\n");
}
fres = f_mount(0, &fatfs);
if(fres != FR_OK) {
if(dogecko)
gecko_printf("Error %d while trying to mount SD\n", fres);
debug_output(0x12);
debug_output(fres&0xFF);
goto boot2;
}
//debug_output(0xF2);
if(dogecko)
gecko_puts("Trying to open SD:" BOOT_FILE "\n");
FIL fd;
u32 read;
fres = f_open(&fd, BOOT_FILE, FA_READ);
if(fres != FR_OK) {
if(dogecko)
gecko_printf("Error %d while trying to open file\n", fres);
//debug_output(0x13);
//debug_output(fres&0xFF);
goto boot2;
}
lcd_puts(".");
// NOTE: END CRITICAL ZONE
// anything from here to boot2: shouldn't be able to cause a brick
debug_output(0xF2);
iosboot = (ioshdr *)ALIGN_FORWARD(((u32)&__end) + 0x100, 0x100);
if(dogecko)
gecko_printf("Trying to read IOSBOOT header to %p\n", iosboot);
fres = f_read(&fd, iosboot, sizeof(ioshdr), &read);
if(fres != FR_OK) {
if(dogecko)
gecko_printf("Error %d while trying to read file header\n", fres);
//debug_output(0x14);
//debug_output(fres&0xFF);
goto boot2;
}
if(read != sizeof(ioshdr)) {
if(dogecko)
gecko_printf("Got %d bytes, expected %d\n", read, sizeof(ioshdr));
//debug_output(0x24);
goto boot2;
}
lcd_puts(".");
//debug_output(0xF5);
if(dogecko) {
gecko_printf("IOSBOOT header (@%p):\n",iosboot);
gecko_printf(" Header size: %08x\n", iosboot->hdrsize);
gecko_printf(" Loader size: %08x\n", iosboot->loadersize);
gecko_printf(" ELF size: %08x\n", iosboot->elfsize);
gecko_printf(" Argument: %08x\n", iosboot->argument);
}
u32 totalsize = iosboot->hdrsize + iosboot->loadersize + iosboot->elfsize;
if(dogecko) {
gecko_printf("Total IOSBOOT size: 0x%x\n", totalsize);
gecko_printf("Trying to read IOSBOOT to %p\n", iosboot);
}
fres = f_read(&fd, iosboot+1, totalsize-sizeof(ioshdr), &read);
if(fres != FR_OK) {
if(dogecko)
gecko_printf("Error %d while trying to read file header\n", fres);
//debug_output(0x15);
//debug_output(fres&0xFF);
goto boot2;
}
if(read != (totalsize-sizeof(ioshdr))) {
if(dogecko)
gecko_printf("Got %d bytes, expected %d\n", read, (totalsize-sizeof(ioshdr)));
//debug_output(0x25);
goto boot2;
}
lcd_puts(".");
//debug_output(0xF6);
if(dogecko) {
gecko_puts("IOSBOOT read\n");
gecko_printf("Setting argument to %p\n", base);
}
iosboot->argument = (u32)base;
void *entry = (void*)(((u32)iosboot) + iosboot->hdrsize);
lcd_puts(" \x7e IOSBOOT \n");
if(dogecko)
gecko_printf("Launching IOSBOOT @ %p\n",entry);
debug_output(0xF3);
return entry;
boot2:
debug_output(0xC8);
if(dogecko)
gecko_puts("Couldn't load from SD, falling back to boot2\n");
lcd_puts(" \x7e BOOT2 \n");
boot2_loadelf(elf);
debug_output(0xC9);
return (void *) 0xFFFF0000;
}

104
stub.ld Normal file
View File

@ -0,0 +1,104 @@
OUTPUT_FORMAT("elf32-bigarm")
OUTPUT_ARCH(arm)
EXTERN(_start)
ENTRY(_start)
__base_addr = 0;
SECTIONS
{
. = __base_addr;
.header :
{
__header = .;
/* Entry point (offset) */
LONG(__code_start);
/* Loader size */
LONG(__loader_size);
/* ELF size */
LONG(0);
/* Boot argument? */
LONG(0);
. = ALIGN(64);
}
__code_start = .;
.init :
{
*(.init)
. = ALIGN(4);
}
.got :
{
__got_start = .;
*(.got.*)
*(.got)
. = ALIGN(4);
__got_end = . ;
}
.text :
{
*(.text.*)
*(.gnu.warning)
*(.gnu.linkonce.t*)
*(.glue_7)
*(.glue_7t)
. = ALIGN(4);
}
__text_end = . ;
.rodata :
{
*(.rodata)
*all.rodata*(*)
*(.roda)
*(.rodata.*)
*(.gnu.linkonce.r*)
. = ALIGN(4);
}
.data :
{
*(.data)
*(.data.*)
*(.gnu.linkonce.d*)
. = ALIGN(4);
}
.bss :
{
__bss_start = . ;
*(.dynbss)
*(.gnu.linkonce.b*)
*(.bss*)
*(.sbss*)
*(COMMON)
. = ALIGN(4);
__bss_end = . ;
}
. = ALIGN(64);
.stack :
{
__stack_end = .;
. += 0x800;
LONG(0);
. = ALIGN(64);
__stack_addr = .;
}
__end = .;
}
__loader_size = __end - __code_start;
PROVIDE (__stack_end = __stack_end);
PROVIDE (__stack_addr = __stack_addr);
PROVIDE (__got_start = __got_start);
PROVIDE (__got_end = __got_end);
PROVIDE (__bss_start = __bss_start);
PROVIDE (__bss_end = __bss_end);

28
types.h Normal file
View File

@ -0,0 +1,28 @@
#ifndef __TYPES_H__
#define __TYPES_H__
typedef unsigned char u8;
typedef unsigned short u16;
typedef unsigned int u32;
typedef unsigned long long u64;
typedef signed char s8;
typedef signed short s16;
typedef signed int s32;
typedef signed long long s64;
typedef volatile unsigned char vu8;
typedef volatile unsigned short vu16;
typedef volatile unsigned int vu32;
typedef volatile unsigned long long vu64;
typedef volatile signed char vs8;
typedef volatile signed short vs16;
typedef volatile signed int vs32;
typedef volatile signed long long vs64;
typedef s32 size_t;
#define NULL ((void *)0)
#endif

40
utils.c Normal file
View File

@ -0,0 +1,40 @@
#include "types.h"
#include "utils.h"
#include "gecko.h"
#include "vsprintf.h"
static char ascii(char s) {
if(s < 0x20) return '.';
if(s > 0x7E) return '.';
return s;
}
void hexdump(void *d, int len) {
u8 *data;
int i, off;
data = (u8*)d;
for (off=0; off<len; off += 16) {
gecko_printf("%08x ",off);
for(i=0; i<16; i++)
if((i+off)>=len) gecko_printf(" ");
else gecko_printf("%02x ",data[off+i]);
gecko_printf(" ");
for(i=0; i<16; i++)
if((i+off)>=len) gecko_printf(" ");
else gecko_printf("%c",ascii(data[off+i]));
gecko_printf("\n");
}
}
int sprintf(char *str, const char *fmt, ...)
{
va_list args;
int i;
va_start(args, fmt);
i = vsprintf(str, fmt, args);
va_end(args);
return i;
}

187
utils.h Normal file
View File

@ -0,0 +1,187 @@
#ifndef __UTILS_H__
#define __UTILS_H__
static inline u32 read32(u32 addr)
{
u32 data;
__asm__ volatile ("ldr\t%0, [%1]" : "=r" (data) : "r" (addr));
return data;
}
static inline void write32(u32 addr, u32 data)
{
__asm__ volatile ("str\t%0, [%1]" : : "r" (data), "r" (addr));
}
static 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]"
: "=&r" (data)
: "r" (addr), "r" (set)
);
return data;
}
static 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]"
: "=&r" (data)
: "r" (addr), "r" (clear)
);
return data;
}
static 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]"
: "=&r" (data)
: "r" (addr), "r" (set), "r" (clear)
);
return data;
}
static inline u16 read16(u32 addr)
{
u32 data;
__asm__ volatile ("ldrh\t%0, [%1]" : "=r" (data) : "r" (addr));
return data;
}
static inline void write16(u32 addr, u16 data)
{
__asm__ volatile ("strh\t%0, [%1]" : : "r" (data), "r" (addr));
}
static 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]"
: "=&r" (data)
: "r" (addr), "r" (set)
);
return data;
}
static 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]"
: "=&r" (data)
: "r" (addr), "r" (clear)
);
return data;
}
static 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]"
: "=&r" (data)
: "r" (addr), "r" (set), "r" (clear)
);
return data;
}
static inline u8 read8(u32 addr)
{
u32 data;
__asm__ volatile ("ldrb\t%0, [%1]" : "=r" (data) : "r" (addr));
return data;
}
static inline void write8(u32 addr, u8 data)
{
__asm__ volatile ("strb\t%0, [%1]" : : "r" (data), "r" (addr));
}
static 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]"
: "=&r" (data)
: "r" (addr), "r" (set)
);
return data;
}
static 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]"
: "=&r" (data)
: "r" (addr), "r" (clear)
);
return data;
}
static 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]"
: "=&r" (data)
: "r" (addr), "r" (set), "r" (clear)
);
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 ATTRIBUTE_ALIGN(v) __attribute__((aligned(v)))
/*
* 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 hexdump(void *d, int len);
int sprintf(char *str, const char *fmt, ...);
#endif

62
utils_asm.S Normal file
View File

@ -0,0 +1,62 @@
.arm
.globl memcpy32
.globl memcpy16
.globl memcpy8
.globl memset32
.globl memset16
.globl memset8
.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: ldr r3, [r1],#2
str r3, [r0],#2
subs r2, #2
bne 1b
bx lr
memset16:
bics r2, #1
bxeq lr
1: str r1, [r0],#2
subs r2, #2
bne 1b
bx lr
memcpy8:
cmp r2, #0
bxeq lr
1: ldr r3, [r1],#1
str r3, [r0],#1
subs r2, #1
bne 1b
bx lr
memset8:
cmp r2, #0
bxeq lr
1: str r1, [r0],#1
subs r2, #1
bne 1b
bx lr

291
vsprintf.c Normal file
View File

@ -0,0 +1,291 @@
/*
* linux/lib/vsprintf.c
*
* Copyright (C) 1991, 1992 Linus Torvalds
*/
/* vsprintf.c -- Lars Wirzenius & Linus Torvalds. */
/*
* Wirzenius wrote this portably, Torvalds fucked it up :-)
*/
#include <stdarg.h>
#include "string.h"
static inline int isdigit(int c)
{
return c >= '0' && c <= '9';
}
static inline int isxdigit(int c)
{
return (c >= '0' && c <= '9')
|| (c >= 'a' && c <= 'f')
|| (c >= 'A' && c <= 'F');
}
static inline int islower(int c)
{
return c >= 'a' && c <= 'z';
}
static inline int toupper(int c)
{
if (islower(c))
c -= 'a'-'A';
return c;
}
static int skip_atoi(const char **s)
{
int i=0;
while (isdigit(**s))
i = i*10 + *((*s)++) - '0';
return i;
}
#define ZEROPAD 1 /* pad with zero */
#define SIGN 2 /* unsigned/signed long */
#define PLUS 4 /* show plus */
#define SPACE 8 /* space if plus */
#define LEFT 16 /* left justified */
#define SPECIAL 32 /* 0x */
#define LARGE 64 /* use 'ABCDEF' instead of 'abcdef' */
#define do_div(n,base) ({ \
int __res; \
__res = ((unsigned long) n) % (unsigned) base; \
n = ((unsigned long) n) / (unsigned) base; \
__res; })
static char * number(char * str, long num, int base, int size, int precision
,int type)
{
char c,sign,tmp[66];
const char *digits="0123456789abcdefghijklmnopqrstuvwxyz";
int i;
if (type & LARGE)
digits = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
if (type & LEFT)
type &= ~ZEROPAD;
if (base < 2 || base > 36)
return 0;
c = (type & ZEROPAD) ? '0' : ' ';
sign = 0;
if (type & SIGN) {
if (num < 0) {
sign = '-';
num = -num;
size--;
} else if (type & PLUS) {
sign = '+';
size--;
} else if (type & SPACE) {
sign = ' ';
size--;
}
}
if (type & SPECIAL) {
if (base == 16)
size -= 2;
else if (base == 8)
size--;
}
i = 0;
if (num == 0)
tmp[i++]='0';
else while (num != 0)
tmp[i++] = digits[do_div(num,base)];
if (i > precision)
precision = i;
size -= precision;
if (!(type&(ZEROPAD+LEFT)))
while(size-->0)
*str++ = ' ';
if (sign)
*str++ = sign;
if (type & SPECIAL) {
if (base==8)
*str++ = '0';
else if (base==16) {
*str++ = '0';
*str++ = digits[33];
}
}
if (!(type & LEFT))
while (size-- > 0)
*str++ = c;
while (i < precision--)
*str++ = '0';
while (i-- > 0)
*str++ = tmp[i];
while (size-- > 0)
*str++ = ' ';
return str;
}
int vsprintf(char *buf, const char *fmt, va_list args)
{
int len;
unsigned long num;
int i, base;
char * str;
const char *s;
int flags; /* flags to number() */
int field_width; /* width of output field */
int precision; /* min. # of digits for integers; max
number of chars for from string */
int qualifier; /* 'h', 'l', or 'L' for integer fields */
for (str=buf ; *fmt ; ++fmt) {
if (*fmt != '%') {
*str++ = *fmt;
continue;
}
/* process flags */
flags = 0;
repeat:
++fmt; /* this also skips first '%' */
switch (*fmt) {
case '-': flags |= LEFT; goto repeat;
case '+': flags |= PLUS; goto repeat;
case ' ': flags |= SPACE; goto repeat;
case '#': flags |= SPECIAL; goto repeat;
case '0': flags |= ZEROPAD; goto repeat;
}
/* get field width */
field_width = -1;
if (isdigit(*fmt))
field_width = skip_atoi(&fmt);
else if (*fmt == '*') {
++fmt;
/* it's the next argument */
field_width = va_arg(args, int);
if (field_width < 0) {
field_width = -field_width;
flags |= LEFT;
}
}
/* get the precision */
precision = -1;
if (*fmt == '.') {
++fmt;
if (isdigit(*fmt))
precision = skip_atoi(&fmt);
else if (*fmt == '*') {
++fmt;
/* it's the next argument */
precision = va_arg(args, int);
}
if (precision < 0)
precision = 0;
}
/* get the conversion qualifier */
qualifier = -1;
if (*fmt == 'h' || *fmt == 'l' || *fmt == 'L') {
qualifier = *fmt;
++fmt;
}
/* default base */
base = 10;
switch (*fmt) {
case 'c':
if (!(flags & LEFT))
while (--field_width > 0)
*str++ = ' ';
*str++ = (unsigned char) va_arg(args, int);
while (--field_width > 0)
*str++ = ' ';
continue;
case 's':
s = va_arg(args, char *);
if (!s)
s = "<NULL>";
len = strnlen(s, precision);
if (!(flags & LEFT))
while (len < field_width--)
*str++ = ' ';
for (i = 0; i < len; ++i)
*str++ = *s++;
while (len < field_width--)
*str++ = ' ';
continue;
case 'p':
if (field_width == -1) {
field_width = 2*sizeof(void *);
flags |= ZEROPAD;
}
str = number(str,
(unsigned long) va_arg(args, void *), 16,
field_width, precision, flags);
continue;
case 'n':
if (qualifier == 'l') {
long * ip = va_arg(args, long *);
*ip = (str - buf);
} else {
int * ip = va_arg(args, int *);
*ip = (str - buf);
}
continue;
case '%':
*str++ = '%';
continue;
/* integer number formats - set up the flags and "break" */
case 'o':
base = 8;
break;
case 'X':
flags |= LARGE;
case 'x':
base = 16;
break;
case 'd':
case 'i':
flags |= SIGN;
case 'u':
break;
default:
*str++ = '%';
if (*fmt)
*str++ = *fmt;
else
--fmt;
continue;
}
if (qualifier == 'l')
num = va_arg(args, unsigned long);
else if (qualifier == 'h') {
num = (unsigned short) va_arg(args, int);
if (flags & SIGN)
num = (short) num;
} else if (flags & SIGN)
num = va_arg(args, int);
else
num = va_arg(args, unsigned int);
str = number(str, num, base, field_width, precision, flags);
}
*str = '\0';
return str-buf;
}

3
vsprintf.h Normal file
View File

@ -0,0 +1,3 @@
#include <stdarg.h>
int vsprintf(char *buf, const char *fmt, va_list args);