/* * ========== Copyright Header Begin ========================================== * * OpenSPARC T2 Processor File: SS_V8Code.s * Copyright (c) 2006 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES. * * The above named program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public * License version 2 as published by the Free Software Foundation. * * The above named program is distributed in the hope that it will be * useful, but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public * License along with this work; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * * ========== Copyright Header End ============================================ */ #if !defined(ARCH_X64) !============================================================================ !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! !============================================================================ ! tHIS COMMENT SECTION IS A MUST READ fOR THOSE THAT ARE GOING TO CHANGE THIS ! CODE. iF YOU DON'T READ IT OR DO NOT KNOW WHAT YOU ARE DOING THEN KEEP OFF. !============================================================================ !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! !============================================================================ ! In v9 mode all the functions relevant in the code below use between 4 and 6 ! arguments. This means that all there functions pass their arguments in ! registers only as v9 has %0 to %05 available for the first 6 64bit arguments. ! ! ! The v8(plus) standard stack frame looks like: ! ! %fp 0| 16-word window save area | (%fp == %i6) ! +--------------------------------+ ! | unspecified | ! | .... | ! | variable size | ! +--------------------------------+ ! +92 | (if needed) outgoing arg 6 ... | ! +--------------------------------+ ! | six words into which callee | ! +68 | may write outgoing arg 0 to 5 | ! +--------------------------------+ ! +64 | struct/union return pointer | ! +--------------------------------+ ! %sp 0 | 16-word window save area | (%sp == %o6) ! +--------------------------------+ ! ! The picture was taken from the documents found on http://www.sparc.com/standards ! ! On function calls registers %o0 to %o5 are arguments 0 to 5. Argument number ! 6 is placed on the stack at offset %sp + 92. The 7th argument is placed at ! offset %sp + 96, etc. In v8(plus) mode the arguments are 32bits in size. ! ! The v8plus "standard" documents says that the kernel preserves the upper ! 32bits of the global and the out registers on trap or interrupt. This suits ! us well as all our assembly code does not use save and restore, so without ! looking we can say these routines are safe for use in v8plus mode. Note we ! know our assembly only tail calls - it doesn't make "nested calls. Nested ! calls can chop the out registers to 32bits !!!! so v9 assembly code that does ! that wouldn't be safe to use in v8plus mode. ! ! There is one problem that we need to fix however. The stack frame and argument ! passing in v8plus is 32bits, and 64bits in v9 mode. So we need calling ! convention converters around the assembly code. ! ! A 64bit value in v8plus is stored in two 32bit memory locations. Following ! the ldd/std instructions the word(32bits) at addr contains bits 31 to 0 and ! the word at addr + 4 contain bits 63 to 32. For argument passing bits 31 ! to 0 is kept argument N and bits 63 to 32 in argumewnt N+1. !============================================================================ #include "SS_Assembly.h" .register %g2,#scratch .register %g3,#scratch .section ".text" !============================================================================ ! run_exe_v8plus_to_v9 - this is the entry point for all the assembly coded ! routines in the run_exe table. From v8plus we call into v9 code. The run_exe ! routine's type signature is ! SS_Vaddr (*execute)( SS_Vaddr, SS_Vaddr, SS_Strand*,SS_Instr* ); ! which fits in 6 registers: %o0 to %o5. However, some of the assembly ! routines need to call routines with more arguments: data_mmu for example. ! Hence this routines created space on the stack for these extra routines, ! it takes the worst case apporach, which is 3 more 4byte arguments is 12 ! bytes. The v8(plus) ABI says that we need to move %sp by 92 + 12 = 104. !============================================================================ .align 8 .global run_exe_v8plus_to_v9 .type run_exe_v8plus_to_v9, #function run_exe_v8plus_to_v9: save %sp,-104,%sp ! reserve 12 bytes of stack space ldsh [%i5 + I_EXE_TBL_IDX],%g2 ! Get exe table index sllx %i0,32,R_PC ! pc = (%i0 << 32) | %i1 srl %i1,0x0,%g1 or R_PC,%g1,R_PC ld [%i4 + S_V8_EXE_TABLE],%g3 ! Get real exe table pointer sllx %i2,32,R_NPC ! npc = (%i2 << 32) | %i3 srl %i3,0x0,%g1 or R_NPC,%g1,R_NPC sll %g2,2,%g2 ld [%g3 + %g2],%g4 ! Get exe routine function mov %i4,S_PTR ! %o2 - s jmpl %g4,%o7 ! call asm exe routine mov %i5,I_PTR ! and it returns pc in v8plus style. mov %o0,%i0 ! return pc, in v8plus mode that's ret restore %o1,0,%o1 !============================================================================ ! v9_to_v8plus - these are the exit points from the assembly routine (v9) to ! the c coded land (v8plus). The code has multiple entry points as the argu- ! ments are pretty much the same. !============================================================================ v9_to_v8plus_pc_npc_s_i_va_mem: v9_to_v8plus_pc_npc_s_i_va_tt: st %o5,[%sp + 100] ! tt - store on the stack v9_to_v8plus_pc_npc_s_i_va: st %o4,[%sp + 96] ! store upper part of 64bit srlx %o4,32,%o4 ! va - store on the stack v9_to_v8plus_pc_npc_s_i_tt: st %o4,[%sp + 92] ! lower part of 64bit (va) or ! 32bit argument (tt) v9_to_v8plus_pc_npc_s_i: sra I_PTR,0,%o5 ! i is %o5 sra S_PTR,0,%o4 ! s is %o4 srl %o1,0,%o3 ! npc is %o2, %o3 srlx %o1,32,%o2 srl %o0,0,%o1 ! pc is %o0, %o1 jmpl %g4,%g0 ! return (%g4)(pc,npc,s,i,...); srlx %o0,32,%o0 !============================================================================ ! SS_Vaddr (*trap)( SS_Vaddr pc, SS_Vaddr npc, SS_Strand* s, SS_Instr* i, ! SS_Trap::Type tt ); !============================================================================ .global trap_v9_to_v8plus .type trap_v9_to_v8plus, #function trap_v9_to_v8plus: ba %xcc,v9_to_v8plus_pc_npc_s_i_tt ld [S_PTR + S_TRAP],%g4 !============================================================================ ! SS_Vaddr (*inst_trap)( SS_Vaddr pc, SS_Vaddr npc, SS_Strand* s, SS_Instr* i, ! SS_Vaddr va, SS_Trap::Type tt ); !============================================================================ .global inst_trap_v9_to_v8plus .type inst_trap_v9_to_v8plus, #function inst_trap_v9_to_v8plus: ba %xcc,v9_to_v8plus_pc_npc_s_i_va_tt ld [S_PTR + S_INST_TRAP],%g4 !============================================================================ ! SS_Vaddr (*data_trap)( SS_Vaddr pc, SS_Vaddr npc, SS_Strand* s, SS_Instr* i, ! SS_Vaddr va, SS_Trap::Type tt ); !============================================================================ .global data_trap_v9_to_v8plus .type data_trap_v9_to_v8plus, #function data_trap_v9_to_v8plus: ba %xcc,v9_to_v8plus_pc_npc_s_i_va_tt ld [S_PTR + S_DATA_TRAP],%g4 !============================================================================ ! SS_Vaddr (*data_mmu)( SS_Vaddr pc, SS_Vaddr npc, SS_Strand* s, SS_Instr* i, ! SS_Vaddr va, uint_t mem ); !============================================================================ .global data_mmu_v9_to_v8plus .type data_mmu_v9_to_v8plus, #function data_mmu_v9_to_v8plus: ba %xcc,v9_to_v8plus_pc_npc_s_i_va_mem ld [S_PTR + S_DATA_MMU],%g4 !============================================================================ ! SS_Vaddr (*invalid_asi)( SS_Vaddr pc, SS_Vaddr npc, SS_Strand*, SS_Instr*, ! SS_Vaddr ); !============================================================================ .global invalid_asi_v9_to_v8plus .type invalid_asi_v9_to_v8plus, #function invalid_asi_v9_to_v8plus: ba %xcc,v9_to_v8plus_pc_npc_s_i_va ld [S_PTR + S_INVALID_ASI],%g4 !============================================================================ ! SS_Vaddr (*inst_dev)( SS_Vaddr, SS_Vaddr, SS_Strand*,SS_Instr* ); !============================================================================ .global inst_dec_v9_to_v8plus .type inst_dec_v9_to_v8plus, #function inst_dec_v9_to_v8plus: ba %xcc,v9_to_v8plus_pc_npc_s_i ld [S_PTR + S_INST_DEC],%g4 #endif