On 18/03/2016 04:59, David Gibson wrote: > On Wed, 16 Mar 2016 16:12:59 +0100 > Laurent Vivier <lvivier@xxxxxxxxxx> wrote: > >> Signed-off-by: Laurent Vivier <lvivier@xxxxxxxxxx> > > >> --- >> lib/powerpc/asm/hcall.h | 1 + >> lib/powerpc/asm/ppc_asm.h | 5 ++ >> lib/powerpc/asm/processor.h | 11 ++++ >> lib/powerpc/processor.c | 38 +++++++++++++ >> lib/powerpc/setup.c | 19 +++++++ >> lib/ppc64/asm-offsets.c | 42 ++++++++++++++ >> lib/ppc64/asm/processor.h | 1 + >> lib/ppc64/asm/ptrace.h | 24 ++++++++ >> powerpc/Makefile.common | 1 + >> powerpc/cstart64.S | 136 ++++++++++++++++++++++++++++++++++++++++++++ >> 10 files changed, 278 insertions(+) >> create mode 100644 lib/powerpc/asm/processor.h >> create mode 100644 lib/powerpc/processor.c >> create mode 100644 lib/ppc64/asm/processor.h >> create mode 100644 lib/ppc64/asm/ptrace.h >> >> diff --git a/lib/powerpc/asm/hcall.h b/lib/powerpc/asm/hcall.h >> index f6f9ea8..99bce79 100644 >> --- a/lib/powerpc/asm/hcall.h >> +++ b/lib/powerpc/asm/hcall.h >> @@ -20,6 +20,7 @@ >> #define H_PAGE_INIT 0x2c >> #define H_PUT_TERM_CHAR 0x58 >> #define H_RANDOM 0x300 >> +#define H_SET_MODE 0x31C >> >> #ifndef __ASSEMBLY__ >> /* >> diff --git a/lib/powerpc/asm/ppc_asm.h b/lib/powerpc/asm/ppc_asm.h >> index f18100e..39620a3 100644 >> --- a/lib/powerpc/asm/ppc_asm.h >> +++ b/lib/powerpc/asm/ppc_asm.h >> @@ -1,6 +1,11 @@ >> #ifndef _ASMPOWERPC_PPC_ASM_H >> #define _ASMPOWERPC_PPC_ASM_H >> >> +#include <asm/asm-offsets.h> >> + >> +#define SAVE_GPR(n, base) std n,GPR0+8*(n)(base) >> +#define REST_GPR(n, base) ld n,GPR0+8*(n)(base) >> + >> #define LOAD_REG_IMMEDIATE(reg,expr) \ >> lis reg,(expr)@highest; \ >> ori reg,reg,(expr)@higher; \ >> diff --git a/lib/powerpc/asm/processor.h b/lib/powerpc/asm/processor.h >> new file mode 100644 >> index 0000000..09692bd >> --- /dev/null >> +++ b/lib/powerpc/asm/processor.h >> @@ -0,0 +1,11 @@ >> +#ifndef _ASMPOWERPC_PROCESSOR_H_ >> +#define _ASMPOWERPC_PROCESSOR_H_ >> + >> +#include <asm/ptrace.h> >> + >> +#ifndef __ASSEMBLY__ >> +void handle_exception(int trap, void (*func)(struct pt_regs *, void *), void *); >> +void do_handle_exception(struct pt_regs *regs); >> +#endif /* __ASSEMBLY__ */ >> + >> +#endif /* _ASMPOWERPC_PROCESSOR_H_ */ >> diff --git a/lib/powerpc/processor.c b/lib/powerpc/processor.c >> new file mode 100644 >> index 0000000..a78bc3c >> --- /dev/null >> +++ b/lib/powerpc/processor.c >> @@ -0,0 +1,38 @@ >> +/* >> + * processor control and status function >> + */ >> + >> +#include <libcflat.h> >> +#include <asm/processor.h> >> +#include <asm/ptrace.h> >> + >> +static struct { >> + void (*func)(struct pt_regs *, void *data); >> + void *data; >> +} handlers[16]; >> + >> +void handle_exception(int trap, void (*func)(struct pt_regs *, void *), >> + void * data) >> +{ >> + trap >>= 8; > > I'm assuming trap starts out as the vector address (e.g. 0x300 for > DSI). Using trap >> 8 is going to break when we want to handle, say, > the SLB miss exceptions at 0x380 and 0x480, which we'll probably want > to do. > > I think there are a few exceptions with even smaller spacing, but we > might be able to ignore those for a while. In fact, the handler is registered on (trap >> 8) (for instance 0x3) but in regs->trap we have the full value (for instance 0x380), so we can have sub-handler for these particular values. > >> + if (trap < 16) { >> + handlers[trap].func = func; >> + handlers[trap].data = data; >> + } >> +} >> + >> +void do_handle_exception(struct pt_regs *regs) >> +{ >> + unsigned char v; >> + >> + v = regs->trap >> 8; >> + >> + if (v < 16 && handlers[v].func) { >> + handlers[v].func(regs, handlers[v].data); >> + return; >> + } >> + >> + printf("unhandled cpu exception 0x%lx\n", regs->trap); >> + abort(); >> +} >> diff --git a/lib/powerpc/setup.c b/lib/powerpc/setup.c >> index 0c0c882..afe7fbc 100644 >> --- a/lib/powerpc/setup.c >> +++ b/lib/powerpc/setup.c >> @@ -16,6 +16,8 @@ >> #include <alloc.h> >> #include <asm/setup.h> >> #include <asm/page.h> >> +#include <asm/ppc_asm.h> >> +#include <asm/hcall.h> >> >> extern unsigned long stacktop; >> extern void io_init(void); >> @@ -33,6 +35,10 @@ struct cpu_set_params { >> unsigned dcache_bytes; >> }; >> >> +#define EXCEPTION_STACK_SIZE (32*1024) /* 32kB */ >> + >> +static char exception_stack[NR_CPUS][EXCEPTION_STACK_SIZE]; >> + >> static void cpu_set(int fdtnode, u32 regval, void *info) >> { >> static bool read_common_info = false; >> @@ -46,6 +52,11 @@ static void cpu_set(int fdtnode, u32 regval, void *info) >> } >> cpus[cpu] = regval; >> >> + /* set exception stack address for this CPU (in SPGR0) */ >> + >> + asm volatile ("mtsprg0 %[addr]" :: >> + [addr] "r" (exception_stack + cpu + 1)); >> + >> if (!read_common_info) { >> const struct fdt_property *prop; >> u32 *data; >> @@ -76,6 +87,14 @@ static void cpu_init(void) >> assert(ret == 0); >> __icache_bytes = params.icache_bytes; >> __dcache_bytes = params.dcache_bytes; >> + >> + /* Interrupt Endianness */ >> + >> +#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ >> + hcall(H_SET_MODE, 1, 4, 0, 0); >> +#else >> + hcall(H_SET_MODE, 0, 4, 0, 0); >> +#endif >> } >> >> static void mem_init(phys_addr_t freemem_start) >> diff --git a/lib/ppc64/asm-offsets.c b/lib/ppc64/asm-offsets.c >> index 2d38a71..7843a20 100644 >> --- a/lib/ppc64/asm-offsets.c >> +++ b/lib/ppc64/asm-offsets.c >> @@ -5,8 +5,50 @@ >> */ >> #include <libcflat.h> >> #include <kbuild.h> >> +#include <asm/ptrace.h> >> >> int main(void) >> { >> + DEFINE(INT_FRAME_SIZE, STACK_INT_FRAME_SIZE); >> + >> + DEFINE(GPR0, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[0])); >> + DEFINE(GPR1, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[1])); >> + DEFINE(GPR2, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[2])); >> + DEFINE(GPR3, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[3])); >> + DEFINE(GPR4, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[4])); >> + DEFINE(GPR5, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[5])); >> + DEFINE(GPR6, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[6])); >> + DEFINE(GPR7, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[7])); >> + DEFINE(GPR8, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[8])); >> + DEFINE(GPR9, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[9])); >> + DEFINE(GPR10, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[10])); >> + DEFINE(GPR11, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[11])); >> + DEFINE(GPR12, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[12])); >> + DEFINE(GPR13, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[13])); >> + DEFINE(GPR14, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[14])); >> + DEFINE(GPR15, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[15])); >> + DEFINE(GPR16, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[16])); >> + DEFINE(GPR17, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[17])); >> + DEFINE(GPR18, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[18])); >> + DEFINE(GPR19, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[19])); >> + DEFINE(GPR20, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[20])); >> + DEFINE(GPR21, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[21])); >> + DEFINE(GPR22, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[22])); >> + DEFINE(GPR23, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[23])); >> + DEFINE(GPR24, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[24])); >> + DEFINE(GPR25, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[25])); >> + DEFINE(GPR26, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[26])); >> + DEFINE(GPR27, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[27])); >> + DEFINE(GPR28, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[28])); >> + DEFINE(GPR29, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[29])); >> + DEFINE(GPR30, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[30])); >> + DEFINE(GPR31, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[31])); >> + DEFINE(_NIP, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, nip)); >> + DEFINE(_MSR, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, msr)); >> + DEFINE(_CTR, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, ctr)); >> + DEFINE(_LINK, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, link)); >> + DEFINE(_XER, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, xer)); >> + DEFINE(_CCR, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, ccr)); >> + DEFINE(_TRAP, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, trap)); >> return 0; >> } >> diff --git a/lib/ppc64/asm/processor.h b/lib/ppc64/asm/processor.h >> new file mode 100644 >> index 0000000..066a51a >> --- /dev/null >> +++ b/lib/ppc64/asm/processor.h >> @@ -0,0 +1 @@ >> +#include "../../powerpc/asm/processor.h" >> diff --git a/lib/ppc64/asm/ptrace.h b/lib/ppc64/asm/ptrace.h >> new file mode 100644 >> index 0000000..076c9d9 >> --- /dev/null >> +++ b/lib/ppc64/asm/ptrace.h >> @@ -0,0 +1,24 @@ >> +#ifndef _ASMPPC64_PTRACE_H_ >> +#define _ASMPPC64_PTRACE_H_ >> + >> +#define KERNEL_REDZONE_SIZE 288 >> +#define STACK_FRAME_OVERHEAD 112 /* size of minimum stack frame */ >> + >> +#ifndef __ASSEMBLY__ >> +struct pt_regs { >> + unsigned long gpr[32]; >> + unsigned long nip; >> + unsigned long msr; >> + unsigned long ctr; >> + unsigned long link; >> + unsigned long xer; >> + unsigned long ccr; >> + unsigned long trap; >> +}; >> + >> +#define STACK_INT_FRAME_SIZE (sizeof(struct pt_regs) + \ >> + STACK_FRAME_OVERHEAD + KERNEL_REDZONE_SIZE) >> + >> +#endif /* __ASSEMBLY__ */ >> + >> +#endif /* _ASMPPC64_PTRACE_H_ */ >> diff --git a/powerpc/Makefile.common b/powerpc/Makefile.common >> index 424983e..ab2caf6 100644 >> --- a/powerpc/Makefile.common >> +++ b/powerpc/Makefile.common >> @@ -31,6 +31,7 @@ cflatobjs += lib/powerpc/io.o >> cflatobjs += lib/powerpc/hcall.o >> cflatobjs += lib/powerpc/setup.o >> cflatobjs += lib/powerpc/rtas.o >> +cflatobjs += lib/powerpc/processor.o >> >> FLATLIBS = $(libcflat) $(LIBFDT_archive) >> %.elf: CFLAGS += $(arch_CFLAGS) >> diff --git a/powerpc/cstart64.S b/powerpc/cstart64.S >> index c87e3d6..bc5aeac 100644 >> --- a/powerpc/cstart64.S >> +++ b/powerpc/cstart64.S >> @@ -9,6 +9,7 @@ >> #include <asm/hcall.h> >> #include <asm/ppc_asm.h> >> #include <asm/rtas.h> >> +#include <asm/ptrace.h> >> >> .section .init >> >> @@ -45,6 +46,34 @@ start: >> add r4, r4, r31 >> bl relocate >> >> + /* relocate vector table to base address 0x0 (MSR_IP = 0) */ >> + >> + /* source: r4, dest end: r5, destination: r6 */ >> + >> + LOAD_REG_ADDR(r4, __start_interrupts) >> + LOAD_REG_ADDR(r5, __end_interrupts) >> + sub r5,r5,r4 >> + li r6,0x100 >> + >> + sub r4,r4,r6 >> + add r5,r5,r6 >> + addi r6,r6,-8 >> +2: li r0,8 >> + mtctr r0 >> + /* copy a cache line size */ >> +3: addi r6,r6,8 >> + ldx r0,r6,r4 >> + stdx r0,0,r6 >> + bdnz 3b >> + dcbst 0,r6 >> + /* flush icache */ >> + sync >> + icbi 0,r6 >> + cmpld 0,r6,r5 >> + blt 2b >> + sync >> + isync >> + >> /* patch sc1 if needed */ >> bl hcall_have_broken_sc1 >> cmpwi r3, 0 >> @@ -105,3 +134,110 @@ rtas_return_loc: >> ld r0, 16(r1) >> mtlr r0 >> blr >> + >> +call_handler: >> + /* save context */ >> + >> + /* GPRs */ >> + >> + .irp i, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16 \ >> + 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31 >> + SAVE_GPR(\i, r1) >> + .endr >> + mfsprg1 r0 >> + std r0,GPR1(r1) >> + >> + /* lr, xer, ccr */ >> + >> + mflr r0 >> + std r0,_LINK(r1) >> + >> + mfxer r0 >> + std r0,_XER(r1) >> + >> + mfcr r0 >> + std r0,_CCR(r1) >> + >> + /* nip and msr */ >> + >> + mfsrr0 r0 >> + std r0, _NIP(r1) >> + >> + mfsrr1 r0 >> + std r0, _MSR(r1) >> + >> + /* FIXME: build stack frame */ >> + >> + /* call generic handler */ >> + >> + addi r3,r1,STACK_FRAME_OVERHEAD >> + bl do_handle_exception >> + >> + /* restore context */ >> + >> + ld r0,_CTR(r1) >> + mtctr r0 >> + >> + ld r0,_LINK(r1) >> + mtlr r0 >> + >> + ld r0,_XER(r1) >> + mtxer r0 >> + >> + ld r0,_CCR(r1) >> + mtcr r0 >> + >> + ld r0, _NIP(r1) >> + mtsrr0 r0 >> + >> + ld r0, _MSR(r1) >> + mtsrr1 r0 >> + >> + .irp i, 0, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16 \ >> + 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 1 > > The fact that '1' has to go last in this list is pretty subtle. I > wonder if it might be clearer to split that out explicitly rather than > including it in the .irp > >> + REST_GPR(\i, r1) If I have to resend the series, I will. > > >> + .endr >> + >> + rfid >> + b . >> + >> +.section .text.ex >> + >> +.macro VECTOR vec >> + . = \vec >> + >> + mtsprg1 r1 /* save r1 */ >> + mfsprg0 r1 /* get exception stack address */ >> + subi r1,r1, INT_FRAME_SIZE >> + >> + /* save r0 and ctr to call generic handler */ >> + >> + SAVE_GPR(0,r1) >> + >> + mfctr r0 >> + std r0,_CTR(r1) >> + >> + LOAD_REG_ADDR(r0, call_handler) >> + mtctr r0 >> + >> + li r0,\vec >> + std r0,_TRAP(r1) >> + >> + bctr >> +.endm >> + >> + . = 0x100 >> + .globl __start_interrupts >> +__start_interrupts: >> + >> +VECTOR(0x300) >> +VECTOR(0x400) >> +VECTOR(0x500) >> +VECTOR(0x600) >> +VECTOR(0x700) >> +VECTOR(0x800) >> +VECTOR(0x900) >> + >> + .align 7 >> + .globl __end_interrupts >> +__end_interrupts: >> -- >> 2.5.0 >> > > -- To unsubscribe from this list: send the line "unsubscribe kvm" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html