| 1 | /** | 
|---|
| 2 | * \file  : reset.S | 
|---|
| 3 | * \date  : 01/12/2012 | 
|---|
| 4 | * \author: Cesar FUGUET & Manuel BOUYER & Alain Greiner | 
|---|
| 5 | * | 
|---|
| 6 | * This is a boot code for a generic multi-clusters / multi-processors | 
|---|
| 7 | * TSAR architecture (up to 256 clusters / up to 4  processors per cluster). | 
|---|
| 8 | * There is one XICU, one TTY, one DMA and one stack segment per cluster. | 
|---|
| 9 | * segment base adresses = base + cluster_segment_increment*cluster_id | 
|---|
| 10 | * | 
|---|
| 11 | * - Each processor initializes the Status Register (SR) to disable interrupts. | 
|---|
| 12 | * - Each processor initializes the Count Register. | 
|---|
| 13 | * - Each processor initialises its private XICU Write Triggered Interruption | 
|---|
| 14 | *   mask register. | 
|---|
| 15 | * - Only processor 0 initializes the stack pointer ($29). | 
|---|
| 16 | * - Only processor 0 (boot processor) executes the boot_load_elf function to | 
|---|
| 17 | *   load in memory the boot loader stored in the block BOOT_LOADER_LBA of | 
|---|
| 18 | *   the disk. | 
|---|
| 19 | * - All non-boot processors wait in a low power consumption mode that the | 
|---|
| 20 | *   processor 0 wakes them using the IPI (Inter Processor Interruption) | 
|---|
| 21 | *   functionality of the XICU device. | 
|---|
| 22 | */ | 
|---|
| 23 |  | 
|---|
| 24 | #include <defs.h> | 
|---|
| 25 | #include <mips32_registers.h> | 
|---|
| 26 |  | 
|---|
| 27 | .section .boot,"ax",@progbits | 
|---|
| 28 |  | 
|---|
| 29 | .extern seg_stack_base | 
|---|
| 30 |  | 
|---|
| 31 | .extern boot_ioc_init | 
|---|
| 32 | .extern boot_putc | 
|---|
| 33 | .extern boot_getc | 
|---|
| 34 | .extern boot_puts | 
|---|
| 35 | .extern boot_ioc_read | 
|---|
| 36 | .extern boot_elf_loader | 
|---|
| 37 | .extern boot_memcpy | 
|---|
| 38 | .extern dtb_addr | 
|---|
| 39 |  | 
|---|
| 40 | .globl  boot                    /* Make reset an external symbol */ | 
|---|
| 41 | .ent    boot | 
|---|
| 42 |  | 
|---|
| 43 | .align  2 | 
|---|
| 44 | .set noreorder | 
|---|
| 45 |  | 
|---|
| 46 | boot: | 
|---|
| 47 | b       _boot                   /* 0xbfc0000 */ | 
|---|
| 48 | nop                             /* 0xbfc0004 */ | 
|---|
| 49 |  | 
|---|
| 50 | /*  Addresses of the functions provided by this pre-loader */ | 
|---|
| 51 |  | 
|---|
| 52 | .word   BOOT_VERSION            /* 0xbfc0008 */ | 
|---|
| 53 | .word   dtb_addr                /* 0xbfc000c */ | 
|---|
| 54 | .word   boot_putc               /* 0xbfc0010 */ | 
|---|
| 55 | .word   boot_getc               /* 0xbfc0014 */ | 
|---|
| 56 | .word   boot_puts               /* 0xbfc0018 */ | 
|---|
| 57 | .word   boot_ioc_read           /* 0xbfc001C */ | 
|---|
| 58 | .word   boot_elf_loader         /* 0xbfc0020 */ | 
|---|
| 59 | .word   boot_memcpy             /* 0xbfc0024 */ | 
|---|
| 60 |  | 
|---|
| 61 | _boot: | 
|---|
| 62 | /* Disable interruptions, keep STATUSbev enabled */ | 
|---|
| 63 |  | 
|---|
| 64 | li      k0,     (1 << 22) | 
|---|
| 65 | mtc0    k0,     CP0_STATUS | 
|---|
| 66 |  | 
|---|
| 67 | /* Computes proc_id, local_id, cluster_id, and cluster_increment */ | 
|---|
| 68 |  | 
|---|
| 69 | mfc0    k0,     CP0_EBASE | 
|---|
| 70 | andi    t0,     k0,     0x3FF   /* t0 <= proc_id (at most 1024 processors)    */ | 
|---|
| 71 |  | 
|---|
| 72 | move    t3,     t0 | 
|---|
| 73 |  | 
|---|
| 74 | la      k0,     NB_PROCS        /* k0 <= number of processors per cluster     */ | 
|---|
| 75 | divu    t3,     k0 | 
|---|
| 76 | mfhi    t1                      /* t1 <= local_id   = proc_id % NB_PROCS      */ | 
|---|
| 77 | mflo    t2                      /* t2 <= cluster_id = proc_id / NB_PROCS      */ | 
|---|
| 78 |  | 
|---|
| 79 | la      k0,     NB_CLUSTERS | 
|---|
| 80 | li      t3,     0x80000000 | 
|---|
| 81 | divu    t3,     k0 | 
|---|
| 82 | mflo    t4 | 
|---|
| 83 | sll     t4,     1               /* t4 <= cluster_increment = 4G / NB_CLUSTERS */ | 
|---|
| 84 |  | 
|---|
| 85 | mult    t4,     t2 | 
|---|
| 86 | mflo    t5                      /* t5 <= cluster_id * cluster_increment       */ | 
|---|
| 87 |  | 
|---|
| 88 | /* Initialization of the count register in the coprocessor 0 */ | 
|---|
| 89 |  | 
|---|
| 90 | mtc0    zero,   CP0_COUNT | 
|---|
| 91 |  | 
|---|
| 92 | /* In each cluster, the ICU base address depends on the cluster_id */ | 
|---|
| 93 |  | 
|---|
| 94 | la      t3,     ICU_BASE | 
|---|
| 95 | addu    t3,     t3,     t5      /* t3 <= ICU_BASE +                       */ | 
|---|
| 96 | /*       (cluster_id * cluster_increment) */ | 
|---|
| 97 |  | 
|---|
| 98 | /** | 
|---|
| 99 | * Compute the output index for the Write Triggered Interruption mask. | 
|---|
| 100 | * Each processor enable the WTI for its irq output | 
|---|
| 101 | * Each processor may have IRQ_PER_PROC private irq outputs from | 
|---|
| 102 | * the XICU | 
|---|
| 103 | */ | 
|---|
| 104 |  | 
|---|
| 105 | move    t4,     t1              /* t4 <= local_id                   */ | 
|---|
| 106 | li      t5,     IRQ_PER_PROC    /* t5 <= IRQ_PER_PROC               */ | 
|---|
| 107 | multu   t4,     t5 | 
|---|
| 108 | mflo    t6                      /* t6 <= IRQ_PER_PROC * local_id    */ | 
|---|
| 109 | sll     t4,     t6,     2       /* t4 <= OUT_INDEX = t6 * 4         */ | 
|---|
| 110 |  | 
|---|
| 111 | li      t5,     (0xC << 7)      /* t5 <= FUNC      = XICU_MSK_WTI   */ | 
|---|
| 112 | or      t4,     t4,     t5      /* t4 <= FUNC | INDEX | 00          */ | 
|---|
| 113 | or      t5,     t3,     t4      /* t5 <= &XICU[MSK_WTI][OUT_INDEX]  */ | 
|---|
| 114 |  | 
|---|
| 115 | /* Compute and set WTI mask */ | 
|---|
| 116 |  | 
|---|
| 117 | li      t4,     1 | 
|---|
| 118 | sllv    t4,     t4,     t1      /* Set XICU[MSK_WTI][INDEX][local_id] */ | 
|---|
| 119 | sw      t4,     0(t5)           /* XICU[MSK_WTI][INDEX] <= t4         */ | 
|---|
| 120 |  | 
|---|
| 121 | /** | 
|---|
| 122 | * We have: | 
|---|
| 123 | * t0: global id | 
|---|
| 124 | * t1: local id | 
|---|
| 125 | * t2: cluster id | 
|---|
| 126 | * t3: xicu base address | 
|---|
| 127 | * | 
|---|
| 128 | * Only processor 0 in cluster 0 executes the boot loader | 
|---|
| 129 | */ | 
|---|
| 130 |  | 
|---|
| 131 | bne     zero,   t0,     _reset_wait | 
|---|
| 132 | nop | 
|---|
| 133 |  | 
|---|
| 134 | /* Initializes stack pointer */ | 
|---|
| 135 |  | 
|---|
| 136 | la      k1,     seg_stack_base | 
|---|
| 137 | li      k0,     BOOT_STACK_SIZE | 
|---|
| 138 | addu    sp,     k1,     k0      /* sp <= seg_stack_base + BOOT_STACK_SIZE */ | 
|---|
| 139 |  | 
|---|
| 140 | #ifndef SOCLIB_IOC | 
|---|
| 141 |  | 
|---|
| 142 | /* Initialize the block device */ | 
|---|
| 143 |  | 
|---|
| 144 | la      k0,     boot_ioc_init | 
|---|
| 145 | jalr    k0 | 
|---|
| 146 | nop | 
|---|
| 147 |  | 
|---|
| 148 | #endif | 
|---|
| 149 |  | 
|---|
| 150 | /** | 
|---|
| 151 | * Jump to the boot elf loader routine | 
|---|
| 152 | * Passing as argument the block number in which it must be | 
|---|
| 153 | * the executable elf file to load | 
|---|
| 154 | */ | 
|---|
| 155 |  | 
|---|
| 156 | la      k0,     boot_elf_loader | 
|---|
| 157 | li      a0,     BOOT_LOADER_LBA | 
|---|
| 158 | jalr    k0 | 
|---|
| 159 | nop | 
|---|
| 160 |  | 
|---|
| 161 | /** | 
|---|
| 162 | * We jump to the entry point address defined in the | 
|---|
| 163 | * ELF file. This address is returned by boot_elf_loader function. | 
|---|
| 164 | * All function arguments are 0 | 
|---|
| 165 | */ | 
|---|
| 166 |  | 
|---|
| 167 | move    a0,     zero | 
|---|
| 168 | move    a1,     zero | 
|---|
| 169 | move    a2,     zero | 
|---|
| 170 | move    a3,     zero | 
|---|
| 171 | jr      v0 | 
|---|
| 172 | nop | 
|---|
| 173 |  | 
|---|
| 174 | /** | 
|---|
| 175 | * Wait in low power consumption mode until the application wakes us. | 
|---|
| 176 | * The application wakes up the non-boot CPUs using a IPI with a non-0 | 
|---|
| 177 | * value in the mailbox. This non-0 value is the address to jump to. | 
|---|
| 178 | */ | 
|---|
| 179 |  | 
|---|
| 180 | _reset_wait: | 
|---|
| 181 | /** | 
|---|
| 182 | * We have: | 
|---|
| 183 | * t0: global id | 
|---|
| 184 | * t1: local id | 
|---|
| 185 | * t2: cluster id | 
|---|
| 186 | * t3: xicu base address | 
|---|
| 187 | */ | 
|---|
| 188 |  | 
|---|
| 189 | sll     t4,     t1,     2       /* t4 <= local_id * 4             */ | 
|---|
| 190 | addu    t5,     t4,     t3      /* t5 <= &XICU[WTI_REG][local_id] */ | 
|---|
| 191 |  | 
|---|
| 192 | wait | 
|---|
| 193 |  | 
|---|
| 194 | lw      k0,     0(t5)           /* k0 <= XICU[WTI_REG][local_id]  */ | 
|---|
| 195 | jr      k0 | 
|---|
| 196 | nop | 
|---|
| 197 |  | 
|---|
| 198 | /* Exception entry point */ | 
|---|
| 199 | .org 0x0380 | 
|---|
| 200 | _excep: | 
|---|
| 201 | mfc0    a0, CP0_STATUS          /* first arg is status */ | 
|---|
| 202 | mfc0    a1, CP0_CAUSE           /* second arg is cause */ | 
|---|
| 203 | mfc0    a2, CP0_EPC             /* third argc is epc   */ | 
|---|
| 204 | nop | 
|---|
| 205 | j       handle_except | 
|---|
| 206 | nop | 
|---|
| 207 |  | 
|---|
| 208 | .end boot | 
|---|
| 209 |  | 
|---|
| 210 | .set reorder | 
|---|
| 211 |  | 
|---|
| 212 | /* | 
|---|
| 213 | * vim: tabstop=4 : shiftwidth=4 : expandtab | 
|---|
| 214 | */ | 
|---|