Add qemu 2.4.0
[kvmfornfv.git] / qemu / roms / openbios / arch / sparc64 / call-client.S
diff --git a/qemu/roms/openbios/arch/sparc64/call-client.S b/qemu/roms/openbios/arch/sparc64/call-client.S
new file mode 100644 (file)
index 0000000..f365e3c
--- /dev/null
@@ -0,0 +1,236 @@
+       .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