.globl sparc64_of_client_interface, client_tba /* * SAVE_WINDOW_STATE and RESTORE_WINDOW_STATE are used to ensure * that the CPU window state is preserved across CIF calls. This is * to workaround a *BSD restriction that window fill/spill traps must * be minimised during trap table takeover, and likely emulates the * behaviour of OBP. */ #define SAVE_WINDOW_STATE(type) \ setx client_window, %g6, %g1; \ rdpr %cwp, %g7; \ stx %g7, [%g1]; \ rdpr %cansave, %g7; \ stx %g7, [%g1 + 0x8]; \ rdpr %canrestore, %g7; \ stx %g7, [%g1 + 0x10]; \ rdpr %otherwin, %g7; \ stx %g7, [%g1 + 0x18]; \ rdpr %wstate, %g7; \ stx %g7, [%g1 + 0x20]; \ rdpr %cleanwin, %g7; \ stx %g7, [%g1 + 0x28]; \ \ stx %o0, [%g1 + 0x30]; \ stx %o1, [%g1 + 0x38]; \ stx %o2, [%g1 + 0x40]; \ stx %o3, [%g1 + 0x48]; \ stx %o4, [%g1 + 0x50]; \ stx %o5, [%g1 + 0x58]; \ stx %o6, [%g1 + 0x60]; \ stx %o7, [%g1 + 0x68]; \ \ rdpr %pstate, %g7; \ stx %g7, [%g1 + 0x70]; \ rd %y, %g7; \ stx %g7, [%g1 + 0x78]; \ rd %fprs, %g7; \ stx %g7, [%g1 + 0x80]; \ \ /* Now iterate through all of the windows saving all l and i registers */ \ add %g1, 0x90, %g5; \ \ /* Get the number of windows in %g6 */ \ rdpr %ver, %g6; \ and %g6, 0xf, %g6; \ inc %g6; \ \ save_cpu_window_##type: \ deccc %g6; \ wrpr %g6, %cwp; \ stx %l0, [%g5]; \ stx %l1, [%g5 + 0x8]; \ stx %l2, [%g5 + 0x10]; \ stx %l3, [%g5 + 0x18]; \ stx %l4, [%g5 + 0x20]; \ stx %l5, [%g5 + 0x28]; \ stx %l6, [%g5 + 0x30]; \ stx %l7, [%g5 + 0x38]; \ stx %i0, [%g5 + 0x40]; \ stx %i1, [%g5 + 0x48]; \ stx %i2, [%g5 + 0x50]; \ stx %i3, [%g5 + 0x58]; \ stx %i4, [%g5 + 0x60]; \ stx %i5, [%g5 + 0x68]; \ stx %i6, [%g5 + 0x70]; \ stx %i7, [%g5 + 0x78]; \ bne save_cpu_window_##type; \ add %g5, 0x80, %g5; \ \ /* For 8 windows with 16 registers to save in the window, memory required \ is 16*8*8 = 0x400 bytes */ \ \ /* Now we should be in window 0 so update the other window registers */ \ rdpr %ver, %g6; \ and %g6, 0xf, %g6; \ dec %g6; \ wrpr %g6, %cansave; \ \ wrpr %g0, %cleanwin; \ wrpr %g0, %canrestore; \ wrpr %g0, %otherwin; #define RESTORE_WINDOW_STATE(type) \ setx client_window, %g6, %g1; \ \ /* Get the number of windows in %g6 */ \ rdpr %ver, %g6; \ and %g6, 0xf, %g6; \ inc %g6; \ \ /* Now iterate through all of the windows restoring all l and i registers */ \ add %g1, 0x90, %g5; \ \ restore_cpu_window_##type: \ deccc %g6; \ wrpr %g6, %cwp; \ ldx [%g5], %l0; \ ldx [%g5 + 0x8], %l1; \ ldx [%g5 + 0x10], %l2; \ ldx [%g5 + 0x18], %l3; \ ldx [%g5 + 0x20], %l4; \ ldx [%g5 + 0x28], %l5; \ ldx [%g5 + 0x30], %l6; \ ldx [%g5 + 0x38], %l7; \ ldx [%g5 + 0x40], %i0; \ ldx [%g5 + 0x48], %i1; \ ldx [%g5 + 0x50], %i2; \ ldx [%g5 + 0x58], %i3; \ ldx [%g5 + 0x60], %i4; \ ldx [%g5 + 0x68], %i5; \ ldx [%g5 + 0x70], %i6; \ ldx [%g5 + 0x78], %i7; \ bne restore_cpu_window_##type; \ add %g5, 0x80, %g5; \ \ /* Restore the window registers to their original value */ \ ldx [%g1], %g7; \ wrpr %g7, %cwp; \ ldx [%g1 + 0x8], %g7; \ wrpr %g7, %cansave; \ ldx [%g1 + 0x10], %g7; \ wrpr %g7, %canrestore; \ ldx [%g1 + 0x18], %g7; \ wrpr %g7, %otherwin; \ ldx [%g1 + 0x20], %g7; \ wrpr %g7, %wstate; \ ldx [%g1 + 0x28], %g7; \ wrpr %g7, %cleanwin; \ \ ldx [%g1 + 0x30], %o0; \ ldx [%g1 + 0x38], %o1; \ ldx [%g1 + 0x40], %o2; \ ldx [%g1 + 0x48], %o3; \ ldx [%g1 + 0x50], %o4; \ ldx [%g1 + 0x58], %o5; \ ldx [%g1 + 0x60], %o6; \ ldx [%g1 + 0x68], %o7; \ \ ldx [%g1 + 0x70], %g7; \ wrpr %g7, %pstate; \ ldx [%g1 + 0x78], %g7; \ wr %g7, 0, %y; \ ldx [%g1 + 0x80], %g7; \ wr %g7, 0, %fprs .data .align 8 .skip 16384 openbios_stack: client_stack: .xword 0 client_tba: .xword 0 client_window: .skip 2048 .text .align 4 .register %g2, #scratch .register %g3, #scratch .register %g6, #scratch .register %g7, #scratch /* make some more space on stack since linux kernel only provides 128 bytes without memory to spill registers (used by gcc in -O0 mode) */ sparc64_of_client_interface: /* Save globals on callers stack */ add %sp, -56, %sp stx %g1, [%sp + 2047 + 0] stx %g2, [%sp + 2047 + 8] stx %g3, [%sp + 2047 + 16] stx %g4, [%sp + 2047 + 24] stx %g5, [%sp + 2047 + 32] stx %g6, [%sp + 2047 + 40] stx %g7, [%sp + 2047 + 48] /* Save client trap table */ setx client_tba, %g6, %g7 rdpr %tba, %g6 stx %g6, [%g7] /* Save existing stack */ setx client_stack, %g6, %g7 stx %sp, [%g7] /* Save windows */ SAVE_WINDOW_STATE(cif) /* Move to OpenBIOS stack */ setx openbios_stack - 2047 - 192, %g6, %g7 mov %g7, %sp /* Call client inteface */ call of_client_interface ldx [%g1 + 0x30], %o0 setx client_window, %g6, %g1 stx %o0, [%g1 + 0x30] /* Restore windows */ RESTORE_WINDOW_STATE(cif) /* Restore stack */ setx client_stack, %g6, %g7 ldx [%g7], %sp /* Restore client trap table */ setx client_tba, %g6, %g7 ldx [%g7], %g6 wrpr %g6, %tba /* Restore globals */ ldx [%sp + 2047 + 0], %g1 ldx [%sp + 2047 + 8], %g2 ldx [%sp + 2047 + 16], %g3 ldx [%sp + 2047 + 24], %g4 ldx [%sp + 2047 + 32], %g5 ldx [%sp + 2047 + 40], %g6 ldx [%sp + 2047 + 48], %g7 add %sp, 56, %sp jmp %o7+8 nop