FeOS/kernel/source/main.c
2013-08-10 20:24:29 +02:00

433 lines
8.9 KiB
C

#include "feos.h"
#include "thread.h"
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include "loader.h"
#include "feosfifo.h"
#include <sys/iosupport.h>
#include "hudicons.h"
#include "caret.h"
// Replacement for newlib iprintf
ssize_t iprintf(const char* fmt, ...)
{
va_list va;
va_start(va, fmt);
ssize_t ret = vfiprintf(stdout, fmt, va);
va_end(va);
return ret;
}
void __SWIHandler();
void __ResetHandler();
PrintConsole* con; // Am I the only one that finds this offensive?
int conbg;
void chk_exit();
extern bool stdioRead;
volatile touchPosition touchPos;
bool conMode = true, bOAMUpd = true, bBgUpd = true, bKeyUpd = true;
extern int keyBufferOffset;
extern int keyBufferLength;
int caretBlink = 0;
extern volatile bool inHeadphoneSleep;
volatile int vblankCounter = 0; // upper bound: ~2.275 years
void KeVBlankISR()
{
// Done here because it's kernel mode code
chk_exit();
vblankCounter ++;
touchRead((touchPosition*)&touchPos);
if (conMode)
{
scanKeys();
bgUpdate();
if (inHeadphoneSleep) return;
oamSub.oamMemory[0].isHidden = !__inFAT;
oamSub.oamMemory[1].isHidden = !stdioRead;
oamMain.oamMemory[0].x = con->cursorX * 8;
oamMain.oamMemory[0].y = con->cursorY * 8;
caretBlink ++;
if (caretBlink >= 30) caretBlink = 0;
oamMain.oamMemory[0].isHidden = (caretBlink > 15);
oamUpdate(&oamMain);
oamUpdate(&oamSub);
if (!stdioRead)
{
int oldOff = keyBufferOffset, oldLen = keyBufferLength;
keyboardUpdate();
keyBufferOffset = oldOff, keyBufferLength = oldLen;
}
}
}
u16* caret_gfx;
u16* hudicon_gfx[2];
void kbd_key();
void videoInit()
{
// Set up the main engine
videoSetMode(MODE_3_2D);
// Set up the sub engine
videoSetModeSub(MODE_0_2D);
// Set the VRAM layout
vramSetBankA(VRAM_A_MAIN_BG);
vramSetBankC(VRAM_C_LCD);
dmaFillWords(0, VRAM_C, 128*1024); // keyboardInit() does not clear the full tilemap...
vramSetBankC(VRAM_C_SUB_BG);
vramSetBankD(VRAM_D_SUB_SPRITE);
// Initialize the console background
con = consoleInit(NULL, 0, BgType_Text4bpp, BgSize_T_256x256, 0, 1, true, true);
conbg = con->bgId;
// Prepare sub screen OAM
oamInit(&oamSub, SpriteMapping_1D_128, false);
dmaCopyWords(3, hudiconsTiles, SPRITE_GFX_SUB, hudiconsTilesLen);
hudicon_gfx[0] = SPRITE_GFX_SUB;
hudicon_gfx[1] = SPRITE_GFX_SUB + (32*32)/2;
// Prepare main screen OAM
oamInit(&oamMain, SpriteMapping_1D_128, false);
dmaCopyWords(3, caretTiles, SPRITE_GFX, caretTilesLen);
caret_gfx = SPRITE_GFX;
oamSet(&oamSub, 0, 8, 8, 0, 0, SpriteSize_32x32, SpriteColorFormat_256Color,
hudicon_gfx[0], -1, false, false, false, false, false);
oamSet(&oamSub, 1, 216, 8, 0, 0, SpriteSize_32x32, SpriteColorFormat_256Color,
hudicon_gfx[1], -1, false, false, false, false, false);
oamSub.oamMemory[0].isHidden = true;
oamSub.oamMemory[1].isHidden = true;
oamSet(&oamMain, 0, 0, 0, 0, 0, SpriteSize_8x8, SpriteColorFormat_16Color,
caret_gfx, -1, false, false, false, false, false);
oamMain.oamMemory[0].isHidden = true;
// Copy the HUD icon palette
dmaCopyHalfWords(3, hudiconsPal, SPRITE_PALETTE_SUB, hudiconsPalLen);
dmaCopyHalfWords(3, caretPal, SPRITE_PALETTE, caretPalLen);
irqSet(IRQ_VBLANK, KeVBlankISR);
// Initialize the keyboard
Keyboard* kbd = keyboardDemoInit();
kbd->OnKeyPressed = kbd_key;
kbd->scrollSpeed = 0;
keyboardShow();
}
void InstallThunks();
void InstallConThunks();
void InstallConDummy();
void DSVideoReset()
{
if (conMode) return;
dmaFillWords(0, (void*)0x04000000, 0x56);
dmaFillWords(0, (void*)0x04001008, 0x56);
videoSetModeSub(0);
lcdMainOnTop();
vramDefault();
setBrightness(3, 0);
VRAM_E_CR = 0;
VRAM_F_CR = 0;
VRAM_G_CR = 0;
VRAM_H_CR = 0;
VRAM_I_CR = 0;
irqEnable(IRQ_VBLANK);
}
void DSConsoleMode()
{
if (conMode) return;
int cS = enterCriticalSection();
DSVideoReset();
videoInit();
InstallConThunks();
conMode = true;
bOAMUpd = true, bBgUpd = true, bKeyUpd = true;
leaveCriticalSection(cS);
}
void DSDirectMode()
{
if (!conMode) return;
int cS = enterCriticalSection();
conMode = false;
DSVideoReset();
InstallConDummy();
bOAMUpd = true, bBgUpd = true, bKeyUpd = true;
leaveCriticalSection(cS);
}
int DSGetCurMode()
{
return (int)conMode;
}
void DSSetAutoUpdate(int which, bool enable)
{
if (conMode) return; // can't tweak
switch (which)
{
case AUTOUPD_OAM: bOAMUpd = enable; break;
case AUTOUPD_BG: bBgUpd = enable; break;
case AUTOUPD_KEYS: bKeyUpd = enable; break;
default: break;
}
}
bool DSGetAutoUpdate(int which)
{
if (conMode) return true;
switch (which)
{
case AUTOUPD_OAM: return bOAMUpd;
case AUTOUPD_BG: return bBgUpd;
case AUTOUPD_KEYS: return bKeyUpd;
default: return false;
}
}
#ifdef CONF_ENABLEAPPKILL
void ForcefulExit()
{
LdrModuleExit(E_APPKILLED);
}
word_t* __getIRQStack();
word_t* __getSWIStack();
void __setSWIStack(word_t*);
void KillCurrentApp_IRQ();
void KillCurrentApp_SWI();
void KillCurrentApp_IRQ()
{
// Retrieve a pointer to the IRQ stack
word_t* irqstack = __getIRQStack();
// The only instructions that push anything to the IRQ stack are (in order of execution):
// (BIOS) push {r0, r1, r2, r3, ip, lr}
// (libnds) stmfd sp!, {r0-r1,r12,lr} @ {spsr, IME, REG_BASE, lr_irq}
// The IRQ stack now looks like this:
// spsr IME REG_BASE lr_irq r0 r1 r2 r3 ip lr
// So, irqstack[9] contains the return address and irqstack[0], the SPSR
#ifdef __thumb__
irqstack[0] |= BIT(5); // THUMB flag
#endif
irqstack[0] &= ~0xF; // Force user mode :)
irqstack[9] = (word_t) ForcefulExit;
// Reset/clear the SWI stack
extern word_t __sp_svc;
__setSWIStack(&__sp_svc);
}
void KillCurrentApp_SWI()
{
// Retrieve a pointer to the SWI stack
word_t* swistack = __getSWIStack();
// The only instruction that pushes anything to the SWI stack is:
// (swihook.s) push {r12, lr} @ spsr and return address
// So, we only need to pop 2 values
__setSWIStack(swistack + 2);
// Switch back to User mode
KeEnterUserMode();
// Kill the application
ForcefulExit();
}
void KillCurrentApp()
{
if (stdioRead) KillCurrentApp_SWI();
else KillCurrentApp_IRQ();
}
#endif
void OnFold()
{
}
void kbd_key(int key)
{
if (stdioRead && key > 0)
{
putchar(key);
return;
}
switch(key)
{
case DVK_MENU:
#ifdef CONF_ENABLEAPPKILL
if (keysHeld() & KEY_DOWN) KillCurrentApp();
#endif
break;
case DVK_FOLD:
OnFold();
break;
}
}
volatile static bool _hasExited = false;
volatile static int _rc = 0;
void chk_exit()
{
if (_hasExited)
exit(_rc);
}
void IoInitStreams();
void KeInitSystemInfo();
void KeSystemError();
static void error_die()
{
iprintf("\nPress START to exit...\n");
for (;;)
{
swiWaitForVBlank();
if (keysDown() & KEY_START)
{
_rc = 1;
_hasExited = true;
}
}
}
#define ANSIESC_RED "\x1b[31;1m"
#define ANSIESC_GREEN "\x1b[32;1m"
#define ANSIESC_YELLOW "\x1b[33;1m"
#define ANSIESC_DEFAULT "\x1b[39;1m"
#define MSG_OK ANSIESC_GREEN " OK\n" ANSIESC_DEFAULT
#define MSG_OK2 ANSIESC_YELLOW " OK\n\n" ANSIESC_DEFAULT
#define WARNING ANSIESC_YELLOW "WARNING: " ANSIESC_DEFAULT
#define MSG_FAIL ANSIESC_RED "FAIL\n\n" ANSIESC_DEFAULT
#ifdef LIBFAT_FEOS_MULTICWD
vu32* g_fatCwdClusterPtr;
#endif
int main()
{
videoInit();
consoleDebugInit(DebugDevice_CONSOLE);
setExceptionHandler(KeSystemError);
SystemVectors.reset = (u32) __ResetHandler;
SystemVectors.swi = (u32) __SWIHandler;
setVectorBase(0);
LdrModuleListInit();
IoInitStreams();
installFeOSFIFO();
KeInitSystemInfo();
iprintf(
"\n FeOS kernel v" FEOS_VERSION_TEXT "\n"
" by FeOS Team, 2010-13\n");
#ifdef DEBUG
iprintf(ANSIESC_YELLOW " **DEBUG BUILD**\n");
iprintf(" Built: " __DATE__ ", " __TIME__ "\n" ANSIESC_DEFAULT);
#endif
iprintf("\nInitializing filesystem... ");
if (!fatInitDefault())
{
iprintf(
MSG_FAIL
"Make sure you have DLDI patched\n"
"the kernel binary. If the issue\n"
"persists, try using HBMenu.\n\n"
" http://devkitpro.org/hbmenu\n"
" http://feos.mtheall.com/forum\n");
error_die();
}
#ifdef LIBFAT_FEOS_MULTICWD
g_fatCwdClusterPtr = (vu32*) _FAT_getCwdClusterPtr("/");
KeInitDefaultExecStatus();
ThrInit();
#endif
InstallThunks();
#ifdef LIBFAT_FEOS_MULTICWD
iprintf(MSG_OK);
#else
iprintf(
MSG_OK2
WARNING "Multi-CWD support is\n"
"disabled due to the usage of an\n"
"old version of libfat.\n\n");
#endif
iprintf("Initializing user mode... ");
KeInitUserMode();
KeEnterUserMode();
iprintf(MSG_OK);
#ifdef DEBUG
iprintf("Loading debug library... ");
module_t hCxxLib = LdrLoadModule("feoscxx");
if (!hCxxLib)
{
iprintf(
MSG_FAIL
"The following file is missing\n"
"or it may have been corrupted:\n"
" /data/FeOS/lib/feoscxx.fx2\n");
error_die();
}
iprintf(MSG_OK);
#endif
iprintf("Startup...\n\n");
const char* argv[] = { "cmd", ":startup", NULL };
_rc = LdrExecuteArgv(2, argv);
if (_rc < 0)
{
iprintf(
MSG_FAIL
"The following file is missing\n"
"or it may have been corrupted:\n"
" /data/FeOS/bin/cmd.fx2\n");
error_die();
}
_hasExited = true;
for(;;) DSWaitForVBlank();
}