diff options
author | Yang Zhang <yang.z.zhang@intel.com> | 2015-08-28 09:58:54 +0800 |
---|---|---|
committer | Yang Zhang <yang.z.zhang@intel.com> | 2015-09-01 12:44:00 +0800 |
commit | e44e3482bdb4d0ebde2d8b41830ac2cdb07948fb (patch) | |
tree | 66b09f592c55df2878107a468a91d21506104d3f /qemu/roms/SLOF/lib/libhvcall | |
parent | 9ca8dbcc65cfc63d6f5ef3312a33184e1d726e00 (diff) |
Add qemu 2.4.0
Change-Id: Ic99cbad4b61f8b127b7dc74d04576c0bcbaaf4f5
Signed-off-by: Yang Zhang <yang.z.zhang@intel.com>
Diffstat (limited to 'qemu/roms/SLOF/lib/libhvcall')
-rw-r--r-- | qemu/roms/SLOF/lib/libhvcall/Makefile | 57 | ||||
-rw-r--r-- | qemu/roms/SLOF/lib/libhvcall/brokensc1.c | 162 | ||||
-rw-r--r-- | qemu/roms/SLOF/lib/libhvcall/hvcall.S | 134 | ||||
-rw-r--r-- | qemu/roms/SLOF/lib/libhvcall/hvcall.code | 131 | ||||
-rw-r--r-- | qemu/roms/SLOF/lib/libhvcall/hvcall.in | 34 | ||||
-rw-r--r-- | qemu/roms/SLOF/lib/libhvcall/libhvcall.h | 107 |
6 files changed, 625 insertions, 0 deletions
diff --git a/qemu/roms/SLOF/lib/libhvcall/Makefile b/qemu/roms/SLOF/lib/libhvcall/Makefile new file mode 100644 index 000000000..2a9b2d7d1 --- /dev/null +++ b/qemu/roms/SLOF/lib/libhvcall/Makefile @@ -0,0 +1,57 @@ +# ***************************************************************************** +# * Copyright (c) 2004, 2008 IBM Corporation +# * All rights reserved. +# * This program and the accompanying materials +# * are made available under the terms of the BSD License +# * which accompanies this distribution, and is available at +# * http://www.opensource.org/licenses/bsd-license.php +# * +# * Contributors: +# * IBM Corporation - initial implementation +# ****************************************************************************/ + +TOPCMNDIR ?= ../.. + +include $(TOPCMNDIR)/make.rules + +ASFLAGS = $(FLAG) $(RELEASE) $(CPUARCHDEF) -Wa,-mregnames +CPPFLAGS = -I../libc/include $(CPUARCHDEF) -I$(INCLBRDDIR) \ + -I$(INCLCMNDIR) -I$(INCLCMNDIR)/$(CPUARCH) +LDFLAGS = -nostdlib + +TARGET = ../libhvcall.a + + +all: $(TARGET) + +SRCS = brokensc1.c +SRCSS = hvcall.S + + +OBJS = $(SRCS:%.c=%.o) $(SRCSS:%.S=%.o) + +$(TARGET): $(OBJS) + $(AR) -rc $@ $(OBJS) + $(RANLIB) $@ + +%.o: %.S + $(CC) $(CPPFLAGS) $(ASFLAGS) -c $< -o $@ + +clean: + $(RM) $(TARGET) $(OBJS) + +distclean: clean + $(RM) Makefile.dep + + +# Rules for creating the dependency file: +depend: + $(RM) Makefile.dep + $(MAKE) Makefile.dep + +Makefile.dep: Makefile + $(CC) -M $(CPPFLAGS) $(CFLAGS) $(SRCS) $(SRCSS) > Makefile.dep + +# Include dependency file if available: +-include Makefile.dep + diff --git a/qemu/roms/SLOF/lib/libhvcall/brokensc1.c b/qemu/roms/SLOF/lib/libhvcall/brokensc1.c new file mode 100644 index 000000000..e6387e0ab --- /dev/null +++ b/qemu/roms/SLOF/lib/libhvcall/brokensc1.c @@ -0,0 +1,162 @@ +#include <stdint.h> +#include <stddef.h> +#include <cpu.h> +#include "libhvcall.h" +#include "byteorder.h" + +// #define DEBUG_PATCHERY + +#define H_SET_DABR 0x28 +#define INS_SC1 0x44000022 +#define INS_SC1_REPLACE 0x7c000268 + +extern volatile uint32_t sc1ins; + +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; + 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), "r" (r5) + : "ctr", "r0", "r6", "r7", "r8", "r9", "r10", "r11", + "r12", "r13", "r31", "lr", "cc"); + return r3; +} + +static int check_broken_sc1(void) +{ + long r; + + /* + * Check if we can do a simple hcall. If it works, we are running in + * a sane environment and everything's fine. If it doesn't, we need + * to patch the hypercall instruction to something that traps into + * supervisor mode. + */ + r = hcall(INS_SC1, H_SET_DABR, 0); + if (r == H_SUCCESS || r == H_HARDWARE) { + /* All is fine */ + return 0; + } + + /* We found a broken sc1 host! */ + return 1; +} + +int patch_broken_sc1(void *start, void *end, uint32_t *test_ins) +{ + uint32_t *p; + /* The sc 1 instruction */ + uint32_t sc1 = INS_SC1; + /* An illegal instruction that KVM interprets as sc 1 */ + uint32_t sc1_replacement = INS_SC1_REPLACE; + int is_le = (test_ins && *test_ins == 0x48000008); +#ifdef DEBUG_PATCHERY + int cnt = 0; +#endif + + /* The host is sane, get out of here */ + if (!check_broken_sc1()) + return 0; + + /* We only get here with a broken sc1 implementation */ + + /* Trim the range we scan to not cover the data section */ + if (test_ins) { + /* This is the cpu table matcher for 970FX */ + uint32_t end_bytes[] = { 0xffff0000, 0x3c0000 }; + /* + * The .__start symbol contains a trap instruction followed + * by lots of zeros. + */ + uint32_t start_bytes[] = { 0x7fe00008, 0, 0, 0, 0 }; + + if (is_le) { + end_bytes[0] = bswap_32(end_bytes[0]); + end_bytes[1] = bswap_32(end_bytes[1]); + start_bytes[1] = bswap_32(start_bytes[1]); + } + + /* Find the start of the text section */ + for (p = test_ins; (long)p > (long)start; p--) { + if (p[0] == start_bytes[0] && + p[1] == start_bytes[1] && + p[2] == start_bytes[2] && + p[3] == start_bytes[3] && + p[4] == start_bytes[4]) { + /* + * We found a match of the instruction sequence + * trap + * .long 0 + * .long 0 + * .long 0 + * .long 0 + * which marks the beginning of the .text + * section on all Linux kernels I've checked. + */ +#ifdef DEBUG_PATCHERY + printf("Shortened start from %p to %p\n", end, p); +#endif + start = p; + break; + } + } + + /* Find the end of the text section */ + for (p = start; (long)p < (long)end; p++) { + if (p[0] == end_bytes[0] && p[1] == end_bytes[1]) { + /* + * We found a match of the PPC970FX entry in the + * guest kernel's CPU table. That table is + * usually found early in the .data section and + * thus marks the end of the .text section for + * us which we need to patch. + */ +#ifdef DEBUG_PATCHERY + printf("Shortened end from %p to %p\n", end, p); +#endif + end = p; + break; + } + } + } + + if (is_le) { + /* + * The kernel was built for LE mode, so our sc1 and replacement + * opcodes are in the wrong byte order. Reverse them. + */ + sc1 = bswap_32(sc1); + sc1_replacement = bswap_32(sc1_replacement); + } + + /* Patch all sc 1 instructions to reserved instruction 31/308 */ + for (p = start; (long)p < (long)end; p++) { + if (*p == sc1) { + *p = sc1_replacement; + flush_cache(p, sizeof(*p)); +#ifdef DEBUG_PATCHERY + cnt++; +#endif + } + } + +#ifdef DEBUG_PATCHERY + printf("Patched %d instructions (%p - %p)\n", cnt, start, end); +#endif + + return 1; +} diff --git a/qemu/roms/SLOF/lib/libhvcall/hvcall.S b/qemu/roms/SLOF/lib/libhvcall/hvcall.S new file mode 100644 index 000000000..92cf22e4c --- /dev/null +++ b/qemu/roms/SLOF/lib/libhvcall/hvcall.S @@ -0,0 +1,134 @@ +#define _ASM +#define __ASSEMBLY__ +#include "macros.h" +#include "libhvcall.h" +#include <termctrl.h> +#include <product.h> + +#define HVCALL .long 0x44000022 + .text + .align 3 + +ENTRY(get_print_banner) + LOAD32(r4, print_version) + LOAD32(r5, print_version_end) + std r4,0(r3) + std r5,8(r3) + blr + +ENTRY(hv_generic) + HVCALL + blr + +/* r3 = char, r4 = hvtermno */ +ENTRY(hv_putchar) + sldi r6,r3,(24+32) + li r3,H_PUT_TERM_CHAR + li r5,1 + HVCALL + blr + +/* r3 = hvtermno */ +ENTRY(hv_getchar) + mflr r10 + bl .hv_haschar + mtlr r10 + cmpwi cr0,r3,0 + beqlr + lis r9,inbuf@h + ori r9,r9,inbuf@l + lwz r4,20(r9) + lbzx r3,r4,r9 + addi r4,r4,1 + stw r4,20(r9) + blr + +/* r3 = hvtermno */ +ENTRY(hv_haschar) + mr r4,r3 + li r3,-1 + lis r9,inbuf@h + ori r9,r9,inbuf@l + lwz r5,16(r9) + lwz r6,20(r9) + cmplw cr0,r5,r6 + bnelr + li r3,H_GET_TERM_CHAR + HVCALL + lis r9,inbuf@h + ori r9,r9,inbuf@l + stw r4,16(r9) + li r3,0 + stw r3,20(r9) + cmplwi cr0,r4,0 + beqlr + li r3,-1 + std r5,0(r9) + std r6,8(r9) + blr + +ENTRY(hv_send_crq) + ld r5,0(r4) + ld r6,8(r4) + mr r4,r3 + li r3,H_SEND_CRQ + HVCALL + blr + +ENTRY(hv_send_logical_lan) + li r11,0 /* no continue token for now */ + mr r10,r9 + mr r9,r8 + mr r8,r7 + mr r7,r6 + mr r6,r5 + mr r5,r4 + mr r4,r3 + li r3,H_SEND_LOGICAL_LAN + HVCALL + blr + +ENTRY(hv_logical_ci_load) + mr r5,r4 + mr r4,r3 + li r3,H_LOGICAL_CI_LOAD + HVCALL + cmpdi cr0,r3,0 + mr r3,r4 + beqlr + li r3,-1 + blr + +ENTRY(hv_logical_ci_store) + mr r6,r5 + mr r5,r4 + mr r4,r3 + li r3,H_LOGICAL_CI_STORE + HVCALL + blr + +ENTRY(hv_logical_memop) + mr r8,r7 + mr r7,r6 + mr r6,r5 + mr r5,r4 + mr r4,r3 + lis r3,KVMPPC_H_LOGICAL_MEMOP@h + ori r3,r3,KVMPPC_H_LOGICAL_MEMOP@l + HVCALL + blr + +ENTRY(hv_cas) + mr r6,r5 + mr r5,r4 + mr r4,r3 + lis r3,KVMPPC_H_CAS@h + ori r3,r3,KVMPPC_H_CAS@l + HVCALL + blr + + .section ".bss" +inbuf: .space 16 +inlen: .space 4 +inpos: .space 4 + .text diff --git a/qemu/roms/SLOF/lib/libhvcall/hvcall.code b/qemu/roms/SLOF/lib/libhvcall/hvcall.code new file mode 100644 index 000000000..0ff50f27e --- /dev/null +++ b/qemu/roms/SLOF/lib/libhvcall/hvcall.code @@ -0,0 +1,131 @@ +/****************************************************************************** + * Copyright (c) 2004, 2011 IBM Corporation + * All rights reserved. + * This program and the accompanying materials + * are made available under the terms of the BSD License + * which accompanies this distribution, and is available at + * http://www.opensource.org/licenses/bsd-license.php + * + * Contributors: + * IBM Corporation - initial implementation + *****************************************************************************/ + +#include <libhvcall.h> + +// : hv-putchar ( hvtermno char -- ) +PRIM(hv_X2d_putchar) + char c = TOS.n; POP; + int hvtermno = TOS.n; POP; + hv_putchar(c, hvtermno); +MIRP + +// : hv-getchar ( hvtermno -- char ) +PRIM(hv_X2d_getchar) + TOS.n = hv_getchar(TOS.n); +MIRP + +// : hv-haschar ( hvtermno -- res ) +PRIM(hv_X2d_haschar) + TOS.n = hv_haschar(TOS.n); +MIRP + +// : hv-reg-crq ( unit qaddr qsize -- res ) +PRIM(hv_X2d_reg_X2d_crq) + unsigned long qsize = TOS.u; POP; + unsigned long qaddr = TOS.u; POP; + unsigned int unit = TOS.u; + TOS.n = hv_reg_crq(unit, qaddr, qsize); +MIRP + +// : hv-free-crq ( unit -- ) +PRIM(hv_X2d_free_X2d_crq) + unsigned int unit = TOS.u; POP; + hv_free_crq(unit); +MIRP + +// : hv-send-crq ( unit msgaddr -- rc ) +PRIM(hv_X2d_send_X2d_crq) + uint64_t *msgaddr = (uint64_t *)TOS.u; POP; + unsigned int unit = TOS.u; + TOS.n = hv_send_crq(unit, msgaddr); +MIRP + +// : hv-put-tce ( liobn ioba tce -- rc ) +PRIM(hv_X2d_put_X2d_tce) + uint64_t tce = TOS.u; POP; + uint64_t ioba = TOS.u; POP; + uint32_t liobn = TOS.u; + TOS.u = hv_generic(H_PUT_TCE, liobn, ioba, tce); +MIRP + +PRIM(RB_X40) + unsigned long qaddr = TOS.u; + TOS.u = hv_logical_ci_load(1, qaddr); +MIRP +PRIM(RB_X21) + unsigned long qaddr = TOS.u; POP; + unsigned char val = TOS.u; POP; + hv_logical_ci_store(1, qaddr, val); +MIRP +PRIM(RW_X40) + unsigned long qaddr = TOS.u; + TOS.u = hv_logical_ci_load(2, qaddr); +MIRP +PRIM(RW_X21) + unsigned long qaddr = TOS.u; POP; + unsigned short val = TOS.u; POP; + hv_logical_ci_store(2, qaddr, val); +MIRP +PRIM(RL_X40) + unsigned long qaddr = TOS.u; + TOS.u = hv_logical_ci_load(4, qaddr); +MIRP +PRIM(RL_X21) + unsigned long qaddr = TOS.u; POP; + unsigned int val = TOS.u; POP; + hv_logical_ci_store(4, qaddr, val); +MIRP +PRIM(RX_X40) + unsigned long qaddr = TOS.u; + TOS.u = hv_logical_ci_load(8, qaddr); +MIRP +PRIM(RX_X21) + unsigned long qaddr = TOS.u; POP; + unsigned long val = TOS.u; POP; + hv_logical_ci_store(8, qaddr, val); +MIRP + +PRIM(hv_X2d_logical_X2d_memop) + unsigned long op = TOS.u; POP; + unsigned long count = TOS.u; POP; + unsigned long esize = TOS.u; POP; + unsigned long src = TOS.u; POP; + unsigned long dst = TOS.u; + TOS.u = hv_logical_memop(dst, src, esize, count, op); +MIRP + +PRIM(hv_X2d_cas) + unsigned long size = TOS.u; POP; + unsigned long buf = TOS.u; POP; + unsigned long vec = TOS.u; + TOS.u = hv_cas(vec, buf, size); +MIRP + +PRIM(hv_X2d_rtas_X2d_update) + unsigned long rtas_entry = TOS.u; POP; + unsigned long rtas_base = TOS.u; + TOS.u = hv_generic(KVMPPC_H_RTAS_UPDATE, rtas_base, rtas_entry); +MIRP + +PRIM(get_X2d_print_X2d_version) + unsigned long addr = TOS.u; POP; + get_print_banner(addr); +MIRP + +PRIM(check_X2d_and_X2d_patch_X2d_sc1) + unsigned long end = TOS.u; POP; + unsigned long start = TOS.u; POP; + unsigned long patch_ins = TOS.u; POP; + + patch_broken_sc1((void*)start, (void*)end, (void*)patch_ins); +MIRP diff --git a/qemu/roms/SLOF/lib/libhvcall/hvcall.in b/qemu/roms/SLOF/lib/libhvcall/hvcall.in new file mode 100644 index 000000000..4437b77f0 --- /dev/null +++ b/qemu/roms/SLOF/lib/libhvcall/hvcall.in @@ -0,0 +1,34 @@ +/****************************************************************************** + * Copyright (c) 2004, 2011 IBM Corporation + * All rights reserved. + * This program and the accompanying materials + * are made available under the terms of the BSD License + * which accompanies this distribution, and is available at + * http://www.opensource.org/licenses/bsd-license.php + * + * Contributors: + * IBM Corporation - initial implementation + *****************************************************************************/ + +cod(hv-putchar) +cod(hv-getchar) +cod(hv-haschar) +cod(hv-reg-crq) +cod(hv-free-crq) +cod(hv-send-crq) +cod(hv-put-tce) +cod(check-and-patch-sc1) + +cod(RB@) +cod(RB!) +cod(RW@) +cod(RW!) +cod(RL@) +cod(RL!) +cod(RX@) +cod(RX!) + +cod(hv-logical-memop) +cod(hv-cas) +cod(hv-rtas-update) +cod(get-print-version) diff --git a/qemu/roms/SLOF/lib/libhvcall/libhvcall.h b/qemu/roms/SLOF/lib/libhvcall/libhvcall.h new file mode 100644 index 000000000..193b7383d --- /dev/null +++ b/qemu/roms/SLOF/lib/libhvcall/libhvcall.h @@ -0,0 +1,107 @@ +#ifndef __LIBHVCALL_H__ +#define __LIBHVCALL_H__ + +#define H_SUCCESS 0 +#define H_HARDWARE -1 + +#define H_GET_TCE 0x1C +#define H_PUT_TCE 0x20 +#define H_LOGICAL_CI_LOAD 0x3c +#define H_LOGICAL_CI_STORE 0x40 +#define H_GET_TERM_CHAR 0x54 +#define H_PUT_TERM_CHAR 0x58 +#define H_REG_CRQ 0xFC +#define H_FREE_CRQ 0x100 +#define H_SEND_CRQ 0x108 +#define H_REGISTER_LOGICAL_LAN 0x114 +#define H_FREE_LOGICAL_LAN 0x118 +#define H_ADD_LOGICAL_LAN_BUFFER 0x11C +#define H_SEND_LOGICAL_LAN 0x120 + +/* KVM specific ones */ +#define KVMPPC_HCALL_BASE 0xf000 +#define KVMPPC_H_RTAS (KVMPPC_HCALL_BASE + 0x0) +#define KVMPPC_H_LOGICAL_MEMOP (KVMPPC_HCALL_BASE + 0x1) +/* Client Architecture support */ +#define KVMPPC_H_CAS (KVMPPC_HCALL_BASE + 0x2) +#define KVMPPC_H_RTAS_UPDATE (KVMPPC_HCALL_BASE + 0x3) +#define KVMPPC_H_REPORT_MC_ERR (KVMPPC_HCALL_BASE + 0x4) +#define KVMPPC_HCALL_MAX KVMPPC_H_NMI_MCE + +#ifndef __ASSEMBLY__ + +extern long hv_generic(unsigned long opcode, ...); + +extern void hv_putchar(char c, int hvtermno); +extern char hv_getchar(int hvtermno); +extern char hv_haschar(int hvtermno); +extern void get_print_banner(unsigned long addr); + +extern int hv_send_crq(unsigned int unit, uint64_t *msgaddr); + +static inline long hv_reg_crq(unsigned int unit, unsigned long qaddr, + unsigned long qsize) +{ + return hv_generic(H_REG_CRQ, unit, qaddr, qsize); +} + +static inline void hv_free_crq(unsigned int unit) +{ + hv_generic(H_FREE_CRQ, unit); +} + +extern long hv_send_logical_lan(unsigned long unit_address, + unsigned long desc1, unsigned long desc2, + unsigned long desc3, unsigned long desc4, + unsigned long desc5, unsigned long desc6); + +static inline long h_register_logical_lan(unsigned long unit_address, + unsigned long buf_list, + unsigned long rec_q, + unsigned long filter_list, + unsigned long mac_address) +{ + return hv_generic(H_REGISTER_LOGICAL_LAN, unit_address, + buf_list, rec_q, filter_list, mac_address); +} + +static inline long h_free_logical_lan(unsigned long unit_address) +{ + return hv_generic(H_FREE_LOGICAL_LAN, unit_address); +} + +static inline long h_add_logical_lan_buffer(unsigned long unit_address, + unsigned long buffer) +{ + return hv_generic(H_ADD_LOGICAL_LAN_BUFFER, unit_address, buffer); +} + +#define HV_RTAS_MAX_ARGRET 5 + +struct hv_rtas_call { + uint32_t token; + uint32_t nargs; + uint32_t nrets; + uint32_t argret[HV_RTAS_MAX_ARGRET]; +}; + +static inline unsigned long h_rtas(struct hv_rtas_call *rtas_buf) +{ + return hv_generic(KVMPPC_H_RTAS, (unsigned long)rtas_buf); +} + +extern unsigned long hv_logical_ci_load(unsigned long size, unsigned long addr); +extern unsigned long hv_logical_ci_store(unsigned long size, unsigned long addr, + unsigned long value); + +extern unsigned long hv_logical_memop(unsigned long dst, unsigned long src, + unsigned long esize, unsigned long count, + unsigned long op); +extern int patch_broken_sc1(void *start, void *end, uint32_t *test_ins); + +extern unsigned long hv_cas(unsigned long vec, unsigned long buf, + unsigned long size); + +#endif /* __ASSEMBLY__ */ + +#endif /* __LIBHVCALL_H__ */ |