@@ -275,6 +275,8 @@ enter_p9_pm_state:
* PEF and bring it out of UV mode. All threads will then be running in HV
* mode and the only way to re-enable UV mode is with a reboot.
*
+ * Power9 hardware requires [h]srr1 to be set explicitly.
+ *
* r3 = 1 if primary thread
* 0 if secondary thread
*/
@@ -327,3 +329,30 @@ enter_uv:
ld %r0,16(%r1)
mtlr %r0
blr
+
+.global ucall
+ucall:
+ mflr %r0
+ stdu %r1,-STACK_FRAMESIZE(%r1)
+ std %r0,STACK_LR(%r1)
+ mfcr %r0
+ stw %r0,STACK_CR(%r1)
+ std %r4,STACK_GPR4(%r1) /* Save ret buffer */
+ mr %r4,%r5
+ mr %r5,%r6
+ mr %r6,%r7
+ mr %r7,%r8
+ mr %r8,%r9
+ mr %r9,%r10
+ sc 2 /* invoke the ultravisor */
+ ld %r12,STACK_GPR4(%r1)
+ std %r4, 0(%r12)
+ std %r5, 8(%r12)
+ std %r6, 16(%r12)
+ std %r7, 24(%r12)
+ lwz %r0,STACK_CR(%r1)
+ mtcrf 0xff,%r0
+ ld %r0,STACK_LR(%r1)
+ mtlr %r0
+ addi %r1,%r1,STACK_FRAMESIZE
+ blr /* return r3 = status */
@@ -32,4 +32,15 @@ extern bool uv_present;
void init_uv(void);
+/*
+ * ucall: Make an ultracall
+ * @opcode: The ultracall to make
+ * @retbuf: Buffer to store up to 4 return arguments
+ *
+ * This call supports up to 6 arguments and 4 return arguments. Use
+ * UCALL_BUFSIZE to size the return argument buffer.
+ */
+#define UCALL_BUFSIZE 4
+extern long ucall(unsigned long opcode, unsigned long *retbuf, ...);
+
#endif /* __ULTRAVISOR_H */