diff options
author | Alexander Graf <agraf@suse.de> | 2014-04-03 11:37:27 +0200 |
---|---|---|
committer | Alexey Kardashevskiy <aik@ozlabs.ru> | 2014-04-04 11:42:20 +1100 |
commit | 9a44f99fa43aa66777a6d3208f42d3cb451e827d (patch) | |
tree | 027ff68d9b3dd02901a126f9451ee360863bc28d | |
parent | 1e0ab50668cdf9500e8ba52dc656318a7497357b (diff) | |
download | SLOF-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>
-rw-r--r-- | board-qemu/slof/Makefile | 2 | ||||
-rw-r--r-- | lib/libhvcall/brokensc1.c | 56 |
2 files changed, 29 insertions, 29 deletions
diff --git a/board-qemu/slof/Makefile b/board-qemu/slof/Makefile index 6a9fa17..d412683 100644 --- a/board-qemu/slof/Makefile +++ b/board-qemu/slof/Makefile @@ -45,7 +45,7 @@ BOARD_SLOF_CODE = $(BOARD_SLOF_IN:%.in=%.code) include $(SLOFCMNDIR)/Makefile.inc -AS1FLAGS = $(CPPFLAGS) $(RELEASE) $(CPUARCHDEF) -Wa,-mregnames +AS1FLAGS = $(CPPFLAGS) $(RELEASE) $(FLAG) $(CPUARCHDEF) -Wa,-mregnames %.o: %.S $(CC) $(AS1FLAGS) -o $@ -c $^ 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 */ |