aboutsummaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
authorAlexander Graf <agraf@suse.de>2014-04-03 11:37:27 +0200
committerAlexey Kardashevskiy <aik@ozlabs.ru>2014-04-04 11:42:20 +1100
commit9a44f99fa43aa66777a6d3208f42d3cb451e827d (patch)
tree027ff68d9b3dd02901a126f9451ee360863bc28d /lib
parent1e0ab50668cdf9500e8ba52dc656318a7497357b (diff)
downloadSLOF-9a44f99fa43aa66777a6d3208f42d3cb451e827d.zip
SLOF-9a44f99fa43aa66777a6d3208f42d3cb451e827d.tar.gz
SLOF-9a44f99fa43aa66777a6d3208f42d3cb451e827d.tar.bz2
Isolate sc 1 detection logic
Under weird circumstances we ended up with unsynchronized data and text section references between the stage1 and paflof binaries. This patch moves the initial sc 1 detection logic to work without any persistent state, making it properly reentrant regardless of the place we end up hitting the code at. This fixes broken sc 1 detection for me on PR KVM. Signed-off-by: Alexander Graf <agraf@suse.de> [aik: added r0 to clobber list and $(FLAG) to AS1FLAGS as suggested by agraf, tested on pHyp] Signed-off-by: Alexey Kardashevskiy <aik@ozlabs.ru>
Diffstat (limited to 'lib')
-rw-r--r--lib/libhvcall/brokensc1.c56
1 files changed, 28 insertions, 28 deletions
diff --git a/lib/libhvcall/brokensc1.c b/lib/libhvcall/brokensc1.c
index c37a0f1..e6387e0 100644
--- a/lib/libhvcall/brokensc1.c
+++ b/lib/libhvcall/brokensc1.c
@@ -6,27 +6,37 @@
// #define DEBUG_PATCHERY
-#define H_SET_DABR 0x28
+#define H_SET_DABR 0x28
+#define INS_SC1 0x44000022
+#define INS_SC1_REPLACE 0x7c000268
-enum broken_sc1 {
- SC1_UNKNOWN,
- SC1_BROKEN,
- SC1_WORKS,
-};
+extern volatile uint32_t sc1ins;
-static unsigned long hcall(unsigned long arg0, unsigned long arg1)
+static unsigned long hcall(uint32_t inst, unsigned long arg0, unsigned long arg1)
{
register unsigned long r3 asm("r3") = arg0;
register unsigned long r4 asm("r4") = arg1;
- asm volatile("sc 1"
+ register unsigned long r5 asm("r5") = inst;
+ asm volatile("bl 1f \n"
+ "1: \n"
+ "li 11, 2f - 1b \n"
+ "mflr 12 \n"
+ "add 11, 11, 12 \n"
+ "stw 5, 0(11) \n"
+ "dcbst 0, 11 \n"
+ "sync \n"
+ "icbi 0, 11 \n"
+ "isync \n"
+ "2: \n"
+ ".long 0 \n"
: "=r" (r3)
- : "r" (r3), "r" (r4)
- : "ctr", "r5", "r6", "r7", "r8", "r9", "r10", "r11",
+ : "r" (r3), "r" (r4), "r" (r5)
+ : "ctr", "r0", "r6", "r7", "r8", "r9", "r10", "r11",
"r12", "r13", "r31", "lr", "cc");
return r3;
}
-static enum broken_sc1 check_broken_sc1(void)
+static int check_broken_sc1(void)
{
long r;
@@ -36,41 +46,31 @@ static enum broken_sc1 check_broken_sc1(void)
* to patch the hypercall instruction to something that traps into
* supervisor mode.
*/
- r = hcall(H_SET_DABR, 0);
+ r = hcall(INS_SC1, H_SET_DABR, 0);
if (r == H_SUCCESS || r == H_HARDWARE) {
/* All is fine */
- return SC1_WORKS;
+ return 0;
}
/* We found a broken sc1 host! */
- return SC1_BROKEN;
+ return 1;
}
int patch_broken_sc1(void *start, void *end, uint32_t *test_ins)
{
- static enum broken_sc1 is_broken_sc1 = SC1_UNKNOWN;
uint32_t *p;
/* The sc 1 instruction */
- uint32_t sc1 = 0x44000022;
+ uint32_t sc1 = INS_SC1;
/* An illegal instruction that KVM interprets as sc 1 */
- uint32_t sc1_replacement = 0x7c000268;
+ uint32_t sc1_replacement = INS_SC1_REPLACE;
int is_le = (test_ins && *test_ins == 0x48000008);
#ifdef DEBUG_PATCHERY
int cnt = 0;
#endif
- switch (is_broken_sc1) {
- case SC1_UNKNOWN:
- /* If we never probed sc1 before, let's do so now! */
- is_broken_sc1 = check_broken_sc1();
- return patch_broken_sc1(start, end, test_ins);
- case SC1_WORKS:
- /* If we know that sc1 works fine, no need to check */
+ /* The host is sane, get out of here */
+ if (!check_broken_sc1())
return 0;
- case SC1_BROKEN:
- /* Handled below */
- break;
- }
/* We only get here with a broken sc1 implementation */