📄 bcm1480_altcpu.s
字号:
mflo t1 daddu t2,t2,t1 sd t0,(t2) # do CPU[a0] /* * Let the secondary CPU(s) out of reset * * XXX This is very BCM1480-specific at the moment. */ la t2,PHYS_TO_K1(A_SCD_SYSTEM_CFG) ld t0,0(t2) dli t1,M_BCM1480_SYS_CPU_RESET_0 # Base reset mask dsll t1,t1,a0 not t1 # clear this bit and t0,t1 # New value to write sd t0,0(t2) # CPU[v0] is now running /* * Wait for the other CPU to ring our doorbell */2: la t2,PHYS_TO_K1(A_BCM1480_IMR_REGISTER(0,R_BCM1480_IMR_MAILBOX_0_CPU)); ld t0,(t2) # Read mailbox beq t0,zero,2b # Loop till the bit is set /* * Clear the mailbox to dismiss the pending interrupts */ la t2,PHYS_TO_K1(A_BCM1480_IMR_REGISTER(0,R_BCM1480_IMR_MAILBOX_0_CLR_CPU)) dli t0,-1 # clear all 64 bits sd t0,(t2) # # It's safe to be cached again. # bal _altcpu_kseg0_switch # # At this point, CPU1 is waiting for us to indicate that it's # okay to use memory again. Ring its doorbell. # la t2,PHYS_TO_K1(A_BCM1480_IMR_REGISTER(0,R_BCM1480_IMR_MAILBOX_0_SET_CPU)) dli t1,BCM1480_IMR_REGISTER_SPACING multu a0,t1 mflo t1 daddu t2,t2,t1 LR t0,mem_datareloc or t0,1 sd t0,(t2) # # CPU[a0] is back in our control. # move ra,t7 move v0,zero j raEND(bcm1480_altcpu_kill)/* ********************************************************************* * ALTCPU_RESET * * Start address for secondary CPU(s) - do the initialization of * the local CPU and then notify CPU0 that we're done. * * This routine is called in KSEG1. * * Input parameters: * t0 - CPU identifier * * Return value: * nothing ********************************************************************* */LEAF(bcm1480_altcpu_reset) GET_CUR_CPU(t0) # read current cpu # to t0 beq t0,zero,iscpu0 # go if on CPU0#if CFG_RELOC /* * SVR4 PIC mode: get a copy of GP for use in the boot ROM. */ lui gp,%hi(_gp) addiu gp,%lo(_gp) or gp,gp,K1BASE#endif /* * Note: we should never get to the CPU1 code if we're * with only one CPU. Theoretically, nobody got past the * check in altcpu_start. But, just in case, if we * get here and we're on CPU1, and we supposedly only * have one CPU, reset CPU1. */ GET_NUM_CPUS(t0, t1) beq t0,1,iscpu0 # If only one CPU, kill off CPU1 /* * Initialize CPU registers. */ JAL_KSEG1(sb1_cpu_init) GET_CUR_CPU(t1) SETLEDS1_ADD('C','P','U','0', t1) /* * Initialize the L1 cache */#if CFG_INIT_L1 JAL_KSEG1(bcm1480_l1cache_init)#endif /* * Notify the SCD that we're done initializing. Do this by * ringing CPU0's doorbell. */ la a0,PHYS_TO_K1(A_BCM1480_IMR_REGISTER(0,R_BCM1480_IMR_MAILBOX_0_SET_CPU)); GET_CUR_CPU(t0) # get our processor # to t0 li t1,1 # make a bit mask depending on CPU sll t1,t1,t0 # calculate t1 = 1 shl cpu number sd t1,0(a0) # set corresponding bit in mailbox /* * Go to the idle loop */ b altcpu_idle # go to idle loop /* * We get here if we were running on CPU0. Make things * pretty for the reset of CPU initialization. */iscpu0: /* * If we are on CPU0, then force secondary CPUs1 into reset. * This is needed for the case where the firmware has crashed * and we need to get control of the system again. */ li a0,PHYS_TO_K1(A_SCD_SYSTEM_CFG) ld t0,0(a0) dli t1,(M_BCM1480_SYS_CPU_RESET_1|M_BCM1480_SYS_CPU_RESET_2|M_BCM1480_SYS_CPU_RESET_3) or t0,t1 # New value to write sd t0,0(a0) # secondary CPUs are now in reset j ra # return (we were on CPU 0)END(bcm1480_altcpu_reset)/* ********************************************************************* * ALTCPU_CMD_START(cpu,addr) * * Start an alternate CPU. * * Input parameters: * a0 - cpu number (must be 1-3 for the BCM1480) * a1 - pointer to start parameters (four 64-bit values) * array[0] = start address (PC) * array[1] = start stack pointer (SP) * array[2] = start global pointer (GP) * array[3] = start user argument (A1) * * Return value: * v0 - 0 if ok * else -1 if request could not be handled ********************************************************************* */#define R_CPUSTART_PCVAL 0#define R_CPUSTART_SPVAL 8#define R_CPUSTART_GPVAL 16#define R_CPUSTART_A1VAL 24LEAF(altcpu_cmd_start) li v0,-1 /* assume failure */ beq a0,0,2f /* can't start CPU0 with this routine */ /* * Return an error if running in uniprocessor mode. */ GET_NUM_CPUS(t0, t1) beq t0,1,2f # If only one CPU, error. /* * Multiprocessor mode, start the other CPU */ move t0,a0 /* get CPU number */ sll t0,5 /* multiply by 5 for cache offset */ la t1,cpu_idledata add t1,t0 /* t1 = desired CPU's idle data */ ld t2,R_CPUSTART_GPVAL(a1) SR t2,R_CPU_GPVAL(t1) ld t2,R_CPUSTART_SPVAL(a1) SR t2,R_CPU_SPVAL(t1) ld t2,R_CPUSTART_A1VAL(a1) SR t2,R_CPU_ARG(t1) ld t2,R_CPUSTART_PCVAL(a1) /* this one actually starts the CPU */ SR t2,R_CPU_STARTVECT(t1) move v0,zero /* success */ j ra /* * Error return - invalid cpu number */2: li v0,-1 j raEND(altcpu_cmd_start)/* ********************************************************************* * ALTCPU_CMD_STOP(cpu) * * Stop the specified CPU. * * We don't really support this at the moment. * * Input parameters: * a0 - cpu number * * Return value: * v0 - 0 if ok, else error code ********************************************************************* */LEAF(altcpu_cmd_stop) beq a0,zero,1f # can't stop CPU0 /* * Return an error if running in uniprocessor mode. */ GET_NUM_CPUS(t0, t1) # t0 = number of CPUs beq t0,1,1f # If only one CPU, error. bge a0,t0,1f # Range check CPU number /* * Multiprocessor mode, stop the other CPU (a0 = cpu number) */ b _bcm1480_altcpu_kill /* kill the CPU */1: li v0,-1 j raEND(altcpu_cmd_stop)/* ********************************************************************* * ALTCPU_IDLE * * Loop forever waiting for someone to tell us where to go. * * Input parameters: * nothing. * * Return value: * nothing ********************************************************************* */altcpu_idle: #if CFG_RELOC lui gp,%hi(_gp) addiu gp,%lo(_gp)#endif GET_CUR_CPU(t1) SETLEDS1_ADD('c','p','u','0', t1) /* * Now wait for CPU0 to ring *our* doorbell. This is our signal that * it's safe to go to the idle loop. Until CPU0 rings our * doorbell, we can't use memory or the cache (since other CPUs * caches may not be initted yet). * XXX Very BCM1480 specific here. */1: la a0,PHYS_TO_K1(A_BCM1480_IMR_REGISTER(0,R_BCM1480_IMR_MAILBOX_0_CPU)) GET_CUR_CPU(t0) li t1,BCM1480_IMR_REGISTER_SPACING multu t0,t1 mflo t1 daddu a0,a0,t1 ld t0,(a0) # Read mailbox beq t0,zero,1b # Loop till the bit is set /* * Switch to KSEG0 (cached) */ bal _altcpu_kseg0_switch /* * Clear all the bits in the mailbox register to dismiss the * pending interrupt */ daddiu a0,a0,(R_BCM1480_IMR_MAILBOX_0_CLR_CPU-R_BCM1480_IMR_MAILBOX_0_CPU) li t1,-1 sd t1,0(a0) /* * We may need GP, especially in relocated version * * Yucky hack: The relocation factor was passed to us in * the mailbox register, which is conveniently in t0 right now. * (except the lower bit is set just in case the reloc was * zero, so clear that first). */ li t1,1 # 1 not t1 # FFFFFFFFE and t0,t1 # clear lower bit.#if (CFG_RELOC) /* * Now that we can talk to memory again, get the "text relocation" * and move the loop into DRAM. */__AltCpuGoRel: la t1,1f # Get address of where to go ADDU gp,t0 # Relocate GP ADDU t1,t0 # Relocate address jr t1 # Go there.1: # we will go "here" in the reloc world#else /* * non-PIC: Standard GP */ la gp,_gp ADD gp,t0 # relocate GP.#endif /* * Get our processor number, and calculate address of cpu's idle data */ GET_CUR_CPU(t0) # processor number to t0 sll t0,t0,5 # Multiply by 32 for cache offset la t1,cpu_idledata # address of base of table addu t0,t1 # t0 = our cpu data /* * Set up registers like we were launching a program. */ la a2,cpu_apientry # A2 = firmware entry vector move a0,gp # A0 = handle li a3,CFE_EPTSEAL # A3 = entrypoint signature /* * Read the start address from the CPU restart table * and jump to it. For an idle CPU, the address in the * table below will be the zero, causing * the CPU to loop forever. To start a secondary CPU, * just write an address in cpu_idledata[cpu_id].start_vector * * Warning: This kind of assumes that this code will * live in cacheable space. If it doesn't, it will * probably cause lots of unwanted bus traffic. */ li s4,0loop_forever: LR t1,R_CPU_STARTVECT(t0) # Load address of routine beq t1,zero,loop_forever LR a1,R_CPU_ARG(t0) # Load user argument (A1) LR sp,R_CPU_SPVAL(t0) # Load stack pointer LR t2,R_CPU_GPVAL(t0) # Load global pointer move gp,t2 # and put in real register j t1 # jump to start address/* ********************************************************************* * End ********************************************************************* */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -