1/* ********************************************************************* 2 * Broadcom Common Firmware Environment (CFE) 3 * 4 * CPU init module File: init_mips.S 5 * 6 * This module contains the vectors and lowest-level CPU startup 7 * functions for CFE. 8 * 9 * Author: Mitch Lichtenberg (mpl@broadcom.com) 10 * 11 ********************************************************************* 12 * 13 * Copyright 2000,2001,2002,2003 14 * Broadcom Corporation. All rights reserved. 15 * 16 * This software is furnished under license and may be used and 17 * copied only in accordance with the following terms and 18 * conditions. Subject to these conditions, you may download, 19 * copy, install, use, modify and distribute modified or unmodified 20 * copies of this software in source and/or binary form. No title 21 * or ownership is transferred hereby. 22 * 23 * 1) Any source code used, modified or distributed must reproduce 24 * and retain this copyright notice and list of conditions 25 * as they appear in the source file. 26 * 27 * 2) No right is granted to use any trade name, trademark, or 28 * logo of Broadcom Corporation. The "Broadcom Corporation" 29 * name may not be used to endorse or promote products derived 30 * from this software without the prior written permission of 31 * Broadcom Corporation. 32 * 33 * 3) THIS SOFTWARE IS PROVIDED "AS-IS" AND ANY EXPRESS OR 34 * IMPLIED WARRANTIES, INCLUDING BUT NOT LIMITED TO, ANY IMPLIED 35 * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR 36 * PURPOSE, OR NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT 37 * SHALL BROADCOM BE LIABLE FOR ANY DAMAGES WHATSOEVER, AND IN 38 * PARTICULAR, BROADCOM SHALL NOT BE LIABLE FOR DIRECT, INDIRECT, 39 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 40 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE 41 * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR 42 * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY 43 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR 44 * TORT (INCLUDING NEGLIGENCE OR OTHERWISE), EVEN IF ADVISED OF 45 * THE POSSIBILITY OF SUCH DAMAGE. 46 ********************************************************************* */ 47 48 49#include "sbmips.h" 50#include "exception.h" 51 52#include "bsp_config.h" 53#include "cpu_config.h" 54 55#ifdef _CFE_ 56#include "cfe_devfuncs.h" 57#else 58 59#if (CFG_BIENDIAN) && defined(__MIPSEB) 60#define CFE_EPTSEAL_REV 0x31454643 61#endif 62#define CFE_EPTSEAL 0x43464531 63 64#define cfe_command_restart 0 65#endif 66 67#if CFG_VAPI /* haul in SB1250-specfic stuff only for VAPI */ 68#include "sb1250_defs.h" 69#include "sb1250_regs.h" 70#include "sb1250_scd.h" 71#endif 72 73/* ********************************************************************* 74 * Macros 75 ********************************************************************* */ 76 77#include "mipsmacros.h" 78 79 80/* ********************************************************************* 81 * SETLEDS(a,b,c,d) 82 * SETLEDS1(a,b,c,d) 83 * 84 * Sets the on-board LED display (if present). Two variants 85 * of this routine are provided. If you're running KSEG1, 86 * call the SETLEDS1 variant, else call SETLEDS. 87 * 88 * Input parameters: 89 * a,b,c,d - four ASCII characters (literal constants) 90 * 91 * Return value: 92 * a0,k1,ra trashed 93 ********************************************************************* */ 94 95#define SETLEDS(a,b,c,d) \ 96 li a0,(((a)<<24)|((b)<<16)|((c)<<8)|(d)) ; \ 97 CALLINIT_KSEG0(init_table,R_INIT_SETLEDS) 98 99#define SETLEDS1(a,b,c,d) \ 100 li a0,(((a)<<24)|((b)<<16)|((c)<<8)|(d)) ; \ 101 CALLINIT_KSEG1(init_table,R_INIT_SETLEDS) 102 103/* ********************************************************************* 104 * Other constants 105 ********************************************************************* */ 106 107/* 108 * This is the size of the stack, rounded to KByte boundaries. 109 */ 110 111#ifndef CFG_STACK_SIZE 112#error "CFG_STACK_SIZE not defined" 113#else 114#define STACK_SIZE ((CFG_STACK_SIZE+1023) & ~1023) 115#endif 116 117#ifdef __MIPSEB 118#define TEXTSECTION 0x2e746578 # ".tex", big-endian 119#else 120#define TEXTSECTION 0x7865742e # ".tex", little-endian 121#endif 122 123/* 124 * Duplicates from cfe_iocb.h -- warning! 125 */ 126 127#define CFE_CACHE_FLUSH_D 1 128#define CFE_CACHE_INVAL_I 2 129#define CFE_CACHE_INVAL_D 4 130#define CFE_CACHE_INVAL_L2 8 131#define CFE_CACHE_FLUSH_L2 16 132#define CFE_CACHE_INVAL_RANGE 32 133#define CFE_CACHE_FLUSH_RANGE 64 134 135 136/* 137 * To make life easier reading this code, define "KSEGBASE" 138 * to either K0BASE or K1BASE depending on whether we're running 139 * uncached. 140 */ 141 142#if CFG_RUNFROMKSEG0 143#define KSEGBASE K0BASE 144#else 145#define KSEGBASE K1BASE 146#endif 147 148 149/* ********************************************************************* 150 * Names of registers used in this module 151 ********************************************************************* */ 152 153#define RELOCOFFSET s8 /* $30 (fp) */ 154#define TEXTOFFSET t9 /* $25 (t9) */ 155#define MEMTOP t8 /* $24 (t8) */ 156#define TEXTBASE s7 /* $23 (s7) */ 157 158 .sdata 159 160#include "initdata.h" /* declare variables we use here */ 161 162#if CFG_MULTI_CPUS 163 .globl cfe_spinlock 164cfe_spinlock: .word 0 165#endif 166 167 .extern _ftext 168 .extern _etext 169 .extern _fdata 170 .extern _edata 171 .extern _fbss 172 .extern _end 173 174/* ********************************************************************* 175 * uninitialized data 176 ********************************************************************* */ 177 178 .bss 179 180 .comm __junk,4 181 182/* ********************************************************************* 183 * Exception Vectors 184 ********************************************************************* */ 185 186 .text 187 188 .set noreorder 189 190/* 191 * If we're building a bi-endian version, this is the base 192 * address that we can expect to find the little-endian version 193 * of the firmware. 194 * 195 * Warning: If you change this, you must also change 196 * the linker script (arch/mips/common/src/cfe_rom_reloc_cached_biendian.lds) 197 * and the mkflashimage program (hosttools/mkflashimage.c) 198 */ 199 200#define BIENDIAN_LE_BASE 0xBFD00000 201 202/* 203 * Declare the actual vectors. This expands to code that 204 * must be at the very beginning of the text segment. 205 */ 206 207DECLARE_VECTOR(0x0000,vec_reset,cpu_reset) 208DECLARE_VECTOR(0x0200,vec_tlbfill,cpu_tlbfill) 209DECLARE_XVECTOR(0x0280,vec_xtlbfill,cpu_xtlbfill,XTYPE_XTLBFILL) 210DECLARE_VECTOR(0x0300,vec_cacheerr,cpu_cacheerr) 211DECLARE_XVECTOR(0x0380,vec_exception,cpu_exception,XTYPE_EXCEPTION) 212DECLARE_XVECTOR(0x0400,vec_interrupt,cpu_interrupt,XTYPE_INTERRUPT) 213DECLARE_XVECTOR(0x0480,vec_ejtag,cpu_ejtag,XTYPE_EJTAG) 214 215 216/* 217 * New location of CFE seal. Will eventually phase out the seal at 218 * offset 0x508 219 */ 220 .org 0x4E0 221cfe_seal: .word CFE_EPTSEAL 222 .word CFE_EPTSEAL 223 224#if (CFG_BIENDIAN) && defined(__MIPSEB) 225 .org 0x4E8 226cfe_seal_rev: .word CFE_EPTSEAL_REV 227 .word CFE_EPTSEAL_REV 228#endif 229 230 .set reorder 231 232/* ********************************************************************* 233 * CFE Entry Point (used by OS boot loaders and such) 234 ********************************************************************* */ 235 236 .set noreorder 237 238DECLARE_VECTOR(0x0500,vec_apientry,cpu_apientry) 239#if !(CFG_BIENDIAN) 240 .org 0x508 241 .word CFE_EPTSEAL 242 .word CFE_EPTSEAL 243#endif 244 245/* ********************************************************************* 246 * Verification APIs (if present) [SB1250-specific] 247 ********************************************************************* */ 248 249#if CFG_VAPI 250#if CFG_EMBEDDED_PIC 251#error "CFG_VAPI is not compatible with relocatable code" 252#endif 253#include "vapi.h" 254/* 255 * Vector should be 16 bytes long 256 */ 257#define VAPI_VECTOR(l,x) \ 258 .extern x ; \ 259 .org (l & 0xFFFF) ; \ 260 j x ; \ 261 nop ; \ 262 .word VAPI_EPTSEAL ; \ 263 .word VAPI_EPTSEAL 264 265VAPI_VECTOR(VAPI_FUNC_EXIT,vapi_exit) 266VAPI_VECTOR(VAPI_FUNC_DUMPGPRS,vapi_dumpgprs) 267VAPI_VECTOR(VAPI_FUNC_SETLOG,vapi_setlog) 268VAPI_VECTOR(VAPI_FUNC_LOGVALUE,vapi_logsingle) 269VAPI_VECTOR(VAPI_FUNC_LOGDATA,vapi_logdata) 270VAPI_VECTOR(VAPI_FUNC_LOGTRACE,vapi_logtrace) 271VAPI_VECTOR(VAPI_FUNC_LOGSOC,vapi_savesoc) 272VAPI_VECTOR(VAPI_FUNC_LOGGPRS,vapi_loggprs) 273VAPI_VECTOR(VAPI_FUNC_DUMPSTRING,vapi_puts) 274VAPI_VECTOR(VAPI_FUNC_SETLEDS,vapi_setleds) 275VAPI_VECTOR(VAPI_FUNC_LOGFPRS,vapi_logfprs) 276#endif 277 278 279 .set reorder 280 281/* ********************************************************************* 282 * Some offsets depend on our current configuration 283 ********************************************************************* */ 284 285#if CFG_EMBEDDED_PIC 286#define RUNTIME_RELOC_START __runtime_reloc_start 287#define RUNTIME_RELOC_STOP __runtime_reloc_stop 288#else 289#define RUNTIME_RELOC_START 0 290#define RUNTIME_RELOC_STOP 0 291#endif 292 293 294/* ********************************************************************* 295 * Segment Table. 296 * 297 * Addresses of data segments and of certain routines we're going 298 * to call from KSEG1. These are here mostly for the embedded 299 * PIC case, since we can't count on the 'la' instruction to 300 * do the expected thing (the assembler expands it into a macro 301 * for doing GP-relative stuff, and the code is NOT GP-relative. 302 * So, we (relocatably) get the offset of this table and then 303 * index within it. 304 * 305 * Pointer values in this segment will be relative to KSEG0 for 306 * cached versions of CFE, so we need to OR in K1BASE in the 307 * case of calling to a uncached address. 308 * 309 * The LOADREL macro handles most of the nastiness here. 310 ********************************************************************* */ 311 312 313#include "segtable.h" 314 315#if CFG_VAPI 316 .org 0x600 # move past exception vectors 317#else 318 .org 0x580 # move past exception vectors 319#endif 320 321#if CFG_EMBEDDED_NVRAM 322 .org 0x1000 323 .globl embedded_nvram 324embedded_nvram: .fill 0x400,4,~(0x48534c46) 325#endif 326 327 .globl segment_table 328segment_table: 329 _LONG_ _etext # [ 0] End of text (R_SEG_ETEXT) 330 _LONG_ _fdata # [ 1] Beginning of data (R_SEG_FDATA) 331 _LONG_ _edata # [ 2] End of data (R_SEG_EDATA) 332 _LONG_ _end # [ 3] End of BSS (R_SEG_END) 333 _LONG_ _ftext # [ 4] Beginning of text (R_SEG_FTEXT) 334 _LONG_ _fbss # [ 5] Beginning of BSS (R_SEG_FBSS) 335 _LONG_ _gp # [ 6] Global Pointer (R_SEG_GP) 336 _LONG_ RUNTIME_RELOC_START # [ 7] Beginning of reloc entries 337 _LONG_ RUNTIME_RELOC_STOP # [ 8] End of reloc entries 338 _LONG_ cpu_apientry # [ 9] R_SEG_APIENTRY 339 340/* ********************************************************************* 341 * Init Table. 342 * 343 * This is like segment_table except it contains pointers to 344 * routines used during initialization. It serves both as a 345 * table for doing PIC stuff and also to separate out 346 * machine-specific init routines. 347 * 348 * The CALLINIT_xxx macros are used to call routines in this table. 349 ********************************************************************* */ 350 351 352 .globl init_table 353init_table: 354 _LONG_ board_earlyinit # [ 0] R_INIT_EARLYINIT 355 _LONG_ board_setleds # [ 1] R_INIT_SETLEDS 356 _LONG_ board_draminfo # [ 2] R_INIT_DRAMINFO 357 _LONG_ CPUCFG_CPUINIT # [ 3] R_INIT_CPUINIT 358 _LONG_ CPUCFG_ALTCPU_START1 # [ 4] R_INIT_ALTCPU_START1 359 _LONG_ CPUCFG_ALTCPU_START2 # [ 5] R_INIT_ALTCPU_START2 360 _LONG_ CPUCFG_ALTCPU_RESET # [ 6] R_INIT_ALTCPU_RESET 361 _LONG_ CPUCFG_CPURESTART # [ 7] R_INIT_CPURESTART 362 _LONG_ CPUCFG_DRAMINIT # [ 8] R_INIT_DRAMINIT 363 _LONG_ CPUCFG_CACHEOPS # [ 9] R_INIT_CACHEOPS 364 _LONG_ CPUCFG_TLBHANDLER # [ 10] R_INIT_TLBHANDLER 365 _LONG_ cfe_main # [ 11] R_INIT_CMDSTART 366 _LONG_ cfe_command_restart # [ 12] R_INIT_CMDRESTART 367 _LONG_ cfe_doxreq # [ 13] R_INIT_DOXREQ 368 369 370#if !CFG_MINIMAL_SIZE 371 .globl diag_table 372diag_table: _LONG_ CPUCFG_DIAG_TEST1 # [ 0 ] R_DIAG_TEST1 373 _LONG_ CPUCFG_DIAG_TEST2 # [ 1 ] R_DIAG_TEST2 374#endif 375 376/* ********************************************************************* 377 * CPU Startup Code 378 ********************************************************************* */ 379 380cpu_reset: 381 382 /* 383 * Start with GP as zero. Nobody should touch 384 * this or set it to any other value until we're ready 385 * to use it. This is used to tell when we should start 386 * using relocated references in the init table, 387 * so beware! (see CALLINIT_RELOC in mipsmacros.h) 388 */ 389 390 move gp,zero # start with no GP. 391 392#if CFG_VAPI 393 /* 394 * VAPI works by using the SCD to reset just the core. 395 * Look for a special signature in the mailbox register 396 * on CPU0 - if present, jump to the start of the diag. 397 * Of course, you need a real 12500 to do this. 398 */ 399 400 li k0,PHYS_TO_K1(A_IMR_REGISTER(0,R_IMR_MAILBOX_CPU)) 401 ld k0,0(k0) 402 dli k1,VAPI_MAGIC_NUMBER_MC 403 beq k0,k1,vapi_runmc 404 dli k1,VAPI_MAGIC_NUMBER_UNC 405 beq k0,k1,vapi_rununc 406 dli k1,VAPI_MAGIC_NUMBER 407 bne k0,k1,vapi_skip 408 409 /* 410 * The only CP0 init we do is to set K0 to cacheable 411 */ 412 413 mfc0 k0,C0_CONFIG # get current CONFIG register 414 srl k0,k0,3 # strip out K0 bits 415 sll k0,k0,3 # k0 bits now zero 416 or k0,k0,K_CFG_K0COH_COHERENT # K0 is cacheable. 417 mtc0 k0,C0_CONFIG 418 419 /* 420 * Set any required defeature bits (for VAPI diagnostics only) 421 * they get cleared by the soft reset. 422 */ 423 424 jal sb1250_reset_defeature /* in sb1250_l1cache.S */ 425 426 /* 427 * Jump to the diagnostic. Two variants, one for cached 428 * and one for uncached. 429 */ 430 431 li k0,VAPI_DIAG_ENTRY 432 j k0 433 434vapi_rununc: li k0,VAPI_DIAG_ENTRY_UNC 435 j k0 436 437vapi_runmc: li k0,VAPI_DIAG_ENTRY_MC 438 j k0 439 440vapi_skip: 441#endif 442 443 /* 444 * Test the CAUSE and STATUS registers for why we 445 * are here. Cold reset, Warm reset, and NMI all 446 * use this vector. 447 */ 448 449 450 451 /* 452 * Test to see if we're on the secondary CPU. If so, 453 * go do the initialization for that CPU. 454 */ 455 456#if CFG_MULTI_CPUS 457 CALLINIT_KSEG1(init_table,R_INIT_ALTCPU_RESET) 458 /* does not return if on CPU1 */ 459#endif 460 461#------------------------------------------------------------------------------ 462 463 /* 464 * Do low-level board initialization. This is our first 465 * chance to customize the startup sequence. 466 */ 467 468 CALLINIT_KSEG1(init_table,R_INIT_EARLYINIT) 469 470 SETLEDS1('H','E','L','O') 471 472 CALLINIT_KSEG1(init_table,R_INIT_CPUINIT) 473 474 /* 475 * Run some diagnostics 476 */ 477 478#if !CFG_MINIMAL_SIZE 479 SETLEDS1('T','S','T','1') 480 481 CALLINIT_KSEG1(diag_table,R_DIAG_TEST1) 482#endif 483 484 485#------------------------------------------------------------------------------ 486#if CFG_MULTI_CPUS 487 /* 488 * Spin up secondary CPU core(s) 489 */ 490 491 CALLINIT_KSEG1(init_table,R_INIT_ALTCPU_START1) 492#endif 493 494 /* 495 * Now, switch from KSEG1 to KSEG0 496 */ 497 498 499#if CFG_RUNFROMKSEG0 500 bal cpu_kseg0_switch 501#endif 502 503#------------------------------------------------------------------------------ 504 /* 505 * Now running on cpu0 in K0SEG. 506 */ 507 508#if CFG_INIT_DRAM 509 SETLEDS('D','R','A','M') 510 511 CALLINIT_KSEG0(init_table,R_INIT_DRAMINFO) 512 513 move a0,v0 # pass these params 514 CALLINIT_KSEG0(init_table,R_INIT_DRAMINIT) 515 srl k0,v0,10 # board_draminit returns memsize in bytes 516#else 517 li k0,CFG_DRAM_SIZE 518#endif 519 520#ifdef CFE_CAPMEM 521 li k0,CFE_CAPMEM 522#endif 523 524 /* Check if we are already in RAM */ 525 bal 1f 526 nop 5271: li t0,0x1fffffff 528 and t0,t0,ra 529 li t1,0x1fc00000 530 blt t0,t1,zbss 531 nop 532 533 SETLEDS('C','O','P','Y') 534 535#if !CFG_EMBEDDED_PIC 536#if !CFG_XIP 537 /* Copy self to RAM */ 538 LOADREL(a0,_ftext) 539 la a1,_ftext 540#else 541 /* Copy data only to RAM */ 542 LOADREL(a0,_etext) 543 la a1,_fdata 544#endif 545 la a2,_edata 546 sub a2,a2,a1 5471: LR t0,0(a0) 548 SR t0,0(a1) 549 add a0,4 550 add a1,4 551 sub a2,4 552 bnez a2,1b 553 nop 554 555zbss: 556 /* Zero BSS */ 557 SETLEDS('Z','B','S','S') 558 559 la a0,_fbss 560 la a1,_end 561 sub a1,a1,a0 562 5631: SR zero,0(a0) 564 add a0,4 565 sub a1,4 566 bnez a1,1b 567 nop 568 569 SETLEDS(' ','D','$','F') 570 571 /* Flush the D cache */ 572 CALLINIT_KSEG0(cacheops_table,_TBLIDX(0)) 573 574 SETLEDS(' ','I','$','I') 575 576 /* and invalidate the I cache */ 577 CALLINIT_KSEG0(cacheops_table,_TBLIDX(1)) 578 579 SETLEDS(' ','J','S','R') 580 581 /* Jump to self in RAM */ 582 la a0,have_ram 583 jr a0 584 nop 585 586 .globl cacheops_table 587cacheops_table: _LONG_ bcmcore_l1cache_flush_d # [ 0 ] DCACHE_FULSH 588 _LONG_ bcmcore_l1cache_inval_i # [ 1 ] ICACHE_INVAL 589#endif 590 591#------------------------------------------------------------------------------ 592 593#if CFG_BOOTRAM 594 b have_ram # No RAM is ok if using emulator RAM 595#endif 596 597 bne k0,zero,have_ram 598 599 SETLEDS('R','A','M','X') # die here if no ram 600 601die1: b die1 602 603have_ram: 604 605 /* 606 * If this is the 64-bit version, turn on the KX bit 607 * to allow 64-bit accesses. 608 */ 609 610#ifdef __long64 611 mfc0 t0,C0_SR 612 or t0,t0,M_SR_KX 613 mtc0 t0,C0_SR 614#endif 615 616#------------------------------------------------------------------------------ 617 /* 618 * K0 contains the RAM size (and therefore the top of RAM 619 * offset). Start there, and subtract the amount of memory 620 * we expect to use. If we have more than 256MB of 621 * physical memory, work backwards from the 256MB 622 * boundary. 623 */ 624 625__CalcMemTop: li MEMTOP,0x40000 # 256MB boundary 626 bgt k0,MEMTOP,1f # use 256MB if k0 is greater 627 move MEMTOP,k0 # otherwise keep top 6281: sll MEMTOP,10 # make into byte amount 629 630 631#if CFG_EMBEDDED_PIC 632 /* 633 * Calculate the data relocation amount. Store in FP 634 * for now. We'll call this register RELOCOFFSET. 635 * 636 * Also calculate a similar offset for relocating code 637 * if we're doing that. Call this TEXTOFFSET (t9). 638 */ 639 640 LOADREL(a0,segment_table) # we'll need this. 641 642 LR t1,R_SEG_ETEXT(a0) 643 LR t0,R_SEG_FTEXT(a0) 644 sub t1,t1,t0 # T1 = text size 645 sub t3,MEMTOP,t1 # reserve room for code 646 li t2,~31 # round down to cache-line boundary 647 and t3,t2 648 move TEXTBASE,t3 # TEXTBASE is current mem top 649 sub TEXTBASE,64 # Reserve top 64 bytes 650 651/* 652 * If you're debugging the relocation stuff, you can uncomment this 653 * line to force CFE to be relocated to a specific address. Sure 654 * makes life easier when setting breakpoints! 655 * 656 * li TEXTBASE,0x3C00000 657 */ 658 659 li t2,KSEGBASE 660 add TEXTBASE,t2 # offset is in K0SEG. 661 sub TEXTOFFSET,TEXTBASE,t0 # TEXTOFFSET is distance to move 662 663__RelocOffset: 664 665 li t0,((CFG_HEAP_SIZE*1024)+STACK_SIZE) # t0 = size of heap + stack 666 LR t1,R_SEG_END(a0) 667 LR t2,R_SEG_FDATA(a0) 668 sub t1,t2 # t1 = data + bss 669 add t0,t1 # t0 = total 670 li t1,31 # round to 32-byte boundary 671 add t0,t1 672 not t1 673 and t0,t1 # t0 = total size rounded up 674 675 sub t1,TEXTBASE,t0 # t1 = TEXTBASE - total size 676 677 /* 678 * t1 now contains the place where we would like to put our 679 * data segment, BSS, and heap. Calculate the difference between that 680 * and where our data segment currently resides. 681 */ 682 683 LR t0,R_SEG_FDATA(a0) # beginning of data 684 subu RELOCOFFSET,t1,t0 # offset = distance to move segment 685 686 li t0,31 # round *down* to a cache line 687 not t0 688 and RELOCOFFSET,t0 689#else /* */ 690 li RELOCOFFSET,0 # not relocating, no offset 691 li TEXTOFFSET,0 692#endif 693 694 /* 695 * DRAM is now running, and we're alive in cacheable memory 696 * on cpu0 in K0SEG. Set up GP. 697 */ 698 699 LOADREL(a0,segment_table) 700 LR gp,R_SEG_GP(a0) 701 add gp,RELOCOFFSET 702 703#if CFG_EMBEDDED_PIC 704#------------------------------------------------------------------------------ 705 /* 706 * Zero BSS 707 */ 708 709 SETLEDS('Z','B','S','S') 710 711 LOADREL(a0,segment_table) 712__ZeroBss: 713 714 LR v0,R_SEG_FBSS(a0) 715 LR v1,R_SEG_END(a0) 716 ADD v0,RELOCOFFSET # Relocate to actual data segment 717 ADD v1,RELOCOFFSET 718 7191: SR zero,0(v0) # Zero one cacheline at a time 720 SR zero,(REGSIZE*1)(v0) 721 SR zero,(REGSIZE*2)(v0) 722 SR zero,(REGSIZE*3)(v0) 723 add v0,REGSIZE*4 724 blt v0,v1,1b 725 726#------------------------------------------------------------------------------ 727 /* 728 * Copy code 729 */ 730 731 SETLEDS('C','O','D','E') 732 733 LOADREL(a0,segment_table) 734__CopyCode: 735 736 move t1,TEXTBASE # destination address 737 738 LR t2,R_SEG_FTEXT(a0) # Source address 739 LR t3,R_SEG_ETEXT(a0) 740 7411: LR t4,0(t2) # read one cache line 742 LR t5,(REGSIZE*1)(t2) 743 LR t6,(REGSIZE*2)(t2) 744 LR t7,(REGSIZE*3)(t2) 745 SR t4,0(t1) # write one cache line 746 SR t5,(REGSIZE*1)(t1) 747 SR t6,(REGSIZE*2)(t1) 748 SR t7,(REGSIZE*3)(t1) 749 add t1,REGSIZE*4 750 add t2,REGSIZE*4 751 bltu t2,t3,1b 752#endif 753 754#------------------------------------------------------------------------------ 755 /* 756 * Copy initialized data 757 */ 758 759#if CFG_BOOTRAM == 0 760 761 SETLEDS('D','A','T','A') 762 763 LOADREL(a0,segment_table) 764 765__CopyData: 766 LR t1,R_SEG_ETEXT(a0) 767 li t0,15 768 add t1,t0 769 not t0 770 and t1,t0 # t1 = _etext rounded up to 16-byte boundary 771 772 LR t2,R_SEG_FDATA(a0) 773 LR t3,R_SEG_EDATA(a0) 774 ADD t2,RELOCOFFSET # Relocate to actual data segment 775 ADD t3,RELOCOFFSET 776 7771: LR t4,0(t1) # read one cache line 778 LR t5,(REGSIZE*1)(t1) 779 LR t6,(REGSIZE*2)(t1) 780 LR t7,(REGSIZE*3)(t1) 781 SR t4,0(t2) # write one cache line 782 SR t5,(REGSIZE*1)(t2) 783 SR t6,(REGSIZE*2)(t2) 784 SR t7,(REGSIZE*3)(t2) 785 add t1,(REGSIZE*4) 786 add t2,(REGSIZE*4) 787 bltu t2,t3,1b 788 789#endif 790 791#------------------------------------------------------------------------------ 792 793#if CFG_EMBEDDED_PIC 794 795 /* 796 * Walk through relocation table and do the data segment 797 * fixups. Each entry in this table is in the following 798 * format: 799 * 800 * <offset> <segment-name> 801 * 4 bytes 8 bytes 802 * 803 * The 'offset' represents the distance into the segment where 804 * a fixup needs to be applied, and the 'segment-name' 805 * is the name of the section where the offset is located. 806 * The basic idea is that you would expect that code and 807 * data are moved by different amounts, so places where 808 * the data segment references the text segment you need 809 * apply the offset that the text segment was moved, not data. 810 */ 811 812__RelocAll: 813 SETLEDS('R','E','L','O') 814 815 LOADREL(a0,segment_table) 816 817 LR a1,R_SEG_FDATA(a0) # beginning of data segment 818 add a1,RELOCOFFSET # relocate it. 819 820 LR v0,R_SEG_RELOCSTART(a0) # relocs start here 821 LR v1,R_SEG_RELOCEND(a0) # and end here 822 li t2,TEXTSECTION # marker for text sections 823 824 # 825 # The bottom bit in the offset will be set if we want to 826 # handle a MIPS_64 relocation. Of course, this bit is not really 827 # part of the relocation offset. 828 # 829 li t4,1 # Make the mask that we 830 not t4 # need to mask off bottom bit 831 832reloclp: lw t0,4(v0) # Get section name 833 beq t0,t2,textreloc # skip if for text section 834 835# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 836 837 lw t0,0(v0) # T0 = relocation offset 838 and t1,t0,1 # test MIPS_64 reloc bit (t1=0 for 32-bit) 839 and t0,t4 # clear MIPS_64 reloc bit 840 add t0,a1 # Add offset to start of data segment 841 842 beq t1,zero,reloc32 # go if doing a 32-bit reloc 843 844reloc64: ld t1,(t0) # Get word from data segment 845 add t1,RELOCOFFSET # Add relocation offset 846 sd t1,(t0) # Put it back 847 b skipreloc # next... 848 849reloc32: lw t1,(t0) # Get word from data segment 850 add t1,RELOCOFFSET # Add relocation offset 851 sw t1,(t0) # Put it back 852 b skipreloc 853 854# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 855 856textreloc: 857 lw t0,0(v0) # T0 = relocation offset 858 and t1,t0,1 # test MIPS_64 reloc bit (t1=0 for 32-bit) 859 and t0,t4 # clear MIPS_64 reloc bit 860 add t0,a1 # Add offset to start of data segment 861 862 beq t1,zero,treloc32 # go if doing a 32-bit reloc 863 864treloc64: ld t1,(t0) # Get word from data segment 865 add t1,TEXTOFFSET # Add relocation offset 866 sd t1,(t0) # Put it back 867 b skipreloc # next... 868 869treloc32: lw t1,(t0) # Get word from data segment 870 add t1,TEXTOFFSET # Add relocation offset 871 sw t1,(t0) # Put it back 872 b skipreloc 873 874skipreloc: add v0,12 # Go to next relocation entry 875 blt v0,v1,reloclp 876#endif 877 878 879#------------------------------------------------------------------------------ 880 881#if CFG_EMBEDDED_PIC 882 /* 883 * Flush the cache, then switch to relocated code 884 * We need to flush the cache since we just moved the code and 885 * it may still live in our L1 DCache. We also need to 886 * flush L2, since there are some rare times we run 887 * uncached from DRAM, like when we start/stop a CPU. 888 * 889 * In the case of running completely uncached, don't flush the 890 * cache. It should not have any dirty lines in it, but you 891 * never know... 892 */ 893 894__GoRelo: 895 896#if CFG_RUNFROMKSEG0 897 SETLEDS('L','1','2','F') 898 899 li a0,CFE_CACHE_FLUSH_D | CFE_CACHE_FLUSH_L2 900 CALLINIT_KSEG0(init_table,R_INIT_CACHEOPS) 901 li a0,CFE_CACHE_INVAL_I 902 CALLINIT_KSEG0(init_table,R_INIT_CACHEOPS) 903#endif /* CFG_RUNFROMKSEG0 */ 904 905 LOADREL(t0,gorelo) # get offset of next instr 906 add t0,TEXTOFFSET # add in our relocation 907 j t0 # and go there 908gorelo: nop 909 910#endif 911 /* 912 * Remember total amount of memory. This is *still* in k0 913 * after all this time. Hopefully. 914 */ 915 916__MemVars: 917 SR k0,mem_totalsize 918 SR RELOCOFFSET,mem_datareloc 919 920 move v0,zero 921 922 LOADREL(a0,segment_table) # trashed by l2 cache flush 923#if CFG_EMBEDDED_PIC 924 LR v0,R_SEG_FDATA(a0) 925 ADD v0,RELOCOFFSET 926#else 927 LR v0,R_SEG_FTEXT(a0) 928 ADD v0,TEXTOFFSET 929#endif 930 LR v1,R_SEG_END(a0) 931 ADD v1,RELOCOFFSET 932 933 SR v0,mem_bottomofmem 934 SR v1,mem_heapstart 935 936#if CFG_EMBEDDED_PIC 937 move t0,MEMTOP # relocated code means top of memory 938 add t0,KSEGBASE # is *after* code. 939 SR t0,mem_topofmem 940 941// SR gp,-8(t0) # Store handle at top of memory 942// SR zero,-16(t0) # Zero out the other handles 943// SR zero,-24(t0) # in our special place. 944// SR zero,-32(t0) # 945// SR zero,-48(t0) # 946// SR zero,-64(t0) # 947#else 948 add v1,(CFG_HEAP_SIZE*1024) # Otherwise 949 add v1,STACK_SIZE 950 SR v1,mem_topofmem 951#endif 952 953 SR TEXTOFFSET,mem_textreloc 954 955 /* At this point it's safe to use the CALLINIT_RELOC macro */ 956 957 958 LR t1,R_SEG_FTEXT(a0) 959 LR t0,R_SEG_ETEXT(a0) 960 sub t0,t0,t1 961 SR t0,mem_textsize 962 add t1,TEXTOFFSET 963 SR t1,mem_textbase 964 965 966#------------------------------------------------------------------------------ 967 968#if CFG_MULTI_CPUS 969 /* 970 * Let secondary CPU(s) run their idle loops. Set the 971 * mailbox register to our relocation factor so we can read 972 * it out of the mailbox register and relocate GP properly. 973 */ 974 975 move a0,RELOCOFFSET 976 CALLINIT_RELOC(init_table,R_INIT_ALTCPU_START2) 977#endif 978 979#ifdef _SB1250_PASS1_WORKAROUNDS_ 980 /* 981 * Okay, it's safe now to be coherent. 982 * Flush the D cache to invalidate all the lines we have, 983 * then change the config register back. 984 */ 985 li a0,CFE_CACHE_FLUSH_D 986 CALLINIT_RELOC(init_table,R_INIT_CACHEOPS) 987 SETCCAMODE(v0,K_CFG_K0COH_COHERENT) /* cacheable coherent */ 988#endif 989 990 /* 991 * Stash away some config register stuff 992 */ 993 994 mfc0 v0,C0_PRID 995 SR v0,cpu_prid 996 997 998#------------------------------------------------------------------------------ 999 1000 /* 1001 * Set up the "C" stack and jump to the main routine. 1002 */ 1003 1004 SETLEDS('M','A','I','N') 1005 1006 LR sp,mem_heapstart 1007 ADD sp,((CFG_HEAP_SIZE*1024)+STACK_SIZE - 8) 1008 li a0,0 # call as "cfe_main(0,0)" 1009 li a1,0 1010 1011 CALLINIT_RELOC(init_table,R_INIT_CMDSTART) # should not return 1012 1013 1014 /* 1015 * Terminate the simulator. 1016 */ 1017 1018crash_sim: li $2,1 1019 li $4,0 1020 syscall 0xCA 1021 b cpu_reset 1022 1023 1024 1025#ifdef _CFE_ 1026/* ********************************************************************* 1027 * CFE_WARMSTART 1028 * 1029 * Restart the command interpreter 1030 * 1031 * Input parameters: 1032 * A0 - command status 1033 * nothing (GP has already been set up for us) 1034 * 1035 * Return value: 1036 * nothing 1037 ********************************************************************* */ 1038 1039LEAF(cfe_warmstart) 1040 1041 SR a0,0(sp) # store on old stack 1042 LOADREL(v0,init_table) 1043 LR v0,R_INIT_CPURESTART(v0) 1044#if CFG_EMBEDDED_PIC 1045 LR t0,mem_textreloc # relocate table entry 1046 ADD v0,v0,t0 1047#endif 1048 1049 jal v0 # had better not trash GP or K1 1050 1051 /* 1052 * If this is the 64-bit version, turn on the KX bit 1053 * to allow 64-bit accesses. Do after calling the cpu 1054 * init routine, but before touching the stack, which 1055 * *could* be a 64-bit address. 1056 */ 1057 1058#ifdef __long64 1059 mfc0 t0,C0_SR 1060 or t0,t0,M_SR_KX 1061 mtc0 t0,C0_SR 1062 HAZARD 1063#endif 1064 1065 LR a0,0(sp) 1066 1067 LR sp,mem_heapstart 1068 ADD sp,((CFG_HEAP_SIZE*1024)+STACK_SIZE - 8) 1069 1070 /* 1071 * If someone called the API to do a warm start, clear the 1072 * spin lock, since the call will never return. 1073 */ 1074 1075#if CFG_MULTI_CPUS 1076 SPIN_UNLOCK(cfe_spinlock,t0) 1077#endif 1078 1079 CALLINIT_RELOC(init_table,R_INIT_CMDRESTART) # should not return 1080 1081END(cfe_warmstart) 1082#endif 1083 1084/* ********************************************************************* 1085 * CFE_FLUSHCACHE 1086 * 1087 * Perform certain cache operations 1088 * 1089 * Input parameters: 1090 * a0 - flags (CFE_CACHE_xxx flags, or zero for a default) 1091 * a1,a2 - start/end of range for "range invalidate" operations 1092 * (not used otherwise) 1093 * 1094 * Return value: 1095 * nothing 1096 ********************************************************************* */ 1097 1098LEAF(_cfe_flushcache) 1099 1100 sub sp,56 1101 SR ra,0(sp) 1102 SR a0,8(sp) 1103 SR s0,16(sp) 1104 SR v1,24(sp) 1105 SR s1,32(sp) 1106 SR s2,40(sp) 1107 SR s3,48(sp) 1108 SR s4,56(sp) 1109 1110 1111 CALLINIT_RELOC(init_table,R_INIT_CACHEOPS) 1112 1113 LR s4,56(sp) 1114 LR s3,48(sp) 1115 LR s2,40(sp) 1116 LR s1,32(sp) 1117 LR v1,24(sp) 1118 LR s0,16(sp) 1119 LR a0,8(sp) 1120 LR ra,0(sp) 1121 add sp,56 1122 j ra 1123 1124END(_cfe_flushcache) 1125 1126 1127/* ********************************************************************* 1128 * CFE_LAUNCH 1129 * 1130 * Start the user program. The program is passed a handle 1131 * that must be passed back when calling the firmware. 1132 * 1133 * Parameters passed to the called program are as follows: 1134 * 1135 * a0 - CFE handle 1136 * a1 - entry vector 1137 * a2 - reserved, will be 0 1138 * a3 - entrypoint signature. 1139 * 1140 * Input parameters: 1141 * a0 - entry vector 1142 * 1143 * Return value: 1144 * does not return 1145 ********************************************************************* */ 1146 1147LEAF(cfe_launch) 1148 1149 sub sp,8 1150 SR a0,0(sp) 1151 1152 1153 /* 1154 * Mask all interrupts. 1155 */ 1156 mfc0 v0,C0_SR # Get current interrupt flag 1157 li v1,M_SR_IE # master interrupt control 1158 not v1 # disable interrupts 1159 and v0,v1 # SR now has IE=0 1160 mtc0 v0,C0_SR # put back into CP0 1161 1162 1163 /* 1164 * Flush the D-Cache, since the program we loaded is "data". 1165 * Invalidate the I-Cache, so that addresses in the program 1166 * region will miss and need to be filled from the data we 1167 * just flushed above. 1168 */ 1169 1170 li a0,CFE_CACHE_FLUSH_D|CFE_CACHE_INVAL_I 1171 CALLINIT_RELOC(init_table,R_INIT_CACHEOPS) 1172 1173 1174 /* 1175 * Set things up for launching the program. Pass the 1176 * handle in A0 - apps need to remember that and pass it 1177 * back. 1178 */ 1179 1180 j RunProgram 1181 1182END(cfe_launch) 1183 1184 /* 1185 * This is a nice place to set a breakpoint. 1186 */ 1187LEAF(RunProgram) 1188 1189 LOADREL(a2,segment_table) 1190 LR a2,R_SEG_APIENTRY(a2) # A2 = code entry 1191 1192#if CFG_EMBEDDED_PIC 1193 LR t1,mem_textreloc # relocate table entry 1194 ADD a2,a2,t1 1195#endif 1196 move t0,a0 # 1197 move a1,zero # A1 = 0 1198 move a0,gp # A0 = handle 1199 li a3,CFE_EPTSEAL # A3 = entrypoint signature 1200 LR t0,0(sp) # entry point 1201 1202 j t0 # go for it. 1203END(RunProgram) 1204 1205 1206 1207 1208/* ********************************************************************* 1209 * CFE_LEDS 1210 * 1211 * Set the on-board LEDs. 1212 * 1213 * Input parameters: 1214 * a0 - LEDs 1215 * 1216 * Return value: 1217 * nothing 1218 ********************************************************************* */ 1219 1220LEAF(cfe_leds) 1221 1222#if CFG_EMBEDDED_PIC 1223 move t1,ra # LOADREL trashes ra! 1224 LOADREL(t0,init_table) 1225 move ra,t1 1226 LR t0,R_INIT_SETLEDS(t0) 1227 jr t0 1228#else 1229 j board_setleds # jump to BSP routine 1230#endif 1231 1232END(cfe_leds) 1233 1234/* ********************************************************************* 1235 * TLB Fill Exeption Handler 1236 ********************************************************************* */ 1237 1238cpu_tlbfill: 1239 move k0,ra # Save, we're about to trash 1240 LOADREL(k1,init_table) # Load offset of init table 1241 LR k1,R_INIT_TLBHANDLER(k1) # Get entry from table 1242 move ra,k0 # restore trashed ra 1243 j k1 # Dispatch to handler 1244 1245/* ********************************************************************* 1246 * XTLB Fill Exception Handler 1247 ********************************************************************* */ 1248 1249cpu_xtlbfill: 1250 j _exc_entry 1251 1252/* ********************************************************************* 1253 * Cache Error Exception Handler 1254 ********************************************************************* */ 1255 1256cpu_cacheerr: 1257 1258#if defined(_CSWARM_) || defined(_SWARM_) || defined(_BCM91120C_) || defined(_PTSWARM_) 1259#define LED_CHAR0 (32+8*3) 1260#define LED_CHAR1 (32+8*2) 1261#define LED_CHAR2 (32+8*1) 1262#define LED_CHAR3 (32+8*0) 1263#if defined(_PTSWARM_) 1264 li k0,0xBB0A0000 /* address of LEDs */ 1265#else 1266 li k0,0xB00A0000 /* address of LEDs */ 1267#endif 1268 li k1,'C' 1269 sb k1,LED_CHAR0(k0) 1270 li k1,'e' 1271 sb k1,LED_CHAR1(k0) 1272 li k1,'r' 1273 sb k1,LED_CHAR2(k0) 1274 li k1,'2' 1275 sb k1,LED_CHAR3(k0) 1276 1277 SETLEDS1('C','e','r','2') 1278#endif 1279 1280cpu_cache_death: b cpu_cache_death 1281 1282 1283 1284/* ********************************************************************* 1285 * General Exception Handler 1286 ********************************************************************* */ 1287 1288cpu_exception: 1289 j _exc_entry 1290 1291 1292/* ********************************************************************* 1293 * General Interrupt Handler 1294 ********************************************************************* */ 1295 1296cpu_interrupt: 1297 j _exc_entry 1298 1299 1300/* ********************************************************************* 1301 * EJTAG Debug Exception Handler 1302 ********************************************************************* */ 1303 1304cpu_ejtag: 1305 .set push 1306 .set mips64 1307 deret 1308 .set pop 1309 j cpu_reset 1310 1311/* ********************************************************************* 1312 * cpu_apientry(handle,iocb) 1313 * 1314 * API entry point for external apps. 1315 * 1316 * Input parameters: 1317 * a0 - firmware handle (used to determine the location of 1318 * our relocated data) 1319 * a1 - pointer to IOCB to execute 1320 * 1321 * Return value: 1322 * v0 - return code, 0 if ok 1323 ********************************************************************* */ 1324 1325#define _regidx(x) ((x)*8) 1326 1327#define CAE_SRSAVE _regidx(0) 1328#define CAE_GPSAVE _regidx(1) 1329#define CAE_RASAVE _regidx(2) 1330#define CAE_S0SAVE _regidx(3) 1331#define CAE_S1SAVE _regidx(4) 1332#define CAE_S2SAVE _regidx(5) 1333#define CAE_S3SAVE _regidx(6) 1334#define CAE_S4SAVE _regidx(7) 1335#define CAE_S5SAVE _regidx(8) 1336#define CAE_S6SAVE _regidx(9) 1337#define CAE_S7SAVE _regidx(10) 1338#define CAE_K0SAVE _regidx(11) 1339#define CAE_K1SAVE _regidx(12) 1340 1341#define CAE_STKSIZE _regidx(13) 1342 1343LEAF(cpu_apientry) 1344 1345 sub sp,CAE_STKSIZE # Make room for our stuff 1346 1347 mfc0 v0,C0_SR # Get current interrupt flag 1348 SR v0,CAE_SRSAVE(sp) # save on stack 1349 li t0,M_SR_IE # master interrupt control 1350 not t0 # disable interrupts 1351 and v0,t0 # SR now has IE=0 1352#ifdef __long64 1353 or v0,M_SR_KX 1354#endif 1355 mtc0 v0,C0_SR # put back into CP0 1356 HAZARD 1357 1358 SR gp,CAE_GPSAVE(sp) # save GP 1359 SR ra,CAE_RASAVE(sp) # and old RA 1360 1361 SR s0,CAE_S0SAVE(sp) 1362 SR s1,CAE_S1SAVE(sp) 1363 SR s2,CAE_S2SAVE(sp) 1364 SR s3,CAE_S3SAVE(sp) 1365 SR s4,CAE_S4SAVE(sp) 1366 SR s5,CAE_S5SAVE(sp) 1367 SR s6,CAE_S6SAVE(sp) 1368 SR s7,CAE_S7SAVE(sp) 1369 SR k0,CAE_K0SAVE(sp) 1370 SR k1,CAE_K1SAVE(sp) 1371 1372 move gp,a0 # set up new GP 1373 move a0,a1 # A0 points at IOCB 1374 1375#if CFG_RUNFROMKSEG0 1376 bal cpu_kseg0_switch # switch to kseg0 if not already there 1377#endif 1378 1379#if CFG_MULTI_CPUS 1380 SPIN_LOCK(cfe_spinlock,t0,t1) 1381#endif 1382 1383 CALLINIT_RELOC(init_table,R_INIT_DOXREQ) 1384 1385#if CFG_MULTI_CPUS 1386 SPIN_UNLOCK(cfe_spinlock,t0) 1387#endif 1388 1389 # 1390 # Restore the saved registers. 1391 # 1392 1393 LR k1,CAE_K1SAVE(sp) 1394 LR k0,CAE_K0SAVE(sp) 1395 LR s7,CAE_S7SAVE(sp) 1396 LR s6,CAE_S6SAVE(sp) 1397 LR s5,CAE_S5SAVE(sp) 1398 LR s4,CAE_S4SAVE(sp) 1399 LR s3,CAE_S3SAVE(sp) 1400 LR s2,CAE_S2SAVE(sp) 1401 LR s1,CAE_S1SAVE(sp) 1402 LR s0,CAE_S0SAVE(sp) 1403 1404 LR ra,CAE_RASAVE(sp) # unwind the stack 1405 LR gp,CAE_GPSAVE(sp) 1406 1407 LR t0,CAE_SRSAVE(sp) # old interrupt mask 1408 1409 add sp,CAE_STKSIZE # restore old stack pointer 1410 1411 mtc0 t0,C0_SR # restore interrupts 1412 HAZARD 1413 j ra 1414 nop 1415 1416END(cpu_apientry) 1417 1418 1419/* ********************************************************************* 1420 * CPU_KSEG0_SWITCH 1421 * 1422 * Hack the return address so we will come back in KSEG0 1423 * 1424 * Input parameters: 1425 * nothing 1426 * 1427 * Return value: 1428 * nothing 1429 ********************************************************************* */ 1430 1431LEAF(cpu_kseg0_switch) 1432 1433 and ra,(K0SIZE-1) 1434 or ra,K0BASE 1435 jr ra 1436 1437END(cpu_kseg0_switch) 1438 1439 1440 1441 1442/* ********************************************************************* 1443 * _GETSTATUS() 1444 * 1445 * Read the STATUS register into v0 1446 * 1447 * Input parameters: 1448 * nothing 1449 * 1450 * Return value: 1451 * v0 - Status register 1452 ********************************************************************* */ 1453 1454LEAF(_getstatus) 1455 1456 mfc0 v0,C0_SR 1457 j ra 1458END(_getstatus) 1459 1460/* ********************************************************************* 1461 * _SETSTATUS() 1462 * 1463 * Set the STATUS register to the value in a0 1464 * 1465 * Input parameters: 1466 * nothing 1467 * 1468 * Return value: 1469 * v0 - Status register 1470 ********************************************************************* */ 1471 1472LEAF(_setstatus) 1473 1474 mtc0 a0,C0_SR 1475 j ra 1476END(_setstatus) 1477 1478 1479/* ********************************************************************* 1480 * _GETCAUSE() 1481 * 1482 * Read the CAUSE register into v0 1483 * 1484 * Input parameters: 1485 * nothing 1486 * 1487 * Return value: 1488 * v0 - Cause register 1489 ********************************************************************* */ 1490 1491LEAF(_getcause) 1492 1493 mfc0 v0,C0_CAUSE 1494 j ra 1495END(_getcause) 1496 1497 1498/* ********************************************************************* 1499 * _GETTICKS() 1500 * 1501 * Read the COUNT register into v0 1502 * 1503 * Input parameters: 1504 * nothing 1505 * 1506 * Return value: 1507 * v0 - count register 1508 ********************************************************************* */ 1509 1510LEAF(_getticks) 1511 1512 mfc0 v0,C0_COUNT 1513 j ra 1514END(_getticks) 1515 1516 1517/* ********************************************************************* 1518 * _SETALARM(ticks) 1519 * 1520 * Set the C0_Compare register from a0 1521 * 1522 * Input parameters: 1523 * a0 - compare register 1524 * 1525 * Return value: 1526 * none 1527 ********************************************************************* */ 1528 1529LEAF(_setalarm) 1530 1531 mtc0 a0,C0_COMPARE 1532 j ra 1533END(_setalarm) 1534 1535 1536/* ********************************************************************* 1537 * _SETCONTEXT() 1538 * 1539 * Set the CONTEXT register. 1540 * 1541 * Input parameters: 1542 * a0 - context 1543 * 1544 * Return value: 1545 * nothing 1546 ********************************************************************* */ 1547 1548LEAF(_setcontext) 1549 1550 mtc0 a0,C0_CTEXT 1551 j ra 1552END(_setcontext) 1553 1554/* ********************************************************************* 1555 * _GETSEGTBL() 1556 * 1557 * Return the address of the segment table. We use this 1558 * to display the startup messages. 1559 * 1560 * You can't just address the table from C because it lives 1561 * in the text segment. 1562 * 1563 * Input parameters: 1564 * nothing 1565 * 1566 * Return value: 1567 * address of table 1568 ********************************************************************* */ 1569 1570 1571LEAF(_getsegtbl) 1572 move t0,ra 1573 LOADREL(v0,segment_table) 1574 move ra,t0 1575 j ra 1576END(_getsegtbl) 1577 1578 1579/* ********************************************************************* 1580 * _wbflush() 1581 * 1582 * Flush the write buffer. This is probably not necessary 1583 * on SiByte CPUs, but we have it for completeness. 1584 * 1585 * Input parameters: 1586 * nothing 1587 * 1588 * Return value: 1589 * nothing 1590 ********************************************************************* */ 1591 1592LEAF(_wbflush) 1593 1594 sync /* drain the buffers */ 1595 la t0,__junk /* do an uncached read to force it out */ 1596 or t0,K1BASE 1597 lw zero,0(t0) 1598 j ra 1599 1600END(_wbflush) 1601 1602 1603/* ********************************************************************* 1604 * End 1605 ********************************************************************* */ 1606 1607 1608