| 1 | /* | 
|---|
| 2 | * \file  : reset.S | 
|---|
| 3 | * \date  : 01/12/2012 | 
|---|
| 4 | * \author: Cesar FUGUET & Manuel BOUYER & Alain Greiner | 
|---|
| 5 | * | 
|---|
| 6 | * This is a generic reset code for a generic multi-clusters / multi-processors | 
|---|
| 7 | * TSAR architecture (up to 256 clusters / up to 4 processors per cluster). | 
|---|
| 8 | * | 
|---|
| 9 | * There is one XICU, one TTY, one DMA, and one memory bank per cluster. | 
|---|
| 10 | * | 
|---|
| 11 | * This preloader uses a stack segment allocated in cluster 0 for processor 0. | 
|---|
| 12 | * The stack allocation is not performed for other processors as they do not | 
|---|
| 13 | * need it during the preloader execution. Therefore, this allocation should be | 
|---|
| 14 | * done by the loaded Operating System. | 
|---|
| 15 | * | 
|---|
| 16 | * The replicated XICU is used to awake the sleeping processors: | 
|---|
| 17 | *      xicu_paddr_base = ICU_PADDR_BASE + (cluster_xy << 32) | 
|---|
| 18 | * | 
|---|
| 19 | * It is intended to be used with various operating systems or nano kernels, | 
|---|
| 20 | * including NetBSD, Linux, ALMOS, and GIET_VM. | 
|---|
| 21 | * | 
|---|
| 22 | * - Each processor initializes its Status Register (SR) to disable interrupts. | 
|---|
| 23 | * - Each processor initializes its Count Register. | 
|---|
| 24 | * - Each processor initialises its private XICU WTI mask register. | 
|---|
| 25 | * - Only processor 0 executes the reset_load_elf function to load into memory | 
|---|
| 26 | *   the system specific boot-loader stored on disk at RESET_LOADER_LBA | 
|---|
| 27 | * - All other processors wait in a low power consumption mode that the | 
|---|
| 28 | *   processor 0 wakes them using an IPI (Inter Processor Interruption) | 
|---|
| 29 | */ | 
|---|
| 30 |  | 
|---|
| 31 | #include <defs.h> | 
|---|
| 32 | #include <mips32_registers.h> | 
|---|
| 33 |  | 
|---|
| 34 | /* These define should be consistent with values defined in map.xml file  */ | 
|---|
| 35 |  | 
|---|
| 36 | .section .reset,"ax",@progbits | 
|---|
| 37 |  | 
|---|
| 38 | .extern dtb_addr | 
|---|
| 39 | .extern reset_putc | 
|---|
| 40 | .extern reset_getc | 
|---|
| 41 | .extern reset_ioc_read | 
|---|
| 42 | .extern reset_elf_loader | 
|---|
| 43 | .extern memcpy | 
|---|
| 44 | .extern reset_puts | 
|---|
| 45 | .extern reset_putx | 
|---|
| 46 | .extern reset_putd | 
|---|
| 47 | .extern reset_ioc_init | 
|---|
| 48 | .extern versionstr | 
|---|
| 49 |  | 
|---|
| 50 | .globl  reset                    /* Makes reset an external symbol */ | 
|---|
| 51 | .ent    reset | 
|---|
| 52 |  | 
|---|
| 53 | .align  2 | 
|---|
| 54 | .set noreorder | 
|---|
| 55 |  | 
|---|
| 56 | reset: | 
|---|
| 57 | b       _reset                   /* 0xbfc0000 */ | 
|---|
| 58 | nop                              /* 0xbfc0004 */ | 
|---|
| 59 |  | 
|---|
| 60 | /*  Addresses of the functions provided by this reset code */ | 
|---|
| 61 |  | 
|---|
| 62 | preloader_vector: | 
|---|
| 63 | .word   RESET_VERSION            /* 0xbfc0008 */ | 
|---|
| 64 | .word   dtb_addr                 /* 0xbfc000c */ | 
|---|
| 65 | .word   reset_putc               /* 0xbfc0010 */ | 
|---|
| 66 | .word   reset_getc               /* 0xbfc0014 */ | 
|---|
| 67 | .word   reset_ioc_read           /* 0xbfc0018 */ | 
|---|
| 68 | .word   reset_elf_loader         /* 0xbfc001C */ | 
|---|
| 69 | .word   memcpy                   /* 0xbfc0020 */ | 
|---|
| 70 | .word   reset_puts               /* 0xbfc0024 */ | 
|---|
| 71 | .word   reset_putx               /* 0xbfc0028 */ | 
|---|
| 72 | .word   reset_putd               /* 0xbfc002C */ | 
|---|
| 73 |  | 
|---|
| 74 | _reset: | 
|---|
| 75 |  | 
|---|
| 76 | /* All processors Disable interruptions, keep STATUSbev enabled */ | 
|---|
| 77 |  | 
|---|
| 78 | li      k0,     (1 << 22) | 
|---|
| 79 | mtc0    k0,     CP0_STATUS | 
|---|
| 80 |  | 
|---|
| 81 | /* All processors compute pid, lpid, cluster_xy */ | 
|---|
| 82 |  | 
|---|
| 83 | mfc0    k0,     CP0_EBASE | 
|---|
| 84 | andi    t0,     k0,     0x3FF    /* t0 <= pid (at most 1024 procs)      */ | 
|---|
| 85 |  | 
|---|
| 86 | move    t3,     t0 | 
|---|
| 87 |  | 
|---|
| 88 | la      k0,     NB_PROCS_MAX     /* k0 <= # of processors per cluster   */ | 
|---|
| 89 | divu    t3,     k0 | 
|---|
| 90 | mfhi    t1                       /* t1 <= lpid       = pid % NB_PROCS   */ | 
|---|
| 91 | mflo    t2                       /* t2 <= cluster_xy = pid / NB_PROCS   */ | 
|---|
| 92 |  | 
|---|
| 93 | /* All processors initialise the count register in CP0 */ | 
|---|
| 94 |  | 
|---|
| 95 | mtc0    zero,   CP0_COUNT | 
|---|
| 96 |  | 
|---|
| 97 | /* | 
|---|
| 98 | * All processors enable the WTI for XICU | 
|---|
| 99 | * Each processor may have IRQ_PER_PROC irq outputs from the XICU | 
|---|
| 100 | * In each cluster, the XICU base address depends on the cluster_xy | 
|---|
| 101 | */ | 
|---|
| 102 |  | 
|---|
| 103 | la      t3,     SEG_XCU_BASE      /* t3 <= ICU base address             */ | 
|---|
| 104 | move    t4,     t1                /* t4 <= local_id                     */ | 
|---|
| 105 | li      t5,     IRQ_PER_PROCESSOR /* t5 <= IRQ_PER_PROCESSOR            */ | 
|---|
| 106 | multu   t4,     t5 | 
|---|
| 107 | mflo    t6                       /* t6 <= IRQ_PER_PROC * local_id       */ | 
|---|
| 108 | sll     t4,     t6,     2        /* t4 <= OUT_INDEX = t6 * 4            */ | 
|---|
| 109 |  | 
|---|
| 110 | li      t5,     (0xC << 7)       /* t5 <= FUNC      = XICU_MSK_WTI      */ | 
|---|
| 111 | or      t4,     t4,     t5       /* t4 <= FUNC | INDEX | 00             */ | 
|---|
| 112 | or      t5,     t3,     t4       /* t5 <= &XICU[MSK_WTI][OUT_INDEX]     */ | 
|---|
| 113 |  | 
|---|
| 114 | /* All processors set WTI mask using the physical address extension */ | 
|---|
| 115 |  | 
|---|
| 116 | li      t4,     1 | 
|---|
| 117 | sllv    t4,     t4,     t1       /* Set XICU[MSK_WTI][INDEX][local_id]  */ | 
|---|
| 118 |  | 
|---|
| 119 | mtc2    t2,     CP2_PADDR_EXT    /* set PADDR extension                 */ | 
|---|
| 120 | sw      t4,     0(t5)            /* XICU[MSK_WTI][INDEX] <= t4          */ | 
|---|
| 121 | mtc2    zero,   CP2_PADDR_EXT    /* reset PADDR extension               */ | 
|---|
| 122 |  | 
|---|
| 123 | /* | 
|---|
| 124 | * Only processor 0 in cluster 0 loads and executes the boot-loader | 
|---|
| 125 | * We have: | 
|---|
| 126 | * t0: global pid | 
|---|
| 127 | * t1: local pid | 
|---|
| 128 | * t2: cluster_xy | 
|---|
| 129 | * t3: xicu physical base address in cluster 0 | 
|---|
| 130 | */ | 
|---|
| 131 |  | 
|---|
| 132 | bne     zero,   t0,     _reset_wait | 
|---|
| 133 | nop | 
|---|
| 134 |  | 
|---|
| 135 | /* Processor 0 initializes stack pointer */ | 
|---|
| 136 |  | 
|---|
| 137 | la      k0,     _stack | 
|---|
| 138 | li      k1,     RESET_STACK_SIZE /* k1 <= P0 stack size                 */ | 
|---|
| 139 | addu    sp,     k0,     k1       /* P0 stack from base to (base + size) */ | 
|---|
| 140 |  | 
|---|
| 141 | /* Processor 0 displays version for this reset code */ | 
|---|
| 142 |  | 
|---|
| 143 | la      a0,     versionstr | 
|---|
| 144 | jal     reset_puts | 
|---|
| 145 | nop | 
|---|
| 146 |  | 
|---|
| 147 | /* Processor 0 initializes the block device */ | 
|---|
| 148 |  | 
|---|
| 149 | jal     reset_ioc_init | 
|---|
| 150 | nop | 
|---|
| 151 |  | 
|---|
| 152 | /* | 
|---|
| 153 | * Processor 0 jumps to the reset_elf_loader routine passing as argument | 
|---|
| 154 | * the block number in which is loaded the .elf file | 
|---|
| 155 | */ | 
|---|
| 156 |  | 
|---|
| 157 | li      a0,     RESET_LOADER_LBA | 
|---|
| 158 | jal     reset_elf_loader | 
|---|
| 159 | nop | 
|---|
| 160 |  | 
|---|
| 161 | /* | 
|---|
| 162 | * Processor O jumps to the entry address defined in the .elf file, and | 
|---|
| 163 | * returned by reset_elf_loader function. | 
|---|
| 164 | * First argument is pointer to the preloader function vectors other | 
|---|
| 165 | * function arguments are 0 | 
|---|
| 166 | */ | 
|---|
| 167 |  | 
|---|
| 168 | la      a0,     preloader_vector | 
|---|
| 169 | move    a1,     zero | 
|---|
| 170 | move    a2,     zero | 
|---|
| 171 | move    a3,     zero | 
|---|
| 172 | jr      v0 | 
|---|
| 173 | nop | 
|---|
| 174 |  | 
|---|
| 175 | /* | 
|---|
| 176 | * All processor (but processor 0) wait in low power mode until processor 0 | 
|---|
| 177 | * wakes them using an IPI. | 
|---|
| 178 | * We have: | 
|---|
| 179 | * t0: global id | 
|---|
| 180 | * t1: local id | 
|---|
| 181 | * t2: cluster id | 
|---|
| 182 | * t3: xicu physical base address in cluster 0 | 
|---|
| 183 | */ | 
|---|
| 184 |  | 
|---|
| 185 | _reset_wait: | 
|---|
| 186 |  | 
|---|
| 187 | sll     t4,     t1,     2        /* t4 <= local_id * 4                  */ | 
|---|
| 188 | addu    t5,     t4,     t3       /* t5 <= &XICU[WTI_REG][local_id]      */ | 
|---|
| 189 |  | 
|---|
| 190 | wait | 
|---|
| 191 |  | 
|---|
| 192 | /* | 
|---|
| 193 | * All other processors, when exiting wait mode, read from XICU the address | 
|---|
| 194 | * to jump. | 
|---|
| 195 | * This address is the boot-loader entry address that has been written in | 
|---|
| 196 | * the mailbox by the IPI sent by processor 0 | 
|---|
| 197 | */ | 
|---|
| 198 |  | 
|---|
| 199 | mtc2    t2,     CP2_PADDR_EXT    /* set PADDR extension                 */ | 
|---|
| 200 | lw      k0,     0(t5)            /* k0 <= XICU[WTI_REG][local_id]       */ | 
|---|
| 201 | mtc2    zero,   CP2_PADDR_EXT    /* reset PADDR extension               */ | 
|---|
| 202 |  | 
|---|
| 203 | jr      k0 | 
|---|
| 204 | nop | 
|---|
| 205 |  | 
|---|
| 206 | /* Exception entry point */ | 
|---|
| 207 |  | 
|---|
| 208 | .org 0x0380 | 
|---|
| 209 | _excep: | 
|---|
| 210 | mfc0    a0,     CP0_STATUS       /* first arg is status                 */ | 
|---|
| 211 | mfc0    a1,     CP0_CAUSE        /* second arg is cause                 */ | 
|---|
| 212 | mfc0    a2,     CP0_EPC          /* third argc is epc                   */ | 
|---|
| 213 | mfc2    a3,     CP2_DBVAR        /* fourth argc is dbvar                */ | 
|---|
| 214 | nop | 
|---|
| 215 | j       handle_except | 
|---|
| 216 | nop | 
|---|
| 217 |  | 
|---|
| 218 | .end reset | 
|---|
| 219 |  | 
|---|
| 220 | .set reorder | 
|---|
| 221 |  | 
|---|
| 222 | .section .data | 
|---|
| 223 |  | 
|---|
| 224 | _stack: | 
|---|
| 225 |  | 
|---|
| 226 | .space RESET_STACK_SIZE | 
|---|
| 227 |  | 
|---|
| 228 | /* | 
|---|
| 229 | * vim: tabstop=4 : shiftwidth=4 : expandtab | 
|---|
| 230 | */ | 
|---|