| 1 | ################################################################################# | 
|---|
| 2 | #   File : reset.s | 
|---|
| 3 | #   Author : Alain Greiner | 
|---|
| 4 | #   Date : 15/04/2011 | 
|---|
| 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 | #   - Each processor initializes the stack pointer ($29) depending on pid. | 
|---|
| 11 | #   - Only processor 0 initializes the Interrupt vector (TTY, DMA & IOC). | 
|---|
| 12 | #       - Each processor initialises its private ICU mask register. | 
|---|
| 13 | #   - Each processor initializes the Status Register (SR) | 
|---|
| 14 | #   - Each processor initializes the EPC register, and jumps to the main | 
|---|
| 15 | #     address in kernel mode... | 
|---|
| 16 | ################################################################################# | 
|---|
| 17 |  | 
|---|
| 18 | #include <defs.h> | 
|---|
| 19 | .section .boot,"ax",@progbits | 
|---|
| 20 |  | 
|---|
| 21 | .extern seg_stack_base | 
|---|
| 22 | .extern _boot_loader_entry | 
|---|
| 23 |  | 
|---|
| 24 | .extern dtb_addr | 
|---|
| 25 | .extern boot_putc | 
|---|
| 26 | .extern boot_getc | 
|---|
| 27 | .extern _ioc_read | 
|---|
| 28 |  | 
|---|
| 29 | .globl  boot               # makes reset an external symbol | 
|---|
| 30 | .ent    boot | 
|---|
| 31 | .align  2 | 
|---|
| 32 | .set noreorder | 
|---|
| 33 |  | 
|---|
| 34 | boot: | 
|---|
| 35 | b       _boot               #0xbfc0000 | 
|---|
| 36 | nop                         #0xbfc0004 | 
|---|
| 37 | .word   BOOT_VERSION        #0xbfc0008 | 
|---|
| 38 | .word   dtb_addr            #0xbfc000c | 
|---|
| 39 | .word   boot_putc           #0xbfc0010 | 
|---|
| 40 | .word   boot_getc           #0xbfc0014 | 
|---|
| 41 | .word   _ioc_read           #0xbfc0018 | 
|---|
| 42 |  | 
|---|
| 43 | _boot: | 
|---|
| 44 | # Disable interruptions | 
|---|
| 45 |  | 
|---|
| 46 | mtc0    $0,     $12 | 
|---|
| 47 |  | 
|---|
| 48 | # computes proc_id, local_id, cluster_id, and cluster_increment | 
|---|
| 49 |  | 
|---|
| 50 | mfc0    $26,    $15,    1 | 
|---|
| 51 | andi    $10,    $26,    0x3FF   # $10 <= proc_id (at most 1024 processors) | 
|---|
| 52 | la      $26,    NB_PROCS        # $26 <= number of processors per cluster | 
|---|
| 53 | divu    $10,    $26 | 
|---|
| 54 | mfhi    $11                     # $11 <= local_id = proc_id % NB_PROCS | 
|---|
| 55 | mflo    $12                     # $12 <= cluster_id = proc_id / NB_PROCS | 
|---|
| 56 |  | 
|---|
| 57 | mfc0    $26,    $15,    1 | 
|---|
| 58 | andi    $10,    $26,    0x3FF   # $10 <= proc_id (at most 1024 processors) | 
|---|
| 59 |  | 
|---|
| 60 | la      $26,    NB_CLUSTERS | 
|---|
| 61 | li      $13,    0x80000000 | 
|---|
| 62 | divu    $13,    $26 | 
|---|
| 63 | mflo    $14 | 
|---|
| 64 | sll     $14,    1               # $14 <= cluster_increment = 4G / NB_CLUSTERS | 
|---|
| 65 | mult    $14,    $12 | 
|---|
| 66 | mflo    $13                     # $13 <= cluster_id * cluster_increment | 
|---|
| 67 |  | 
|---|
| 68 | # Initialization of the count register in the coprocessor 0 | 
|---|
| 69 |  | 
|---|
| 70 | mtc0    $0 ,    $9 | 
|---|
| 71 |  | 
|---|
| 72 | # in each cluster, the ICU base address depends on the cluster_id | 
|---|
| 73 |  | 
|---|
| 74 | la      $20,    ICU_BASE | 
|---|
| 75 | addu    $20,    $20,    $13     # $20 <= ICU_BASE + cluster_id*cluster_increment | 
|---|
| 76 | # we have: | 
|---|
| 77 | # $20 xicu base address | 
|---|
| 78 | # $12 cluster id | 
|---|
| 79 | # $11 local id | 
|---|
| 80 | # $10 global id | 
|---|
| 81 | # | 
|---|
| 82 | # only processor 0 in cluster 0 executes the boot loader | 
|---|
| 83 | bne     $0,    $10,     _reset_wait | 
|---|
| 84 | nop | 
|---|
| 85 | # initializes stack pointer | 
|---|
| 86 |  | 
|---|
| 87 | la      $27,    seg_stack_base | 
|---|
| 88 | li      $26,    0x10000         # $26 <= 0x10000 | 
|---|
| 89 | addu    $29,    $27,    $26     # $29 <= seg_stack_base + 0x10000 | 
|---|
| 90 |  | 
|---|
| 91 | # Jump to the boot loader routine | 
|---|
| 92 | la      $26,    _boot_loader_entry | 
|---|
| 93 | jalr    $26 | 
|---|
| 94 | nop | 
|---|
| 95 |  | 
|---|
| 96 | # We jump to the main function, which is the entry point in the | 
|---|
| 97 | # ELF file. The address is returned by _boot_loader_entry | 
|---|
| 98 | # all arguments are 0 | 
|---|
| 99 |  | 
|---|
| 100 | move    $4,    $0 | 
|---|
| 101 | move    $5,    $0 | 
|---|
| 102 | move    $6,    $0 | 
|---|
| 103 | move    $7,    $0 | 
|---|
| 104 | jr      $2 | 
|---|
| 105 | nop | 
|---|
| 106 |  | 
|---|
| 107 |  | 
|---|
| 108 | # Wait until the application wakes us. | 
|---|
| 109 | # The application wakes up the non-boot CPUs with a IPI with a non-0 | 
|---|
| 110 | # value in the mailbox. This non-0 value is the address to jump to. | 
|---|
| 111 | _reset_wait: | 
|---|
| 112 | # we have: | 
|---|
| 113 | # $20 xicu base address | 
|---|
| 114 | # $12 cluster id | 
|---|
| 115 | # $11 local id | 
|---|
| 116 | # $10 global id | 
|---|
| 117 |  | 
|---|
| 118 | sll     $13,    $11,    2   # $13 = local_id * 4 | 
|---|
| 119 | addu    $21,    $13,    $20 # $21 = XICU_WTI_REG(local_id) | 
|---|
| 120 | 1: | 
|---|
| 121 | lw      $2,     0($21) | 
|---|
| 122 | beq     $0,     $2,     1b | 
|---|
| 123 | nop | 
|---|
| 124 | jr      $2 | 
|---|
| 125 |  | 
|---|
| 126 | .end    boot | 
|---|
| 127 |  | 
|---|
| 128 | .set reorder | 
|---|