summaryrefslogtreecommitdiff
path: root/arm9/lib/NitroSDK/src/OS_reset.c
blob: 083f23216e97fdad58bf997a2b3f89384d766bb2 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
#include "OS_reset.h"

#include "global.h"
#include "MB_mb.h"
#include "OS_terminate_proc.h"
#include "OS_interrupt.h"
#include "OS_system.h"
#include "OS_spinLock.h"
#include "OS_cache.h"
#include "sections.h"
#include "MI_dma.h"
#include "CARD_common.h"
#include "PXI_init.h"
#include "PXI_fifo.h"

static u16 OSi_IsInitReset = 0;
vu16 OSi_IsResetOccurred = 0;

static void OSi_CommonCallback(PXIFifoTag tag, u32 data, BOOL err);
static void OSi_SendToPxi(u16 data);
static void OSi_DoResetSystem(void);
static void OSi_CpuClear32(register u32 data, register void *destp, register u32 size);
static void OSi_ReloadRomData(void);
static void OSi_ReadCardRom32(u32 src, void *dst, s32 len);

ARM_FUNC void OS_InitReset(void) {
    if (OSi_IsInitReset) {
        return;
    }
    OSi_IsInitReset = TRUE;
    PXI_Init();
    while (!PXI_IsCallbackReady(PXI_FIFO_TAG_OS, PXI_PROC_ARM7)) { }

    PXI_SetFifoRecvCallback(PXI_FIFO_TAG_OS, OSi_CommonCallback);
}

ARM_FUNC static void OSi_CommonCallback(PXIFifoTag tag, u32 data, BOOL err) {
#pragma unused(tag, err) //needed because otherwise -W all errors
    u16 command = (u16)((data & OS_PXI_COMMAND_MASK) >> OS_PXI_COMMAND_SHIFT);
    if (command == OS_PXI_COMMAND_RESET)
    {
        OSi_IsResetOccurred = TRUE;
        return;
    }
    OS_Terminate();
}

ARM_FUNC static void OSi_SendToPxi(u16 data) {
    while (PXI_SendWordByFifo(PXI_FIFO_TAG_OS, (u32)data << 0x8, FALSE)) {}
}

ARM_FUNC void OS_ResetSystem(u32 parameter) {
    if (MB_IsMultiBootChild()) {
        OS_Terminate();
    }
    CARD_LockRom((u16)OS_GetLockID());
    MI_StopDma(0);
    MI_StopDma(1);
    MI_StopDma(2);
    MI_StopDma(3);
    (void)OS_SetIrqMask(0x40000);
    (void)OS_ResetRequestIrqMask((u32)~0);
    *(u32 *)HW_RESET_PARAMETER_BUF = parameter;
    OSi_SendToPxi(OS_PXI_COMMAND_RESET);
    OSi_DoResetSystem();
}

#pragma section ITCM begin
ARM_FUNC static void OSi_DoResetSystem(void)
{
    while (!OSi_IsResetOccurred) { }

    reg_OS_IME = 0;
    OSi_ReloadRomData();
    OSi_DoBoot();
}

ARM_FUNC asm void OSi_DoBoot(void)
{
    mov ip, #0x04000000
    str ip, [ip, #0x208]
    ldr r1, =SDK_AUTOLOAD_DTCM_START
    add r1, r1, #0x3fc0
    add r1, r1, #0x3c
    mov r0, #0x0
    str r0, [r1]
    ldr r1, =REG_SUBPINTF_ADDR
_01FF81D4:
    ldrh r0, [r1]
    and r0, r0, #0xf
    cmp r0, #0x1
    bne _01FF81D4
    mov r0, #0x100
    strh r0, [r1]
    mov r0, #0x0
    ldr r3, =HW_EXCP_VECTOR_MAIN
    ldr r4, [r3]
    ldr r1, =HW_BIOS_EXCP_STACK_MAIN
    mov r2, #0x80
    bl OSi_CpuClear32
    str r4, [r3]
    ldr r1, =HW_PXI_SIGNAL_PARAM_ARM9
    mov r2, #0x18
    bl OSi_CpuClear32
    ldr r1, =HW_WM_RSSI_POOL
    strh r0, [r1]
    ldr r1, =HW_COMPONENT_PARAM
    mov r2, #0x64
    bl OSi_CpuClear32
    ldr r1, =REG_SUBPINTF_ADDR
_01FF822C:
    ldrh r0, [r1]
    and r0, r0, #0xf
    cmp r0, #0x1
    beq _01FF822C
    mov r0, #0x0
    strh r0, [r1]
    ldr r3, =HW_ROM_HEADER_BUF
    ldr ip, [r3, #0x24]
    mov lr, ip
    ldr r11, =HW_PXI_SIGNAL_PARAM_ARM9
    ldmia r11, {r0-r10}
    mov r11, #0x0
    bx ip
}

ARM_FUNC static asm void OSi_CpuClear32(register u32 data, register void *destp, register u32 size)
{
    add ip, r1, r2
_01FF8284:
    cmp r1, ip
    stmltia r1!, {r0}
    blt _01FF8284
    bx lr
}

ARM_FUNC static void OSi_ReloadRomData(void)
{
    u32 header = (u32)HW_ROM_HEADER_BUF;
    const u32 rom_base = *(u32 *)HW_ROM_BASE_OFFSET_BUF;

    if (rom_base >= 0x8000)
    {
        OSi_ReadCardRom32(rom_base, (void *)header, 0x160);
    }

    u32 src_arm9 = *(u32 *)(header + 0x20);
    u32 dst_arm9 = *(u32 *)(header + 0x28);
    u32 len_arm9 = *(u32 *)(header + 0x2c);
    u32 src_arm7 = *(u32 *)(header + 0x30);
    u32 dst_arm7 = *(u32 *)(header + 0x38);
    u32 len_arm7 = *(u32 *)(header + 0x3c);

    OSIntrMode prevIntrMode = OS_DisableInterrupts();
    DC_StoreAll();
    DC_InvalidateAll();
    (void)OS_RestoreInterrupts(prevIntrMode);

    IC_InvalidateAll();
    DC_WaitWriteBufferEmpty();

    src_arm9 += rom_base;
    src_arm7 += rom_base;

    if (src_arm9 < 0x8000)
    {
        u32 diff = 0x8000 - src_arm9;
        src_arm9 = 0x8000;
        dst_arm9 += diff;
        len_arm9 -= diff;
    }
    OSi_ReadCardRom32(src_arm9, (void *)dst_arm9, (s32)len_arm9);

    OSi_ReadCardRom32(src_arm7, (void *)dst_arm7, (s32)len_arm7);
}

enum
{
    CARD_MASTER_SELECT_ROM = 0x0,
    CARD_MASTER_ENABLE = 0x80,
    CARD_CMD_READ_PAGE = 0xb7,
    CARD_CTRL_CMD_MASK = 0x07000000,
    CARD_CTRL_CMD_PAGE = 0x01000000,
    CARD_CTRL_READ = 0x00000000,
    CARD_CTRL_RESET_HI = 0x20000000,
    CARD_CTRL_START = 0x80000000,
    CARD_CTRL_READY = 0x00800000,
    CARD_ENUM_END
};

ARM_FUNC static void OSi_ReadCardRom32(u32 src, void *dst, s32 len)
{
    vu32 *const hdr_GAME_BUF = (vu32 *)(HW_ROM_HEADER_BUF + 0x60);

    const u32 ctrl_start = (u32)((*hdr_GAME_BUF &~CARD_CTRL_CMD_MASK)
                                 | (CARD_CTRL_CMD_PAGE | CARD_CTRL_READ
                                    | CARD_CTRL_START | CARD_CTRL_RESET_HI));

    s32 pos = -(s32)(src & 511);

    while (reg_CARD_CNT & CARD_CTRL_START) {}
    reg_CARD_MASTERCNT = (u32)(CARD_MASTER_SELECT_ROM | CARD_MASTER_ENABLE);

    for (src = (u32)(src + pos); pos < len; src += 512)
    {
        (&reg_CARD_CMD)[0] = (u8)(CARD_CMD_READ_PAGE);
        (&reg_CARD_CMD)[1] = (u8)(src >> 24);
        (&reg_CARD_CMD)[2] = (u8)(src >> 16);
        (&reg_CARD_CMD)[3] = (u8)(src >> 8);
        (&reg_CARD_CMD)[4] = (u8)(src >> 0);
        (&reg_CARD_CMD)[5] = 0;
        (&reg_CARD_CMD)[6] = 0;
        (&reg_CARD_CMD)[7] = 0;

        reg_CARD_CNT = ctrl_start;
        for (;;)
        {
            u32 ctrl = reg_CARD_CNT;

            if ((ctrl & CARD_CTRL_READY))
            {
                const u32 data = reg_CARD_DATA;

                if ((pos >= 0) && (pos < len))
                {
                    *(u32 *)((u32)dst + pos) = data;
                }

                pos += sizeof(u32);
            }

            if (!(ctrl & CARD_CTRL_START))
            {
                break;
            }
        }
    }
}
#pragma section ITCM end