diff options
author | Shakeeb <shakeebbk@in.ibm.com> | 2016-09-01 06:24:44 -0500 |
---|---|---|
committer | AMIT J. TENDOLKAR <amit.tendolkar@in.ibm.com> | 2016-09-01 07:48:28 -0400 |
commit | 5e83bcb5cf9d400739cfb2beaab1a3173e8cafb2 (patch) | |
tree | b3d6cd12b5eb0c92404ae5ac0352bb360b38fa95 /src/import/chips/p9/procedures/ppe/pk/ppe42 | |
parent | 1008ef70a71fcfdec398ff30923d5025991c85f4 (diff) | |
download | talos-sbe-5e83bcb5cf9d400739cfb2beaab1a3173e8cafb2.tar.gz talos-sbe-5e83bcb5cf9d400739cfb2beaab1a3173e8cafb2.zip |
SBE move import`
Change-Id: I726951318cdb19fd445af2f7910e0d6872eff18c
Reviewed-on: http://ralgit01.raleigh.ibm.com/gerrit1/29086
Tested-by: Jenkins Server <pfd-jenkins+hostboot@us.ibm.com>
Reviewed-by: Sachin Gupta <sgupta2m@in.ibm.com>
Reviewed-by: AMIT J. TENDOLKAR <amit.tendolkar@in.ibm.com>
Diffstat (limited to 'src/import/chips/p9/procedures/ppe/pk/ppe42')
29 files changed, 6019 insertions, 0 deletions
diff --git a/src/import/chips/p9/procedures/ppe/pk/ppe42/Makefile b/src/import/chips/p9/procedures/ppe/pk/ppe42/Makefile new file mode 100644 index 00000000..60f8d7f8 --- /dev/null +++ b/src/import/chips/p9/procedures/ppe/pk/ppe42/Makefile @@ -0,0 +1,50 @@ +# IBM_PROLOG_BEGIN_TAG +# This is an automatically generated prolog. +# +# $Source: import/chips/p9/procedures/ppe/pk/ppe42/Makefile $ +# +# OpenPOWER sbe Project +# +# Contributors Listed Below - COPYRIGHT 2015,2016 +# [+] International Business Machines Corp. +# +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or +# implied. See the License for the specific language governing +# permissions and limitations under the License. +# +# IBM_PROLOG_END_TAG +# This Makefile is designed to be invoked with the -I argument set to +# the location of the "pk.mk" for the build + +include img_defs.mk +include pkppe42files.mk + +ifeq "$(PK_TIMER_SUPPORT)" "1" +PPE42_OBJECTS += ${PPE42-TIMER-C-SOURCES:.c=.o} ${PPE42-TIMER-S-SOURCES:.S=.o} +endif + +ifeq "$(PK_THREAD_SUPPORT)" "1" +PPE42_OBJECTS += ${PPE42-THREAD-C-SOURCES:.c=.o} ${PPE42-THREAD-S-SOURCES:.S=.o} +endif + +OBJS := $(addprefix $(OBJDIR)/, $(PPE42_OBJECTS)) + +all: $(OBJS) + +$(OBJS) $(OBJS:.o=.d): | $(OBJDIR) + +$(OBJDIR): + mkdir -p $(OBJDIR) + +ifneq ($(MAKECMDGOALS),clean) +include $(OBJS:.o=.d) +endif diff --git a/src/import/chips/p9/procedures/ppe/pk/ppe42/div64.S b/src/import/chips/p9/procedures/ppe/pk/ppe42/div64.S new file mode 100644 index 00000000..cf19fa6e --- /dev/null +++ b/src/import/chips/p9/procedures/ppe/pk/ppe42/div64.S @@ -0,0 +1,272 @@ +/* IBM_PROLOG_BEGIN_TAG */ +/* This is an automatically generated prolog. */ +/* */ +/* $Source: import/chips/p9/procedures/ppe/pk/ppe42/div64.S $ */ +/* */ +/* OpenPOWER sbe Project */ +/* */ +/* Contributors Listed Below - COPYRIGHT 2015,2016 */ +/* [+] International Business Machines Corp. */ +/* */ +/* */ +/* Licensed under the Apache License, Version 2.0 (the "License"); */ +/* you may not use this file except in compliance with the License. */ +/* You may obtain a copy of the License at */ +/* */ +/* http://www.apache.org/licenses/LICENSE-2.0 */ +/* */ +/* Unless required by applicable law or agreed to in writing, software */ +/* distributed under the License is distributed on an "AS IS" BASIS, */ +/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or */ +/* implied. See the License for the specific language governing */ +/* permissions and limitations under the License. */ +/* */ +/* IBM_PROLOG_END_TAG */ +//----------------------------------------------------------------------------- +// *! (C) Copyright International Business Machines Corp. 2014 +// *! All Rights Reserved -- Property of IBM +// *! *** IBM Confidential *** +//----------------------------------------------------------------------------- + +/// \file div64.S +/// \brief Unsigned 64/64 bit division +/// +/// This is IBM code, originally part of OS Open. The code has been slightly +/// modified from its original form, both to be compatible with PK and to +/// change the function prototype slightly. +/// +/// The code was provided by Matt Tyrlik in Raleigh. + +/* @#START#@ +** +** PSCN (Power Service and Control Network) +** Cage Controller OS Open Code +** +** (C) Copyright International Business Machines Corporation 2002 +** All Rights Reserved +** Licensed Material - Program Property of I B M +** Refer to copyright instructions: Form G120-2083 +** +** Module: +** div64.s +** +** Description: +** Divide 64 bit unsigned values on 32 bit CPU +** div64(uint64_t dividen, uint64_t divisor, +** uint64_t *quotient, uint64_t *remainder) +** +** Original source from: +** "The PowerPC Compiler Writer's Guide", pp62-65 by +** Steve Hoxey, Faraydon Karim, Bill Hay, Hank Warray, +** published by Warthman Associates, 240 Hamilton Avenue, +** Palo Alto, CA 94301, USA, 1996 for IBM. +** ISBN 0-9649654-0-2. +** +** This version checks for divisor equal to zero. +** +** Environment: +** OS Open (XCOFF) +** +** Linkage: +** AIX 4.3.3 +** +** @author +** Thomas Richter +** +** History: +** Date Author Description +** ----------------------------------------------------------------------------- +** 23-Sep-02 Richter Created +** +** @#END#@*/ + + .nolist +#include "pk.h" + .list + + .global_function __ppe42_udiv64 + + /* + ** Code comment notation: + ** msw = most-significant (high-order) word, i.e. bits 0..31 + ** lsw = least-significant (low-order) word, i.e. bits 32..63 + ** LZ = Leading Zeroes + ** SD = Significant Digits + ** + ** R3:R4 = Input parameter, dividend. + ** R5:R6 = Input parameter, divisor. + ** R7 = Output parameter, pointer to quotient. + ** R8 = Output parameter, pointer to remainder. + ** + ** Pointer arguments point to a uint64_t. + ** + ** Division is achieved using a shift/rotate/substract algorithsm + ** described above. + ** The registers are used as follows: + ** R3:R4 = dividend (upper 32bits:lower 32bits) + ** R5:R6 = divisor (upper 32bits:lower 32bits) + ** + ** R7:R8 = temporary 64 bit register (upper 32bits:lower 32bits) + ** count the number of leading 0s in the dividend + ** + ** Here is the description from the book. The dividend is placed + ** in the low order part of a 4 (32bit) register sequence named + ** tmp-high:tmp-low:dividend-high:dividend:low or tmp:dvd for short. + ** + ** Each iteration includes the following steps: + ** 1. Shift tmp:dvd by one bit to the left. + ** 2. Subtract the divisor from tmp. This is a 64 bit operation. + ** 3. If result is greater than or equal, place result in tmp and + ** set the low order bit of dividend + ** 4. If result is negative, do not modify tmp and + ** clear the low order bit of dividend + ** 5. If the number of iterations is less than the width of the + ** dividend, goto step 1. + ** + ** Now the algorithm can be improved by reducing the number of + ** iterations to be executed. + ** 1. Calculate the leading zeroes of the dividend. + ** 2. Calculate the leading zeroes of the divisor. + ** 3. Calculate the significant ones of the dividend. + ** 4. Calculate the significant ones of the divisor. + ** + ** Initial tmp := dvd >> (dvd.SD - dvs.SD) + ** Initial dvd := dvd << (dvd.LZ + dvs.SD) + ** Loops: dvd.SD - dvs.SD. + ** + ** Warning: Special care must be taken if dvd.LZ == dvs.LZ. The code + ** below does so by reducing the number of dvs.SD by one. This leads + ** to the loop being executed 1 more time than really necessary, + ** but avoids to check for the case when dvd.LZ == dvs.LZ. + ** This case (dvd.LZ == dvs.LZ) only checks for the number of leading + ** zeroes, but does not check if dividend is really greater than the + ** divisor. + ** Consider 16/17, both have an LZ value of 59. The code sets dvs.LZ + ** 60. This resutls in dvs.SD to 4, thus one iteration after which + ** tmp is the remainder 16. + */ + +__ppe42_udiv64: // PK + + /* push R30 & R31 onto the stack */ + stwu r1, -16(r1) + stvd r30, 8(r1) + + /* Save result pointers on volatile spare registers */ + ori r31, r8, 0 /* Save remainder address */ + ori r30, r7, 0 /* Save quotient address */ + + /* count the number of leading 0s in the dividend */ + cmpwi cr0, r3, 0 /* dvd.msw == 0? */ + cntlzw r0, r3 /* R0 = dvd.msw.LZ */ + cntlzw r9, r4 /* R9 = dvd.lsw.LZ */ + bne cr0, lab1 /* if(dvd.msw == 0) dvd.LZ = dvd.msw.LZ */ + addi r0, r9, 32 /* dvd.LZ = dvd.lsw.LZ + 32 */ +lab1: + /* count the number of leading 0s in the divisor */ + cmpwi cr0, r5, 0 /* dvd.msw == 0? */ + cntlzw r9, r5 /* R9 = dvs.msw.LZ */ + cntlzw r10, r6 /* R10 = dvs.lsw.LZ */ + bne cr0, lab2 /* if(dvs.msw == 0) dvs.LZ = dvs.msw.LZ */ + cmpwi cr0, r6, 0 /* dvd.lsw == 0? */ + beq cr0, lab10 /* dvs.msw == 0 */ + addi r9, r10, 32 /* dvs.LZ = dvs.lsw.LZ + 32 */ + +lab2: + /* Determine shift amounts to minimize the number of iterations */ + cmpw cr0, r0, r9 /* Compare dvd.LZ to dvs.LZ */ + subfic r10, r0, 64 /* R10 = dvd.SD */ + bgt cr0, lab9 /* if(dvs > dvd) quotient = 0 */ + addi r9, r9, 1 /* See comment above. ++dvs.LZ (or --dvs.SD) */ + subfic r9, r9, 64 /* R9 = dvs.SD */ + add r0, r0, r9 /* (dvd.LZ + dvs.SD) = left shift of dvd for */ + /* initial dvd */ + subf r9, r9, r10 /* (dvd.SD - dvs.SD) = right shift of dvd for */ + /* initial tmp */ + mtctr r9 /* Number of iterations = dvd.SD - dvs.SD */ + + /* R7:R8 = R3:R4 >> R9 */ + cmpwi cr0, r9, 32 /* compare R9 to 32 */ + addi r7, r9, -32 + blt cr0, lab3 /* if(R9 < 32) jump to lab3 */ + srw r8, r3, r7 /* tmp.lsw = dvd.msw >> (R9 - 32) */ + addi r7, r0, 0 /* tmp.msw = 0 */ + b lab4 + +lab3: + srw r8, r4, r9 /* R8 = dvd.lsw >> R9 */ + subfic r7, r9, 32 + slw r7,r3,r7 /* R7 = dvd.msw << 32 - R9 */ + or r8, r8,r7 /* tmp.lsw = R8 | R7 */ + srw r7,r3,r9 /* tmp.msw = dvd.msw >> R9 */ +lab4: + /* R3:R4 = R3:R4 << R0 */ + cmpwi cr0, r0, 32 /* Compare R0 to 32 */ + addic r9, r0, -32 + blt cr0, lab5 /* if(R0 < 32) jump to lab5 */ + slw r3, r4, r9 /* dvd.msw = dvd.lsw << R9 */ + addi r4, r0, 0 /* dvd.lsw = 0 */ + b lab6 + +lab5: + slw r3, r3, r0 /* r3 = dvd.msw << r0 */ + subfic r9, r0, 32 + srw r9, r4, r9 /* r9 = dvd.lsw >> 32 - r0 */ + or r3, r3, r9 /* dvd.msw = r3 | r9 */ + slw r4, r4, r0 /* dvd.lsw = dvd.lsw << r0 */ +lab6: + /* Restoring division shift and subtract loop */ + addi r10, r0, -1 /* r10 = -1 */ + addic r7, r7, 0 /* Clear carry bit before loop starts */ +lab7: + /* + ** tmp:dvd is considered one large register + ** each portion is shifted left 1 bit by adding it to itself + ** adde sums the carry from the previous and creates a new carry + */ + adde r4, r4, r4 /* Shift dvd.lsw left 1 bit */ + adde r3, r3, r3 /* Shift dvd.msw to left 1 bit */ + adde r8, r8, r8 /* Shift tmp.lsw to left 1 bit */ + adde r7, r7, r7 /* Shift tmp.msw to left 1 bit */ + subfc r0, r6, r8 /* tmp.lsw - dvs.lsw */ + subfe. r9, r5, r7 /* tmp.msw - dvs.msw */ + blt cr0, lab8 /* if(result < 0) clear carry bit */ + or r8, r0, r0 /* Move lsw */ + or r7, r9, r9 /* Move msw */ + addic r0, r10, 1 /* Set carry bit */ + +lab8: + bdnz lab7 + + /* Write quotient and remainder */ + adde r4, r4, r4 /* quo.lsw (lsb = CA) */ + adde r3, r3, r3 /* quo.msw (lsb from lsw) */ + stw r4, 4(r30) + stw r3, 0(r30) + stw r8, 4(r31) /* rem.lsw */ + stw r7, 0(r31) /* rem.msw */ + b lab11 + +lab9: + /* Qoutient is 0, divisor > dividend */ + addi r0, r0, 0 + stw r3, 0(r31) /* Store remainder */ + stw r4, 4(r31) + stw r0, 0(r30) /* Set quotient to zero */ + stw r0, 4(r30) + b lab11 + +lab10: + /* Divisor is 0 */ + addi r0, r0, -1 + stw r0, 0(r31) /* Set remainder to zero */ + stw r0, 4(r31) + stw r0, 0(r30) /* Set quotient to zero */ + stw r0, 4(r30) + +lab11: + //pop r30 & r31 from stack + lvd r30, 8(r1) + lwz r1, 0(r1) + blr + .epilogue __ppe42_udiv64 diff --git a/src/import/chips/p9/procedures/ppe/pk/ppe42/eabi.c b/src/import/chips/p9/procedures/ppe/pk/ppe42/eabi.c new file mode 100644 index 00000000..140cc2be --- /dev/null +++ b/src/import/chips/p9/procedures/ppe/pk/ppe42/eabi.c @@ -0,0 +1,46 @@ +/* IBM_PROLOG_BEGIN_TAG */ +/* This is an automatically generated prolog. */ +/* */ +/* $Source: import/chips/p9/procedures/ppe/pk/ppe42/eabi.c $ */ +/* */ +/* OpenPOWER sbe Project */ +/* */ +/* Contributors Listed Below - COPYRIGHT 2016 */ +/* [+] International Business Machines Corp. */ +/* */ +/* */ +/* Licensed under the Apache License, Version 2.0 (the "License"); */ +/* you may not use this file except in compliance with the License. */ +/* You may obtain a copy of the License at */ +/* */ +/* http://www.apache.org/licenses/LICENSE-2.0 */ +/* */ +/* Unless required by applicable law or agreed to in writing, software */ +/* distributed under the License is distributed on an "AS IS" BASIS, */ +/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or */ +/* implied. See the License for the specific language governing */ +/* permissions and limitations under the License. */ +/* */ +/* IBM_PROLOG_END_TAG */ +// assuming link script instructs the c++ compiler to put +// ctor_start_address and ctor_end_address in .rodata + +//extern void (*ctor_start_address)() __attribute__ ((section (".rodata"))); +//extern void (*ctor_end_address)() __attribute__((section(".rodata"))); +#ifdef __cplusplus + extern "C" +#endif +__attribute__((weak)) void __eabi() +{ + // This is the default eabi and can be overridden. + // eabi environment is already set up by the PK kernel + // Call static C++ constructors if you use C++ global/static objects + + //void(**ctors)() = &ctor_start_address; + //while(ctors != &ctor_end_address) + //{ + // (*ctors)(); + // ctors++; + //} +} + diff --git a/src/import/chips/p9/procedures/ppe/pk/ppe42/endian.h b/src/import/chips/p9/procedures/ppe/pk/ppe42/endian.h new file mode 100644 index 00000000..dade05cf --- /dev/null +++ b/src/import/chips/p9/procedures/ppe/pk/ppe42/endian.h @@ -0,0 +1,48 @@ +/* IBM_PROLOG_BEGIN_TAG */ +/* This is an automatically generated prolog. */ +/* */ +/* $Source: import/chips/p9/procedures/ppe/pk/ppe42/endian.h $ */ +/* */ +/* OpenPOWER sbe Project */ +/* */ +/* Contributors Listed Below - COPYRIGHT 2016 */ +/* [+] International Business Machines Corp. */ +/* */ +/* */ +/* Licensed under the Apache License, Version 2.0 (the "License"); */ +/* you may not use this file except in compliance with the License. */ +/* You may obtain a copy of the License at */ +/* */ +/* http://www.apache.org/licenses/LICENSE-2.0 */ +/* */ +/* Unless required by applicable law or agreed to in writing, software */ +/* distributed under the License is distributed on an "AS IS" BASIS, */ +/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or */ +/* implied. See the License for the specific language governing */ +/* permissions and limitations under the License. */ +/* */ +/* IBM_PROLOG_END_TAG */ +#ifndef __ENDIAN_H__ +#define __ENDIAN_H__ + +#ifndef __PPE42__ + #include_next <endian.h> +#else + // Currently not provided with PPE42 native compiler as PPE42 + // is compiled with no clib support. + // endian.h provides: + // htobe16, + // htole16, + // be16toh, + // le16toh, + // htobe32, + // htole32, + // be32toh, + // le32toh, + // htobe64, + // htole64, + // be64toh, + // le64toh +#endif + +#endif diff --git a/src/import/chips/p9/procedures/ppe/pk/ppe42/math.c b/src/import/chips/p9/procedures/ppe/pk/ppe42/math.c new file mode 100644 index 00000000..1cddc624 --- /dev/null +++ b/src/import/chips/p9/procedures/ppe/pk/ppe42/math.c @@ -0,0 +1,206 @@ +/* IBM_PROLOG_BEGIN_TAG */ +/* This is an automatically generated prolog. */ +/* */ +/* $Source: import/chips/p9/procedures/ppe/pk/ppe42/math.c $ */ +/* */ +/* OpenPOWER sbe Project */ +/* */ +/* Contributors Listed Below - COPYRIGHT 2016 */ +/* [+] International Business Machines Corp. */ +/* */ +/* */ +/* Licensed under the Apache License, Version 2.0 (the "License"); */ +/* you may not use this file except in compliance with the License. */ +/* You may obtain a copy of the License at */ +/* */ +/* http://www.apache.org/licenses/LICENSE-2.0 */ +/* */ +/* Unless required by applicable law or agreed to in writing, software */ +/* distributed under the License is distributed on an "AS IS" BASIS, */ +/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or */ +/* implied. See the License for the specific language governing */ +/* permissions and limitations under the License. */ +/* */ +/* IBM_PROLOG_END_TAG */ +#include "ppe42math.h" + +#ifdef __cplusplus +extern "C" +{ +#endif + +unsigned long +udivmodsi4(unsigned long num, unsigned long den, int modwanted) +{ + unsigned long bit = 1; + unsigned long res = 0; + + while (den < num && bit && !(den & (1L << 31))) + { + den <<= 1; + bit <<= 1; + } + + while (bit) + { + if (num >= den) + { + num -= den; + res |= bit; + } + + bit >>= 1; + den >>= 1; + } + + if (modwanted) + { + return num; + } + + return res; +} + +// 64 bit divide. Note: TBD add when needed +//unsigned long long __udivdi3(unsigned long long a, unsigned long long b) +//{ +// unsigned long long c = 0; +// return c; +//} + +// 32 bit unsigned integer divide +unsigned long __udivsi3(unsigned long a, unsigned long b) +{ + return udivmodsi4(a, b, 0); +} + +// 32 bit modulus +unsigned long __umodsi3(unsigned long a, unsigned long b) +{ + return udivmodsi4(a, b, 1); +} + +// 32 bit signed divide +int __divsi3(int _a, int _b) +{ + register unsigned long neg = 0; + + if(_a & 0x80000000) + { + neg = !neg; + _a = (~_a) + 1; + } + + if(_b & 0x80000000) + { + _b = (~_b) + 1; + neg = !neg; + } + + int c = __udivsi3((unsigned long)_a, (unsigned long)_b); + + if(neg) + { + c = (~c) + 1; + } + + return c; +} + +// 32 bit unsigned mutiply +unsigned long __umulsi3(unsigned long _a, unsigned long _b) +{ + register unsigned long a = _a; + register unsigned long b = _b; + register unsigned long c; + register unsigned long d; + asm volatile("mullhwu %0, %1, %2" : "=r"(c) : "r"(a), "r"(b)); + d = c; + c = a >> 16; + asm volatile("mullhwu %0, %1, %2" : "=r"(c) : "r"(c), "r"(b)); + d += (c << 16); + c = b >> 16; + asm volatile("mullhwu %0, %1, %2" : "=r"(c) : "r"(c), "r"(a)); + d += (c << 16); + return d; +} + +// 32 bit signed multiply +unsigned int __mulsi3(unsigned int _a, unsigned int _b) +{ + register unsigned long neg = 0; + register unsigned long a = _a; + register unsigned long b = _b; + register unsigned long c; + register unsigned long d; + + if(a & 0x80000000) + { + a = (~a) + 1; + neg = !neg; + } + + if(b & 0x80000000) + { + b = (~b) + 1; + neg = !neg; + } + + asm volatile("mullhwu %0, %1, %2" : "=r"(c) : "r"(a), "r"(b)); + d = c; + c = a >> 16; + asm volatile("mullhwu %0, %1, %2" : "=r"(c) : "r"(c), "r"(b)); + d += (c << 16); + c = b >> 16; + asm volatile("mullhwu %0, %1, %2" : "=r"(c) : "r"(c), "r"(a)); + d += (c << 16); + + if(neg) + { + d = (~d) + 1; + } + + return d; +} + +// 64 bit signed multiply +unsigned long long __muldi3(unsigned long long _a, unsigned long long _b) +{ + unsigned long long sum = 0; + + while(_a) + { + if(_a & 1) + { + sum += _b; + } + + _a >>= 1; + _b <<= 1; + } + + return sum; +} + +//float __mulsf3(float _a , float _b) +//{ +// // floating point math +// return 0.0; +//} + +//float __subsf3(float _a, float _b) +//{ +// // floating point sub +// return 0.0; +//} + +//unsigned long __fixsfsi (float _a) +//{ +// // float to int +// return 0; +//} + +#ifdef __cplusplus +}; +#endif + diff --git a/src/import/chips/p9/procedures/ppe/pk/ppe42/pk_panic_codes.h b/src/import/chips/p9/procedures/ppe/pk/ppe42/pk_panic_codes.h new file mode 100644 index 00000000..0e079657 --- /dev/null +++ b/src/import/chips/p9/procedures/ppe/pk/ppe42/pk_panic_codes.h @@ -0,0 +1,340 @@ +/* IBM_PROLOG_BEGIN_TAG */ +/* This is an automatically generated prolog. */ +/* */ +/* $Source: import/chips/p9/procedures/ppe/pk/ppe42/pk_panic_codes.h $ */ +/* */ +/* OpenPOWER sbe Project */ +/* */ +/* Contributors Listed Below - COPYRIGHT 2016 */ +/* [+] International Business Machines Corp. */ +/* */ +/* */ +/* Licensed under the Apache License, Version 2.0 (the "License"); */ +/* you may not use this file except in compliance with the License. */ +/* You may obtain a copy of the License at */ +/* */ +/* http://www.apache.org/licenses/LICENSE-2.0 */ +/* */ +/* Unless required by applicable law or agreed to in writing, software */ +/* distributed under the License is distributed on an "AS IS" BASIS, */ +/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or */ +/* implied. See the License for the specific language governing */ +/* permissions and limitations under the License. */ +/* */ +/* IBM_PROLOG_END_TAG */ +#ifndef __PK_PANIC_CODES_H__ +#define __PK_PANIC_CODES_H__ + +// On PPE42, PANIC codes are stored as part of the trap word instruction. +// tw 31, RA, RB Where RA and RB would used to encode the trap code. +// There are 16 valid gprs on PP42, so this gives 256 possible trap codes. +// The trap code is defined as a two byte code defined as 0xYYZZ where YY +// is encoded into the RA field and ZZ is incoded into the RB field +// YY and ZZ are limited to the values: +// 00,01,02,03,04,05,06,07,08,09,0a,0d,1c,1d,1e,1f (valid gpr ids) +// +// To add a new panic code, select an unused values and rename it. +// This enum contains all the valid values that can be used. Using a +// panic code not in this list will result in a compiler/assembler error. +#ifndef __ASSEMBLER__ + +typedef enum +{ + PPE42_MACHINE_CHECK_PANIC = 0x0001, + PPE42_DATA_STORAGE_PANIC = 0x0002, + PPE42_INSTRUCTION_STORAGE_PANIC = 0x0003, + PPE42_DATA_ALIGNMENT_PANIC = 0x0004, + PK_BOOT_VECTORS_NOT_ALIGNED = 0x0005, + PK_DEFAULT_IRQ_HANDLER = 0x0006, + PK_DEFAULT_SPECIAL_HANDLER = 0x0007, + PPE42_PHANTOM_INTERRUPT = 0x0008, + PPE42_ILLEGAL_INSTRUCTION = 0x0009, + PK_UNUSED_000a = 0x000a, + PK_UNUSED_000d = 0x000d, + PK_UNUSED_001c = 0x001c, + PK_UNUSED_001d = 0x001d, + PK_UNUSED_001e = 0x001e, + PK_UNUSED_001f = 0x001f, + + // API return codes + PK_ILLEGAL_CONTEXT_THREAD_CONTEXT = 0x0100, + PK_ILLEGAL_CONTEXT_INTERRUPT_CONTEXT = 0x0101, + PK_ILLEGAL_CONTEXT_THREAD = 0x0102, + PK_ILLEGAL_CONTEXT_TIMER = 0x0103, + PK_INVALID_THREAD_AT_RESUME1 = 0x0104, + PK_INVALID_THREAD_AT_RESUME2 = 0x0105, + PK_INVALID_THREAD_AT_SUSPEND1 = 0x0106, + PK_INVALID_THREAD_AT_SUSPEND2 = 0x0107, + PK_INVALID_THREAD_AT_DELETE = 0x0108, + PK_INVALID_THREAD_AT_INFO = 0x0109, + PK_INVALID_THREAD_AT_CHANGE = 0x010a, + PK_INVALID_THREAD_AT_SWAP1 = 0x010d, + PK_INVALID_THREAD_AT_SWAP2 = 0x011c, + PK_INVALID_THREAD_AT_CREATE = 0x011d, + PK_INVALID_SEMAPHORE_AT_POST = 0x011e, + PK_INVALID_SEMAPHORE_AT_PEND = 0x011f, + PK_INVALID_SEMAPHORE_AT_RELEASE = 0x0200, + PK_INVALID_SEMAPHORE_AT_INFO = 0x0201, + PK_INVALID_SEMAPHORE_AT_CREATE = 0x0202, + PK_INVALID_TIMER_AT_SCHEDULE = 0x0203, + PK_INVALID_TIMER_AT_CANCEL = 0x0204, + PK_INVALID_TIMER_AT_INFO = 0x0205, + PK_INVALID_TIMER_AT_CREATE = 0x0206, + PK_INVALID_ARGUMENT_IRQ_SETUP = 0x0207, + PK_INVALID_ARGUMENT_IRQ_HANDLER = 0x0208, + PK_INVALID_ARGUMENT_INTERRUPT = 0x0209, + PK_INVALID_ARGUMENT_CONTEXT_SET = 0x020a, + PK_INVALID_ARGUMENT_CONTEXT_GET = 0x020d, + PK_INVALID_ARGUMENT_FIT = 0x021c, + PK_INVALID_ARGUMENT_WATCHDOG = 0x021d, + PK_INVALID_ARGUMENT_INIT = 0x021e, + PK_INVALID_ARGUMENT_SEMAPHORE = 0x021f, + PK_INVALID_ARGUMENT_THREAD_CHANGE = 0x0300, + PK_INVALID_ARGUMENT_THREAD_PRIORITY = 0x0301, + PK_INVALID_ARGUMENT_THREAD1 = 0x0302, + PK_INVALID_ARGUMENT_THREAD2 = 0x0303, + PK_INVALID_ARGUMENT_THREAD3 = 0x0304, + PK_STACK_OVERFLOW = 0x0305, + PK_TIMER_ACTIVE = 0x0306, + PK_TIMER_NOT_ACTIVE = 0x0307, + PK_PRIORITY_IN_USE_AT_RESUME = 0x0308, + PK_PRIORITY_IN_USE_AT_CHANGE = 0x0309, + PK_PRIORITY_IN_USE_AT_SWAP = 0x030a, + PK_SEMAPHORE_OVERFLOW = 0x030d, + PK_SEMAPHORE_PEND_NO_WAIT = 0x031c, + PK_SEMAPHORE_PEND_TIMED_OUT = 0x031d, + PK_SEMAPHORE_PEND_WOULD_BLOCK = 0x031e, + PK_INVALID_DEQUE_SENTINEL = 0x031f, + PK_INVALID_DEQUE_ELEMENT = 0x0400, + PK_INVALID_OBJECT = 0x0401, + + // PK Kernel panics + PK_NO_TIMER_SUPPORT = 0x0402, + PK_START_THREADS_RETURNED = 0x0403, + PK_UNIMPLEMENTED = 0x0404, + PK_SCHEDULING_INVARIANT = 0x0405, + PK_TIMER_HANDLER_INVARIANT = 0x0406, + PK_THREAD_TIMEOUT_STATE = 0x0407, + + // PK + PK_UNUSED_0408 = 0x0408, + PK_UNUSED_0409 = 0x0409, + PK_UNUSED_040a = 0x040a, + PK_UNUSED_040d = 0x040d, + PK_UNUSED_041c = 0x041c, + PK_UNUSED_041d = 0x041d, + PK_UNUSED_041e = 0x041e, + PK_UNUSED_041f = 0x041f, + + // Sync panic codes + SYNC_INVALID_OBJECT = 0x0500, + SYNC_INVALID_ARGUMENT = 0x0501, + SYNC_BARRIER_PEND_TIMED_OUT = 0x0502, + SYNC_BARRIER_OVERFLOW = 0x0503, + SYNC_BARRIER_UNDERFLOW = 0x0504, + SYNC_BARRIER_INVARIANT = 0x0505, + SYNC_SHARED_UNDERFLOW = 0x0506, + + OCCHW_INSTANCE_MISMATCH = 0x0507, + OCCHW_IRQ_ROUTING_ERROR = 0x0508, + OCCHW_XIR_INVALID_POINTER = 0x0509, + OCCHW_XIR_INVALID_GPE = 0x050a, + + PK_UNUSED_050d = 0x050d, + PK_UNUSED_051c = 0x051c, + PK_UNUSED_051d = 0x051d, + PK_UNUSED_051e = 0x051e, + PK_UNUSED_051f = 0x051f, + + PK_UNUSED_0600 = 0x0600, + PK_UNUSED_0601 = 0x0601, + PK_UNUSED_0602 = 0x0602, + PK_UNUSED_0603 = 0x0603, + PK_UNUSED_0604 = 0x0604, + PK_UNUSED_0605 = 0x0605, + PK_UNUSED_0606 = 0x0606, + PK_UNUSED_0607 = 0x0607, + PK_UNUSED_0608 = 0x0608, + PK_UNUSED_0609 = 0x0609, + PK_UNUSED_060a = 0x060a, + PK_UNUSED_060d = 0x060d, + PK_UNUSED_061c = 0x061c, + PK_UNUSED_061d = 0x061d, + PK_UNUSED_061e = 0x061e, + PK_UNUSED_061f = 0x061f, + + PK_UNUSED_0700 = 0x0700, + PK_UNUSED_0701 = 0x0701, + PK_UNUSED_0702 = 0x0702, + PK_UNUSED_0703 = 0x0703, + PK_UNUSED_0704 = 0x0704, + PK_UNUSED_0705 = 0x0705, + PK_UNUSED_0706 = 0x0706, + PK_UNUSED_0707 = 0x0707, + PK_UNUSED_0708 = 0x0708, + PK_UNUSED_0709 = 0x0709, + PK_UNUSED_070a = 0x070a, + PK_UNUSED_070d = 0x070d, + PK_UNUSED_071c = 0x071c, + PK_UNUSED_071d = 0x071d, + PK_UNUSED_071e = 0x071e, + PK_UNUSED_071f = 0x071f, + + PK_UNUSED_0800 = 0x0800, + PK_UNUSED_0801 = 0x0801, + PK_UNUSED_0802 = 0x0802, + PK_UNUSED_0803 = 0x0803, + PK_UNUSED_0804 = 0x0804, + PK_UNUSED_0805 = 0x0805, + PK_UNUSED_0806 = 0x0806, + PK_UNUSED_0807 = 0x0807, + PK_UNUSED_0808 = 0x0808, + PK_UNUSED_0809 = 0x0809, + PK_UNUSED_080a = 0x080a, + PK_UNUSED_080d = 0x080d, + PK_UNUSED_081c = 0x081c, + PK_UNUSED_081d = 0x081d, + PK_UNUSED_081e = 0x081e, + PK_UNUSED_081f = 0x081f, + + PK_UNUSED_0900 = 0x0900, + PK_UNUSED_0901 = 0x0901, + PK_UNUSED_0902 = 0x0902, + PK_UNUSED_0903 = 0x0903, + PK_UNUSED_0904 = 0x0904, + PK_UNUSED_0905 = 0x0905, + PK_UNUSED_0906 = 0x0906, + PK_UNUSED_0907 = 0x0907, + PK_UNUSED_0908 = 0x0908, + PK_UNUSED_0909 = 0x0909, + PK_UNUSED_090a = 0x090a, + PK_UNUSED_090d = 0x090d, + PK_UNUSED_091c = 0x091c, + PK_UNUSED_091d = 0x091d, + PK_UNUSED_091e = 0x091e, + PK_UNUSED_091f = 0x091f, + + PK_UNUSED_0a00 = 0x0a00, + PK_UNUSED_0a01 = 0x0a01, + PK_UNUSED_0a02 = 0x0a02, + PK_UNUSED_0a03 = 0x0a03, + PK_UNUSED_0a04 = 0x0a04, + PK_UNUSED_0a05 = 0x0a05, + PK_UNUSED_0a06 = 0x0a06, + PK_UNUSED_0a07 = 0x0a07, + PK_UNUSED_0a08 = 0x0a08, + PK_UNUSED_0a09 = 0x0a09, + PK_UNUSED_0a0a = 0x0a0a, + PK_UNUSED_0a0d = 0x0a0d, + PK_UNUSED_0a1c = 0x0a1c, + PK_UNUSED_0a1d = 0x0a1d, + PK_UNUSED_0a1e = 0x0a1e, + PK_UNUSED_0a1f = 0x0a1f, + + PK_UNUSED_0d00 = 0x0d00, + PK_UNUSED_0d01 = 0x0d01, + PK_UNUSED_0d02 = 0x0d02, + PK_UNUSED_0d03 = 0x0d03, + PK_UNUSED_0d04 = 0x0d04, + PK_UNUSED_0d05 = 0x0d05, + PK_UNUSED_0d06 = 0x0d06, + PK_UNUSED_0d07 = 0x0d07, + PK_UNUSED_0d08 = 0x0d08, + PK_UNUSED_0d09 = 0x0d09, + PK_UNUSED_0d0a = 0x0d0a, + PK_UNUSED_0d0d = 0x0d0d, + PK_UNUSED_0d1c = 0x0d1c, + PK_UNUSED_0d1d = 0x0d1d, + PK_UNUSED_0d1e = 0x0d1e, + PK_UNUSED_0d1f = 0x0d1f, + + // The following are reserved for instance specific use. + // Each engine must define its own XXX_panic_codes.h + // Where XXX = SBE, CME, GPE0, GPE1, PGPE, SGPE + // They are listed here to show the valid trap values that + // can be used. + + //_UNUSED_1c00 = 0x1c00, + //_UNUSED_1c01 = 0x1c01, + //_UNUSED_1c02 = 0x1c02, + //_UNUSED_1c03 = 0x1c03, + //_UNUSED_1c04 = 0x1c04, + //_UNUSED_1c05 = 0x1c05, + //_UNUSED_1c06 = 0x1c06, + //_UNUSED_1c07 = 0x1c07, + //_UNUSED_1c08 = 0x1c08, + //_UNUSED_1c09 = 0x1c09, + //_UNUSED_1c0a = 0x1c0a, + //_UNUSED_1c0d = 0x1c0d, + //_UNUSED_1c1c = 0x1c1c, + //_UNUSED_1c1d = 0x1c1d, + //_UNUSED_1c1e = 0x1c1e, + //_UNUSED_1c1f = 0x1c1f, + + //_UNUSED_1d00 = 0x1d00, + //_UNUSED_1d01 = 0x1d01, + //_UNUSED_1d02 = 0x1d02, + //_UNUSED_1d03 = 0x1d03, + //_UNUSED_1d04 = 0x1d04, + //_UNUSED_1d05 = 0x1d05, + //_UNUSED_1d06 = 0x1d06, + //_UNUSED_1d07 = 0x1d07, + //_UNUSED_1d08 = 0x1d08, + //_UNUSED_1d09 = 0x1d09, + //_UNUSED_1d0a = 0x1d0a, + //_UNUSED_1d0d = 0x1d0d, + //_UNUSED_1d1c = 0x1d1c, + //_UNUSED_1d1d = 0x1d1d, + //_UNUSED_1d1e = 0x1d1e, + //_UNUSED_1d1f = 0x1d1f, + + //_UNUSED_1e00 = 0x1e00, + //_UNUSED_1e01 = 0x1e01, + //_UNUSED_1e02 = 0x1e02, + //_UNUSED_1e03 = 0x1e03, + //_UNUSED_1e04 = 0x1e04, + //_UNUSED_1e05 = 0x1e05, + //_UNUSED_1e06 = 0x1e06, + //_UNUSED_1e07 = 0x1e07, + //_UNUSED_1e08 = 0x1e08, + //_UNUSED_1e09 = 0x1e09, + //_UNUSED_1e0a = 0x1e0a, + //_UNUSED_1e0d = 0x1e0d, + //_UNUSED_1e1c = 0x1e1c, + //_UNUSED_1e1d = 0x1e1d, + //_UNUSED_1e1e = 0x1e1e, + //_UNUSED_1e1f = 0x1e1f, + + //_UNUSED_1f00 = 0x1f00, + //_UNUSED_1f01 = 0x1f01, + //_UNUSED_1f02 = 0x1f02, + //_UNUSED_1f03 = 0x1f03, + //_UNUSED_1f04 = 0x1f04, + //_UNUSED_1f05 = 0x1f05, + //_UNUSED_1f06 = 0x1f06, + //_UNUSED_1f07 = 0x1f07, + //_UNUSED_1f08 = 0x1f08, + //_UNUSED_1f09 = 0x1f09, + //_UNUSED_1f0a = 0x1f0a, + //_UNUSED_1f0d = 0x1f0d, + //_UNUSED_1f1c = 0x1f1c, + //_UNUSED_1f1d = 0x1f1d, + //_UNUSED_1f1e = 0x1f1e, + //_UNUSED_1f1f = 0x1f1f +} pkPanicCode_t; + +#else + +/// Assembler specific panic codes +#define PPE42_MACHINE_CHECK_PANIC 0x0001 +#define PPE42_DATA_STORAGE_PANIC 0x0002 +#define PPE42_INSTRUCTION_STORAGE_PANIC 0x0003 +#define PPE42_DATA_ALIGNMENT_PANIC 0x0004 + +#define PK_BOOT_VECTORS_NOT_ALIGNED 0x0005 +#define PPE42_ILLEGAL_INSTRUCTION 0x001c + + + +#endif // __ASSEMBLER__ +#endif diff --git a/src/import/chips/p9/procedures/ppe/pk/ppe42/pk_port_types.h b/src/import/chips/p9/procedures/ppe/pk/ppe42/pk_port_types.h new file mode 100644 index 00000000..7a368d4e --- /dev/null +++ b/src/import/chips/p9/procedures/ppe/pk/ppe42/pk_port_types.h @@ -0,0 +1,65 @@ +/* IBM_PROLOG_BEGIN_TAG */ +/* This is an automatically generated prolog. */ +/* */ +/* $Source: import/chips/p9/procedures/ppe/pk/ppe42/pk_port_types.h $ */ +/* */ +/* OpenPOWER sbe Project */ +/* */ +/* Contributors Listed Below - COPYRIGHT 2015,2016 */ +/* [+] International Business Machines Corp. */ +/* */ +/* */ +/* Licensed under the Apache License, Version 2.0 (the "License"); */ +/* you may not use this file except in compliance with the License. */ +/* You may obtain a copy of the License at */ +/* */ +/* http://www.apache.org/licenses/LICENSE-2.0 */ +/* */ +/* Unless required by applicable law or agreed to in writing, software */ +/* distributed under the License is distributed on an "AS IS" BASIS, */ +/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or */ +/* implied. See the License for the specific language governing */ +/* permissions and limitations under the License. */ +/* */ +/* IBM_PROLOG_END_TAG */ +#ifndef __PK_PORT_TYPES_H__ +#define __PK_PORT_TYPES_H__ +//----------------------------------------------------------------------------- +// *! (C) Copyright International Business Machines Corp. 2014 +// *! All Rights Reserved -- Property of IBM +// *! *** IBM Confidential *** +//----------------------------------------------------------------------------- + +/// \file pk_port_types.h +/// \brief Type definitions required by the PK port. +/// +/// \todo GCC provides a portable version of cntlzw called __builtin_clz(). +/// We should make the PK priority queues portable by using this facility. +/// +/// \todo I think that if more of the port-dependent types were moved here, we +/// could break the circular dependencies in some of the header inclusion and +/// simplify the way the PK/port/chip headers are included. + +/// An PkIrqId is an integer in the range of valid interrupts defined by the +/// interrupt controller. + +typedef uint8_t PkIrqId; + +/// PK requires the port to define the type PkThreadQueue, which is a +/// priority queue (where 0 is the highest priority). This queue must be able +/// to handle PK_THREADS + 1 priorities (the last for the idle thread). The +/// port must also define methods for clearing, insertion, deletion and min +/// (with assumed legal priorities). The min operation returns PK_THREADS if +/// the queue is empty. (Or a queue could be initialized with the PK_THREADS +/// entry always present - PK code never tries to delete the idle thread from +/// a thread queue). +/// +/// These queues are used both for the run queue and the pending queue +/// associated with every semaphore. +/// +/// On PPE42 with 32 threads (implied), this is a job for a uint32_t and +/// cntlzw(). + +typedef uint32_t PkThreadQueue; + +#endif /* __PK_PORT_TYPES_H__ */ diff --git a/src/import/chips/p9/procedures/ppe/pk/ppe42/pkppe42files.mk b/src/import/chips/p9/procedures/ppe/pk/ppe42/pkppe42files.mk new file mode 100644 index 00000000..accca3f4 --- /dev/null +++ b/src/import/chips/p9/procedures/ppe/pk/ppe42/pkppe42files.mk @@ -0,0 +1,72 @@ +# IBM_PROLOG_BEGIN_TAG +# This is an automatically generated prolog. +# +# $Source: import/chips/p9/procedures/ppe/pk/ppe42/pkppe42files.mk $ +# +# OpenPOWER sbe Project +# +# Contributors Listed Below - COPYRIGHT 2015,2016 +# [+] International Business Machines Corp. +# +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or +# implied. See the License for the specific language governing +# permissions and limitations under the License. +# +# IBM_PROLOG_END_TAG +# @file pkppe42files.mk +# +# @brief mk for including ppe42 object files +# +# @page ChangeLogs Change Logs +# @section pkppe42files.mk +# @verbatim +# +# +# Change Log ****************************************************************** +# Flag Defect/Feature User Date Description +# ------ -------------- ---------- ------------ ----------- +# +# @endverbatim +# +########################################################################## +# Include Files +########################################################################## + + + +########################################################################## +# Object Files +########################################################################## +PPE42-C-SOURCES = ppe42_core.c \ + ppe42_init.c \ + ppe42_irq_core.c\ + ppe42_gcc.c\ + ppe42_scom.c\ + eabi.c\ + math.c\ + ppe42_string.c + +PPE42-S-SOURCES = ppe42_boot.S \ + ppe42_exceptions.S\ + div64.S\ + ppe42_timebase.S + +PPE42-TIMER-C-SOURCES = +PPE42-TIMER-S-SOURCES = + +PPE42-THREAD-C-SOURCES = +PPE42-THREAD-S-SOURCES = ppe42_thread_init.S + +PPE42_THREAD_OBJECTS= $(PPE42-THREAD-S-SOURCES:.S=.o) +PPE42_OBJECTS = $(PPE42-C-SOURCES:.c=.o) +PPE42_OBJECTS += $(PPE42-S-SOURCES:.S=.o) + diff --git a/src/import/chips/p9/procedures/ppe/pk/ppe42/ppe42.h b/src/import/chips/p9/procedures/ppe/pk/ppe42/ppe42.h new file mode 100644 index 00000000..6857ce10 --- /dev/null +++ b/src/import/chips/p9/procedures/ppe/pk/ppe42/ppe42.h @@ -0,0 +1,813 @@ +/* IBM_PROLOG_BEGIN_TAG */ +/* This is an automatically generated prolog. */ +/* */ +/* $Source: import/chips/p9/procedures/ppe/pk/ppe42/ppe42.h $ */ +/* */ +/* OpenPOWER sbe Project */ +/* */ +/* Contributors Listed Below - COPYRIGHT 2015,2016 */ +/* [+] International Business Machines Corp. */ +/* */ +/* */ +/* Licensed under the Apache License, Version 2.0 (the "License"); */ +/* you may not use this file except in compliance with the License. */ +/* You may obtain a copy of the License at */ +/* */ +/* http://www.apache.org/licenses/LICENSE-2.0 */ +/* */ +/* Unless required by applicable law or agreed to in writing, software */ +/* distributed under the License is distributed on an "AS IS" BASIS, */ +/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or */ +/* implied. See the License for the specific language governing */ +/* permissions and limitations under the License. */ +/* */ +/* IBM_PROLOG_END_TAG */ +#ifndef __PPE42_H__ +#define __PPE42_H__ +//----------------------------------------------------------------------------- +// *! (C) Copyright International Business Machines Corp. 2014 +// *! All Rights Reserved -- Property of IBM +// *! *** IBM Confidential *** +//----------------------------------------------------------------------------- + +/// \file ppe42.h +/// \brief PPE42 port header for PK + +// Macros to define where declared code is actually compiled + +#ifdef __PPE42_CORE_C__ + #define IF__PPE42_CORE_C__(x) x + #define UNLESS__PPE42_CORE_C__(x) +#else + #define IF__PPE42_CORE_C__(x) + #define UNLESS__PPE42_CORE_C__(x) x +#endif + +#ifdef __PPE42_IRQ_CORE_C__ + #define IF__PPE42_IRQ_CORE_C__(x) x + #define UNLESS__PPE42_IRQ_CORE_C__(x) +#else + #define IF__PPE42_IRQ_CORE_C__(x) + #define UNLESS__PPE42_IRQ_CORE_C__(x) x +#endif + +#ifdef HWMACRO_GPE + #include "gpe.h" +#elif defined(HWMACRO_STD) + #include "std.h" +#elif defined(HWMACRO_PPE) + #include "ppe.h" +#else + #error "Macro Type not specified. Are you building from the correct directory?" +#endif + + +#include "ppe42_asm.h" +#include "ppe42_gcc.h" +#include "ppe42_spr.h" +#include "ppe42_msr.h" + + +///start + +/// The synchronization macros defined here all create a compiler +/// memory barrier that will cause GCC to flush/invalidate all memory data +/// held in registers before the macro. This is consistent with other systems, +/// e.g., the PowerPC Linux kernel, and is the safest way to define these +/// macros. + + +// Condition register fields + +#define CR_LT(n) (0x80000000u >> (4 * (n))) +#define CR_GT(n) (0x40000000u >> (4 * (n))) +#define CR_EQ(n) (0x20000000u >> (4 * (n))) +#define CR_SO(n) (0x10000000u >> (4 * (n))) + + +#ifndef __ASSEMBLER__ + +#include "stdint.h" + +/// ssize_t is defined explictly rather than bringing in all of <unistd.h> +#ifndef __ssize_t_defined + #define __ssize_t_defined + typedef int ssize_t; +#endif + +/// A memory barrier +#define barrier() asm volatile ("" : : : "memory") + +/// Ensure In-order Execution of Input/Output +#define eieio() asm volatile ("sync" : : : "memory") + +/// Memory barrier +#define sync() asm volatile ("sync" : : : "memory") + +/// Instruction barrier +#define isync() asm volatile ("sync" : : : "memory") + +/// CouNT Leading Zeros Word +#define cntlzw(x) \ + ({uint32_t __x = (x); \ + uint32_t __lzw; \ + asm volatile ("cntlzw %0, %1" : "=r" (__lzw) : "r" (__x)); \ + __lzw;}) + +/// CouNT Leading Zeros : uint32_t +static inline int +cntlz32(uint32_t x) +{ + return cntlzw(x); +} + +/// CouNT Leading Zeros : uint64_t +static inline int +cntlz64(uint64_t x) +{ + if (x > 0xffffffff) + { + return cntlz32(x >> 32); + } + else + { + return 32 + cntlz32(x); + } +} + + +/// 32-bit population count +static inline int +popcount32(uint32_t x) +{ + return __builtin_popcount(x); +} + + +/// 64-bit population count +static inline int +popcount64(uint64_t x) +{ + return __builtin_popcountll(x); +} + + +// NB: Normally we wouldn't like to force coercion inside a macro because it +// can mask programming errors, but for the MMIO macros the addresses are +// typically manifest constants or 32-bit unsigned integer expressions so we +// embed the coercion to avoid warnings. + +/// 8-bit MMIO Write +#define out8(addr, data) \ + do {*(volatile uint8_t *)(addr) = (data);} while(0) + +/// 8-bit MMIO Read +#define in8(addr) \ + ({uint8_t __data = *(volatile uint8_t *)(addr); __data;}) + +/// 16-bit MMIO Write +#define out16(addr, data) \ + do {*(volatile uint16_t *)(addr) = (data);} while(0) + +/// 16-bit MMIO Read +#define in16(addr) \ + ({uint16_t __data = *(volatile uint16_t *)(addr); __data;}) + +/// 32-bit MMIO Write +#define out32(addr, data) \ + do {*(volatile uint32_t *)(addr) = (data);} while(0) + +/// 32-bit MMIO Read +#define in32(addr) \ + ({uint32_t __data = *(volatile uint32_t *)(addr); __data;}) + +#ifdef HWMACRO_GPE + +/// 64-bit MMIO Write +#define out64(addr, data) \ + do { \ + uint64_t __data = (data); \ + volatile uint32_t *__addr_hi = (uint32_t *)(addr); \ + volatile uint32_t *__addr_lo = __addr_hi + 1; \ + *__addr_hi = (__data >> 32); \ + *__addr_lo = (__data & 0xffffffff); \ + } while(0) + +#else /* standard PPE's require a 64 bit write */ + +/// 64-bit MMIO Write +#define out64(addr, data) \ + {\ + uint64_t __d = (data); \ + uint32_t* __a = (uint32_t*)(addr); \ + asm volatile \ + (\ + "stvd %1, %0 \n" \ + : "=o"(*__a) \ + : "r"(__d) \ + ); \ + } + +#endif /* HWMACRO_GPE */ + +#ifdef HWMACRO_GPE +/// 64-bit MMIO Read +#define in64(addr) \ + ({ \ + uint64_t __data; \ + volatile uint32_t *__addr_hi = (uint32_t *)(addr); \ + volatile uint32_t *__addr_lo = __addr_hi + 1; \ + __data = *__addr_hi; \ + __data = (__data << 32) | *__addr_lo; \ + __data;}) + +#else /* Standard PPE's require a 64 bit read */ + +#define in64(addr) \ + ({\ + uint64_t __d; \ + uint32_t* __a = (uint32_t*)(addr); \ + asm volatile \ + (\ + "lvd %0, %1 \n" \ + :"=r"(__d) \ + :"o"(*__a) \ + ); \ + __d; \ + }) + +#endif /* HWMACRO_GPE */ + +#endif /* __ASSEMBLER__ */ + +#include "ppe42_irq.h" + +#ifndef __ASSEMBLER__ + +/// Store revision information as a (global) string constant +#define REVISION_STRING(symbol, rev) const char* symbol = rev; + +#else // __ASSEMBLER__ +// *INDENT-OFF* + +/// Store revision information as a global string constant + .macro .revision_string, symbol:req, rev:req + .pushsection .rodata + .balign 4 + .global \symbol +\symbol\(): + .asciz "\rev" + .balign 4 + .popsection + .endm + +// *INDENT-ON* +#endif // __ASSEMBLER__ + + + +#include "ppe42_context.h" +#include "pk_panic_codes.h" + +// PPE42 stack characteristics for PK. The pre-pattern pattern is selected +// to be easily recognizable yet be an illegal instruction. + +#define PK_STACK_DIRECTION -1 +#define PK_STACK_PRE_DECREMENT 1 +#define PK_STACK_ALIGNMENT 8 +#define PK_STACK_TYPE unsigned int +#define PK_STACK_PATTERN 0x03abcdef + +// Kernel data structure offsets for assembler code + +#define PK_THREAD_OFFSET_SAVED_STACK_POINTER 0 +#define PK_THREAD_OFFSET_STACK_LIMIT 4 +#define PK_THREAD_OFFSET_STACK_BASE 8 + + +// Application-overrideable definitions + +/// The default thread machine context has MSR[CE], MSR[EE] and MSR[ME] set, +/// and all other MSR bits cleared. +/// +/// The default definition allows external and machine check exceptions. This +/// definition can be overriden by the application. + +#ifndef PK_THREAD_MACHINE_CONTEXT_DEFAULT +#define PK_THREAD_MACHINE_CONTEXT_DEFAULT \ + (MSR_UIE | MSR_EE | MSR_ME) + +#endif + + +#ifndef __ASSEMBLER__ + +/// The PK kernel default panic sequence for C code is to issue a trap +/// instruction with DBCR[TRAP] set, which causes XSR[TRAP] <- 1 +/// and causes the PPE to halt. +/// +/// +/// The Simics environment does not model Debug events correctly. It executes +/// the TRAP as an illegal instruction and branches to the Program Interrupt +/// handler, destroying the contents of SRR0 and SRR1. Therefore we always +/// insert a special Simics magic breakpoint (which is an effective NOP) +/// before the hardware trap. The special-form magic instruction is +/// recognized by our Simics support scripts which decode the kernel state and +/// try to help the user interpret what happened based on the TRAP code. +/// NOTE! SIMICS does not seem to recognize the "magic breakpoint" on PPE! + + +#ifndef PK_PANIC + +#if SIMICS_ENVIRONMENT +#define PK_PANIC(code) \ + do { \ + asm volatile ("stw %r3, __pk_panic_save_r3@sda21(0)"); \ + asm volatile ("lwz %r3, __pk_panic_dbcr@sda21(0)"); \ + asm volatile ("mtdbcr %r3"); \ + asm volatile (".long %0" : : "i" (code)); \ + } while(0) +#else +#define PK_PANIC(code) \ + do { \ + asm volatile ("tw 31, %0, %1" : : "i" (code/256) , "i" (code%256)); \ + } while (0) +#endif +#endif // SIMICS_ENVIRONMENT + +// These variables are used by the PK_PANIC() definition above to save and +// restore state. __pk_panic_dbcr is the value loaded into DBCR to force +// traps to halt the PPE and freeze the timers. + +#if SIMICS_ENVIRONMENT +#ifdef __PPE42_CORE_C__ +uint32_t __pk_panic_save_r3; +uint32_t __pk_panic_dbcr = DBCR_RST_HALT; +#define __PK_PANIC_DEFS__ +#else +#define __PK_PANIC_DEFS__ \ + extern uint32_t __pk_panic_save_r3; \ + extern uint32_t __pk_panic_dbcr; +#endif //SIMICS_ENVIRONMENT + +#endif // PK_PANIC + +/// This is the Simics 'magic breakpoint' instruction. +/// +/// Note that this form does not include a memory barrier, as doing so might +/// change the semantics of the program. There is an alternative form +/// SIMICS_MAGIC_BREAKPOINT_BARRIER that does include a barrier. + +//#define SIMICS_MAGIC_BREAKPOINT asm volatile ("rlwimi 0,0,0,0,0") + +/// This is the Simics 'magic breakpoint' instruction including a memory +/// barrier. +/// +/// Note that the memory barrier guarantees that all variables held in +/// registers are flushed to memory before the breakpoint, however this might +/// change the semantics of the program. There is an alternative form of +/// SIMICS_MAGIC_BREAKPOINT that does not include a barrier. If the idea is +/// to use the breakpoint for tracing code execution in Simics, the barrier +/// form may be preferred so that variable values will be visible in memory. + +/*#define SIMICS_MAGIC_BREAKPOINT_BARRIER \ + asm volatile ("rlwimi 0,0,0,0,0" : : : "memory") +*/ + +#else // __ASSEMBLER__ +// *INDENT-OFF* + +/// This is the Simics 'magic breakpoint' instruction. An assembler macro +/// form is also provided for use within macros. + +//#define SIMICS_MAGIC_BREAKPOINT rlwimi 0,0,0,0,0 + +// .macro _simics_magic_breakpoint +// rlwimi 0,0,0,0,0 +// .endm + +/// The PK kernel panic default panic sequence for assembler code +/// +/// By default a kernel panic from assembler forces external debug mode then +/// generates a \c trap instruction followed by the error code. The \a code +/// argument must be a compile-time integer immediate. This definition can be +/// overriden by the application. +/// +/// See the comments for the non-ASSEMBLER version for further details. Note +/// that the code space reserved for exception handlers is only 8 +/// instructions, so in the assembler context we don't save DBCR0 as doing so +/// would require 10. + +#ifndef PK_PANIC + +#define PK_PANIC(code) _pk_panic code +#if SIMICS_ENVIRONMENT + .macro _pk_panic, code + stw %r3, __pk_panic_save_r3@sda21(0) + lwz %r3, __pk_panic_dbcr@sda21(0) + mtdbcr %r3, + .long (\code) + .endm +#else + .macro _pk_panic, code + tw 31,(\code)/256, (\code)%256 + .endm +#endif // SIMICS_ENVIRONMENT +#endif // PK_PANIC + +// *INDENT-ON* +#endif // __ASSEMBLER__ + + +// Application-overridible definitions for the PK boot loader + +/// In order to enable the default kernel panic (a trap) to halt the machine, +/// the Debug Control Register 0 (DBCR0) is initialized in externel debug +/// mode, with the Trap Debug Event enabled so that the trap will not cause a +/// program exception, and the FT bit set so that the timers will freeze. +/// This definition can be overridden by the application. +/// +/// NB: It is expected that a reliable production system will redefine all of +/// the 'panic' macros and the default DBCR0 setup. + +#ifndef PPE42_DBCR_INITIAL +#define PPE42_DBCR_INITIAL DBCR_TRAP +#endif + +/// This is the value of the MSR used during initialization. Once PK threads +/// are started (with \c pk_start_threads()), all machine contexts derive +/// from the default thread context \c +/// PK_THREAD_MACHINE_CONTEXT_DEFAULT. This definition can be overriden by +/// the application. +/// +/// The default is to enable machine checks only. + +#ifndef PPE42_MSR_INITIAL +#define PPE42_MSR_INITIAL MSR_ME +#endif + +/// The \a argc argument passed to \c main(). This definition can be overriden +/// by the application. + +#ifndef PPE42_ARGC_INITIAL +#define PPE42_ARGC_INITIAL 0 +#endif + +/// The \a argv argument passed to \c main(). This definition can be overriden +/// by the application. + +#ifndef PPE42_ARGV_INITIAL +#define PPE42_ARGV_INITIAL 0 +#endif + +/// Optionally trap the reset for the debugger, which means that the PPE42 +/// will simply spin at the symbol \c __reset_trap after a chip reset. Set R0 +/// to a non-zero value in the debugger to continue execution. This definition +/// can be overriden by the application. + +#ifndef PPE42_RESET_TRAP +#define PPE42_RESET_TRAP 0 +#endif + +#ifndef __ASSEMBLER__ + +/// The PPE42 PK machine context is simply the MSR, a 32-bit integer. + +typedef uint32_t PkMachineContext; + +/// Disable interrupts and return the current +/// context. +/// +/// \param context A pointer to an PkMachineContext, this is the context that +/// existed before interrupts were disabled. Typically this +/// context is restored at the end of a critical section. +/// +/// Return values other then PK_OK (0) are errors; see \ref pk_errors +/// +/// \retval 0 Successful completion +/// +/// \retval -PK_INVALID_ARGUMENT_INTERRUPT An illegal priority was specified. + +UNLESS__PPE42_CORE_C__(extern) +inline int +pk_interrupt_disable(PkMachineContext* context) +{ +*context = mfmsr(); + +wrteei(0); + +return PK_OK; +} + +/// Set the machine context. +/// +/// \param context A pointer to an PkMachineContext +/// +/// Return values other then PK_OK (0) are errors; see \ref pk_errors +/// +/// \retval 0 Successful completion +/// +/// \retval -PK_INVALID_ARGUMENT_CONTEXT_SET A null pointer was provided as +/// the \a context argument or an illegal machine context was specified. + +UNLESS__PPE42_CORE_C__(extern) +inline int +pk_machine_context_set(PkMachineContext* context) +{ +if (PK_ERROR_CHECK_API) +{ +PK_ERROR_IF(context == 0, PK_INVALID_ARGUMENT_CONTEXT_SET); +} + +mtmsr(*context); + +return PK_OK; +} + +/// Get the machine context. +/// +/// \param context A pointer to an PkMachineContext. +/// +/// Return values other then PK_OK (0) are errors; see \ref pk_errors +/// +/// \retval 0 Successful completion +/// +/// \retval -PK_INVALID_ARGUMENT_CONTEXT_GET A null pointer was provided as +/// the \a context argument. + +UNLESS__PPE42_CORE_C__(extern) +inline int +pk_machine_context_get(PkMachineContext* context) +{ +if (PK_ERROR_CHECK_API) +{ +PK_ERROR_IF(context == 0, PK_INVALID_ARGUMENT_CONTEXT_GET); +} + +*context = mfmsr(); + +return PK_OK; +} + +extern void __ctx_switch(); +/// The PK context switch for the PPE kernel +// There is no protected mode in PPE42 so just call kernel code +#define __pk_switch() __ctx_switch() + + +/// In the PowerPC EABI all initial stack frames require 8 bytes - the 4 bytes +/// at the SP are zeroed to indicate the end of the stack, and the 4 bytes +/// behind the SP are for the initial subroutine's LR. + +static inline void +__pk_stack_create_initial_frame(PkAddress* stack, size_t* size) +{ +*stack -= 8; +* size -= 8; +* ((PK_STACK_TYPE*)(*stack)) = 0; +} + +/// The PK Kernel Context for PPE42 +/// +/// The PK portable kernel does not define how the kernel keeps track of +/// whether PK is running, interrupt levels, and other debug +/// information. Instead it defines an API that the port must provide to the +/// portable kernel. +/// +/// In the PPE42 port, the kernel context is maintained in SPRG0. This +/// 32-bit value is treated as 6 distinct fields as indicated in the structure +/// definition. +typedef union +{ + +uint32_t value; + +struct +{ + +/// A flag indicating that PK is in thread mode after a call of +/// pk_start_threads(). +unsigned thread_mode : 1; + +/// If this field is non-zero then PK is processing an interrupt +/// and the \c irq field will contain the PkIrqId of the interrupt +/// that kicked off interrupt processing. +unsigned processing_interrupt : 1; + +/// The priority of the currently running thread. In an interrupt +/// context, this is the priority of the thread that was interrupted. +unsigned thread_priority : 6; + +/// This bit tracks whether the current context can be discarded or +/// if the context must be saved. If the processor takes an interrupt +/// and this bit is set, then the current context will be discarded. +/// This bit is set at the end of handling an interrupt and prior +/// to entering the wait enabled state. +unsigned discard_ctx : 1; + +/// The PkIrqId of the currently running (or last run) handler. If +/// \c processing_interrupt is set, then this is the +/// PkIrqId of the IRQ that is currently executing. +unsigned irq : 7; + +/// Each PPE application will define (or not) the interpretation of +/// this field. Since SPRG0 is saved and restored during during thread +/// context switches, this field can be used to record the progress of +/// individual threads. The kernel and/or application will provide +/// APIs or macros to read and write this field. +unsigned app_specific : 16; + +} fields; + +} __PkKernelContext; + +// These APIs are provided for applications to get and set the app_specific +// field of the kernel context which is held in sprg0. + +static inline uint16_t ppe42_app_ctx_get(void) +{ +__PkKernelContext __ctx; +__ctx.value = mfspr(SPRN_SPRG0); +return __ctx.fields.app_specific; +} + +static inline void ppe42_app_ctx_set(uint16_t app_ctx) +{ +PkMachineContext mctx; +__PkKernelContext __ctx; +mctx = mfmsr(); +wrteei(0); +__ctx.value = mfspr(SPRN_SPRG0); +__ctx.fields.app_specific = app_ctx; +mtspr(SPRN_SPRG0, __ctx.value); +mtmsr(mctx); +} + +// These APIs are provided to the PK portable kernel by the port. + +/// PK threads have been started by a call of pk_start_threads(). + +#define __pk_kernel_mode_thread() \ + ({ \ + __PkKernelContext __ctx; \ + __ctx.value = mfspr(SPRN_SPRG0); \ + __ctx.fields.thread_mode;}) + + +/// PK is executing in a thread context (not an interrupt handler). + +#define __pk_kernel_context_thread() \ + ({ \ + __PkKernelContext __ctx; \ + __ctx.value = mfspr(SPRN_SPRG0); \ + __ctx.fields.thread_mode && !__ctx.fields.processing_interrupt;}) + + +/// PK is executing an interrupt handler of any priority. + +#define __pk_kernel_context_any_interrupt() \ + ({ \ + __PkKernelContext __ctx; \ + __ctx.value = mfspr(SPRN_SPRG0); \ + __ctx.fields.processing_interrupt;}) + + +// PK requires the port to define the type PkThreadQueue, which is a +// priority queue (where 0 is the highest priority). This queue must be able +// to handle PK_THREADS + 1 priorities (the last for the idle thread) The +// port must also define methods for clearing, insertion, deletion and min +// (with assumed legal priorities). The min operation returns PK_THREADS if +// the queue is empty (or a queue could be initialized with that entry always +// present - PK code never tries to delete the idle thread from a thread +// queue). +// +// These queues are used both for the run queue and the pending queue +// associated with every semaphore. +// +// On PPE42 with 32 threads (implied), this is a job for a uint32_t and +// cntlzw(). + +static inline void +__pk_thread_queue_clear(volatile PkThreadQueue* queue) +{ +*queue = 0; +} + +static inline void +__pk_thread_queue_insert(volatile PkThreadQueue* queue, PkThreadPriority priority) +{ +*queue |= (0x80000000u >> priority); +} + +static inline void +__pk_thread_queue_delete(volatile PkThreadQueue* queue, PkThreadPriority priority) +{ +*queue &= ~(0x80000000u >> priority); +} + +static inline PkThreadPriority +__pk_thread_queue_min(volatile PkThreadQueue* queue) +{ +return cntlzw(*queue); +} + +static inline int +__pk_thread_queue_member(volatile PkThreadQueue* queue, PkThreadPriority priority) +{ +return ((*queue >> (31 - priority)) & 1); +} + +static inline void +__pk_thread_queue_union(volatile PkThreadQueue* queue0, +volatile PkThreadQueue* queue1) +{ +*queue0 |= *queue1; +} + +static inline int +__pk_thread_queue_count(volatile PkThreadQueue* queue) +{ +return __builtin_popcount(*queue); +} + + +/// This macro is used to call __pk_start_threads() using the kernel stack, +/// in a critical section. + +#define __pk_call_pk_start_threads() \ + do { \ + PkMachineContext ctx; \ + pk_critical_section_enter(&ctx); \ + asm volatile ("mr 1, %0; mtlr %1; blrl" : : \ + "r" (__pk_kernel_stack), \ + "r" (__pk_start_threads)); \ + PK_PANIC(PK_START_THREADS_RETURNED); \ + } while (0) + + +#endif /* __ASSEMBLER__ */ + +/// The __PkKernelContext 'thread_mode' bit as a flag + +#define PPE42_THREAD_MODE 0x8000 +#define PPE42_PROC_IRQ 0x4000 +#define PPE42_DISCARD_CTX 0x0080 + +#define PPE42_THREAD_MODE_BIT 0 +#define PPE42_PROC_IRQ_BIT 1 +#define PPE42_DISCARD_CTX_BIT 8 + +#ifndef __ASSEMBLER__ + +/// Code breakpoints for PPE42 +/// +/// This macro inserts a special PPE42-only breakpoint into the object code +/// at the place the macro invocation appears. This facility is designed for +/// VBU/VPO procedure debugging. This type of breakpoint may not be required +/// on real hardware as we will then have the full power of RISCWatch, gdb, +/// etc. Once inserted into the code, code breakpoints can be enabled or +/// disabled by manipulating the global variable _code_breakpoint_enable, +/// which defaults to 1. +/// +/// The code breakpoint is implemented as a setup routine and a teardown +/// routine, executed in an critical section. The actual break +/// will occur at the address of the call of the teardown routine, in the +/// context of the calling code. The setup routine saves the state of DBCR0/1 +/// and IAC4, then programs the DBCR for an external debug mode, IAC4 +/// breakpoint. The IAC4 breakpoint is set for the address of the call of the +/// teardown routine. The teardown routine simply restores the state of the +/// debug registers that existed before the code breakpoint. +/// +/// Once hit, restarting from the break requires clearing IAC4 and restarting +/// instructions: +/// +/// \code +/// +/// putspr pu.occ iac4 0 +/// cipinstruct pu.occ start +/// +/// \endcode +/// +/// The above restart processes is also encapsulated as the p8_tclEcmd +/// procedure 'unbreakOcc'. +/// +/// In code built for the Simics environment (i.e., with the preprocessor +/// macro SIMICS_ENVIRONMENT=1) this macro simply expands into +/// SIMICS_MAGIC_BREAKPOINT, and simulation can be continued from the break as +/// normal. This Simics magic breakpoint is also under the control of +/// _code_breakpoint_enable. In code not built with SIMICS_ENVIROMENT=1, note +/// that the CODE_BREAKPOINT is ignored by the Simics PPE42 model as it does +/// not model debug events. + +//void +//_code_breakpoint_prologue(void); + +//void +//_code_breakpoint_epilogue(void); + +//extern uint32_t _code_breakpoint_enable; + +#endif // __ASSEMBLER__ + + +#endif /* __PPE42_H__ */ diff --git a/src/import/chips/p9/procedures/ppe/pk/ppe42/ppe42_asm.h b/src/import/chips/p9/procedures/ppe/pk/ppe42/ppe42_asm.h new file mode 100644 index 00000000..6f3923aa --- /dev/null +++ b/src/import/chips/p9/procedures/ppe/pk/ppe42/ppe42_asm.h @@ -0,0 +1,634 @@ +/* IBM_PROLOG_BEGIN_TAG */ +/* This is an automatically generated prolog. */ +/* */ +/* $Source: import/chips/p9/procedures/ppe/pk/ppe42/ppe42_asm.h $ */ +/* */ +/* OpenPOWER sbe Project */ +/* */ +/* Contributors Listed Below - COPYRIGHT 2015,2016 */ +/* [+] International Business Machines Corp. */ +/* */ +/* */ +/* Licensed under the Apache License, Version 2.0 (the "License"); */ +/* you may not use this file except in compliance with the License. */ +/* You may obtain a copy of the License at */ +/* */ +/* http://www.apache.org/licenses/LICENSE-2.0 */ +/* */ +/* Unless required by applicable law or agreed to in writing, software */ +/* distributed under the License is distributed on an "AS IS" BASIS, */ +/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or */ +/* implied. See the License for the specific language governing */ +/* permissions and limitations under the License. */ +/* */ +/* IBM_PROLOG_END_TAG */ +#ifndef __PPE42_ASM_H__ +#define __PPE42_ASM_H__ +//----------------------------------------------------------------------------- +// *! (C) Copyright International Business Machines Corp. 2014 +// *! All Rights Reserved -- Property of IBM +// *! *** IBM Confidential *** +//----------------------------------------------------------------------------- + +/// \file ppe42_asm.h +/// \brief Generic assembler macros for 32-bit PPE42 + +// Doxygen is confused by assembler; the best I know how to make it +// work is to put all of the documentation at the beginning like below +// and effectively comment out the code using Doxygen cond/endcond. + +/// \page ppe42_asm Generic assembler macros for 32-bit PPE42 +/// +/// +/// \section _lxzi _l<w,h,b>zi - Load register and Zero from Immediate address +/// +/// These macros encapsulate the 2-instruction sequence required to +/// load from a 32-bit immediate address. +/// +/// \arg \c dreg A register to receive the load data. +/// \arg \c areg A register to hold the immediate address. This can \e +/// not be register 0. Note that if \a areg != \a dreg +/// then \a areg will contain the address at the end of +/// the macro sequence. +/// \arg \c addr A 32-bit immediate address, which may be either an +/// absolute or relocatable expression. +/// +/// Forms: +/// +/// \b _lbzi \a dreg, \a areg, \a addr - Load Byte and Zero from Immediate address \n +/// \b _lhzi \a dreg, \a areg, \a addr - Load Halfword and Zero from Immediate address \n +/// \b _lwzi \a dreg, \a areg, \a addr - Load Word and Zero from Immediate address \n +/// +/// +/// \section _stxi _st<w,h,b>i - STore register to Immediate address +/// +/// These macros encapsulate the 2-instruction sequence required to +/// store to a 32-bit immediate address. +/// +/// \arg \c dreg The register to store. +/// \arg \c areg A register to hold the immediate address. This can \e +/// not be register 0, and can not be the same as \a dreg. +/// Note that \a areg will contain the address at the end of +/// the macro sequence. +/// \arg \c addr A 32-bit immediate address, which may be either an +/// absolute or relocatable expression. +/// +/// Forms: +/// +/// \b _stbi \a dreg, \a areg, \a addr - STore Byte to Immediate address \n +/// \b _sthi \a dreg, \a areg, \a addr - STore Halfword to Immediate address \n +/// \b _stwi \a dreg, \a areg, \a addr - STore Word to Immediate address \n +/// +/// +/// \section _lstzsd _<l,st><w,h,b><z>sd - Load/STore register from/to Small Data area +/// +/// These macros encapulate the small data area relocations for access +/// to storage in the small data sections .sbss, .sdata, .sbss2 and +/// .sdata2. Use of these macros implies small data area support in +/// the compile environment (for variables shared between compiled and +/// assembled code) and initialization code that sets up the small data +/// area registers R13 (and optionally R2). +/// +/// The relocations generated by this macro will work for both SVR4 ABI +/// and EABI environments. In particular, for EABI environments +/// the link editor will insert offsets to either R13 or R2 depending +/// on the section of the symbol. +/// +/// \arg \c dreg The register to load or store. +/// \arg \c addr A 32-bit immediate address, assumed to be a +/// relocatable address in one of the small data sections. +/// +/// Forms: +/// +/// \b _lbzsd \a dreg, \a addr - Load Byte and Zero from Small Data area \n +/// \b _lhzsd \a dreg, \a addr - Load Halfword and Zero from Small Data area \n +/// \b _lwzsd \a dreg, \a addr - Load Word and Zero from Small Data area \n +/// \b _stbsd \a dreg, \a addr - STore Byte to Small Data area \n +/// \b _sthsd \a dreg, \a addr - STore Halfword to Small Data area \n +/// \b _stwsd \a dreg, \a addr - STore Word to Small Data area \n +/// +/// +/// \section _liw _liw<a> - Load Immediate Word (Absolute) +/// +/// These macros encapsulate the two instructions required to load a +/// 32-bit immediate value into a register. If the immediate is an +/// absolute expression, then the \c 'a' form may be able to optimize +/// to a single instruction depending on whether only the high- or +/// low-order bits of the immediate are non-zero. +/// +/// Forms: +/// +/// \b _liw \a rd, \a imm - Load register \a rd with the 32-bit immediate \a imm \n +/// \b _liwa \a rd, \a imm - Load register \a rd with the 32-bit absolute immediate \a imm \n +/// +/// +/// \section _oriwa _oriwa - OR Immediate Word Absolute +/// +/// This macro encapsulates the logical OR of a 32-bit immediate with a +/// register. The immediate value must be an absolute expression. +/// +/// The PowerPC has instructions for OR-ing 16-bit immediates into the +/// upper (\c oris) and lower (\c ori) portions of a register. This +/// macro optimizes the generated code based on which bits (if any) of +/// the absolte immediate are non-zero. +/// +/// This special macro is only provided for the OR function. For other +/// logical operations and recording forms it is necessary in general +/// to first load the 32-bit immediate into a register (e.g., with \c +/// _liwa) then perform the logical operation. +/// +/// \arg \c rd The destination register; at the end will contain \c rs +/// OR \a imm +/// \arg \c rs The source register. +/// \arg \c imm 32-bit absolute expression. +/// +/// Forms: +/// +/// \b _oriwa \a rd, \a rs, \a imm - \a rd gets \a rs OR \a imm \n +/// +/// +/// \section _incr64_fast - 64-bit increment for fast interrupt handlers +/// +/// This macros implements 64-bit counter update in fast interrupt handlers +/// which are forbidden from using the carry-bit in the XER (without +/// saving/restoring it.) +/// +/// \arg \c rs Scratch register +/// \arg \c ra Register containing the counter address at entry +/// +/// \a rs and \a ra must be unique. At the end of the macro the count +/// is updated to memory and \a ra is unmodified. +/// +/// +/// \section _setclear_bits Set/Clear/Copy Bits from Immediate Positions +/// +/// There are situations where it is easier/faster to clear individual bits +/// and bit fields, set bits or copy fields, based on immediate bit numbers +/// and locations, rather than loading masks, since setting up a mask +/// requires 2 instruction in general, whereas these macros generate a single +/// instruction. +/// +/// \arg \c rd - The destination register +/// \arg \c rs - The source register +/// \arg \c n - An immediate size of a bit field, in the range 0 to 32 +/// \arg \c b - An immediate big-endian bit number in the range 0 to 31 +/// +/// Forms: +/// +/// \b _clrfield \a rd, \a rs, \a n, \a b - Clear an \a n bit field from \a rs +/// to \a rd starting from bit \a b \n +/// \b _clrbit \a rd, \a rs, \a b - Clear bit \a b \n +/// \b _setbit \a rd, \a rs, \a b - Set bit \a b \n +/// \b _copyfield \a rd, \a rs, \a n, \a b - Copy an n-bit field from \a rs to +/// \a rd starting from bit \a b \n +/// +/// +/// \section pseudo_ops Assembler Pseudo-Ops Macros +/// +/// Several macros define new 'pseudo-ops'. +/// +/// \subsection cache_align .cache_align +/// +/// The \c .cache_align pseudo-op is used to force alignment on a +/// cache-line boundary. It requires a preprocessor symbol definition for +/// \c LOG_CACHE_LINE_SIZE +/// +/// Forms: +/// +/// \b .cache_align \n +/// +/// +/// \subsection global_function Local and Global Functions +/// +/// The \c .function and \c .global_function pseudo-ops define function +/// symbols in the \c .text section. +/// +/// Forms: +/// +/// \b .function \a symbol - Define a local function \a symbol \n +/// \b .global_function \a symbol - Define a global function \a symbol \n +/// +/// +/// \subsection epilogue .epilogue +/// +/// The \c .epilogue pseudo-op adds size and type information for +/// functions defined in assembler. +/// +/// \arg \c symbol - Assembler epilogue for the function \a symbol. +/// +/// Forms: +/// +/// \b .epilogue \a symbol \n +/// +/// +/// \cond + +#ifdef __ASSEMBLER__ +// *INDENT-OFF* + + +### **************************************************************************** +### _l<b,h,w>zi +### _st<b,h,w>i +### **************************************************************************** + + .macro _lbzi dreg, areg, addr + lis \areg, \addr@ha + .ifc \areg, \dreg + lbz \dreg, \addr@l(\areg) + .else + lbzu \dreg, \addr@l(\areg) + .endif + .endm + + .macro _lhzi dreg, areg, addr + lis \areg, \addr@ha + .ifc \areg, \dreg + lhz \dreg, \addr@l(\areg) + .else + lhzu \dreg, \addr@l(\areg) + .endif + .endm + + .macro _lwzi dreg, areg, addr + lis \areg, \addr@ha + .ifc \areg, \dreg + lwz \dreg, \addr@l(\areg) + .else + lwzu \dreg, \addr@l(\areg) + .endif + .endm + + .macro _stbi dreg, areg, addr + .ifc \areg, \dreg + .err + .endif + lis \areg, \addr@ha + stbu \dreg, \addr@l(\areg) + .endm + + .macro _sthi dreg, areg, addr + .ifc \areg, \dreg + .err + .endif + lis \areg, \addr@ha + sthu \dreg, \addr@l(\areg) + .endm + + .macro _stwi dreg, areg, addr + .ifc \areg, \dreg + .err + .endif + lis \areg, \addr@ha + stwu \dreg, \addr@l(\areg) + .endm + + +### **************************************************************************** +### _l<b,h,w>zsd +### _st<b,h,w>sd +### **************************************************************************** + + .macro _lbzsd dreg, addr + lbz \dreg, \addr@sda21(0) + .endm + + .macro _lhzsd dreg, addr + lhz \dreg, \addr@sda21(0) + .endm + + .macro _lwzsd dreg, addr + lwz \dreg, \addr@sda21(0) + .endm + + .macro _stbsd dreg, addr + stb \dreg, \addr@sda21(0) + .endm + + .macro _sthsd dreg, addr + sth \dreg, \addr@sda21(0) + .endm + + .macro _stwsd dreg, addr + stw \dreg, \addr@sda21(0) + .endm + + +### **************************************************************************** +### _liw<a> +### _oriwa +### **************************************************************************** + + .macro _liw rd, imm + lis \rd, \imm@h + ori \rd, \rd, \imm@l + .endm + + .macro _liwa rd, imm + .if (\imm & 0xffff0000) + lis \rd, \imm@h + .if (\imm & 0xffff) + ori \rd, \rd, \imm@l + .endif + .else + li \rd, \imm@l + .endif + .endm + + .macro _oriwa rd, rs, imm + .if (\imm & 0xffff0000) + oris \rd, \rs, \imm@h + .if (\imm & 0xffff) + ori \rd, \rd, \imm@l + .endif + .else + ori \rd, \rs, \imm@l + .endif + .endm + +### **************************************************************************** +### _incr64_fast +### **************************************************************************** + + .macro _incr64_fast, rs:req, ra:req + + lwz \rs, 4(\ra) + addi \rs, \rs, 1 + cmpwi \rs, 0 + stw \rs, 4(\ra) + bne 233643278f + + lwz \rs, 0(\ra) + addi \rs, \rs, 1 + stw \rs, 0(\ra) +233643278: + + .endm + +### **************************************************************************** +### _clrfield +### _clrbit +### _setbit +### _copyfield +### **************************************************************************** + + .macro _clrfield, rd, rs, n, b + rlwinm \rd, \rs, 0, (\b + \n) & 0x1f, (\b - 1) & 0x1f + .endm + + .macro _clrbit, rd, rs, b + _clrfield \rd, \rs, 1, \b + .endm + + .macro _setbit, rd, rs, b + .ifle \b - 15 + oris \rd, \rs, 1 << (15 - \b) + .else + ori \rd, \rs, 1 << (31 - \b) + .endif + .endm + + .macro _copyfield, rd, rs, n, b + rlwimi \rd, \rs, 0, \b , (\b + \n - 1) + .endm + +### **************************************************************************** +### .cache_align +### .<global_>function +### .epilogue +### **************************************************************************** + + .set _log_cache_line_size, LOG_CACHE_LINE_SIZE + + .macro .cache_align + .align _log_cache_line_size + .endm + + .macro .function symbol + .text + .align 2 + .endm + + .macro .global_function symbol + .text + .align 2 + .global \symbol + .endm + + .macro .epilogue symbol + .type \symbol, @function + .size \symbol, . - \symbol + .endm + +### *************************************************************************** +### 64-bit macros +### *************************************************************************** + +### *************************************************************************** +### Using symbols for register names makes the code more readable and allows +### us to do register arithmetic within macros. +### *************************************************************************** + +.equiv r0, 0 +.equiv r1, 1 +.equiv sp, 1 +.equiv r3, 3 +.equiv r4, 4 +.equiv r5, 5 +.equiv r6, 6 +.equiv r7, 7 +.equiv r8, 8 +.equiv r9, 9 +.equiv r10, 10 + +.equiv r28, 28 +.equiv r29, 29 +.equiv r30, 30 +.equiv r31, 31 + +.equiv d3, 3 +.equiv d4, 4 +.equiv d5, 5 +.equiv d6, 6 +.equiv d7, 7 +.equiv d8, 8 +.equiv d9, 9 +.equiv d10, 10 +.equiv d28, 28 +.equiv d29, 29 +.equiv d30, 30 +.equiv d31, 31 + +### *************************************************************************** +### Load virtual doubleword generic. Load a virtual doubleword from a relocatable +### address expression. If the optional RA is specified, the address remains in +### RA. +### *************************************************************************** +.macro _lvdg DT:req addr:req RA=-1 + .if \RA == -1 + lis \DT, (\addr)@ha + lvd \DT, (\addr)@l(\DT) + .else + lis \RA, (\addr)@ha + lvdu \DT, (\addr)@l(\RA) + .endif +.endm + +### *************************************************************************** +### Load virtual doubleword from a relocatable small data area address +### *************************************************************************** +.macro _lvdsd DT:req addr:req + lvd \DT, (\addr)@sda21(0) +.endm + +### *************************************************************************** +### Store virtual doubleword generic. Store a virtual doubleword based on a +### relocatable address expression. The address remains in RA. +### *************************************************************************** +.macro _stvdg DS:req addr:req RA:req + lis \RA, (\addr)@ha + stvdu \DS, (\addr)@l(\RA) +.endm + +### *************************************************************************** +### Store virtual doubleword to a relocatable small data address expression +### *************************************************************************** +.macro _stvdsd DS:req addr:req + stvd \DS, (\addr)@sda21(0) +.endm + +### *************************************************************************** +### Load virtual doubleword absolute. Set DT to an absolute 64-bit constant +### *************************************************************************** +.macro _lvda DT, cvalue + lwa (\DT + 1)%32, (\cvalue) & 0x00000000ffffffff + lwa \DT, (\cvalue) >> 32 +.endm + +### *************************************************************************** +### +### 64-bit arithmetic macros +### +### *************************************************************************** + +.macro check_overlap2 DA, DB + .if ((\DA - \DB) % 32) == 1 || ((\DA - \DB) % 32) == -1 + .error "virtual doubleword registers must be identical or non-overlapping" + .endif +.endm + +.macro check_overlap3 DA, DB, DC + check_overlap2 \DA, \DB + check_overlap2 \DA, \DC + check_overlap2 \DB, \DC +.endm + +### *************************************************************************** +### Add virtual doubleword carrying +### *************************************************************************** +.macro _addvdc DT, DA, DB + check_overlap3 \DT, \DA, \DB + addc (\DT+1)%32, (\DA+1)%32, (\DB+1)%32 + adde \DT, \DA, \DB +.endm + +### *************************************************************************** +### Add virtual doubleword to signed 16-bit immediate carrying +### *************************************************************************** +.macro _addvdic DT, DA, SI + .if \DA == 31 + .error "d31 for addend register is not supported" + .endif + check_overlap2 \DT, \DA + addi (\DT+1)%32, \DA+1, SI + addze \DT, \DA +.endm + +### *************************************************************************** +### Add virtual doubleword to unsigned word carrying +### *************************************************************************** +.macro _addvdwuc DT, DA, RB + check_overlap2 \DT, \DA + addc (\DT+1)%32, (\DA+1)%32, \RB + addze \DT, \DA +.endm + +### *************************************************************************** +### Subtract virtual doubleword carrying +### *************************************************************************** +.macro _subvdc DT, DA, DB + check_overlap3 \DT, \DA, \DB + subfc (\DT+1)%32, (\DA+1)%32, (\DB+1)%32 + subfe \DT, \DA, \DB +.endm + +### *************************************************************************** +### +### 64-bit logic macros +### +### *************************************************************************** + +### *************************************************************************** +### AND virtual doubleword +### *************************************************************************** +.macro _andvd DT, DA, DB + check_overlap3 \DT, \DA, \DB + and (\DT+1)%32, (\DA+1)%32, (\DB+1)%32 + and \DT, \DA, \DB +.endm + +### *************************************************************************** +### ANDC virtual doubleword +### *************************************************************************** +.macro _andcvd DT, DA, DB + check_overlap3 \DT, \DA, \DB + andc (\DT+1)%32, (\DA+1)%32, (\DB+1)%32 + andc \DT, \DA, \DB +.endm + +### *************************************************************************** +### EQV virtual doubleword +### *************************************************************************** +.macro _eqvvd DT, DA, DB + check_overlap3 \DT, \DA, \DB + eqv (\DT+1)%32, (\DA+1)%32, (\DB+1)%32 + eqv \DT, \DA, \DB +.endm + +### *************************************************************************** +### OR virtual doubleword +### *************************************************************************** +.macro _orvd DT, DA, DB + check_overlap3 \DT, \DA, \DB + or (\DT+1)%32, (\DA+1)%32, (\DB+1)%32 + or \DT, \DA, \DB +.endm + +### *************************************************************************** +### ORC virtual doubleword +### *************************************************************************** +.macro _orcvd DT, DA, DB + check_overlap3 \DT, \DA, \DB + orc (\DT+1)%32, (\DA+1)%32, (\DB+1)%32 + orc \DT, \DA, \DB +.endm + +### *************************************************************************** +### XOR virtual doubleword +### *************************************************************************** +.macro _xorvd DT, DA, DB + check_overlap3 \DT, \DA, \DB + xor (\DT+1)%32, (\DA+1)%32, (\DB+1)%32 + xor \DT, \DA, \DB +.endm + +// *INDENT-ON* +#endif /* __ASSEMBLER__ */ + +/// \endcond + +// Local Variables: +// mode:asm +// End: + +#endif /* __PPE42_ASM_H__ */ diff --git a/src/import/chips/p9/procedures/ppe/pk/ppe42/ppe42_boot.S b/src/import/chips/p9/procedures/ppe/pk/ppe42/ppe42_boot.S new file mode 100644 index 00000000..6c3424f5 --- /dev/null +++ b/src/import/chips/p9/procedures/ppe/pk/ppe42/ppe42_boot.S @@ -0,0 +1,193 @@ +/* IBM_PROLOG_BEGIN_TAG */ +/* This is an automatically generated prolog. */ +/* */ +/* $Source: import/chips/p9/procedures/ppe/pk/ppe42/ppe42_boot.S $ */ +/* */ +/* OpenPOWER sbe Project */ +/* */ +/* Contributors Listed Below - COPYRIGHT 2015,2016 */ +/* [+] International Business Machines Corp. */ +/* */ +/* */ +/* Licensed under the Apache License, Version 2.0 (the "License"); */ +/* you may not use this file except in compliance with the License. */ +/* You may obtain a copy of the License at */ +/* */ +/* http://www.apache.org/licenses/LICENSE-2.0 */ +/* */ +/* Unless required by applicable law or agreed to in writing, software */ +/* distributed under the License is distributed on an "AS IS" BASIS, */ +/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or */ +/* implied. See the License for the specific language governing */ +/* permissions and limitations under the License. */ +/* */ +/* IBM_PROLOG_END_TAG */ +//----------------------------------------------------------------------------- +// *! (C) Copyright International Business Machines Corp. 2014 +// *! All Rights Reserved -- Property of IBM +// *! *** IBM Confidential *** +//----------------------------------------------------------------------------- + +/// \file ppe42_boot.S +/// \brief PK bootloader for PPE42 + + .nolist +#include "pk.h" + .list + +### PK Bootloader for PPE42 +### +### This is the basic restart initialization of the processor. +### Parts of this code were derived from examples in the IBM OSopen +### OpenBIOS for the 405GP written by James Burke. +### +### This code does not really do very much, just makes sure that there will +### be a reasonable state in the machine when control is turned over to +### the PK application. Any core setup that requires SPR access will be done +### here. All other setup is expected to take place in system-specific +### routines. +### +### From the PowerPC 405-S Embedded Core User's manual: +### +### "In general, the contents of SPRs are undefined after a core, chip or +### system reset. Some SPRs retain the content they had before the reset +### occurred." +### +### Registers fully reset: +### DBCR1 - Data compares disabled +### DCWR - Data cache write-through disabled +### ESR - No exception syndromes +### MSR - No exceptions/interrupts are allowed +### +### Registers partially reset: +### CCR0 = 0x00700000 - Sets ICU and DCU PLB Priority +### DBCR0 [EDM] = 0 - External debug mode disabled +### [RST] = 0 - No reset action +### DBSR [MRR] = x - x indicates most recent reset action +### SGR = 0xffffffff - Storage is guarded +### TCR [WRC] = 0 - Watchdog timer reset disabled +### TSR [WRS] = x - x is a copy of TCR[WRC] Watchdog reset status +### [PIS] = x - undefined + + .global_function __pk_boot + .global __reset_trap + +__pk_boot: + + ## Trap the reset for the debugger. Set R0 to a non-zero value in the + ## debugger to continue. + + .if PPE42_RESET_TRAP + li %r0, 0 +__reset_trap: + cmpwi %r0, 0 + beq __reset_trap + .endif + + ## Set up PowerPC EABI constant registers. These registers are never + ## again touched by the PK kernel or the application (if they are + ## behaving). + + _liw %r2, _SDA2_BASE_ + _liw %r13, _SDA_BASE_ + + ## Clear the timer control register. This masks all timer interrupts. + + li %r3, 0 + mttcr %r3 + + ## The stack pointer is initialized for use by the remainder of the + ## initialization, including the application main(). The linker script + ## defines the initial stack area. + ## + ## Stacks are always 8-byte aligned. A '0' is stored at the + ## stack pointer to indicate the end of the stack chain. Stack frames + ## always consist of at least 8 bytes - the backchain pointer and the + ## slot above the backchain pointer for the callee's LR. + + _liw %r1, _PK_INITIAL_STACK + _clrfield %r1, %r1, 3, 29 # 8-byte align + li %r3, 0 + stwu %r3, -8(%r1) + + ## SPRG0 (__PkKernelContext) is initialized to 0 + ## indicating that the PK kernel is not in thread mode, and no + ## interrupts are active. + + li %r3, 0 + mtsprg0 %r3 + + ## Set up the initial value of Debug Control Register 0. Note that + ## DBCR1 is specified to be cleared at reset. VBU simulation requested + ## an option that this register not be modified so that they could + ## completely control debug behavior from reset of the PPE42. + +#ifndef NO_INIT_DBCR0 + _liwa %r3, PPE42_DBCR_INITIAL + mtdbcr %r3 +#endif + + ## The exception vector prefix is set - it must be 512 byte aligned. + ## NOTE: for PPE42, the IVPR is read only, but can be changed through scoms + + #_liw %r3, __vectors + #andi. %r4, %r3, 0x01ff + #beq 1f + #_pk_panic PK_BOOT_VECTORS_NOT_ALIGNED +#1: + #mtivpr %r3 + #sync + + ## The MSR to be used during the rest of intialization is + ## established. This MSR should NOT enable + ## interrupts, but could enable machine check exceptions. + + _liwa %r3, PPE42_MSR_INITIAL + mtmsr %r3 + sync + +#ifdef PK_BOOT_FROM_ROM + + ## NB: I don't think the old linker scripts were necessarily the most + ## optimal. We need to revisit this if we actually do ROM boots in PK + ## Version 2. Not sure the comments are correct. + + ## Data is copied from the initial ROM image to the RAM. The + ## address symbols are defined in the linker command file. The linker + ## will have zeroed this area in the ROM image. + + liw %r3, __pk_ram_lma - 4 # src + liw %r4, __pk_ram_vma - 4 # dest + liw %r5, __pk_ram_size + liw %r6, 2 + srw %r5, %r5, %r6 # Number of word transfers + mtctr %r5 + +copy_loop: + lwzu %r5, 4(%r3) + stwu %r5, 4(%r4) + bdnz copy_loop + +#endif /* PK_BOOT_FROM_ROM */ + + + ## Call the system setup code. + + bl __ppe42_system_setup + + ## Call the application. If for some reason we return from + ## the call of the application we call an alternate entry point of the + ## idle thread. + ## + ## An initial argc/argv can be passed into main(). argc is expected to + ## be a 32-bit immediate integer, and argv is expected to be a 32-bit + ## absolute or relocatable expression. + + _liwa %r3, PPE42_ARGC_INITIAL + _liw %r4, PPE42_ARGV_INITIAL + bl __pk_main + + b __pk_idle_thread_from_bootloader + + .epilogue __pk_boot + diff --git a/src/import/chips/p9/procedures/ppe/pk/ppe42/ppe42_cache.h b/src/import/chips/p9/procedures/ppe/pk/ppe42/ppe42_cache.h new file mode 100644 index 00000000..cb06196d --- /dev/null +++ b/src/import/chips/p9/procedures/ppe/pk/ppe42/ppe42_cache.h @@ -0,0 +1,126 @@ +/* IBM_PROLOG_BEGIN_TAG */ +/* This is an automatically generated prolog. */ +/* */ +/* $Source: import/chips/p9/procedures/ppe/pk/ppe42/ppe42_cache.h $ */ +/* */ +/* OpenPOWER sbe Project */ +/* */ +/* Contributors Listed Below - COPYRIGHT 2015,2016 */ +/* [+] International Business Machines Corp. */ +/* */ +/* */ +/* Licensed under the Apache License, Version 2.0 (the "License"); */ +/* you may not use this file except in compliance with the License. */ +/* You may obtain a copy of the License at */ +/* */ +/* http://www.apache.org/licenses/LICENSE-2.0 */ +/* */ +/* Unless required by applicable law or agreed to in writing, software */ +/* distributed under the License is distributed on an "AS IS" BASIS, */ +/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or */ +/* implied. See the License for the specific language governing */ +/* permissions and limitations under the License. */ +/* */ +/* IBM_PROLOG_END_TAG */ +#ifndef __PPE42_CACHE_H__ +#define __PPE42_CACHE_H__ + +//----------------------------------------------------------------------------- +// *! (C) Copyright International Business Machines Corp. 2014 +// *! All Rights Reserved -- Property of IBM +// *! *** IBM Confidential *** +//----------------------------------------------------------------------------- + +/// \file ppe42_cache.h +/// \brief PowerPC-lite (PPE) cache management header for PK +/// +/// The data cache flush/invalidate macros defined here create a compiler +/// memory barrier that will cause GCC to flush/invalidate all memory data +/// held in registers before the macro. + +#ifndef __ASSEMBLER__ + +/// Determine cache-alignment of a pointer or byte-count +#define cache_aligned(x) \ + ((((unsigned long)(x)) & (POW2_32(LOG_CACHE_LINE_SIZE) - 1)) == 0) + +/// Cache-align a pointer or byte count. If the 'direction' is <= 0 then we +/// round down, else round up. +#define cache_align(x, direction) \ + ({ \ + unsigned long __x = (unsigned long)(x); \ + unsigned long __r; \ + if ((direction) <= 0) { \ + __r = __x & ~(((unsigned long)CACHE_LINE_SIZE) - 1); \ + } else { \ + if (__x % CACHE_LINE_SIZE) { \ + __r = __x + (CACHE_LINE_SIZE - (__x % CACHE_LINE_SIZE)); \ + } \ + } \ + (void *)__r; \ + }) + +/// Data Cache Block Flush +#define dcbf(p) asm volatile ("dcbf 0, %0" : : "r" (p) : "memory") + +/// Data Cache Block Touch +#define dcbt(p) asm volatile ("dcbt 0, %0" : : "r" (p) : "memory") + +/// Data Cache Block Invalidate (Privileged) +#define dcbi(p) asm volatile ("dcbi 0, %0" : : "r" (p) : "memory") + +void +dcache_invalidate_all(void); + +void +dcache_flush_all(void); + +void +dcache_invalidate(void* p, size_t bytes); + +void +dcache_flush(void* p, size_t bytes); + +/// Invalidate a line in the D-cache +/// +/// \param p An address withing the cache line to be invalidated. +/// +/// The dcache_invalidate_line() API is used to invalidate a single cache line +/// containing the address \a p. Note that invalidation is a destructive +/// operation that may cause the loss of information. It is the caller's +/// responsibility to insure that no useful data is inadverdently invalidated. +/// D-cache invalidation is more-or-less a no-op for data either not in the +/// cache or marked as non-cacheable. +/// +/// This API always issues a sync() after the invalidation. + +static inline void +dcache_invalidate_line(void* p) +{ + dcbi(p); + sync(); +} + +/// Flush and invalidate a line from the D-cache +/// +/// \param p An address within the cache line to be flushed. +/// +/// The dcache_flush_line() API can be used as a shortcut to flush and +/// invalidate a single cache line. Note that flushing is not a destructive +/// operation in the sense that no information is lost, however the caller +/// must make sure that the entirity of the data to be flushed is contained in +/// the line that includes the address \a p. D-cache flush is more-or-less a +/// no-op for data either not in the cache or marked as non-cacheable. +/// +/// This API always issues a sync() after the flush. + +static inline void +dcache_flush_line(void* p) +{ + dcbf(p); + sync(); +} + +#endif /* __ASSEMBLER__ */ + +#endif /* __PPE42_CAHE_H__ */ diff --git a/src/import/chips/p9/procedures/ppe/pk/ppe42/ppe42_context.h b/src/import/chips/p9/procedures/ppe/pk/ppe42/ppe42_context.h new file mode 100644 index 00000000..e54f255d --- /dev/null +++ b/src/import/chips/p9/procedures/ppe/pk/ppe42/ppe42_context.h @@ -0,0 +1,228 @@ +/* IBM_PROLOG_BEGIN_TAG */ +/* This is an automatically generated prolog. */ +/* */ +/* $Source: import/chips/p9/procedures/ppe/pk/ppe42/ppe42_context.h $ */ +/* */ +/* OpenPOWER sbe Project */ +/* */ +/* Contributors Listed Below - COPYRIGHT 2015,2016 */ +/* [+] International Business Machines Corp. */ +/* */ +/* */ +/* Licensed under the Apache License, Version 2.0 (the "License"); */ +/* you may not use this file except in compliance with the License. */ +/* You may obtain a copy of the License at */ +/* */ +/* http://www.apache.org/licenses/LICENSE-2.0 */ +/* */ +/* Unless required by applicable law or agreed to in writing, software */ +/* distributed under the License is distributed on an "AS IS" BASIS, */ +/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or */ +/* implied. See the License for the specific language governing */ +/* permissions and limitations under the License. */ +/* */ +/* IBM_PROLOG_END_TAG */ +#ifndef __PPE42_CONTEXT_H__ +#define __PPE42_CONTEXT_H__ +//----------------------------------------------------------------------------- +// *! (C) Copyright International Business Machines Corp. 2014 +// *! All Rights Reserved -- Property of IBM +// *! *** IBM Confidential *** +//----------------------------------------------------------------------------- + +/// \file ppe42_context.h +/// \brief PPE42 Machine and Thread context for PK + +/// \page ppe42_machine_context PPE42 Assembler Macros for PK Machine +/// Context (Critical Sections) +/// +/// \section _pk_enter_critical \b _pk_critical_section_enter/exit +/// +/// These macro encapsulates the instruction sequences required to enter and +/// exit critical sections, along with the machine context save for later +/// exiting the critical section. +/// +/// \arg \c ctxreg A register that will hold (holds) the machine context (MSR) +/// prior to entering the critical section (to be restored) for \c +/// _pk_critical_section_enter (\c _pk_critical_section_exit). +/// +/// \arg \c scrreg A scratch register required for the computation of +/// \c _pk_critical_section_enter. +/// +/// Forms: +/// +/// \b _pk_critical_section_enter \a priority, \a ctxreg, \a scrreg - Enter a +/// critical section \n +/// \b _pk_critical_section_exit \a ctxreg - Exit a critical section + +#ifdef __ASSEMBLER__ +// *INDENT-OFF* + + .set _msr_ee_bit, MSR_EE_BIT + + .macro _pk_critical_section_enter ctxreg, scrreg + mfmsr \ctxreg + wrteei 0 + .endm + + .macro _pk_critical_section_exit ctxreg + mtmsr \ctxreg + .endm + +// **************************************************************************** +// PK context save/restore macros for 32-bit Embedded PowerPC +// **************************************************************************** + +// All stack frames are 8-byte aligned in conformance with the EABI. PK +// never saves or restores GPR2 or GPR13. GPR13 is constant in (E)ABI +// applications - the base of the read-write small data area. GPR2 is +// system-reserved in ABI applications, and is the base for read-only small data +// in EABI applications. + +// USPRG0 holds the __PkKernelContext structure (defined in ppe42.h) that +// represents the current kernel context. The layout is as follows: +// +// Bits Meaning +// ============== +// 0 The 'thread_mode' flag +// 1 The 'processing_interrupt" flag +// 2:7 The thread priority of the running thread +// 8 The 'discard_ctx' flag +// 9:15 The IRQ currently being processed +// 16:31 The application specific data +// +// When PK is initialized USPRG0 is initialized to 0. When thread-mode is +// entered (by pk_start_threads()) bit 0 is set to 1. If desired, +// once initialized (with pk_initialize()) PK can simply +// handle interrupts, reverting back to the non-thread-mode idle loop when +// there's nothing to do. +// + + ## ------------------------------------------------------------ + ## Unused registers for embedded PPE42` + ## ------------------------------------------------------------ + + ## Registers GPR2 and GPR13 are never saved or restored. In ABI and + ## EABI applications these registers are constant. + + .set UNUSED_GPR2, 0x2 # Dedicated; EABI read-only small data area + .set UNUSED_GPR13, 0xd # Dedicated; (E)ABI read-write small data area + + ## ------------------------------------------------------------ + ## The PK context layout for Embedded PPE42 + ## ------------------------------------------------------------ + + .set PK_CTX_GPR1, 0x00 # Dedicated; Stack pointer + .set PK_CTX_LINKAGE, 0x04 # Slot for handler to store LR + .set PK_CTX_GPR3, 0x08 # Volatile; Parameter; Return Value + .set PK_CTX_GPR4, 0x0c # Volatile; Parameter + .set PK_CTX_GPR5, 0x10 # Volatile; Parameter + .set PK_CTX_GPR6, 0x14 # Volatile; Parameter + .set PK_CTX_CR, 0x18 # Condition register + .set PK_CTX_LR, 0x1c # Link register + + .set PK_CTX_GPR7, 0x20 # Volatile; Parameter + .set PK_CTX_GPR8, 0x24 # Volatile; Parameter + .set PK_CTX_GPR9, 0x28 # Volatile; Parameter + .set PK_CTX_GPR10, 0x2c # Volatile; Parameter + .set PK_CTX_GPR28, 0x30 # Non-volatile + .set PK_CTX_GPR29, 0x34 # Non-volatile + .set PK_CTX_GPR30, 0x38 # Non-volatile + .set PK_CTX_GPR31, 0x3c # Non-volatile + + .set PK_CTX_XER, 0x40 # Fixed-point exception register + .set PK_CTX_CTR, 0x44 # Count register + .set PK_CTX_SRR0, 0x48 # Save/restore register 0 + .set PK_CTX_SRR1, 0x4c # Save/restore register 1 + .set PK_CTX_GPR0, 0x50 # Volatile; Language specific + .set PK_CTX_KERNEL_CTX, 0x54 # Saved __PkKernelContext for IRQ + + .set PK_CTX_SIZE, 0x58 # Must be 8-byte aligned + + ## ------------------------------------------------------------ + ## Push the interrupted context if necessary + ## + ## This macro saves off some context in preparation for calling + ## the pk_ctx_check_discard routine. This is an attempt to use + ## the 32 byte cache more efficiently. + ## + ## 8 Instructions + ## ------------------------------------------------------------ + ## + + .macro _pk_ctx_push_as_needed branch_addr:req + + stwu %r1, -PK_CTX_SIZE(%r1) + stvd %d3, PK_CTX_GPR3(%r1) + mfcr %r3 + mflr %r4 + stvd %d3, PK_CTX_CR(%r1) + _liw %r3, \branch_addr + b ctx_check_discard + .endm + + + ## ------------------------------------------------------------ + ## update the kernel context in response to an interrupt. + ## ------------------------------------------------------------ + + ## The kernel context is updated with the currently active + ## IRQ in bits 9:15. + + .macro _update_kernel_context irqreg, ctxreg + rlwimi \ctxreg, \irqreg, 16, 9, 15 //set the irq # + oris \ctxreg, \ctxreg, 0x4000 //set the 'processing_interrupt' flag + mtsprg0 \ctxreg + +#if PK_KERNEL_TRACE_ENABLE + mr %r31, \irqreg + srwi \ctxreg, \ctxreg, 16 + PK_KERN_TRACE_ASM16("INTERRUPT_CONTEXT(0x%04x)", \ctxreg) + mr \irqreg, %r31 +#endif + + .endm +// *INDENT-ON* + +#else /* __ASSEMBLER__ */ + +/// PK thread context layout as a C structure. +/// +/// This is the structure of the stack area pointed to by +/// thread->saved_stack_pointer when a thread is fully context-switched out. + +typedef struct +{ + uint32_t r1; + uint32_t linkage; + uint32_t r3; + uint32_t r4; + uint32_t r5; + uint32_t r6; + uint32_t cr; + uint32_t lr; + + uint32_t r7; + uint32_t r8; + uint32_t r9; + uint32_t r10; + uint32_t r28; + uint32_t r29; + uint32_t r30; + uint32_t r31; + + uint32_t xer; + uint32_t ctr; + uint32_t srr0; + uint32_t srr1; + uint32_t r0; + uint32_t sprg0; + +} PkThreadContext; + + +#endif /* __ASSEMBLER__ */ + +#endif /* __PPE42_CONTEXT_H__ */ + + diff --git a/src/import/chips/p9/procedures/ppe/pk/ppe42/ppe42_core.c b/src/import/chips/p9/procedures/ppe/pk/ppe42/ppe42_core.c new file mode 100644 index 00000000..ec8aec6d --- /dev/null +++ b/src/import/chips/p9/procedures/ppe/pk/ppe42/ppe42_core.c @@ -0,0 +1,157 @@ +/* IBM_PROLOG_BEGIN_TAG */ +/* This is an automatically generated prolog. */ +/* */ +/* $Source: import/chips/p9/procedures/ppe/pk/ppe42/ppe42_core.c $ */ +/* */ +/* OpenPOWER sbe Project */ +/* */ +/* Contributors Listed Below - COPYRIGHT 2015,2016 */ +/* [+] International Business Machines Corp. */ +/* */ +/* */ +/* Licensed under the Apache License, Version 2.0 (the "License"); */ +/* you may not use this file except in compliance with the License. */ +/* You may obtain a copy of the License at */ +/* */ +/* http://www.apache.org/licenses/LICENSE-2.0 */ +/* */ +/* Unless required by applicable law or agreed to in writing, software */ +/* distributed under the License is distributed on an "AS IS" BASIS, */ +/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or */ +/* implied. See the License for the specific language governing */ +/* permissions and limitations under the License. */ +/* */ +/* IBM_PROLOG_END_TAG */ +//----------------------------------------------------------------------------- +// *! (C) Copyright International Business Machines Corp. 2014 +// *! All Rights Reserved -- Property of IBM +// *! *** IBM Confidential *** +//----------------------------------------------------------------------------- + +/// \file ppe42_core.c +/// \brief The final bits of PK runtime code required to complete the PPE42 +/// port. +/// +/// The entry points in this file are considered 'core' routines that will +/// always be present during runtime in any PK application. + +#define __PPE42_CORE_C__ + +#include "pk.h" + +typedef union +{ + uint64_t value; + struct + { + uint32_t dec_start; + uint32_t dec_change_tag; + }; +} ppe42_timebase_data_t; + +ppe42_timebase_data_t ppe42_tb_data = {0}; +PkTimebase ppe42_64bit_timebase = 0; + + +#if PK_TIMER_SUPPORT + +// The tickless kernel timer mechanism for PPE42 +// +// This routine must be called from a critical section. +// +// Tickless timeouts are provided by programming the PIT timer based on when +// the next timeout will occur. If the timeout is for the end of time there's +// nothing to do - PK does not use auto-reload mode so no more PIT interrupts +// will be arriving. Otherwise, if the timeout is longer than the 32-bit PIT +// timer can handle, we simply schedule the timeout for 2**32 - 1 and +// __pk_timer_handler() will keep rescheduling it until it finally occurs. +// If the \a timeout is in the past, we schedule the PIT interrupt for 1 tick +// in the future in accordance with the PK specification. + +#ifndef APPCFG_USE_EXT_TIMEBASE +void +__pk_schedule_hardware_timeout(PkTimebase timeout) +{ + PkTimebase now; + uint32_t new_dec; + uint32_t dec; + + if (timeout != PK_TIMEBASE_MAX) + { + + now = pk_timebase_get(); + + if (timeout <= now) + { + new_dec = 1; + } + else if ((timeout - now) > 0xffff0000) + { + new_dec = 0xffff0000; + } + else + { + new_dec = timeout - now; + } + + //read and write the DEC back-to-back so that we lose as little time + //as possible + dec = mfspr(SPRN_DEC); + mtspr(SPRN_DEC, new_dec); + + //update our 64bit accumulator with how much time has advanced since + //we last changed it. + ppe42_64bit_timebase += ppe42_tb_data.dec_start - dec; + + //update our start time so we know how much time has advanced since + //this update of the accumulator + ppe42_tb_data.dec_start = new_dec; + ppe42_tb_data.dec_change_tag++; + } +} + +#else + +void +__pk_schedule_hardware_timeout(PkTimebase timeout) +{ + PkTimebase now; + PkTimebase diff; + uint32_t new_dec; + + if (timeout != PK_TIMEBASE_MAX) + { + + now = pk_timebase_get(); + + //update our 64bit accumulator with the current snapshot + ppe42_64bit_timebase = now; + + if (timeout <= now) + { + new_dec = 1; + } + else + { + diff = (timeout - now); + + if (diff > 0xfffffffful) + { + new_dec = 0xffffffff; + } + else + { + new_dec = diff; + } + } + + mtspr(SPRN_DEC, new_dec); + + } +} + +#endif /* APPCFG_USE_EXT_TIMEBASE */ + +#endif /* PK_TIMER_SUPPORT */ + +#undef __PPE42_CORE_C__ diff --git a/src/import/chips/p9/procedures/ppe/pk/ppe42/ppe42_exceptions.S b/src/import/chips/p9/procedures/ppe/pk/ppe42/ppe42_exceptions.S new file mode 100644 index 00000000..9c89284c --- /dev/null +++ b/src/import/chips/p9/procedures/ppe/pk/ppe42/ppe42_exceptions.S @@ -0,0 +1,525 @@ +/* IBM_PROLOG_BEGIN_TAG */ +/* This is an automatically generated prolog. */ +/* */ +/* $Source: import/chips/p9/procedures/ppe/pk/ppe42/ppe42_exceptions.S $ */ +/* */ +/* OpenPOWER sbe Project */ +/* */ +/* Contributors Listed Below - COPYRIGHT 2015,2016 */ +/* [+] International Business Machines Corp. */ +/* */ +/* */ +/* Licensed under the Apache License, Version 2.0 (the "License"); */ +/* you may not use this file except in compliance with the License. */ +/* You may obtain a copy of the License at */ +/* */ +/* http://www.apache.org/licenses/LICENSE-2.0 */ +/* */ +/* Unless required by applicable law or agreed to in writing, software */ +/* distributed under the License is distributed on an "AS IS" BASIS, */ +/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or */ +/* implied. See the License for the specific language governing */ +/* permissions and limitations under the License. */ +/* */ +/* IBM_PROLOG_END_TAG */ +//----------------------------------------------------------------------------- +// *! (C) Copyright International Business Machines Corp. 2014 +// *! All Rights Reserved -- Property of IBM +// *! *** IBM Confidential *** +//----------------------------------------------------------------------------- + +/// \file ppe42_exceptions.S +/// \brief PPE42 exception vector area. +/// +/// \cond + + .nolist +#include "pk.h" + .list + +## declare and initializes global variables that hold external irq config data +## Each PPE macro type (GPE, CME, and SBE) will have it's own implementation of this macro +## defined in (gpe, cme, sbe)_common.h + .hwmacro_irq_cfg_bitmaps + +### **************************************************************************** +### .vectors - This section contains all ppe42 exception vectors +### +### **************************************************************************** + + .section .vectors, "ax", @progbits + + .global __vectors + +__vectors: + + ############################################################ + # 0x0000 : Machine Check + ############################################################ + + ### Unmaskable interrupts (including program interrupts) are promoted + ### to machine check interrupts if MSR[UIE] = 0 and MSR[ME] = 1. + ### If the machine check was caused by a program interrupt it + ### will be forwarded to the program exception handler. +__machine_check: + + PPE42_MACHINE_CHECK_HANDLER + + ############################################################ + # 0x0040 : System Reset + ############################################################ + .global __system_reset + .org __vectors + 0x0040 +__system_reset: + b __pk_boot + + ############################################################ + # 0x0060 : Data Storage Interrupt + ############################################################ + + .org __vectors + 0x0060 +__data_storage: + + PPE42_DATA_STORAGE_HANDLER + + ############################################################ + # 0x0080 : Instruction Storage Interrupt + ############################################################ + + .org __vectors + 0x0080 +__instruction_storage: + + PPE42_INSTRUCTION_STORAGE_HANDLER + + + ############################################################ + # 0x00A0 : External Interrupt + ############################################################ + + .org __vectors + 0x00A0 +__external_interrupt_vector: + _pk_ctx_push_as_needed __get_ext_irq + + ############################################################ + # 0x00C0 : Alignment Exception + ############################################################ + + .org __vectors + 0x00C0 +__alignment_exception: + + PPE42_ALIGNMENT_HANDLER + + + ############################################################ + # 0x00E0 : Program Interrupt + ############################################################ + + .org __vectors + 0x00E0 + + ### Program exceptions are utilized for emulating the system call + ### instruction (0x44000002) which is used for doing context + ### switches between threads. They can also be used by the code + ### to signal an exception in an error scenario. +__program_exception: + _pk_ctx_push_as_needed program_exception_handler + + + ############################################################ + # 0x0100 : DEC Interrupts + ############################################################ + + .org __vectors + 0x0100 +__dec_interrupt: + _pk_ctx_push_as_needed dec_handler + + ############################################################ + # 0x0120 : FIT Interrupts + ############################################################ + .org __vectors + 0x0120 +__fit_interrupt: + + _pk_ctx_push_as_needed fit_handler + + ############################################################ + # 0x0140 : Watchdog Interrupts + ############################################################ + .org __vectors + 0x0140 +__watchdog_interrupt: + + _pk_ctx_push_as_needed watchdog_handler + + +### **************************************************************************** +### The rest of the code in this file doesn't have to be placed anywhere +### special, so just place it in the .text section. +### **************************************************************************** + + .section .text, "ax", @progbits + + + ## The idle thread has no permanent register context. The idle thread + ## entry point is re-entered whenever the idle thread is scheduled. + + .global __pk_idle_thread + .global __pk_idle_thread_from_bootloader + +__pk_idle_thread: + + ## The idle thread 'uses' the kernel stack. Any register context + ## pushed here is redundant and is wiped out/ignored every time the + ## idle thread is re-scheduled. + + ## The idle thread simply establishes a default machine context and + ## enters the wait-enable state. The idle thread is always entered + ## with interrupts disabled. + ## + ## The kernel context is initialized to indicate that the idle thread + ## is running - the idle thread priority is PK_THREADS, the + ## 'thread-mode' bit is asserted and so is the 'discard-ctx" bit. + ## In addition, the previous kernel context is stored in the lower + ## 16 bits. + ## + ## This loop can also be called from the PK bootloader if main() + ## returns - in which case we don't muck with the SPRG0 or the stack + ## pointer. + mfsprg0 %r3 + srwi %r3, %r3, 16 + oris %r3, %r3, (PK_THREADS << 8) | PPE42_THREAD_MODE | PPE42_DISCARD_CTX + mtsprg0 %r3 + _lwzsd %r1, __pk_kernel_stack + +__pk_idle_thread_from_bootloader: + + PK_KERN_TRACE_ASM16("ENTER_IDLE_STATE") + + _lwzsd %r3, __pk_thread_machine_context_default + _oriwa %r3, %r3, MSR_WE + mtmsr %r3 + b . + + ## pk_halt() is implemented on the ppe42 by writing a value of 0x3 to + ## the RST field of the DBCR. + .global pk_halt +pk_halt: + lis %r31, 0x3000 + mtdbcr %r31 + .long 0 + + +dec_handler: + + ## The portable timer handler of PK is a full-mode handler with the prototype: + ## void (*pk_timer_handler)(void). + ## + ## To support the portable specification, the kernel clears the + ## interrupt by writing the DIS back into the TSR before calling the + ## handler. The timer handler does not take any arguments. + + li %r4, PPE42_IRQ_DEC + _update_kernel_context %r4, %r3 + + _liwa %r3, TSR_DIS + mttsr %r3 + + bl __pk_timer_handler + b check_for_ext_interrupt + +program_exception_handler: + _pk_panic PPE42_ILLEGAL_INSTRUCTION + + .global __pk_next_thread_resume +__pk_next_thread_resume: + + _lwzsd %r3, __pk_next_thread + _stwsd %r3, __pk_current_thread + + ## Enter the wait enabled state if the thread pointer is null + bwz %r3, __pk_idle_thread + + ## switch to the new thread stack + lwz %r1, PK_THREAD_OFFSET_SAVED_STACK_POINTER(%r3) + + ## load sprg0 from the stack and update the thread priority + ## in case it changed. +restore_and_update_sprg0: + _lbzsd %r31, __pk_next_priority + + PK_KERN_TRACE_ASM16("RESUME_THREAD(%d)", %r31) + + lwz %r3, PK_CTX_KERNEL_CTX(%r1) + rlwimi %r3, %r31, 24, 2, 7 + mtsprg0 %r3 + + b ctx_pop + +fit_handler: + + ## The FIT handler is user defined. By + ## convention the kernel clears the interrupt by writing the FIS back + ## into the TSR. + + li %r4, PPE42_IRQ_FIT + + _update_kernel_context %r4, %r3 + + _lwzsd %r3, __ppe42_fit_arg + + _liwa %r6, TSR_FIS + mttsr %r6 + + _lwzsd %r6, __ppe42_fit_routine + mtlr %r6 + blrl + + b check_for_ext_interrupt + +watchdog_handler: + ## Watchdog setup is described in the PK Specification. + ## The kernel clears TSR[WIS] prior to calling the handler. + + li %r4, PPE42_IRQ_WATCHDOG + + _update_kernel_context %r4, %r3 + + _liwa %r6, TSR_WIS + mttsr %r6 + + _lwzsd %r6, __ppe42_watchdog_routine + mtlr %r6 + blrl + + b check_for_ext_interrupt + + + ## Check if we can disard the interrupted context. + ## This routine expects r3, r4, lr, and cr to already be pushed. + ## It also expects r3 to hold the address of the function to jump + ## to after the interrupted context has been pushed (if necessary). + + .align 5 +ctx_check_discard: + + ## Prepare to jump to the branch function that was passed in + mtlr %r3 + + ## Check if the DISCARD_CTX bit is set in the kernel context + mfsprg0 %r3 + bb0wi %r3, PPE42_DISCARD_CTX_BIT, ctx_continue_push + +ctx_discard: + ## DISCARD_CTX bit was set. Discard stack and branch to interrupt + ## handler code + addi %r1, %r1, PK_CTX_SIZE + blr + + ## DISCARD_CTX bit was not set. Continue saving full context. + ## (r3, r4, lr, and cr have already been saved for us) and + ## r3 contains the interrupted kernel context + + .global __ctx_switch +__ctx_switch: + stwu %r1, -PK_CTX_SIZE(%r1) + stvd %d3, PK_CTX_GPR3(%r1) + mfcr %r3 + mflr %r4 + stvd %d3, PK_CTX_CR(%r1) + _liw %r3 __pk_next_thread_resume + mtlr %r3 + ## emulate what interrupt would do + mtsrr0 %r4 + mfmsr %r3 + mtsrr1 %r3 + + ## ctx_continue_push expects r3 to be value of sprg0 + mfsprg0 %r3 + +ctx_continue_push: + + stvd %d5, PK_CTX_GPR5(%r1) + stvd %d7, PK_CTX_GPR7(%r1) + stvd %d9, PK_CTX_GPR9(%r1) + stvd %d28, PK_CTX_GPR28(%r1) + stvd %d30, PK_CTX_GPR30(%r1) + mfxer %r5 + mfctr %r6 + stvd %d5, PK_CTX_XER(%r1) + mfsrr0 %r7 + mfsrr1 %r8 + stvd %d7, PK_CTX_SRR0(%r1) + stw %r0, PK_CTX_GPR0(%r1) + stw %r3, PK_CTX_KERNEL_CTX(%r1) + + ## If the 'processing interrupt' bit is set then we were already + ## using the kernel stack and don't need to modify or save the current + ## stack pointer. + bb1wi %r3, PPE42_PROC_IRQ_BIT, ctx_push_completed + + ## load the pointer to the current thread control block + _lwzsd %r4, __pk_current_thread + + ## don't save the stack pointer in the thread control block + ## if the current thread was the idle thread (null pointer) + bwz %r4, switch_to_kernel_stack + + ## we interrupted a bonafide thread, so save off the stack + ## pointer + stw %r1, PK_THREAD_OFFSET_SAVED_STACK_POINTER(%r4) + +switch_to_kernel_stack: + _stwsd %r1, __pk_saved_sp + _lwzsd %r1, __pk_kernel_stack + +ctx_push_completed: + blr + +__get_ext_irq: + + ## Entry invariants: + ## 1. external interupts are disabled; + ## 2. previous context has ben saved off + ## 3. r3 contains the kernel context + ## 4. r1 points to the kernel stack + + ## This is HW Macro specific code that is responsible for finding the + ## IRQ # and storing it in r4 (phantom IRQ's are assigned a value of EXTERNAL_IRQS). + + hwmacro_get_ext_irq + + ## An active or phantom IRQ was found. + ## R3 has the context of the interrupted thread or bottom half + ## R4 has the IRQ number. + ## The IRQ is converted into a pointer to an 8-byte handler + ## structure, and the handler is dispatched. The call is made with the + ## parameters: + + ## R3 = private data ptr + ## R4 = irq + +call_external_irq_handler: + + _update_kernel_context %r4, %r3 + slwi %r3, %r4, 3 //multiply the irq# by 8 + _liw %r6, __ppe42_irq_handlers + lwzx %r5, %r6, %r3 + addi %r3, %r3, 4 + lwzx %r3, %r6, %r3 + mtlr %r5 + blrl + + ## Once the interrupt handler returns, check if any interrupts are + ## waiting and handle them now. + +check_for_ext_interrupt: + + ## Set the CTX_DISCARD bit in the kernel context so that if there is + ## an interrupt it will not bother saving the full context. + mfsprg0 %r31 + oris %r31, %r31, PPE42_DISCARD_CTX + mtsprg0 %r31 + + ###### Enable/Disable External Interrupts ##### + wrteei 1 + wrteei 0 + + ## If we made it this far, there must not be any interrupts pending. + ## If bottom half processing was interrupted we need to restore it +check_interrupted_bh: + + ## If the thread ID is 33 then the bottom half handler was interrupted + ## and needs to be restored. + extrwi %r4, %r31, 6, 2 + cmpwi %r4, 33 + beq ctx_pop_with_sprg0 + +check_for_bh: + ## if the bottom half queue is pointing to itself then the queue is + ## empty and there are no bottom halves that need processing. + _lwzsd %r4, _pk_bh_queue + lwz %r5, 0(%r4) + cmplwbeq %r4, %r5, restore_interrupted_sp + +process_bottom_halves: + ## Clear the CTX_DISCARD bit so that interrupted bottom half context + ## will be saved in case an interrupt occurs after this point. Also + ## set the thread ID to 33 so that we know to restore the bottom half + ## context that was interrupted. + rlwinm %r3, %r31, 0, 9, 1 //clear thread id + discard bit + oris %r3, %r3, 0x2100 //set thread id to 33 + mtsprg0 %r3 //set bottom half context + + ## branch to a C function that processes bottom halves + wrteei 1 + bl _pk_process_bh + wrteei 0 + + ## restore the previous kernel context (with discard bit set) + mtsprg0 %r31 + +restore_interrupted_sp: + ## restore the interrupted thread stack pointer + _lwzsd %r1, __pk_saved_sp + + ## If we are not in thread mode (i.e., we took an interrupt in an + ## interupt-only configuration of PK or after pk_initialize() but + ## before pk_start_threads) simply pop the context and RFI - in this + ## case we'll most likely be returning to main() or the non-thread-mode + ## idle thread. + +check_thread_mode: + bb0wi %r31, PPE42_THREAD_MODE_BIT, ctx_pop_with_sprg0 + + ## Check if external interrupt activated a delayed context switch. The + ## C-level code has taken care of the scheduling decisions - we simply + ## need to implement them here. +check_for_ctx_switch: + + _lwzsd %r3, __pk_delayed_switch + bwz %r3, check_for_idle_thread + + ## Clear the delayed switch flag and go to the context switch code to + ## finish the switch. + + li %r3, 0 + _stwsd %r3, __pk_delayed_switch + + b __pk_next_thread_resume + + ## check if we should switch to the wait enabled state (idle) +check_for_idle_thread: + _lwzsd %r3, __pk_current_thread + bwz %r3, __pk_idle_thread + +ctx_pop_with_sprg0: + ## we must ensure that interrupts are disabled while restoring context + ## + ## restore sprg0 from the saved context + lwz %r0, PK_CTX_KERNEL_CTX(%r1) + mtsprg0 %r0 + +#if PK_KERNEL_TRACE_ENABLE + srwi %r0, %r0, 16 + PK_KERN_TRACE_ASM16("RESUME_CONTEXT(0x%04x)", %r0) +#endif + +ctx_pop: + lwz %r0, PK_CTX_GPR0(%r1) + lvd %d7, PK_CTX_SRR0(%r1) + mtsrr1 %r8 + mtsrr0 %r7 + lvd %d5, PK_CTX_XER(%r1) + mtctr %r6 + mtxer %r5 + lvd %d30, PK_CTX_GPR30(%r1) + lvd %d28, PK_CTX_GPR28(%r1) + lvd %d9, PK_CTX_GPR9(%r1) + lvd %d7, PK_CTX_GPR7(%r1) + lvd %d5, PK_CTX_GPR5(%r1) + lvd %d3, PK_CTX_CR(%r1) + mtlr %r4 + mtcr0 %r3 + lvd %d3, PK_CTX_GPR3(%r1) + addi %r1, %r1, PK_CTX_SIZE + + rfi + +/// \endcond diff --git a/src/import/chips/p9/procedures/ppe/pk/ppe42/ppe42_gcc.c b/src/import/chips/p9/procedures/ppe/pk/ppe42/ppe42_gcc.c new file mode 100644 index 00000000..9b7aa8a8 --- /dev/null +++ b/src/import/chips/p9/procedures/ppe/pk/ppe42/ppe42_gcc.c @@ -0,0 +1,369 @@ +/* IBM_PROLOG_BEGIN_TAG */ +/* This is an automatically generated prolog. */ +/* */ +/* $Source: import/chips/p9/procedures/ppe/pk/ppe42/ppe42_gcc.c $ */ +/* */ +/* OpenPOWER sbe Project */ +/* */ +/* Contributors Listed Below - COPYRIGHT 2015,2016 */ +/* [+] International Business Machines Corp. */ +/* */ +/* */ +/* Licensed under the Apache License, Version 2.0 (the "License"); */ +/* you may not use this file except in compliance with the License. */ +/* You may obtain a copy of the License at */ +/* */ +/* http://www.apache.org/licenses/LICENSE-2.0 */ +/* */ +/* Unless required by applicable law or agreed to in writing, software */ +/* distributed under the License is distributed on an "AS IS" BASIS, */ +/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or */ +/* implied. See the License for the specific language governing */ +/* permissions and limitations under the License. */ +/* */ +/* IBM_PROLOG_END_TAG */ +//----------------------------------------------------------------------------- +// *! (C) Copyright International Business Machines Corp. 2014 +// *! All Rights Reserved -- Property of IBM +// *! *** IBM Confidential *** +//----------------------------------------------------------------------------- + +/// \file ppe42_gcc.h +/// \brief 32-bit PowerPC functions expected by GCC +/// +/// GCC expects certain built-in functions to be defined in the environment. +/// Since PK applications are statically linked, we must define these +/// functions ourselves to avoid a static link with the GCC libraries, which +/// would legaly require us to distribute (at least) the binary forms of PK +/// applications. +/// +/// We obviously had to look at some GCC library code to understand the +/// specifications of these routines. However, all of the code here is new - +/// no structure definitions or lines of executable code were copied from the +/// GCC sources. + +#include "pk.h" +#include "ppe42_gcc.h" + +/// A 64-bit logical right shift. +/// +/// Note that shifts with negative shift counts or shifts with shift counts +/// longer than 63 bits are undefined. + +uint64_t +__lshrdi3(uint64_t x, int i) +{ + Uint64 input, result; + + if (i == 0) + { + return x; + } + + input.value = x; + + if (i >= 32) + { + result.word[0] = 0; + result.word[1] = input.word[0] >> (i - 32); + } + else + { + result.word[0] = input.word[0] >> i; + result.word[1] = (input.word[1] >> i) | (input.word[0] << (32 - i)); + } + + return result.value; +} + + +/// A 64 bit arithmetic left shift. +/// +/// Note that shifts with negative shift counts or shifts with shift counts +/// longer than 63 bits are undefined. + +uint64_t +__ashldi3(uint64_t x, int i) +{ + Uint64 input, result; + + if (i == 0) + { + return x; + } + + input.value = x; + + if (i >= 32) + { + result.word[1] = 0; + result.word[0] = input.word[1] << (i - 32); + } + else + { + result.word[1] = input.word[1] << i; + result.word[0] = (input.word[0] << i) | (input.word[1] >> (32 - i)); + } + + return result.value ; + +} + + +/// A 64 bit arithmetic right shift. +/// +/// Note that shifts with negative shift counts or shifts with shift counts +/// longer than 63 bits are undefined. + +uint64_t +__ashrdi3(uint64_t x, int i) +{ + Int64 input, result; + + if (i == 0) + { + return x; + } + + input.value = x; + + if (i >= 32) + { + result.word[0] = input.word[0] >> 31; + result.word[1] = input.word[0] >> (i - 32); + } + else + { + result.word[0] = input.word[0] >> i; + result.word[1] = + (((uint32_t)input.word[1]) >> i) | + (input.word[0] << (32 - i)); + } + + return result.value ; + +} + + +/// 32-bit Population count + +// This is a well-known divide-and-conquer algorithm, e.g. look on Wikipedia +// under "Hamming Weight". The idea is to compute sums of adjacent bit +// segments in parallel, in place. + +int +__popcountsi2(uint32_t x) +{ + uint32_t m1 = 0x55555555; + uint32_t m2 = 0x33333333; + uint32_t m4 = 0x0f0f0f0f; + x -= (x >> 1) & m1; /* Sum pairs of bits */ + x = (x & m2) + ((x >> 2) & m2);/* Sum 4-bit segments */ + x = (x + (x >> 4)) & m4; /* Sum 8-bit segments */ + x += x >> 8; /* Sum 16-bit segments */ + return (x + (x >> 16)) & 0x3f; /* Final sum */ +} + + +/// 64-bit Population count + +int +__popcountdi2(uint64_t x) +{ + return __popcountsi2(x >> 32) + __popcountsi2(x & 0xffffffff); +} + + +// 64-bit divides +// +// For the unsigned case, note that divide by 0 returns quotient = remainder = +// 0. +// +// For the signed case, in general we perform the division on the absolute +// values and fix the signs of the quotient and remainder at the end. +// +// For the signed case, the convention in other libraries seems to be to +// ignore the case of the most-negative integer. Although it seems "wrong" to +// return the wrong answer when the right answer can be easily computed, in +// the interest of code size we follow the convention here and ignore the most +// negative integer. +// +// The assembler routine __ppe42_udiv64() assembles to ??? bytes. The full C +// routine __ppc_sdiv64 compiles to ??? bytes with the most-negative checks, +// but only ??? bytes as configured here. + +// For the signed cases, we need to handle the special case that the dividend +// or divisor is the most negative integer. +// +// If the dividend is the most negative integer, then dividing this integer by +// -1 would overflow as a positive quotient, so we set quotient and remainder +// to 0 in this case. For divide by 1, the quotient is the most negative +// integer. Otherwise we adjust the dividend by the absolute value of the +// divisor, then fix up the quotient later by adding or subtracting 1. +// +// If the divisor is the most negative integer, then the quotient is always 0 +// unless the dividend is also the most negative integer, in which case the +// quotient is 1 and the remainder is 0. +// + +uint64_t +__udivdi3(uint64_t u, uint64_t v) +{ + uint64_t quotient, remainder; + + __ppe42_udiv64(u, v, "ient, &remainder); + return quotient; +} + + +uint64_t +__umoddi3(uint64_t u, uint64_t v) +{ + uint64_t quotient, remainder; + + __ppe42_udiv64(u, v, "ient, &remainder); + return remainder; +} + + +#if 0 + #define INT64_T_MIN ((int64_t)(0x8000000000000000ull)) +#endif + +void +__ppe42_sdiv64(int64_t u, int64_t v, + int64_t* quotient, int64_t* remainder) +{ + int q_negate, r_negate; + uint64_t uu, uv; +#if 0 + int fixup = 0; +#endif + + q_negate = (u < 0) ^ (v < 0); + r_negate = (u < 0); + uu = (u < 0 ? -u : u); + uv = (v < 0 ? -v : v); + +#if 0 + + if (u == INT64_T_MIN) + { + if (v == -1) + { + *quotient = 0; + *remainder = 0; + return; + } + else if (v == 1) + { + *quotient = INT64_T_MIN; + *remainder = 0; + return; + } + else if (v == INT64_T_MIN) + { + *quotient = 1; + *remainder = 0; + return; + } + else + { + fixup = 1; + u += (v < 0 ? -v : v); + } + } + else if (v == INT64_T_MIN) + { + *quotient = 0; + *remainder = u; + return; + } + +#endif + + __ppe42_udiv64(uu, uv, (uint64_t*)quotient, (uint64_t*)remainder); + +#if 0 + + if (fixup) + { + *quotient += 1; + } + +#endif + + if (q_negate) + { + *quotient = -(*quotient); + } + + if (r_negate) + { + *remainder = -(*remainder); + } +} + + +int64_t +__divdi3(int64_t u, int64_t v) +{ + int64_t quotient, remainder; + + __ppe42_sdiv64(u, v, "ient, &remainder); + return quotient; +} + + +int64_t +__moddi3(int64_t u, int64_t v) +{ + int64_t quotient, remainder; + + __ppe42_sdiv64(u, v, "ient, &remainder); + return remainder; +} + + +/// 64-bit unsigned compare as a function, returning 0 (<), 1 (==) or 2 (>). + +int +__ucmpdi2(uint64_t i_a, uint64_t i_b) +{ + Uint64 a, b; + int rv; + + a.value = i_a; + b.value = i_b; + + if (a.word[0] < b.word[0]) + { + rv = 0; + } + else if (a.word[0] > b.word[0]) + { + rv = 2; + } + else if (a.word[1] < b.word[1]) + { + rv = 0; + } + else if (a.word[1] > b.word[1]) + { + rv = 2; + } + else + { + rv = 1; + } + + return rv; +} + + + + + + + + diff --git a/src/import/chips/p9/procedures/ppe/pk/ppe42/ppe42_gcc.h b/src/import/chips/p9/procedures/ppe/pk/ppe42/ppe42_gcc.h new file mode 100644 index 00000000..7b9d37e1 --- /dev/null +++ b/src/import/chips/p9/procedures/ppe/pk/ppe42/ppe42_gcc.h @@ -0,0 +1,98 @@ +/* IBM_PROLOG_BEGIN_TAG */ +/* This is an automatically generated prolog. */ +/* */ +/* $Source: import/chips/p9/procedures/ppe/pk/ppe42/ppe42_gcc.h $ */ +/* */ +/* OpenPOWER sbe Project */ +/* */ +/* Contributors Listed Below - COPYRIGHT 2015,2016 */ +/* [+] International Business Machines Corp. */ +/* */ +/* */ +/* Licensed under the Apache License, Version 2.0 (the "License"); */ +/* you may not use this file except in compliance with the License. */ +/* You may obtain a copy of the License at */ +/* */ +/* http://www.apache.org/licenses/LICENSE-2.0 */ +/* */ +/* Unless required by applicable law or agreed to in writing, software */ +/* distributed under the License is distributed on an "AS IS" BASIS, */ +/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or */ +/* implied. See the License for the specific language governing */ +/* permissions and limitations under the License. */ +/* */ +/* IBM_PROLOG_END_TAG */ +#ifndef __PPE42_GCC_H__ +#define __PPE42_GCC_H__ +//----------------------------------------------------------------------------- +// *! (C) Copyright International Business Machines Corp. 2014 +// *! All Rights Reserved -- Property of IBM +// *! *** IBM Confidential *** +//----------------------------------------------------------------------------- + +/// \file ppe42_gcc.h +/// \brief 32-bit functions expected by GCC + +#ifndef __ASSEMBLER__ + +#include <stdint.h> + +/// A 64-bit unsigned integer type + +typedef union +{ + uint64_t value; + uint32_t word[2]; +} Uint64; + +/// A 64-bit signed integer type + +typedef union +{ + int64_t value; + int32_t word[2]; +} Int64; + +uint64_t +__lshrdi3(uint64_t x, int i); + +uint64_t +__ashldi3(uint64_t x, int i); + +uint64_t +__ashrdi3(uint64_t x, int i); + +int +__popcountsi2(uint32_t x); + +int +__popcountdi2(uint64_t x); + +/// Unsigned 64/64 bit divide, returning quotient and remainder via pointers. + +void +__ppe42_udiv64(uint64_t u, uint64_t v, uint64_t* q, uint64_t* r); + +/// Signed 64/64 bit divide, returning quotient and remainder via pointers. + +void +__ppe42_sdiv64(int64_t u, int64_t v, int64_t* q, int64_t* r); + +uint64_t +__udivdi3(uint64_t u, uint64_t v); + +int64_t +__divdi3(int64_t u, int64_t v); + +int64_t +__moddi3(int64_t u, int64_t v); + +uint64_t +__umoddi3(uint64_t u, uint64_t v); + +int +__ucmpdi2(uint64_t a, uint64_t b); + +#endif /* __ASSEMBLER__ */ + +#endif /* __PPE42_GCC_H__ */ diff --git a/src/import/chips/p9/procedures/ppe/pk/ppe42/ppe42_init.c b/src/import/chips/p9/procedures/ppe/pk/ppe42/ppe42_init.c new file mode 100644 index 00000000..f81b5863 --- /dev/null +++ b/src/import/chips/p9/procedures/ppe/pk/ppe42/ppe42_init.c @@ -0,0 +1,102 @@ +/* IBM_PROLOG_BEGIN_TAG */ +/* This is an automatically generated prolog. */ +/* */ +/* $Source: import/chips/p9/procedures/ppe/pk/ppe42/ppe42_init.c $ */ +/* */ +/* OpenPOWER sbe Project */ +/* */ +/* Contributors Listed Below - COPYRIGHT 2015,2016 */ +/* [+] International Business Machines Corp. */ +/* */ +/* */ +/* Licensed under the Apache License, Version 2.0 (the "License"); */ +/* you may not use this file except in compliance with the License. */ +/* You may obtain a copy of the License at */ +/* */ +/* http://www.apache.org/licenses/LICENSE-2.0 */ +/* */ +/* Unless required by applicable law or agreed to in writing, software */ +/* distributed under the License is distributed on an "AS IS" BASIS, */ +/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or */ +/* implied. See the License for the specific language governing */ +/* permissions and limitations under the License. */ +/* */ +/* IBM_PROLOG_END_TAG */ +//----------------------------------------------------------------------------- +// *! (C) Copyright International Business Machines Corp. 2014 +// *! All Rights Reserved -- Property of IBM +// *! *** IBM Confidential *** +//----------------------------------------------------------------------------- + +/// \file ppe42_init.c +/// \brief PPE42 initialization routines +/// +/// The entry points in this file are routines that are typically used during +/// initialization, and their code space could be deallocated and recovered if +/// no longer needed by the application after initialization. + +#include "pk.h" +#include "pk_trace.h" + +// Note that __ppe42_system_setup() is called from the PK bootloader early +// in the initialization, at a point before the aplication has enabled +// interrupts. + +// This function is expected to be defined by the macro specific code (GPE, CME, SBE) +void __hwmacro_setup(void); + + +void +__ppe42_system_setup() +{ + //Only do this if the application hasn't provided a static table definition +#ifndef STATIC_IRQ_TABLE + PkIrqId irq; + + // Initialize the interrupt vectors. + for (irq = 0; irq < EXTERNAL_IRQS; irq++) + { + __ppe42_irq_handlers[irq].handler = __ppe42_default_irq_handler; + } + + //NOTE: EXTERNAL_IRQS is the phantom interrupt assigned irq + __ppe42_irq_handlers[irq].handler = __ppe42_phantom_irq_handler; + + // Initialize special interrupt handlers + + __ppe42_fit_routine = __ppe42_default_irq_handler; + __ppe42_fit_arg = 0; + + __ppe42_watchdog_routine = __ppe42_default_irq_handler; + __ppe42_watchdog_arg = 0; + + /* + __ppe42_debug_routine = __ppe42_default_irq_handler; + __ppe42_debug_arg = 0; + */ +#endif /*STATIC_IRQ_TABLE*/ + + //Clear all status bits in the TSR + mtspr(SPRN_TSR, TSR_ENW | TSR_WIS | TSR_DIS | TSR_FIS); + +#ifdef APPCFG_USE_EXT_TIMEBASE + //Enable the DEC interrupt and configure it to use the external dec_timer signal + mtspr(SPRN_TCR, TCR_DIE | TCR_DS); +#else + //Enable the DEC interrupt and configure it to use the internal clock signal + mtspr(SPRN_TCR, TCR_DIE); +#endif /* APPCFG_USE_EXT_TIMEBASE */ + +#if PK_TIMER_SUPPORT +#if PK_TRACE_SUPPORT + extern PkTraceBuffer g_pk_trace_buf; + //set the ppe instance id + g_pk_trace_buf.instance_id = (uint16_t)(mfspr(SPRN_PIR) & PIR_PPE_INSTANCE_MASK); +#endif /* PK_TRACE_SUPPORT */ +#endif /* PK_TIMER_SUPPORT */ + + //call macro-specific setup + __hwmacro_setup(); +} + + diff --git a/src/import/chips/p9/procedures/ppe/pk/ppe42/ppe42_irq.h b/src/import/chips/p9/procedures/ppe/pk/ppe42/ppe42_irq.h new file mode 100644 index 00000000..24f30fa1 --- /dev/null +++ b/src/import/chips/p9/procedures/ppe/pk/ppe42/ppe42_irq.h @@ -0,0 +1,244 @@ +/* IBM_PROLOG_BEGIN_TAG */ +/* This is an automatically generated prolog. */ +/* */ +/* $Source: import/chips/p9/procedures/ppe/pk/ppe42/ppe42_irq.h $ */ +/* */ +/* OpenPOWER sbe Project */ +/* */ +/* Contributors Listed Below - COPYRIGHT 2015,2016 */ +/* [+] International Business Machines Corp. */ +/* */ +/* */ +/* Licensed under the Apache License, Version 2.0 (the "License"); */ +/* you may not use this file except in compliance with the License. */ +/* You may obtain a copy of the License at */ +/* */ +/* http://www.apache.org/licenses/LICENSE-2.0 */ +/* */ +/* Unless required by applicable law or agreed to in writing, software */ +/* distributed under the License is distributed on an "AS IS" BASIS, */ +/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or */ +/* implied. See the License for the specific language governing */ +/* permissions and limitations under the License. */ +/* */ +/* IBM_PROLOG_END_TAG */ +#ifndef __PPE42_IRQ_H__ +#define __PPE42_IRQ_H__ +//----------------------------------------------------------------------------- +// *! (C) Copyright International Business Machines Corp. 2014 +// *! All Rights Reserved -- Property of IBM +// *! *** IBM Confidential *** +//----------------------------------------------------------------------------- + +/// \file ppe42_irq.h +/// \brief PPE42 interrupt handling for PK +/// +/// Interrupt handling protocols and interrupt controller programming are +/// inherently non-portable, however PK defines APIs that may be useful among +/// different machines. +/// + + +// Define pseudo-IRQ numbers for PPE42 built-in interrupts. These numbers +// will appear in bits 16:23 of SPRG0 (__PkKernelContext) when the handlers +// are active + +#define PPE42_EXC_MACHINE_CHECK 0x50 +#define PPE42_EXC_DATA_STORAGE 0x53 +#define PPE42_EXC_INSTRUCTION_STORAGE 0x54 +#define PPE42_EXC_ALIGNMENT 0x56 +#define PPE42_EXC_PROGRAM 0x57 +#define PPE42_IRQ_DEC 0x58 +#define PPE42_IRQ_FIT 0x59 +#define PPE42_IRQ_WATCHDOG 0x5A + + +// Unhandled exceptions default to a kernel panic, but the application can +// override these definition. Note that the exception area only allocates 32 +// bytes (8 instructions) to an unhandled exception, so any redefinition +// would most likely be a branch to an application-defined handler. + +#ifndef PPE42_MACHINE_CHECK_HANDLER + #define PPE42_MACHINE_CHECK_HANDLER PK_PANIC( PPE42_MACHINE_CHECK_PANIC) +#endif + +#ifndef PPE42_DATA_STORAGE_HANDLER + #define PPE42_DATA_STORAGE_HANDLER PK_PANIC(PPE42_DATA_STORAGE_PANIC) +#endif + +#ifndef PPE42_INSTRUCTION_STORAGE_HANDLER +#define PPE42_INSTRUCTION_STORAGE_HANDLER \ + PK_PANIC(PPE42_INSTRUCTION_STORAGE_PANIC) +#endif + +#ifndef PPE42_ALIGNMENT_HANDLER + #define PPE42_ALIGNMENT_HANDLER PK_PANIC(PPE42_DATA_ALIGNMENT_PANIC) +#endif + + +//////////////////////////////////////////////////////////////////////////// +// PK API +//////////////////////////////////////////////////////////////////////////// + +#ifndef __ASSEMBLER__ + +/// An IRQ handler takes 2 arguments: +/// \arg \c arg - Private handler data installed by \c ssx_irq_setup() or +/// \c ssx_irq_handler_set(). +/// \arg \c irq - The IRQ id; to enable a generic handler to manipulate +/// its own interrupt status . + +typedef void (*PkIrqHandler)(void* arg, PkIrqId irq); + +/// Declare a subroutine as an IRQ handler + +#define PK_IRQ_HANDLER(f) void f(void* arg, PkIrqId irq) + +int pk_irq_setup(PkIrqId irq, + int polarity, + int trigger); + +int pk_irq_handler_set(PkIrqId irq, + PkIrqHandler handler, + void* arg); + +void pk_irq_enable(PkIrqId irq); +void pk_irq_disable(PkIrqId irq); +void pk_irq_statusclear(PkIrqId irq); + +PK_IRQ_HANDLER(__ppe42_default_irq_handler); +PK_IRQ_HANDLER(__ppe42_phantom_irq_handler); + + +int +ppe42_fit_setup(int tcr_fp, PkIrqHandler handler, void* arg); + + +/// The address of the optional FIT interrupt handler + +UNLESS__PPE42_IRQ_CORE_C__(extern) +volatile +PkIrqHandler __ppe42_fit_routine; + + +/// The private data of the optional FIT interrupt handler + +UNLESS__PPE42_IRQ_CORE_C__(extern) +volatile +void* __ppe42_fit_arg; + + +int +ppe42_watchdog_setup(int tcr_wp, int tcr_wrc, + PkIrqHandler handler, void* arg); + + +/// The address of the optional Watchdog interrupt handler + +UNLESS__PPE42_IRQ_CORE_C__(extern) +volatile +PkIrqHandler __ppe42_watchdog_routine; + + +/// The private data of the optional Watchdog interrupt handler + +UNLESS__PPE42_IRQ_CORE_C__(extern) +volatile +void* __ppe42_watchdog_arg; + + +int +ppe42_debug_setup(PkIrqHandler handler, void* arg); + + +/// The address of the optional Debug interrupt handler + +UNLESS__PPE42_IRQ_CORE_C__(extern) +volatile +PkIrqHandler __ppe42_debug_routine; + + +/// The private data of the optional Watchdog interrupt handler + +UNLESS__PPE42_IRQ_CORE_C__(extern) +volatile +void* __ppe42_debug_arg; + +#endif /* __ASSEMBLER__ */ + +// It's hard to be portable and get all of the definitions and headers in the +// correct order. We need to bring in the system IRQ header here. + +#ifdef HWMACRO_GPE + #include "gpe_irq.h" +#else + #ifdef HWMACRO_STD + #include "std_irq.h" + #endif +#endif + +/// \page ppe42_irq_macros_page PPE42 PK IRQ Assembler Macros +/// +/// + +#ifndef __ASSEMBLER__ + + +/// This structure holds the interrupt handler routine addresses and private +/// data. Assembler code assumes the given structure layout, so any changes +/// to this structure will need to be reflected down into the interrupt +/// dispatch assembler code. + +typedef struct +{ + PkIrqHandler handler; + void* arg; +} Ppe42IrqHandler; + + +#ifdef STATIC_IRQ_TABLE + +#define IRQ_HANDLER(func, arg) \ + {func, arg}, + +#define IRQ_HANDLER_DEFAULT \ + {__ppe42_default_irq_handler, 0}, + +#define EXTERNAL_IRQ_TABLE_END \ + {__ppe42_phantom_irq_handler, 0}\ + }; + +#define EXTERNAL_IRQ_TABLE_START \ + Ppe42IrqHandler __ppe42_irq_handlers[EXTERNAL_IRQS + 1] = \ + { + +#else + +#define EXTERNAL_IRQ_TABLE_START + +#define IRQ_HANDLER(func, arg) + +#define IRQ_HANDLER_DEFAULT + +#define EXTERNAL_IRQ_TABLE_END + +#endif /*STATIC_IRQ_TABLE*/ + +/// Interrupt handlers for real (implemented interrupts) plus one for the phantom interrupt handler +extern Ppe42IrqHandler __ppe42_irq_handlers[EXTERNAL_IRQS + 1]; + + +/// The 'phantom interrupt' handler +/// +/// A 'phantom' interrupt occurs when the interrupt handling code in the +/// kernel is entered, but no interrupt is found pending in the controller. +/// This is considered a serious bug, as it indictates a short window +/// condition where a level-sensitive interrupt has been asserted and then +/// quickly deasserted before it can be handled. + +UNLESS__PPE42_IRQ_CORE_C__(extern) +Ppe42IrqHandler __ppe42_phantom_irq; + +#endif /* __ASSEMBLER__ */ + +#endif /* __PPE42_IRQ_H__ */ diff --git a/src/import/chips/p9/procedures/ppe/pk/ppe42/ppe42_irq_core.c b/src/import/chips/p9/procedures/ppe/pk/ppe42/ppe42_irq_core.c new file mode 100644 index 00000000..0021457f --- /dev/null +++ b/src/import/chips/p9/procedures/ppe/pk/ppe42/ppe42_irq_core.c @@ -0,0 +1,71 @@ +/* IBM_PROLOG_BEGIN_TAG */ +/* This is an automatically generated prolog. */ +/* */ +/* $Source: import/chips/p9/procedures/ppe/pk/ppe42/ppe42_irq_core.c $ */ +/* */ +/* OpenPOWER sbe Project */ +/* */ +/* Contributors Listed Below - COPYRIGHT 2015,2016 */ +/* [+] International Business Machines Corp. */ +/* */ +/* */ +/* Licensed under the Apache License, Version 2.0 (the "License"); */ +/* you may not use this file except in compliance with the License. */ +/* You may obtain a copy of the License at */ +/* */ +/* http://www.apache.org/licenses/LICENSE-2.0 */ +/* */ +/* Unless required by applicable law or agreed to in writing, software */ +/* distributed under the License is distributed on an "AS IS" BASIS, */ +/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or */ +/* implied. See the License for the specific language governing */ +/* permissions and limitations under the License. */ +/* */ +/* IBM_PROLOG_END_TAG */ +//----------------------------------------------------------------------------- +// *! (C) Copyright International Business Machines Corp. 2014 +// *! All Rights Reserved -- Property of IBM +// *! *** IBM Confidential *** +//----------------------------------------------------------------------------- + +/// \file ppe42_irq_core.c +/// \brief Core IRQ routines required of any PPE42 configuration of PK +/// +/// This file is mostly only a placeholder - where 'extern inline' API +/// functions and 'extern' variables are realized. A couple of default +/// handlers are also installed here. The entry points in this file are +/// considered 'core' routines that will always be present at runtime in any +/// PK application. + +#define __PPE42_IRQ_CORE_C__ + +#include "pk.h" + +#ifndef STATIC_IRQ_TABLE + Ppe42IrqHandler __ppe42_irq_handlers[EXTERNAL_IRQS + 1]; +#endif + +/// This function is installed by default for interrupts not explicitly set up +/// by the application. These interrupts should never fire. + +void +__ppe42_default_irq_handler(void* arg, PkIrqId irq) +{ + PK_PANIC(PK_DEFAULT_IRQ_HANDLER); +} + + +/// This function is installed by default to handle the case that the +/// interrupt dispatch code is entered in response to an external +/// interrupt, but no interrupt is found pending in the interrupt +/// controller. This should never happen, as it would indicate that a +/// 'glitch' occurred on the external interrupt input +/// to the PPE42 core. + +void __ppe42_phantom_irq_handler(void* arg, PkIrqId irq) +{ + PK_PANIC(PPE42_PHANTOM_INTERRUPT); +} + + +#undef __PPE42_IRQ_CORE_C__ diff --git a/src/import/chips/p9/procedures/ppe/pk/ppe42/ppe42_msr.h b/src/import/chips/p9/procedures/ppe/pk/ppe42/ppe42_msr.h new file mode 100644 index 00000000..8660f20d --- /dev/null +++ b/src/import/chips/p9/procedures/ppe/pk/ppe42/ppe42_msr.h @@ -0,0 +1,112 @@ +/* IBM_PROLOG_BEGIN_TAG */ +/* This is an automatically generated prolog. */ +/* */ +/* $Source: import/chips/p9/procedures/ppe/pk/ppe42/ppe42_msr.h $ */ +/* */ +/* OpenPOWER sbe Project */ +/* */ +/* Contributors Listed Below - COPYRIGHT 2015,2016 */ +/* [+] International Business Machines Corp. */ +/* */ +/* */ +/* Licensed under the Apache License, Version 2.0 (the "License"); */ +/* you may not use this file except in compliance with the License. */ +/* You may obtain a copy of the License at */ +/* */ +/* http://www.apache.org/licenses/LICENSE-2.0 */ +/* */ +/* Unless required by applicable law or agreed to in writing, software */ +/* distributed under the License is distributed on an "AS IS" BASIS, */ +/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or */ +/* implied. See the License for the specific language governing */ +/* permissions and limitations under the License. */ +/* */ +/* IBM_PROLOG_END_TAG */ +#ifndef __PPE42_MSR_H__ +#define __PPE42_MSR_H__ +//----------------------------------------------------------------------------- +// *! (C) Copyright International Business Machines Corp. 2014 +// *! All Rights Reserved -- Property of IBM +// *! *** IBM Confidential *** +//----------------------------------------------------------------------------- + +/// \file ppe42_msr.h +/// \brief Everything related to the PPE42 Machine State Register +/// +/// All of the macros defined here that \e modify the MSR create a compiler +/// memory barrier that will cause GCC to flush/invalidate all memory data +/// held in registers before the macro. This is consistent with other systems, +/// e.g., the PowerPC Linux kernel, and is the safest way to define these +/// macros as it guarantess for example that kernel data structure updates +/// have completed before exiting a critical section. + +#define MSR_SEM 0x7f000000 /* SIB Error Mask */ +#define MSR_IS0 0x00800000 /* Instance-Specific Field 0 */ +#define MSR_SIBRC 0x00700000 /* Last SIB return code */ +#define MSR_LP 0x00080000 /* Low Priority */ +#define MSR_WE 0x00040000 /* Wait State Enable */ +#define MSR_IS1 0x00020000 /* Instance-Specific Field 1 */ +#define MSR_UIE 0x00010000 /* Unmaskable Interrupt Enable */ +#define MSR_EE 0x00008000 /* External Interrupt Enable */ +#define MSR_ME 0x00001000 /* Machine Check Exception Enable */ +#define MSR_IPE 0x00000100 /* Imprecise Mode Enable */ +#define MSR_SIBRCA 0x000000ff /* SIB Return Code Accumulator */ + +//#define MSR_CE_BIT 14 +#define MSR_EE_BIT 16 +//#define MSR_IR_BIT 26 +//#define MSR_DR_BIT 27 + + +#define MSR_SEM_START_BIT 1 +#define MSR_SEM_LEN 7 +#define MSR_SIBRC_START_BIT 9 +#define MSR_SIBRC_LEN 3 + + +#ifndef __ASSEMBLER__ + +/// Move From MSR + +#define mfmsr() \ + ({uint32_t __msr; \ + asm volatile ("mfmsr %0" : "=r" (__msr)); \ + __msr;}) + + +/// Move to MSR + +#define mtmsr(value) \ + asm volatile ("mtmsr %0" : : "r" (value) : "memory") + + +/// Read-Modify-Write the MSR with OR (Set MSR bits). This operation is only +/// guaranteed atomic in a critical section. + +#define or_msr(x) \ + mtmsr(mfmsr() | (x)) + + +/// Read-Modify-Write the MSR with AND complement (Clear MSR bits). This +/// operation is only guaranteed atomic in a critical section. + +#define andc_msr(x) \ + mtmsr(mfmsr() & ~(x)) + + +/// Write MSR[EE] with an immediate value (0/1) +/// +/// Note that the immediate value \a i must be a compile-time constant. + +#define wrteei(i) \ + asm volatile ("wrteei %0" : : "i" (i) : "memory") + + +/// Write MSR[EE] from the EE bit of another MSR + +#define wrtee(other_msr) \ + asm volatile ("wrtee %0" : : "r" (other_msr) : "memory") + +#endif /* __ASSEMBLER__ */ + +#endif /* __PPE42_MSR_H__ */ diff --git a/src/import/chips/p9/procedures/ppe/pk/ppe42/ppe42_scom.c b/src/import/chips/p9/procedures/ppe/pk/ppe42/ppe42_scom.c new file mode 100755 index 00000000..1dffcef4 --- /dev/null +++ b/src/import/chips/p9/procedures/ppe/pk/ppe42/ppe42_scom.c @@ -0,0 +1,103 @@ +/* IBM_PROLOG_BEGIN_TAG */ +/* This is an automatically generated prolog. */ +/* */ +/* $Source: import/chips/p9/procedures/ppe/pk/ppe42/ppe42_scom.c $ */ +/* */ +/* OpenPOWER sbe Project */ +/* */ +/* Contributors Listed Below - COPYRIGHT 2015,2016 */ +/* [+] International Business Machines Corp. */ +/* */ +/* */ +/* Licensed under the Apache License, Version 2.0 (the "License"); */ +/* you may not use this file except in compliance with the License. */ +/* You may obtain a copy of the License at */ +/* */ +/* http://www.apache.org/licenses/LICENSE-2.0 */ +/* */ +/* Unless required by applicable law or agreed to in writing, software */ +/* distributed under the License is distributed on an "AS IS" BASIS, */ +/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or */ +/* implied. See the License for the specific language governing */ +/* permissions and limitations under the License. */ +/* */ +/* IBM_PROLOG_END_TAG */ +//----------------------------------------------------------------------------- +// *! (C) Copyright International Business Machines Corp. 2015 +// *! All Rights Reserved -- Property of IBM +// *! *** IBM Confidential *** +//----------------------------------------------------------------------------- + +/// \file ppe42_scom.c +/// \brief Lowest level PK SCOM definitions. +/// +/// Currently these SCOM functions are only optimized for functionality, not +/// speed. Speed optimization will be done when we have full compiler support +/// for the low-level stvd and lvd SCOM OPs. +/// +/// A FAPI-lite SCOM can call these PK SCOM functions. +/// +/// Comment: +/// - No need to poll for SCOM completion, nor return error code of SCOM fails. +/// A SCOM fail will cause the GPE to hang if configured to do so. But do we +/// necessarily have to do this? Wouldn't a gentle recovery from a SCOM fail +/// be preferred? + +#include "pk.h" +#include "ppe42_scom.h" +#include "ppe42_msr.h" + + +uint32_t putscom_abs(const uint32_t i_address, uint64_t i_data) +{ + + // Perform the Store Virtual Double instruction + PPE_STVD(i_address, i_data); + + // Get the MSR[SIBRC] as the return code + uint32_t rc = mfmsr(); + rc = ((rc & MSR_SIBRC) >> (32 - (MSR_SIBRC_START_BIT + MSR_SIBRC_LEN))); + return (rc); + +} + +uint32_t _putscom( uint32_t i_chiplet_id, uint32_t i_address, uint64_t i_data) +{ + + // Perform the Store Virtual Double Index instruction + PPE_STVDX(i_chiplet_id, i_address, i_data); + + // Get the MSR[SIBRC] as the return code + uint32_t rc = mfmsr(); + rc = ((rc & MSR_SIBRC) >> (32 - (MSR_SIBRC_START_BIT + MSR_SIBRC_LEN))); + return (rc); + +} + +uint32_t getscom_abs( const uint32_t i_address, uint64_t* o_data) +{ + uint64_t temp; + // Perform the Load Virtual Double instruction + PPE_LVD(i_address, temp); + PPE_STVD(o_data, temp); + + // Get the MSR[SIBRC] as the return code + uint32_t rc = mfmsr(); + rc = ((rc & MSR_SIBRC) >> (32 - (MSR_SIBRC_START_BIT + MSR_SIBRC_LEN))); + return (rc); +} + + +uint32_t _getscom( const uint32_t i_chiplet_id, const uint32_t i_address, uint64_t* o_data) +{ + uint64_t temp; + // Perform the Load Virtual Double Index instruction + PPE_LVDX(i_chiplet_id, i_address, temp); + PPE_STVD(o_data, temp); + + // Get the MSR[SIBRC] as the return code + uint32_t rc = mfmsr(); + rc = ((rc & MSR_SIBRC) >> (32 - (MSR_SIBRC_START_BIT + MSR_SIBRC_LEN))); + return (rc); + +} diff --git a/src/import/chips/p9/procedures/ppe/pk/ppe42/ppe42_scom.h b/src/import/chips/p9/procedures/ppe/pk/ppe42/ppe42_scom.h new file mode 100755 index 00000000..d3a8d2a7 --- /dev/null +++ b/src/import/chips/p9/procedures/ppe/pk/ppe42/ppe42_scom.h @@ -0,0 +1,158 @@ +/* IBM_PROLOG_BEGIN_TAG */ +/* This is an automatically generated prolog. */ +/* */ +/* $Source: import/chips/p9/procedures/ppe/pk/ppe42/ppe42_scom.h $ */ +/* */ +/* OpenPOWER sbe Project */ +/* */ +/* Contributors Listed Below - COPYRIGHT 2015,2016 */ +/* [+] International Business Machines Corp. */ +/* */ +/* */ +/* Licensed under the Apache License, Version 2.0 (the "License"); */ +/* you may not use this file except in compliance with the License. */ +/* You may obtain a copy of the License at */ +/* */ +/* http://www.apache.org/licenses/LICENSE-2.0 */ +/* */ +/* Unless required by applicable law or agreed to in writing, software */ +/* distributed under the License is distributed on an "AS IS" BASIS, */ +/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or */ +/* implied. See the License for the specific language governing */ +/* permissions and limitations under the License. */ +/* */ +/* IBM_PROLOG_END_TAG */ +//----------------------------------------------------------------------------- +// *! (C) Copyright International Business Machines Corp. 2015 +// *! All Rights Reserved -- Property of IBM +// *! *** IBM Confidential *** +//----------------------------------------------------------------------------- + +/// \file ppe42_scom.h +/// \brief Include file for PK SCOMs +/// + +#ifndef __PK_SCOM_H__ +#define __PK_SCOM_H__ + +/// SCOM operations return non-zero error codes that may or may not indicate +/// an actual error, depending on which SCOM is begin accessed. This error +/// code will appear in the MSR[SIBRC] field, bits[9:11] right after the +/// SCOM OP returns. The error code value increases with the severity of the +/// error. +#define PCB_ERROR_NONE 0 +#define PCB_ERROR_RESOURCE_OCCUPIED 1 +#define PCB_ERROR_CHIPLET_OFFLINE 2 +#define PCB_ERROR_PARTIAL_GOOD 3 +#define PCB_ERROR_ADDRESS_ERROR 4 +#define PCB_ERROR_CLOCK_ERROR 5 +#define PCB_ERROR_PACKET_ERROR 6 +#define PCB_ERROR_TIMEOUT 7 + +#ifdef __cplusplus +extern "C" { +#endif + + +/// PPE Load Virtual Double operation +#define PPE_LVD(_m_address, _m_data) \ + asm volatile \ + ( \ + "lvd %[data], 0(%[address]) \n" \ + : [data]"=r"(_m_data) \ + : [address]"b"(_m_address) \ + ); + + +// PPE Store Virtual Double operation +#define PPE_STVD(_m_address, _m_data) \ + asm volatile \ + ( \ + "stvd %[data], 0(%[address]) \n" \ + : [data]"=&r"(_m_data) \ + : "[data]"(_m_data), \ + [address]"b"(_m_address) \ + : "memory" \ + ); + +/// PPE Load Virtual Double Indexed operation +#define PPE_LVDX(_m_base, _m_offset, _m_data) \ + asm volatile \ + ( \ + "lvdx %[data], %[base], %[offset] \n" \ + : [data]"=r"(_m_data) \ + : [base]"b"(_m_base), \ + [offset]"r"(_m_offset) \ + ); + + +// PPE Store Virtual Double Indexed operation +#define PPE_STVDX(_m_base, _m_offset, _m_data) \ + asm volatile \ + ( \ + "stvdx %[data], %[base], %[offset] \n" \ + : [data]"=&r"(_m_data) \ + : "[data]"(_m_data), \ + [base]"b"(_m_base), \ + [offset]"r"(_m_offset) \ + : "memory" \ + ); + +#define PPE_MFMSR(_m_data) \ + asm volatile \ + ( \ + "mfmsr %[data] \n" \ + : [data]"=&r"(*_m_data) \ + : "[data]"(*_m_data) \ + ); + +/// @brief putscom with absolute address +/// @param [in] i_address Fully formed SCOM address +/// @param [in] i_data Pointer to uint64_t data to be written. A pointer is used +/// to optimize the underlying hardware execution +/// +/// @retval On PPE42 platform, unmasked errors will take machine check interrupts +uint32_t putscom_abs(const uint32_t i_address, uint64_t i_data); + +/// @brief getscom with absolute address +/// @param [in] i_address Fully formed SCOM address +/// @param [in] *o_data Pointer to uint64_t data read +/// +/// @retval On PPE42 platform, unmasked errors will take machine check interrupts + +uint32_t getscom_abs( const uint32_t i_address, uint64_t* o_data); + +/// @brief Implementation of PPE putscom functionality +/// @param [in] i_chiplet Chiplet ID (@todo Should only be right justified) +/// @param [in] i_address Base SCOM address +/// @param [in] i_data Pointer to uint64_t data to be written. A pointer is used +/// to optimize the underlying hardware execution +/// +/// @retval On PPE42 platform, unmasked errors will take machine check interrupts +uint32_t _putscom( const uint32_t i_chiplet, const uint32_t i_address, uint64_t i_data); + + +/// @brief Implementation of PPE getscom functionality +/// @param [in] i_chiplet Chiplet ID (@todo Should only be right justified) +/// @param [in] i_address Base SCOM address +/// @param [in] i_data Pointer to uint64_t data read +/// +/// @retval On PPE42 platform, unmasked errors will take machine check interrupts +uint32_t _getscom( uint32_t i_chiplet, uint32_t i_address, uint64_t* o_data); + +extern inline uint32_t putscom(const uint32_t i_chiplet, const uint32_t i_address, uint64_t i_data) +{ + return _putscom(i_chiplet, i_address, i_data); +} + + +extern inline uint32_t getscom(const uint32_t i_chiplet, const uint32_t i_address, uint64_t* o_data) +{ + return _getscom(i_chiplet, i_address, o_data); +} + +#ifdef __cplusplus +} // extern C +#endif + +#endif // __PK_SCOM_H__ diff --git a/src/import/chips/p9/procedures/ppe/pk/ppe42/ppe42_spr.h b/src/import/chips/p9/procedures/ppe/pk/ppe42/ppe42_spr.h new file mode 100644 index 00000000..f95139bd --- /dev/null +++ b/src/import/chips/p9/procedures/ppe/pk/ppe42/ppe42_spr.h @@ -0,0 +1,205 @@ +/* IBM_PROLOG_BEGIN_TAG */ +/* This is an automatically generated prolog. */ +/* */ +/* $Source: import/chips/p9/procedures/ppe/pk/ppe42/ppe42_spr.h $ */ +/* */ +/* OpenPOWER sbe Project */ +/* */ +/* Contributors Listed Below - COPYRIGHT 2015,2016 */ +/* [+] International Business Machines Corp. */ +/* */ +/* */ +/* Licensed under the Apache License, Version 2.0 (the "License"); */ +/* you may not use this file except in compliance with the License. */ +/* You may obtain a copy of the License at */ +/* */ +/* http://www.apache.org/licenses/LICENSE-2.0 */ +/* */ +/* Unless required by applicable law or agreed to in writing, software */ +/* distributed under the License is distributed on an "AS IS" BASIS, */ +/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or */ +/* implied. See the License for the specific language governing */ +/* permissions and limitations under the License. */ +/* */ +/* IBM_PROLOG_END_TAG */ +#ifndef __PPE42_SPR_H__ +#define __PPE42_SPR_H__ +//----------------------------------------------------------------------------- +// *! (C) Copyright International Business Machines Corp. 2014 +// *! All Rights Reserved -- Property of IBM +// *! *** IBM Confidential *** +//----------------------------------------------------------------------------- + +/// \file ppe42_spr.h +/// \brief Everything related to PPE42-specific SPRs + +/// \defgroup ppe42_sprs PPE42 SPRs +/// +/// These are the documented SPRs of the PPE42. Most of these SPRs are +/// available in RISCWatch and eCmd using the defined names (minus SPRN_). In +/// some cases RISCWatch/eCMD use different names, which appear in square +/// brackets in the brief comments for each register. RISCWatch/eCMD also +/// allow CR, MSR and IAR (Instruction Address Register) to be accessed as +/// SPRs. +/// +/// @{ + +#define SPRN_XER 0x001 /// Fixed-point exception register +#define SPRN_LR 0x008 /// Link register +#define SPRN_CTR 0x009 /// Count register +#define SPRN_DEC 0x016 /// Decrementer +#define SPRN_SRR0 0x01a /// Save/restore register 0 +#define SPRN_SRR1 0x01b /// Save/restore register 1 +#define SPRN_EDR 0x03d /// Error Data Register +#define SPRN_ISR 0x03e /// Interrupt Status Register +#define SPRN_IVPR 0x03f /// Interrupt Vector Prefix Register +#define SPRN_SPRG0 0x110 /// SPR general register 0 +#define SPRN_PIR 0x11e /// Processor Identification Register +#define SPRN_PVR 0x11f /// Processor version register +#define SPRN_DBCR 0x134 /// Debug Control Register +#define SPRN_DACR 0x13c /// Debug Address Compare Register +#define SPRN_TSR 0x150 /// Timer Status Register +#define SPRN_TCR 0x154 /// Timer Control Register + +/* DBCR - Debug Control Register */ + +#define DBCR_RST_SOFT 0x10000000 /* Reset: 01=Soft Reset */ +#define DBCR_RST_HARD 0x20000000 /* Reset: 10=Hard Reset */ +#define DBCR_RST_HALT 0x30000000 /* Reset: 11=Halt */ +#define DBCR_TRAP 0x01000000 /* Trap Instruction Enable */ +#define DBCR_IACE 0x00800000 /* Instruction Address Compare Enable */ +#define DBCR_DACE_ST 0x00040000 /* Data Address Compare Enable: 01=store */ +#define DBCR_DACE_LD 0x00080000 /* Data Address Compare Enable: 10=load */ +#define DBCR_DACE_STLD 0x000C0000 /* Data Address Compare Enable: 11=both */ + +/* TCR - Timer Control Register */ + +#define TCR_WP_MASK 0xc0000000 /* Watchdog timer select bits */ +#define TCR_WP_0 0x00000000 /* WDT uses timer 0 */ +#define TCR_WP_1 0x40000000 /* WDT uses timer 1 */ +#define TCR_WP_2 0x80000000 /* WDT uses timer 2 */ +#define TCR_WP_3 0xc0000000 /* WDT uses timer 3 */ +#define TCR_WRC_MASK 0x30000000 /* Watchdog Reset Control mask */ +#define TCR_WRC_NONE 0x00000000 /* WDT results in no action */ +#define TCR_WRC_SOFT 0x10000000 /* WDT results in Soft reset */ +#define TCR_WRC_HARD 0x20000000 /* WDT results in Hard reset */ +#define TCR_WRC_HALT 0x30000000 /* WDT results in Halt */ +#define TCR_WIE 0x08000000 /* Watchdog Interrupt Enable */ +#define TCR_DIE 0x04000000 /* Decrementer Interrupt Enable */ +#define TCR_FP_MASK 0x03000000 /* FIT Timer Select bits*/ +#define TCR_FP_0 0x00000000 /* FIT uses timer 0 */ +#define TCR_FP_1 0x01000000 /* FIT uses timer 1 */ +#define TCR_FP_2 0x02000000 /* FIT uses timer 2 */ +#define TCR_FP_3 0x03000000 /* FIT uses timer 3 */ +#define TCR_FIE 0x00800000 /* FIT Interrupt Enable */ +#define TCR_DS 0x00400000 /* Decrementer timer select: 0=every cycle, 1=use dec_timer input signal */ + +#ifndef __ASSEMBLER__ + +typedef union +{ + uint32_t value; + struct + { + unsigned int wp : 2; + unsigned int wrc : 2; + unsigned int wie : 1; + unsigned int die : 1; + unsigned int fp : 2; + unsigned int fie : 1; + unsigned int ds : 1; + unsigned int reserved : 22; + } fields; +} Ppe42TCR; + +#endif /* __ASSEMBLER__ */ + +/* TSR - Timer Status Register */ + +#define TSR_ENW 0x80000000 /* Enable Next Watchdog */ +#define TSR_WIS 0x40000000 /* Watchdog Interrupt Status */ +#define TSR_WRS_MASK 0x30000000 /* Watchdog Reset Status */ +#define TSR_WRS_NONE 0x00000000 /* No watchdog reset has occurred */ +#define TSR_WRS_SOFT 0x10000000 /* Soft reset was forced by the watchdog */ +#define TSR_WRS_HARD 0x20000000 /* Hard reset was forced by the watchdog */ +#define TSR_WRS_HALT 0x30000000 /* Halt was forced by the watchdog */ +#define TSR_DIS 0x08000000 /* Decrementer Interrupt Status */ +#define TSR_FIS 0x04000000 /* FIT Interrupt Status */ + +/* PIR - Processor Identification Register */ +#define PIR_PPE_TYPE_MASK 0x000000E0 +#define PIR_PPE_TYPE_GPE 0x00000020 +#define PIR_PPE_TYPE_CME 0x00000040 +#define PIR_PPE_INSTANCE_MASK 0x0000001F + +#ifndef __ASSEMBLER__ + +/// Move From SPR +/// +/// Note that \a sprn must be a compile-time constant. + +#define mfspr(sprn) \ + ({uint32_t __value; \ + asm volatile ("mfspr %0, %1" : "=r" (__value) : "i" (sprn)); \ + __value;}) + + +/// Move to SPR +/// +/// Note that \a sprn must be a compile-time constant. + +#define mtspr(sprn, value) \ + ({uint32_t __value = (value); \ + asm volatile ("mtspr %0, %1" : : "i" (sprn), "r" (__value)); \ + }) + + +/// Read-Modify-Write an SPR with OR (Set SPR bits) +/// +/// Note that \a sprn must be a compile-time constant. This operation is only +/// guaranteed atomic in a critical section. + +#define or_spr(sprn, x) \ + mtspr(sprn, mfspr(sprn) | (x)) + + +/// Read-Modify-Write an SPR with AND complement (Clear SPR bits) +/// +/// Note that \a sprn must be a compile-time constant. This operation is only +/// guaranteed atomic in a critical section. + +#define andc_spr(sprn, x) \ + mtspr(sprn, mfspr(sprn) & ~(x)) + +#endif /* __ASSEMBLER__ */ + +#ifdef __ASSEMBLER__ +// *INDENT-OFF* + + /// \cond + + // Use this macro to define new mt<spr> and mf<spr> instructions that + // may not exist in the assembler. + + .macro _sprinstrs, name, num + .macro mt\name, reg + mtspr \num, \reg + .endm + .macro mf\name, reg + mfspr \reg, \num + .endm + .endm + + _sprinstrs dbcr, SPRN_DBCR + _sprinstrs tcr, SPRN_TCR + _sprinstrs tsr, SPRN_TSR + _sprinstrs sprg0, SPRN_SPRG0 + _sprinstrs ivpr, SPRN_IVPR + _sprinstrs dec, SPRN_DEC + + /// \endcond + +// *INDENT-ON* +#endif /* __ASSEMBLER__ */ + +#endif /* __PPE42_SPR_H__ */ diff --git a/src/import/chips/p9/procedures/ppe/pk/ppe42/ppe42_string.c b/src/import/chips/p9/procedures/ppe/pk/ppe42/ppe42_string.c new file mode 100644 index 00000000..4f0e954c --- /dev/null +++ b/src/import/chips/p9/procedures/ppe/pk/ppe42/ppe42_string.c @@ -0,0 +1,351 @@ +/* IBM_PROLOG_BEGIN_TAG */ +/* This is an automatically generated prolog. */ +/* */ +/* $Source: import/chips/p9/procedures/ppe/pk/ppe42/ppe42_string.c $ */ +/* */ +/* OpenPOWER sbe Project */ +/* */ +/* Contributors Listed Below - COPYRIGHT 2016 */ +/* [+] International Business Machines Corp. */ +/* */ +/* */ +/* Licensed under the Apache License, Version 2.0 (the "License"); */ +/* you may not use this file except in compliance with the License. */ +/* You may obtain a copy of the License at */ +/* */ +/* http://www.apache.org/licenses/LICENSE-2.0 */ +/* */ +/* Unless required by applicable law or agreed to in writing, software */ +/* distributed under the License is distributed on an "AS IS" BASIS, */ +/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or */ +/* implied. See the License for the specific language governing */ +/* permissions and limitations under the License. */ +/* */ +/* IBM_PROLOG_END_TAG */ + +// Note: this code does not compile under the ppc2ppe backend. +// It emits illegal ppe42 asm instructions. +// __PPE42__ is set by the ppe42 compiler +#ifdef __PPE42__ + +#include <ppe42_string.h> +#ifdef __cplusplus +extern "C" +{ +#endif +void* memset(void* vdest, int ch, size_t len) +{ + uint32_t addr = (uint32_t)vdest; + + while(len && (addr & 0x7)) // not 8 byte aligned + { + uint8_t* p = (uint8_t*)addr; + *p = ch; + ++addr; + --len; + } + + if(len >= sizeof(uint64_t)) + { + uint64_t lch = ch & 0xff; + lch |= lch << 8; + lch |= lch << 16; + lch |= lch << 32; + + while(len >= sizeof(uint64_t)) + { + uint64_t* p = (uint64_t*)addr; + *p = lch; + len -= sizeof(uint64_t); + addr += sizeof(uint64_t); + } + } + + while(len) + { + uint8_t* p = (uint8_t*)addr; + *p = ch; + ++addr; + --len; + } + + return vdest; +} + + +void* memcpy(void* vdest, const void* vsrc, size_t len) +{ + + // Loop, copying 4 bytes + long* ldest = (long*)vdest; + const long* lsrc = (const long*)vsrc; + + while (len >= sizeof(long)) + { + *ldest++ = *lsrc++; + len -= sizeof(long); + } + + // Loop, copying 1 byte + char* cdest = (char*)ldest; + const char* csrc = (const char*)lsrc; + size_t i = 0; + + for (; i < len; ++i) + { + cdest[i] = csrc[i]; + } + + return vdest; +} + +void* memmove(void* vdest, const void* vsrc, size_t len) +{ + // Copy first-to-last + if (vdest <= vsrc) + { + return memcpy(vdest, vsrc, len); + } + + // Copy last-to-first (TO_DO: optimize) + char* dest = (char*)(vdest); + const char* src = (const char*)(vsrc); + size_t i = len; + + for (; i > 0;) + { + --i; + dest[i] = src[i]; + } + + return vdest; +} + +int memcmp(const void* p1, const void* p2, size_t len) +{ + const char* c1 = (const char*)(p1); + const char* c2 = (const char*)(p2); + + size_t i = 0; + + for (; i < len; ++i) + { + long n = (long)(c1[i]) - (long)(c2[i]); + + if (n != 0) + { + return n; + } + } + + return 0; +} + +void* memmem(const void* haystack, size_t haystacklen, + const void* needle, size_t needlelen) +{ + const void* result = NULL; + + if (haystacklen >= needlelen) + { + const char* c_haystack = (const char*)(haystack); + const char* c_needle = (const char*)(needle); + bool match = false; + + size_t i = 0; + + for (; i <= (haystacklen - needlelen); i++) + { + match = true; + + size_t j = 0; + + for (; j < needlelen; j++) + { + if (*(c_haystack + i + j) != *(c_needle + j)) + { + match = false; + break; + } + } + + if (match) + { + result = (c_haystack + i); + break; + } + } + } + + return (void*)(result); +} + + +char* strcpy(char* d, const char* s) +{ + char* d1 = d; + + do + { + *d1 = *s; + + if (*s == '\0') + { + return d; + } + + d1++; + s++; + } + while(1); +} + +char* strncpy(char* d, const char* s, size_t l) +{ + char* d1 = d; + size_t len = 0; + + do + { + if (len++ >= l) + { + break; + } + + *d1 = *s; + + if (*s == '\0') + { + break; + } + + d1++; + s++; + } + while(1); + + // pad the remainder + while( len < l ) + { + d1[len++] = '\0'; + } + + return d; +} + +int strcmp(const char* a, const char* b) +{ + while((*a != '\0') && (*b != '\0')) + { + if (*a == *b) + { + a++; + b++; + } + else + { + return (*a > *b) ? 1 : -1; + } + } + + if (*a == *b) + { + return 0; + } + + if (*a == '\0') + { + return -1; + } + else + { + return 1; + } +} + +size_t strlen(const char* a) +{ + size_t length = 0; + + while(*a++) + { + length++; + } + + return length; +} + +size_t strnlen(const char* s, size_t n) +{ + size_t length = 0; + + while((length < n) && (*s++)) + { + length++; + } + + return length; +} + +char* strcat(char* d, const char* s) +{ + char* _d = d; + + while(*_d) + { + _d++; + } + + while(*s) + { + *_d = *s; + _d++; + s++; + } + + *_d = '\0'; + + return d; +} + +char* strncat(char* d, const char* s, size_t n) +{ + char* _d = d; + + while(*_d) + { + _d++; + } + + while((*s) && (0 != n)) + { + *_d = *s; + _d++; + s++; + n--; + } + + *_d = '\0'; + + return d; +} + + +char* strchr(const char* s, int c) +{ + while((*s != '\0') && (*s != c)) + { + s++; + } + + if (*s == c) + { + return (char*)s; + } + + return NULL; +} +#ifdef __cplusplus +}; +#endif +#endif diff --git a/src/import/chips/p9/procedures/ppe/pk/ppe42/ppe42_string.h b/src/import/chips/p9/procedures/ppe/pk/ppe42/ppe42_string.h new file mode 100644 index 00000000..dfa79c26 --- /dev/null +++ b/src/import/chips/p9/procedures/ppe/pk/ppe42/ppe42_string.h @@ -0,0 +1,73 @@ +/* IBM_PROLOG_BEGIN_TAG */ +/* This is an automatically generated prolog. */ +/* */ +/* $Source: import/chips/p9/procedures/ppe/pk/ppe42/ppe42_string.h $ */ +/* */ +/* OpenPOWER sbe Project */ +/* */ +/* Contributors Listed Below - COPYRIGHT 2016 */ +/* [+] International Business Machines Corp. */ +/* */ +/* */ +/* Licensed under the Apache License, Version 2.0 (the "License"); */ +/* you may not use this file except in compliance with the License. */ +/* You may obtain a copy of the License at */ +/* */ +/* http://www.apache.org/licenses/LICENSE-2.0 */ +/* */ +/* Unless required by applicable law or agreed to in writing, software */ +/* distributed under the License is distributed on an "AS IS" BASIS, */ +/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or */ +/* implied. See the License for the specific language governing */ +/* permissions and limitations under the License. */ +/* */ +/* IBM_PROLOG_END_TAG */ +#ifndef __STRING_H +#define __STRING_H + +#include <stdint.h> +typedef uint32_t size_t; + +#ifndef NULL + #ifdef __cplusplus + #define NULL 0 + #else + #define NULL ((void*)0) + #endif +#endif + +#ifndef __cplusplus + typedef int bool; + #define false 0 + #define true 1 +#endif + +#ifdef __cplusplus +extern "C" +{ +#endif +void* memset(void* s, int c, size_t n) __attribute__ ((weak)); +// void bzero(void *vdest, size_t len); USE memset +void* memcpy(void* dest, const void* src, size_t num) __attribute__ ((weak)); +void* memmove(void* vdest, const void* vsrc, size_t len) __attribute__ ((weak)); +int memcmp(const void* p1, const void* p2, size_t len) __attribute__((weak, pure)); +void* memmem(const void* haystack, size_t haystacklen, + const void* needle, size_t needlelen) __attribute__((weak, pure)); + +char* strcpy(char* d, const char* s) __attribute__ ((weak)); +char* strncpy(char* d, const char* s, size_t l) __attribute__ ((weak)); +int strcmp(const char* s1, const char* s2) __attribute__((weak, pure)); +size_t strlen(const char* s1) __attribute__((weak, pure)); +size_t strnlen(const char* s1, size_t n) __attribute__((weak, pure)); + +char* strcat(char* d, const char* s) __attribute__ ((weak)); +char* strncat(char* d, const char* s, size_t n) __attribute__ ((weak)); + +char* strchr(const char* s, int c) __attribute__((weak, pure)); + + +#ifdef __cplusplus +}; +#endif + +#endif diff --git a/src/import/chips/p9/procedures/ppe/pk/ppe42/ppe42_thread_init.S b/src/import/chips/p9/procedures/ppe/pk/ppe42/ppe42_thread_init.S new file mode 100644 index 00000000..1bed7882 --- /dev/null +++ b/src/import/chips/p9/procedures/ppe/pk/ppe42/ppe42_thread_init.S @@ -0,0 +1,134 @@ +# IBM_PROLOG_BEGIN_TAG +# This is an automatically generated prolog. +# +# $Source: import/chips/p9/procedures/ppe/pk/ppe42/ppe42_thread_init.S $ +# +# OpenPOWER sbe Project +# +# Contributors Listed Below - COPYRIGHT 2015,2016 +# [+] International Business Machines Corp. +# +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or +# implied. See the License for the specific language governing +# permissions and limitations under the License. +# +# IBM_PROLOG_END_TAG +/// \file ppe42_thread_init.S +/// \brief PPE42-specific thread initialization +/// +/// The entry points in this file are routines that are typically used during +/// initialization, and their code space could be deallocated and recovered if +/// no longer needed by the application after initialization. + + .nolist +#include "pk.h" + .list + +/// \fn void __pk_thread_context_initialize(PkThread *thread, PkThreadRoutine thread_routine, void *private) +/// \brief Create the initial thread context on the stack +/// +/// The non-reserved GPRs are prepatterned with 0x0000\<rn\>\<rn\> where \<rn\> is +/// the register number (as decimal). The initial context is set up with the +/// thread running in the default machine context, and when the thread is +/// switched in it will begin executing at the entry point of the thread +/// routine with the \c private parameter in R3. The LR is initialized such +/// that when the thread returns, it will return to the entry point of \c +/// pk_complete(). +#ifdef DOXYGEN_ONLY +void +__pk_thread_context_initialize(PkThread *thread, + PkThreadRoutine thread_routine, + void *private); +#endif +//----------------------------------------------------------------------------- +// *! (C) Copyright International Business Machines Corp. 2014 +// *! All Rights Reserved -- Property of IBM +// *! *** IBM Confidential *** +//----------------------------------------------------------------------------- + +/// \cond + + .global_function __pk_thread_context_initialize + +__pk_thread_context_initialize: + + ## R3 = thread (param) + ## R4 = thread_routine (param) + ## R5 = private (param) + ## R6 = thread stack pointer (computed) + ## R7 = scratch + + .macro _gpr_init, prefix, reg, val + li %r7, \val + stw %r7, \prefix\reg(%r6) + .endm + + ## Initialize volatile context on the thread stack. The CR is cleared, + ## the LR = pk_complete(), R3 has the private parameter. + + lwz %r6, PK_THREAD_OFFSET_SAVED_STACK_POINTER(%r3) + + stwu %r6, -PK_CTX_SIZE(%r6) + + li %r7, 0 + stw %r7, PK_CTX_CR(%r6) + + _liw %r7, pk_complete + stw %r7, PK_CTX_LR(%r6) + + stw %r5, PK_CTX_GPR3(%r6) + + _gpr_init PK_CTX_GPR, 4, 0x0404 + _gpr_init PK_CTX_GPR, 5, 0x0505 + _gpr_init PK_CTX_GPR, 6, 0x0606 + + ## XER and CTR are clear, SRR0 = thread_routine, SRR1 = default machine + ## context. + + li %r7, 0 + stw %r7, PK_CTX_XER(%r6) + stw %r7, PK_CTX_CTR(%r6) + + stw %r4, PK_CTX_SRR0(%r6) + + _lwzsd %r7, __pk_thread_machine_context_default + stw %r7, PK_CTX_SRR1(%r6) + + _gpr_init PK_CTX_GPR, 0, 0x0000 + _gpr_init PK_CTX_GPR, 7, 0x0707 + _gpr_init PK_CTX_GPR, 8, 0x0808 + _gpr_init PK_CTX_GPR, 9, 0x0909 + _gpr_init PK_CTX_GPR, 10, 0x1010 + + ## Initialize the non-volatile context on the thread stack. + + _gpr_init PK_CTX_GPR, 28, 0x2828 + _gpr_init PK_CTX_GPR, 29, 0x2929 + _gpr_init PK_CTX_GPR, 30, 0x3030 + _gpr_init PK_CTX_GPR, 31, 0x3131 + + ## Initialize the kernel context on the thread stack. + ## Note: Thread priority is set later each time the thread is + ## resumed. + + lis %r7, PPE42_THREAD_MODE + stw %r7, PK_CTX_KERNEL_CTX(%r6) + + ## Initialization is done - the stack pointer is stored back in the + ## thread. + + stw %r6, PK_THREAD_OFFSET_SAVED_STACK_POINTER(%r3) + blr + + .epilogue __pk_thread_context_initialize + +/// \endcond diff --git a/src/import/chips/p9/procedures/ppe/pk/ppe42/ppe42_timebase.S b/src/import/chips/p9/procedures/ppe/pk/ppe42/ppe42_timebase.S new file mode 100644 index 00000000..cc40bce4 --- /dev/null +++ b/src/import/chips/p9/procedures/ppe/pk/ppe42/ppe42_timebase.S @@ -0,0 +1,140 @@ +/* IBM_PROLOG_BEGIN_TAG */ +/* This is an automatically generated prolog. */ +/* */ +/* $Source: import/chips/p9/procedures/ppe/pk/ppe42/ppe42_timebase.S $ */ +/* */ +/* OpenPOWER sbe Project */ +/* */ +/* Contributors Listed Below - COPYRIGHT 2015,2016 */ +/* [+] International Business Machines Corp. */ +/* */ +/* */ +/* Licensed under the Apache License, Version 2.0 (the "License"); */ +/* you may not use this file except in compliance with the License. */ +/* You may obtain a copy of the License at */ +/* */ +/* http://www.apache.org/licenses/LICENSE-2.0 */ +/* */ +/* Unless required by applicable law or agreed to in writing, software */ +/* distributed under the License is distributed on an "AS IS" BASIS, */ +/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or */ +/* implied. See the License for the specific language governing */ +/* permissions and limitations under the License. */ +/* */ +/* IBM_PROLOG_END_TAG */ +/// \file ppe42_timebase.S +/// \brief PPE42-specific 64 bit timebase emulation +/// + .nolist +#include "pk.h" + .list + +/// \fn PkTimebase pk_timebase_get(void) +/// \brief Returns a 64 bit timebase +/// +#ifdef DOXYGEN_ONLY +PkTimebase +pk_timebase_get(void); +#endif +//----------------------------------------------------------------------------- +// *! (C) Copyright International Business Machines Corp. 2014 +// *! All Rights Reserved -- Property of IBM +// *! *** IBM Confidential *** +//----------------------------------------------------------------------------- + +/// \cond + .global ppe42_64bit_timebase + .global ppe42_tb_data + .global_function pk_timebase_get + +#ifndef APPCFG_USE_EXT_TIMEBASE + + /// Note that it is ok to use this function in a fast interrupt + /// context + .align 5 + .global_function pk_timebase32_get +pk_timebase32_get: + + //load the decrementer start time and change tag + lvd %r4, ppe42_tb_data@sda21(0) + + //load the lower 32 bits of the 64bit timebase accumulator + lwz %r3, ppe42_64bit_timebase+4@sda21(0) + + //load the current decrementer value + mfdec %r0 + + //load the change tag again (should already be in the cache) + lwz %r6, ppe42_tb_data+4@sda21(0) + + //loop until the change tag is the same (typically should be same) + cmplwbne %r5, %r6, pk_timebase32_get + + //calculate how much time has passed since the decrementer was started and store in r6 + subf %r5, %r0, %r4 + + //add the 32bit difference to our 32bit timebase accumulator + add %r3, %r5, %r3 + + blr + + +/// Use the DEC for our timebase until we have a real timebase register (uses +/// 9 instructions). +/// Note: It is not ok to use this function in a fast interrupt context due to +/// its use of r7 + .align 5 +pk_timebase_get: + + //load the decrementer start time and change tag + lvd %r5, ppe42_tb_data@sda21(0) + + //load 64bit timebase accumulator + lvd %r3, ppe42_64bit_timebase@sda21(0) + + + //load the current decrementer value + mfdec %r0 + + //load the change tag again (should already be in the cache) + lwz %r7, ppe42_tb_data+4@sda21(0) + + //loop until the change tag is the same + cmplwbne %r6, %r7, pk_timebase_get + + //calculate how much time has passed since the decrementer was started and store in r6 + subf %r6, %r0, %r5 + + //add the 32bit difference to the 64bit timebase accumulator + addc %r4, %r6, %r4 + addze %r3, %r3 + + blr + +//enable this once we have a local timebase register in the model +#else + +// use the local timebase register to keep more accurate time with just 6 instructions +// in the common case and 7 otherwise. + .align 5 +pk_timebase_get: + + //load the 64bit timebase accumulator + lvd r3, ppe42_64bit_timebase@sda21(0) + + //read the local timebase register (2 instructions) + _pk_timebase32_get r5, r5 + + //increment the upper 32 bits if the lower 32 bits have flipped + cmplwbge r5, r4, update_lower_32 + + //increment the upper 32 bits + addi r3, r3, 1 + +update_lower_32: + //replace the lower 32bits with what we read from the local timebase register + mr r4, r5 + + blr +#endif /* APPCFG_USE_EXT_TIMEBASE */ +/// \endcond diff --git a/src/import/chips/p9/procedures/ppe/pk/ppe42/ppe42math.h b/src/import/chips/p9/procedures/ppe/pk/ppe42/ppe42math.h new file mode 100644 index 00000000..e4f98cdd --- /dev/null +++ b/src/import/chips/p9/procedures/ppe/pk/ppe42/ppe42math.h @@ -0,0 +1,84 @@ +/* IBM_PROLOG_BEGIN_TAG */ +/* This is an automatically generated prolog. */ +/* */ +/* $Source: import/chips/p9/procedures/ppe/pk/ppe42/ppe42math.h $ */ +/* */ +/* OpenPOWER sbe Project */ +/* */ +/* Contributors Listed Below - COPYRIGHT 2016 */ +/* [+] International Business Machines Corp. */ +/* */ +/* */ +/* Licensed under the Apache License, Version 2.0 (the "License"); */ +/* you may not use this file except in compliance with the License. */ +/* You may obtain a copy of the License at */ +/* */ +/* http://www.apache.org/licenses/LICENSE-2.0 */ +/* */ +/* Unless required by applicable law or agreed to in writing, software */ +/* distributed under the License is distributed on an "AS IS" BASIS, */ +/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or */ +/* implied. See the License for the specific language governing */ +/* permissions and limitations under the License. */ +/* */ +/* IBM_PROLOG_END_TAG */ +#ifndef _MATH_H +#define _MATH_H + +#ifdef __cplusplus +extern "C" +{ +#endif +// These names are emitted by the ppe42 compiler. +// Implement the ones that will be used. + +// 64 bit unsigned divide. Implement if needed +// unsigned long long __udivdi3(unsigned long long a, unsigned long long b); + +/** 32 bit unsigned divide + * @param[in] Dividend + * @param[in] Divisor + * @return quotient + */ +unsigned long __udivsi3(unsigned long a, unsigned long b); + +/** 32 bit signed divide + * @param[in] Dividend + * @param[in] Divisor + * @return quotient + */ +int __divsi3(int _a, int _b); + +/** 32 bit unsigned modulus + * @param[in] Dividend + * @param[in] Divisor + * @return modulus + */ +unsigned long __umodsi3(unsigned long a, unsigned long b); + +/** 32 bit unsigned multiply + * @param[in] multiplier + * @param[in] multiplier + * @return product + */ +unsigned long __umulsi3(unsigned long _a, unsigned long _b); + +/** 32 bit signed multiply + * @param[in] multiplier + * @param[in] multiplier + * @return product + */ +unsigned int __mulsi3(unsigned int _a, unsigned int _b); + +/** 64 bit signed multiply + * @param[in] multiplier + * @param[in] multiplier + * @return product + */ +unsigned long long __muldi3(unsigned long long _a, unsigned long long _b); + +#ifdef __cplusplus +}; +#endif + +#endif |