[444] | 1 | /* |
---|
| 2 | * crt0.S -- startup file for MIPS. |
---|
| 3 | * |
---|
| 4 | * Copyright (c) 1995, 1996, 1997, 2001 Cygnus Support |
---|
| 5 | * |
---|
| 6 | * The authors hereby grant permission to use, copy, modify, distribute, |
---|
| 7 | * and license this software and its documentation for any purpose, provided |
---|
| 8 | * that existing copyright notices are retained in all copies and that this |
---|
| 9 | * notice is included verbatim in any distributions. No written agreement, |
---|
| 10 | * license, or royalty fee is required for any of the authorized uses. |
---|
| 11 | * Modifications to this software may be copyrighted by their authors |
---|
| 12 | * and need not follow the licensing terms described here, provided that |
---|
| 13 | * the new terms are clearly indicated on the first page of each file where |
---|
| 14 | * they apply. |
---|
| 15 | */ |
---|
| 16 | |
---|
| 17 | /* This file does not use any floating-point ABI. */ |
---|
| 18 | .gnu_attribute 4,0 |
---|
| 19 | |
---|
| 20 | #ifdef __mips16 |
---|
| 21 | /* This file contains 32 bit assembly code. */ |
---|
| 22 | .set nomips16 |
---|
| 23 | #endif |
---|
| 24 | |
---|
| 25 | #include "regs.S" |
---|
| 26 | #include "abiflags.S" |
---|
| 27 | |
---|
| 28 | /* |
---|
| 29 | * Set up some room for a stack. We just grab a chunk of memory. |
---|
| 30 | */ |
---|
| 31 | #define STACK_SIZE 0x4000 |
---|
| 32 | #define GLOBAL_SIZE 0x2000 |
---|
| 33 | |
---|
| 34 | #define STARTUP_STACK_SIZE 0x0100 |
---|
| 35 | |
---|
| 36 | /* This is for referencing addresses that are not in the .sdata or |
---|
| 37 | .sbss section under embedded-pic, or before we've set up gp. */ |
---|
| 38 | #ifdef __mips_embedded_pic |
---|
| 39 | # ifdef __mips64 |
---|
| 40 | # define LA(t,x) la t,x-PICBASE ; daddu t,s0,t |
---|
| 41 | # else |
---|
| 42 | # define LA(t,x) la t,x-PICBASE ; addu t,s0,t |
---|
| 43 | # endif |
---|
| 44 | #else /* __mips_embedded_pic */ |
---|
| 45 | # define LA(t,x) la t,x |
---|
| 46 | #endif /* __mips_embedded_pic */ |
---|
| 47 | |
---|
| 48 | .comm __memsize, 12 |
---|
| 49 | .comm __lstack, STARTUP_STACK_SIZE |
---|
| 50 | |
---|
| 51 | .text |
---|
| 52 | .align 2 |
---|
| 53 | |
---|
| 54 | /* Without the following nop, GDB thinks _start is a data variable. |
---|
| 55 | * This is probably a bug in GDB in handling a symbol that is at the |
---|
| 56 | * start of the .text section. |
---|
| 57 | */ |
---|
| 58 | nop |
---|
| 59 | |
---|
| 60 | .globl hardware_hazard_hook .text |
---|
| 61 | .globl _start |
---|
| 62 | .ent _start |
---|
| 63 | _start: |
---|
| 64 | #ifdef __mips_embedded_pic |
---|
| 65 | #define PICBASE start_PICBASE |
---|
| 66 | .set noreorder |
---|
| 67 | PICBASE = .+8 |
---|
| 68 | bal PICBASE |
---|
| 69 | nop |
---|
| 70 | move s0,$31 |
---|
| 71 | .set reorder |
---|
| 72 | #endif |
---|
| 73 | #if __mips<3 |
---|
| 74 | # define STATUS_MASK (SR_CU1|SR_PE) |
---|
| 75 | #else |
---|
| 76 | /* Post-mips2 has no SR_PE bit. */ |
---|
| 77 | # ifdef __mips64 |
---|
| 78 | /* Turn on 64-bit addressing and additional float regs. */ |
---|
| 79 | # define STATUS_MASK (SR_CU1|SR_FR|SR_KX|SR_SX|SR_UX) |
---|
| 80 | # else |
---|
| 81 | # if __mips_fpr==32 |
---|
| 82 | # define STATUS_MASK (SR_CU1) |
---|
| 83 | # else |
---|
| 84 | /* Turn on additional float regs. */ |
---|
| 85 | # define STATUS_MASK (SR_CU1|SR_FR) |
---|
| 86 | # endif |
---|
| 87 | # endif |
---|
| 88 | #endif |
---|
| 89 | |
---|
| 90 | /* Clear Cause register. */ |
---|
| 91 | mtc0 zero,C0_CAUSE |
---|
| 92 | nop |
---|
| 93 | |
---|
| 94 | /* Read MIPS_abiflags structure and set status/config registers |
---|
| 95 | accordingly. */ |
---|
| 96 | .weak __MIPS_abiflags_start |
---|
| 97 | .weak __MIPS_abiflags_end |
---|
| 98 | LA (t0,__MIPS_abiflags_start) |
---|
| 99 | LA (t1,__MIPS_abiflags_end) |
---|
| 100 | addiu t1,t1,-24 |
---|
| 101 | move v0,zero /* Mask for C0_SR. */ |
---|
| 102 | |
---|
| 103 | /* Branch to 1f is the .MIPS.abiflags section is not 24 bytes. This |
---|
| 104 | indicates it is either missing or corrupt. */ |
---|
| 105 | bne t0,t1,1f |
---|
| 106 | |
---|
| 107 | /* Check isa_level. */ |
---|
| 108 | lbu t1,ABIFlags_isa_level(t0) |
---|
| 109 | sltu v1,t1,3 /* Is MIPS < 3? */ |
---|
| 110 | xori t1,t1,64 /* Is MIPS64? */ |
---|
| 111 | beq v1,zero,4f |
---|
| 112 | li v1,SR_PE |
---|
| 113 | or v0,v0,v1 /* Enable soft reset. */ |
---|
| 114 | 4: |
---|
| 115 | li v1,(SR_KX|SR_SX|SR_UX) |
---|
| 116 | bne t1,zero,5f |
---|
| 117 | or v0,v0,v1 /* Enable extended addressing. */ |
---|
| 118 | 5: |
---|
| 119 | /* Check fp_abi. */ |
---|
| 120 | lbu t1,ABIFlags_fp_abi(t0) |
---|
| 121 | xori t1,t1,Val_GNU_MIPS_ABI_FP_SOFT |
---|
| 122 | li v1,SR_CU1 |
---|
| 123 | beq t1,zero,2f /* Skip MSA and cpr1_size checks. */ |
---|
| 124 | or v0,v0,v1 /* Enable co-processor 1. */ |
---|
| 125 | |
---|
| 126 | /* Check cpr1_size. */ |
---|
| 127 | lbu t1,ABIFlags_cpr1_size(t0) |
---|
| 128 | xori t1,t1,AFL_REG_64 |
---|
| 129 | li v1,SR_FR |
---|
| 130 | bne t1,zero,3f |
---|
| 131 | or v0,v0,v1 /* Enable 64-bit FPU registers. */ |
---|
| 132 | 3: |
---|
| 133 | /* Check ases. */ |
---|
| 134 | lw t1,ABIFlags_ases(t0) |
---|
| 135 | andi t1,t1,AFL_ASE_MSA |
---|
| 136 | li v1,SR_FR |
---|
| 137 | beq t1,zero,2f |
---|
| 138 | or v0,v0,v1 /* Enable 64-bit FPU registers. */ |
---|
| 139 | li v1,SR_MSA |
---|
| 140 | .set push |
---|
| 141 | .set mips32 |
---|
| 142 | mtc0 v1,C0_CONFIG,5 /* Enable MSA. */ |
---|
| 143 | .set pop |
---|
| 144 | b 2f |
---|
| 145 | |
---|
| 146 | 1: |
---|
| 147 | /* MIPS_abiflags structure is not available. Set status/config |
---|
| 148 | registers based on flags defined by compiler. */ |
---|
| 149 | #ifdef __mips_soft_float |
---|
| 150 | li v0,(STATUS_MASK-(STATUS_MASK & SR_CU1)) |
---|
| 151 | #else |
---|
| 152 | li v0,STATUS_MASK |
---|
| 153 | #endif |
---|
| 154 | |
---|
| 155 | 2: |
---|
| 156 | /* Set C0_SR, */ |
---|
| 157 | mtc0 v0,C0_SR |
---|
| 158 | nop |
---|
| 159 | |
---|
| 160 | /* Avoid hazard from C0_SR changes. */ |
---|
| 161 | LA (t0, hardware_hazard_hook) |
---|
| 162 | beq t0,zero,2f |
---|
| 163 | jalr t0 |
---|
| 164 | 2: |
---|
| 165 | |
---|
| 166 | |
---|
| 167 | /* Fix high bits, if any, of the PC so that exception handling doesn't get |
---|
| 168 | confused. */ |
---|
| 169 | LA (v0, 3f) |
---|
| 170 | jr v0 |
---|
| 171 | 3: |
---|
| 172 | LA (gp, _gp) # set the global data pointer |
---|
| 173 | .end _start |
---|
| 174 | |
---|
| 175 | /* |
---|
| 176 | * zero out the bss section. |
---|
| 177 | */ |
---|
| 178 | .globl __memsize |
---|
| 179 | .globl get_mem_info .text |
---|
| 180 | .globl __stack |
---|
| 181 | .globl __global |
---|
| 182 | .ent zerobss |
---|
| 183 | zerobss: |
---|
| 184 | LA (v0, _fbss) |
---|
| 185 | LA (v1, _end) |
---|
| 186 | beq v0,v1,2f |
---|
| 187 | 1: |
---|
| 188 | addiu v0,v0,4 |
---|
| 189 | sw zero,-4(v0) |
---|
| 190 | bne v0,v1,1b |
---|
| 191 | 2: |
---|
| 192 | la t0, __lstack # make a small stack so we |
---|
| 193 | addiu sp, t0, STARTUP_STACK_SIZE # can run some C code |
---|
| 194 | la a0, __memsize # get the usable memory size |
---|
| 195 | jal get_mem_info |
---|
| 196 | |
---|
| 197 | /* setup the stack pointer */ |
---|
| 198 | LA (t0, __stack) # is __stack set ? |
---|
| 199 | bne t0,zero,4f |
---|
| 200 | |
---|
| 201 | /* NOTE: a0[0] contains the amount of memory available, and |
---|
| 202 | not the last memory address. */ |
---|
| 203 | la a0, __memsize |
---|
| 204 | lw t0,0(a0) # last address of memory available |
---|
| 205 | la t1,K0BASE # cached kernel memory |
---|
| 206 | addu t0,t0,t1 # get the end of memory address |
---|
| 207 | /* Allocate 32 bytes for the register parameters. Allocate 16 |
---|
| 208 | bytes for a null argv and envp. Round the result up to 64 |
---|
| 209 | bytes to preserve alignment. */ |
---|
| 210 | subu t0,t0,64 |
---|
| 211 | 4: |
---|
| 212 | move sp,t0 # set stack pointer |
---|
| 213 | .end zerobss |
---|
| 214 | |
---|
| 215 | /* |
---|
| 216 | * initialize target specific stuff. Only execute these |
---|
| 217 | * functions it they exist. |
---|
| 218 | */ |
---|
| 219 | .globl hardware_init_hook .text |
---|
| 220 | .globl software_init_hook .text |
---|
| 221 | .type _fini,@function |
---|
| 222 | .type _init,@function |
---|
| 223 | .globl atexit .text |
---|
| 224 | .globl exit .text |
---|
| 225 | .ent init |
---|
| 226 | init: |
---|
| 227 | LA (t9, hardware_init_hook) # init the hardware if needed |
---|
| 228 | beq t9,zero,6f |
---|
| 229 | jalr t9 |
---|
| 230 | 6: |
---|
| 231 | LA (t9, software_init_hook) # init the hardware if needed |
---|
| 232 | beq t9,zero,7f |
---|
| 233 | jalr t9 |
---|
| 234 | 7: |
---|
| 235 | LA (a0, _fini) |
---|
| 236 | jal atexit |
---|
| 237 | |
---|
| 238 | #ifdef GCRT0 |
---|
| 239 | .globl _ftext |
---|
| 240 | .globl _extext |
---|
| 241 | LA (a0, _ftext) |
---|
| 242 | LA (a1, _etext) |
---|
| 243 | jal monstartup |
---|
| 244 | #endif |
---|
| 245 | |
---|
| 246 | |
---|
| 247 | jal _init # run global constructors |
---|
| 248 | |
---|
| 249 | addiu a1,sp,32 # argv = sp + 32 |
---|
| 250 | addiu a2,sp,40 # envp = sp + 40 |
---|
| 251 | #if __mips64 |
---|
| 252 | sd zero,(a1) # argv[argc] = 0 |
---|
| 253 | sd zero,(a2) # envp[0] = 0 |
---|
| 254 | #else |
---|
| 255 | sw zero,(a1) |
---|
| 256 | sw zero,(a2) |
---|
| 257 | #endif |
---|
| 258 | move a0,zero # set argc to 0 |
---|
| 259 | jal main # call the program start function |
---|
| 260 | |
---|
| 261 | # fall through to the "exit" routine |
---|
| 262 | move a0,v0 # pass through the exit code |
---|
| 263 | jal exit # call libc exit to run the G++ |
---|
| 264 | # destructors |
---|
| 265 | .end init |
---|
| 266 | |
---|
| 267 | |
---|
| 268 | /* Assume the PICBASE set up above is no longer valid below here. */ |
---|
| 269 | #ifdef __mips_embedded_pic |
---|
| 270 | #undef PICBASE |
---|
| 271 | #endif |
---|
| 272 | |
---|
| 273 | /* |
---|
| 274 | * _exit -- Exit from the application. Normally we cause a user trap |
---|
| 275 | * to return to the ROM monitor for another run. NOTE: This is |
---|
| 276 | * the only other routine we provide in the crt0.o object, since |
---|
| 277 | * it may be tied to the "_start" routine. It also allows |
---|
| 278 | * executables that contain a complete world to be linked with |
---|
| 279 | * just the crt0.o object. |
---|
| 280 | */ |
---|
| 281 | .globl hardware_exit_hook .text |
---|
| 282 | .globl _exit |
---|
| 283 | .ent _exit |
---|
| 284 | _exit: |
---|
| 285 | 7: |
---|
| 286 | #ifdef __mips_embedded_pic |
---|
| 287 | /* Need to reinit PICBASE, since we might be called via exit() |
---|
| 288 | rather than via a return path which would restore old s0. */ |
---|
| 289 | #define PICBASE exit_PICBASE |
---|
| 290 | .set noreorder |
---|
| 291 | PICBASE = .+8 |
---|
| 292 | bal PICBASE |
---|
| 293 | nop |
---|
| 294 | move s0,$31 |
---|
| 295 | .set reorder |
---|
| 296 | #endif |
---|
| 297 | #ifdef GCRT0 |
---|
| 298 | LA (t0, _mcleanup) |
---|
| 299 | jalr t0 |
---|
| 300 | #endif |
---|
| 301 | LA (t0, hardware_exit_hook) |
---|
| 302 | beq t0,zero,1f |
---|
| 303 | jalr t0 |
---|
| 304 | 1: |
---|
| 305 | |
---|
| 306 | # break instruction can cope with 0xfffff, but GAS limits the range: |
---|
| 307 | break 1023 |
---|
| 308 | b 7b # but loop back just in-case |
---|
| 309 | .end _exit |
---|
| 310 | |
---|
| 311 | /* Assume the PICBASE set up above is no longer valid below here. */ |
---|
| 312 | #ifdef __mips_embedded_pic |
---|
| 313 | #undef PICBASE |
---|
| 314 | #endif |
---|
| 315 | |
---|
| 316 | /* EOF crt0.S */ |
---|