mirror of
https://github.com/fail0verflow/mini.git
synced 2024-11-28 06:04:19 +01:00
Add miniios
This commit is contained in:
commit
91836dca85
3
.gitignore
vendored
Normal file
3
.gitignore
vendored
Normal file
@ -0,0 +1,3 @@
|
||||
*.d
|
||||
*.bin
|
||||
|
45
Makefile
Normal file
45
Makefile
Normal 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
125
diskio.c
Normal 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
71
diskio.h
Normal 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
44
elf.h
Normal 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
|
339
ff.h
Normal file
339
ff.h
Normal 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
201
gecko.c
Normal 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
18
gecko.h
Normal 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
258
hollywood.h
Normal 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
30
integer.h
Normal 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
208
lcd.c
Normal 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
11
lcd.h
Normal 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
168
main.c
Normal 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
218
memory.c
Normal 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
27
memory.h
Normal 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
39
memory_asm.S
Normal 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
39
panic.c
Normal 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
8
panic.h
Normal 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
58
powerpc.c
Normal 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
9
powerpc.h
Normal 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
89
powerpc_elf.c
Normal 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
6
powerpc_elf.h
Normal file
@ -0,0 +1,6 @@
|
||||
#ifndef __POWERPC_H__
|
||||
#define __POWERPC_H__ 1
|
||||
|
||||
int powerpc_load_file(const char *path);
|
||||
|
||||
#endif
|
40
sdhc.h
Normal file
40
sdhc.h
Normal 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
177
start.S
Normal 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
13
start.h
Normal 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
94
string.c
Normal 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
15
string.h
Normal 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
327
stub.c
Normal 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
104
stub.ld
Normal 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
28
types.h
Normal 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
40
utils.c
Normal 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
187
utils.h
Normal 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
62
utils_asm.S
Normal 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
291
vsprintf.c
Normal 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
3
vsprintf.h
Normal file
@ -0,0 +1,3 @@
|
||||
#include <stdarg.h>
|
||||
|
||||
int vsprintf(char *buf, const char *fmt, va_list args);
|
Loading…
Reference in New Issue
Block a user