/* IBM_PROLOG_BEGIN_TAG */ /* This is an automatically generated prolog. */ /* */ /* $Source: src/include/arch/ppc.H $ */ /* */ /* OpenPOWER HostBoot Project */ /* */ /* Contributors Listed Below - COPYRIGHT 2011,2016 */ /* [+] Google Inc. */ /* [+] 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 __KERNEL_PPCARCH_H #define __KERNEL_PPCARCH_H #include #include ALWAYS_INLINE inline uint64_t getSRR0() { register uint64_t srr0 = 0; asm volatile("mfsrr0 %0" : "=r" (srr0)); return srr0; } ALWAYS_INLINE inline uint64_t getSRR1() { register uint64_t srr1 = 0; asm volatile("mfsrr1 %0" : "=r" (srr1)); return srr1; } ALWAYS_INLINE inline void setSRR0(uint64_t _srr0) { register uint64_t srr0 = _srr0; asm volatile("mtsrr0 %0" : : "r" (srr0)); } ALWAYS_INLINE inline void setSRR1(uint64_t _srr1) { register uint64_t srr1 = _srr1; asm volatile("mtsrr1 %0" : : "r" (srr1)); } ALWAYS_INLINE inline uint64_t getHSRR0() { register uint64_t hsrr0 = 0; asm volatile("mfspr %0, 314" : "=r" (hsrr0)); return hsrr0; } ALWAYS_INLINE inline uint64_t getHSRR1() { register uint64_t hsrr1 = 0; asm volatile("mfspr %0, 315" : "=r" (hsrr1)); return hsrr1; } ALWAYS_INLINE inline void setHSRR0(uint64_t _hsrr0) { register uint64_t hsrr0 = _hsrr0; asm volatile("mtspr 314, %0" : : "r" (hsrr0)); } ALWAYS_INLINE inline void setHSRR1(uint64_t _hsrr1) { register uint64_t hsrr1 = _hsrr1; asm volatile("mtspr 315, %0" : : "r" (hsrr1)); } ALWAYS_INLINE inline uint64_t getPVR() { register uint64_t pvr = 0; asm volatile("mfspr %0, 287" : "=r" (pvr)); return pvr; } ALWAYS_INLINE inline uint64_t getPIR() { register uint64_t pir = 0; asm volatile("mfspr %0, 1023" : "=r" (pir)); return pir; } ALWAYS_INLINE inline uint64_t getSPRG2() { register uint64_t sprg2 = 0; asm volatile("mfsprg2 %0" : "=r" (sprg2)); return sprg2; } ALWAYS_INLINE inline void setSPRG2(uint64_t _sprg2) { register uint64_t sprg2 = _sprg2; asm volatile("mtsprg2 %0" : : "r" (sprg2)); return; } ALWAYS_INLINE inline uint64_t getSPRG3() { register uint64_t sprg3 = 0; asm volatile("mfsprg3 %0" : "=r" (sprg3)); return sprg3; } ALWAYS_INLINE inline void setSPRG3(uint64_t _sprg3) { register uint64_t sprg3 = _sprg3; asm volatile("mtsprg3 %0" : : "r" (sprg3)); return; } ALWAYS_INLINE inline uint64_t getMSR() { register uint64_t msr = 0; asm volatile("mfmsr %0" : "=r" (msr)); return msr; } ALWAYS_INLINE inline void setMSR(uint64_t _msr) { register uint64_t msr = _msr; asm volatile("mtmsr %0; isync" :: "r" (msr)); } ALWAYS_INLINE inline uint64_t getDSISR() { register uint64_t dsisr = 0; asm volatile("mfspr %0, 18" : "=r" (dsisr)); return dsisr; } ALWAYS_INLINE inline uint64_t getDAR() { register uint64_t dar = 0; asm volatile("mfspr %0, 19" : "=r" (dar)); return dar; } ALWAYS_INLINE inline uint64_t getTB() { register uint64_t tb = 0; asm volatile("mfspr %0, 268" : "=r" (tb)); return tb; } ALWAYS_INLINE inline void setTB(uint64_t _tb) { // The bottom 24 bits of the timebase can't be written so round it up. register uint64_t tb = (_tb + 0x1000000); // Note that SPR 286 is intended (while getTB is 268) here. // This is the mttbu40 instruction and not the mttb, which doesn't exist. asm volatile("mtspr 286, %0" :: "r" (tb)); } ALWAYS_INLINE inline void setDEC(uint64_t _dec) { register uint64_t dec = _dec; asm volatile("mtdec %0" :: "r" (dec)); } ALWAYS_INLINE inline void setRPR(uint64_t _rpr) { register uint64_t rpr = _rpr; asm volatile("mtspr 186, %0" :: "r"(rpr)); } ALWAYS_INLINE inline void sync() { asm volatile("sync" ::: "memory"); } ALWAYS_INLINE inline void lwsync() { asm volatile("lwsync" ::: "memory"); } ALWAYS_INLINE inline void isync() { asm volatile("isync" ::: "memory"); } ALWAYS_INLINE inline void eieio() { asm volatile("eieio" ::: "memory"); } ALWAYS_INLINE inline uint64_t getHMER() { register uint64_t hmer = 0; asm volatile("mfspr %0, 336" : "=r" (hmer)); return hmer; } ALWAYS_INLINE inline void setHMER(uint64_t _hmer) { register uint64_t hmer = _hmer; asm volatile("mtspr 336, %0" : : "r" (hmer)); return; } ALWAYS_INLINE inline uint64_t getHEIR() { register uint64_t heir = 0; asm volatile("mfspr %0, 339" : "=r" (heir)); return heir; } ALWAYS_INLINE inline uint64_t getLPCR() { register uint64_t lpcr = 0; asm volatile("mfspr %0, 318" : "=r" (lpcr)); return lpcr; } ALWAYS_INLINE inline void setLPCR(uint64_t _lpcr) { register uint64_t lpcr = _lpcr; asm volatile("mtspr 318, %0; isync" :: "r" (lpcr)); } ALWAYS_INLINE inline uint64_t getHRMOR() { register uint64_t hrmor = 0; asm volatile("mfspr %0, 313" : "=r" (hrmor)); return hrmor; } ALWAYS_INLINE inline uint64_t getPTCR() { register uint64_t ptcr = 0; asm volatile("mfspr %0, 464" : "=r" (ptcr)); return ptcr; } ALWAYS_INLINE inline void setPTCR(uint64_t _ptcr) { register uint64_t ptcr = _ptcr; asm volatile("mtspr 464, %0; isync" :: "r" (ptcr)); } ALWAYS_INLINE inline void setThreadPriorityLow() { asm volatile("or 1,1,1"); } ALWAYS_INLINE inline void setThreadPriorityHigh() { asm volatile("or 2,2,2"); } ALWAYS_INLINE inline void setThreadPriorityVeryHigh() { asm volatile("or 7,7,7"); } ALWAYS_INLINE inline void dcbf(void* _ptr) { register void* ptr = _ptr; asm volatile("dcbf 0, %0" : : "b" (ptr) : "memory"); } ALWAYS_INLINE inline void dcbst(void* _ptr) { register void* ptr = _ptr; asm volatile("dcbst 0, %0" : : "b" (ptr) : "memory"); } ALWAYS_INLINE inline void dcbz(void* _ptr) { register void* ptr = _ptr; asm volatile("dcbz 0, %0" : : "b" (ptr) : "memory"); } ALWAYS_INLINE inline void icbi(void* _ptr) { register void* ptr = _ptr; asm volatile("icbi 0, %0" : : "b" (ptr) : "memory"); } ALWAYS_INLINE inline void nap() { // @todo-RTC:130186 Add new stop command support //asm volatile("nap"); // Nap should be equivalent to 'stop 1' (no state loss) // 855 reg for HYPV, 823 reg otherwise // using EC(bit43) as 1 here (system reset or LPCR event) // PHYP uses bit 42 as 1 also // register uint64_t psscr = 0x0000000000310001; // asm volatile("mtspr 823, %0; isync" :: "r" (psscr)); // asm volatile(".long 0x4C0002E4"); // When GCC supports 'stop', use it } ALWAYS_INLINE inline void setPSSCR(uint64_t _psscr) { register uint64_t psscr = _psscr; asm volatile("mtspr 855, %0; isync" :: "r" (psscr)); } ALWAYS_INLINE inline uint64_t getPSSCR() { register uint64_t psscr = 0; asm volatile("mfspr %0, 855" : "=r" (psscr)); return psscr; } ALWAYS_INLINE inline size_t getCacheLineBytes() { return 128; } ALWAYS_INLINE inline size_t getCacheLineWords() { return getCacheLineBytes() / sizeof(uint64_t); } ALWAYS_INLINE inline void writeScratchReg(uint64_t _scratch_addr, uint64_t _data) { register uint64_t scratch_addr = _scratch_addr; register uint64_t data = _data; asm volatile("mtspr 276, %0\n" "isync\n" "mtspr 277, %1" :: "r" (scratch_addr), "r" (data)); } /** @brief This is a special assembler instruction that is a nop on * regular hardware, but has special meaning to Simics. Code that * executes this instruction in Simics will cause a "hap," a * Simics term. If there is no hap handler registered, and magic * breakpoints have not been enabled with * simics> enable-magic-breakpoint * then this instruction is also a nop in Simics. * * If magic breakpoints are enabled, and there is no hap handler, then * when Hostboot code executes this instruction in Simics, Simics will * stop the simulation. (Prompt changes from running> to simics> ) * * If a hap is registered, then Simics will call the hap handler. Hap * handlers are written in Python, and the best place for them is * * src/build/debug/simics-debug-framework.py * * Sample code to register the hap handler: * # arg contains the integer parameter n passed to MAGIC_INSTRUCTION(n) * def magic_instruction_callback(user_arg, cpu, arg): * # print to console works... * print "Hit magic instruction ", arg * # Or else stop the simulation... * SIM_break_simulation( "Stopped at magic instruction" ) * * # Register the magic instruction callback. * SIM_hap_add_callback( "Core_Magic_Instruction", magic_instruction_callback, None ) * * # Better to register the Hostboot range 7000-7999 * # so that PHYP and others won't be affected. * SIM_hap_add_callback_range( "Core_Magic_Instruction", magic_instruction_callback, None, 7000, 7999 ) * * The argument n is an integer from 0..8191 which Simics passes to the hap * handler in parameter 3, or "arg" in the sample code above. */ ALWAYS_INLINE inline void MAGIC_INSTRUCTION(int _n) { register int n = _n; asm volatile("rlwimi %0,%0,0,%1,%2" \ :: "i" (((n) >> 8) & 0x1f), \ "i" (((n) >> 4) & 0xf), \ "i" ((((n) >> 0) & 0xf) | 16)); } // Arguments to MAGIC_INSTRUCTION(). // To ensure they do not conflict with haps from other groups (PHYP // for example), assign hap numbers in the range 7000..7999 (decimal). // Presently, the hap handler for magic instruction is found in // src/build/debug/simics-debug-framework.py // Jan 2012 Monte enum { MAGIC_SIMICS_CORESTATESAVE = 10, // Indicate to the PHYP model of simics // that we are preparing to wake up a core // or thread. This allows them to save // some state from the core doing the // wakeup to apply into the woken one. MAGIC_SIMICS_FUSEDCOREWAKE = 11, // Indicate to the PHYP model of simics // that we are waking up and expecting // CORES to become fused. MAGIC_SHUTDOWN = 7006, // KernelMisc::shutdown() called. MAGIC_BREAK = 7007, // hard-code a breakpoint MAGIC_RANDOM = 7008, // generate random number MAGIC_MEMORYLEAK_FUNCTION = 7009, // A memory was function called. MAGIC_FAKEPAYLOAD_ENTER = 7010, // Entered the fake payload. MAGIC_SIMICS_CHECK = 7011, // Check if system is running on simics MAGIC_LOAD_PAYLOAD = 7012, // load payload from flash // These are used for getting threads // going after doing 'stop/winkle' MAGIC_WAKE_MASTER_THREAD = 7015, // Wake master thread MAGIC_WAKE_OTHER_THREADS = 7016, // Wake other threads on initial CORE MAGIC_WAKE_FUSED_THREADS = 7017, // Wake up fused core threads MAGIC_BREAK_ON_ERROR = 7018, // Breakpoint in error cases if // env var HB_BREAK_ON_ERROR MAGIC_CONTINUOUS_TRACE = 7055, // extract mixed trace buffer }; #endif