diff options
| author | William Bryan <wilbryan@us.ibm.com> | 2017-07-27 16:50:06 -0500 |
|---|---|---|
| committer | William A. Bryan <wilbryan@us.ibm.com> | 2017-07-31 13:21:05 -0400 |
| commit | 2ada7c5aec31f6f57e6f244cb10f02b07256536d (patch) | |
| tree | 7fb47f8ac7981a35991ecb3b163edfd98019d599 /src/ppe/pk/kernel | |
| parent | fb653af4fedc8f816eb5685a5432e7a2e3726a1b (diff) | |
| download | talos-occ-2ada7c5aec31f6f57e6f244cb10f02b07256536d.tar.gz talos-occ-2ada7c5aec31f6f57e6f244cb10f02b07256536d.zip | |
Update PK
Change-Id: Icaa343a57595e43ce3f6b1b8fc3fa86efd76fa91
Reviewed-on: http://ralgit01.raleigh.ibm.com/gerrit1/43808
Tested-by: FSP CI Jenkins <fsp-CI-jenkins+hostboot@us.ibm.com>
Reviewed-by: Christopher J. Cain <cjcain@us.ibm.com>
Reviewed-by: Martha Broyles <mbroyles@us.ibm.com>
Reviewed-by: William A. Bryan <wilbryan@us.ibm.com>
Diffstat (limited to 'src/ppe/pk/kernel')
| -rw-r--r-- | src/ppe/pk/kernel/pk_api.h | 404 | ||||
| -rw-r--r-- | src/ppe/pk/kernel/pk_init.c | 37 | ||||
| -rw-r--r-- | src/ppe/pk/kernel/pk_kernel.h | 78 | ||||
| -rw-r--r-- | src/ppe/pk/kernel/pk_stack_init.c | 52 |
4 files changed, 302 insertions, 269 deletions
diff --git a/src/ppe/pk/kernel/pk_api.h b/src/ppe/pk/kernel/pk_api.h index 4381e90..f1cde20 100644 --- a/src/ppe/pk/kernel/pk_api.h +++ b/src/ppe/pk/kernel/pk_api.h @@ -5,7 +5,7 @@ /* */ /* OpenPOWER OnChipController Project */ /* */ -/* Contributors Listed Below - COPYRIGHT 2015,2016 */ +/* Contributors Listed Below - COPYRIGHT 2015,2017 */ /* [+] International Business Machines Corp. */ /* */ /* */ @@ -49,78 +49,8 @@ // API return codes #define PK_OK 0 -#define PK_ILLEGAL_CONTEXT_THREAD_CONTEXT 0x00779002 -#define PK_ILLEGAL_CONTEXT_INTERRUPT_CONTEXT 0x00779003 -#define PK_ILLEGAL_CONTEXT_THREAD 0x00779004 -#define PK_ILLEGAL_CONTEXT_TIMER 0x00779005 -#define PK_INVALID_THREAD_AT_RESUME1 0x00779007 -#define PK_INVALID_THREAD_AT_RESUME2 0x00779008 -#define PK_INVALID_THREAD_AT_SUSPEND1 0x00779009 -#define PK_INVALID_THREAD_AT_SUSPEND2 0x0077900a -#define PK_INVALID_THREAD_AT_DELETE 0x0077900b -#define PK_INVALID_THREAD_AT_INFO 0x0077900c -#define PK_INVALID_THREAD_AT_CHANGE 0x0077900d -#define PK_INVALID_THREAD_AT_SWAP1 0x0077900e -#define PK_INVALID_THREAD_AT_SWAP2 0x0077900f -#define PK_INVALID_THREAD_AT_CREATE 0x00779010 -#define PK_INVALID_SEMAPHORE_AT_POST 0x00779011 -#define PK_INVALID_SEMAPHORE_AT_PEND 0x00779012 -#define PK_INVALID_SEMAPHORE_AT_RELEASE 0x00779013 -#define PK_INVALID_SEMAPHORE_AT_INFO 0x00779014 -#define PK_INVALID_SEMAPHORE_AT_CREATE 0x00779015 -#define PK_INVALID_TIMER_AT_SCHEDULE 0x00779016 -#define PK_INVALID_TIMER_AT_CANCEL 0x00779017 -#define PK_INVALID_TIMER_AT_INFO 0x00779018 -#define PK_INVALID_TIMER_AT_CREATE 0x00779019 -#define PK_INVALID_ARGUMENT_IRQ_SETUP 0x0077901a -#define PK_INVALID_ARGUMENT_IRQ_HANDLER 0x0077901b -#define PK_INVALID_ARGUMENT_INTERRUPT 0x00779024 -#define PK_INVALID_ARGUMENT_CONTEXT_SET 0x00779025 -#define PK_INVALID_ARGUMENT_CONTEXT_GET 0x00779026 -#define PK_INVALID_ARGUMENT_FIT 0x00779027 -#define PK_INVALID_ARGUMENT_WATCHDOG 0x00779028 -#define PK_INVALID_ARGUMENT_INIT 0x00779029 -#define PK_INVALID_ARGUMENT_SEMAPHORE 0x0077902a -#define PK_INVALID_ARGUMENT_THREAD_CHANGE 0x0077902b -#define PK_INVALID_ARGUMENT_THREAD_PRIORITY 0x0077902c -#define PK_INVALID_ARGUMENT_THREAD1 0x0077902d -#define PK_INVALID_ARGUMENT_THREAD2 0x0077902e -#define PK_INVALID_ARGUMENT_THREAD3 0x0077902f -#define PK_STACK_OVERFLOW 0x00779030 -#define PK_TIMER_ACTIVE 0x00779031 -#define PK_TIMER_NOT_ACTIVE 0x00779032 -#define PK_PRIORITY_IN_USE_AT_RESUME 0x00779033 -#define PK_PRIORITY_IN_USE_AT_CHANGE 0x00779034 -#define PK_PRIORITY_IN_USE_AT_SWAP 0x00779035 -#define PK_SEMAPHORE_OVERFLOW 0x00779036 -#define PK_SEMAPHORE_PEND_NO_WAIT 0x00779037 -#define PK_SEMAPHORE_PEND_TIMED_OUT 0x00779038 -#define PK_SEMAPHORE_PEND_WOULD_BLOCK 0x00779039 -#define PK_INVALID_DEQUE_SENTINEL 0x0077903a -#define PK_INVALID_DEQUE_ELEMENT 0x0077903b -#define PK_INVALID_OBJECT 0x0077903c - -// Kernel panics - -#define PK_NO_TIMER_SUPPORT 0x0077903d -#define PK_START_THREADS_RETURNED 0x0077903e -#define PK_UNIMPLEMENTED 0x0077903f -#define PK_SCHEDULING_INVARIANT 0x00779040 -#define PK_TIMER_HANDLER_INVARIANT 0x00779041 -#define PK_THREAD_TIMEOUT_STATE 0x00779045 - -// Application-level panic offsets -// (Use these as offsets for your application code panics and keep -// track of them locally in your application code domain, including -// sharing the panic defines with other developers making codes -// for the same engine.) - -#define PK_APP_OFFSET_SBE 0x0077a000 -#define PK_APP_OFFSET_GPE0 0x0077b000 -#define PK_APP_OFFSET_GPE1 0x0077c000 -#define PK_APP_OFFSET_GPE2 0x0077d000 -#define PK_APP_OFFSET_GPE3 0x0077e000 -#define PK_APP_OFFSET_CME 0x0077f000 + +/// @see pk_panic_codes.h for valid return/panic codes /// \defgroup pk_thread_states PK Thread States /// @@ -160,7 +90,7 @@ /// blocked on a semaphore with timeout). The flag PK_THREAD_FLAG_TIMED_OUT /// indicates that a thread timer timed out before the thread became /// runnable. Currently only the semaphore-pend-with-timeout code uses this -/// flag. +/// flag. /// /// Note that a thread can be mapped and runnable (in the run queue) even /// though PK_THREAD_FLAG_SEMAPHORE_PEND and/or PK_THREAD_FLAG_TIMER_PEND @@ -180,7 +110,7 @@ // Critical Sections /// Enter a critical section, saving the current machine -/// context. +/// context. #define pk_critical_section_enter(pctx) \ pk_interrupt_disable(pctx) @@ -204,22 +134,22 @@ // Application-overrideable definitions -/// Control whether or not the API functions check for errors. +/// Control whether or not the API functions check for errors. /// /// This definition can be overriden by the application. #ifndef PK_ERROR_CHECK_API -#define PK_ERROR_CHECK_API 1 + #define PK_ERROR_CHECK_API 1 #endif /// Control whether API errors cause kernel panics or return negative error -/// codes. +/// codes. /// /// This selection is only valid if \c PK_ERROR_CHECK_API is defined /// non-0. This definition can be overriden by the application. #ifndef PK_ERROR_PANIC -#define PK_ERROR_PANIC 1 + #define PK_ERROR_PANIC 1 #endif /// Control whether or not the PK kernel checks key invariants. @@ -228,7 +158,7 @@ /// definition can be overriden by the application. #ifndef PK_ERROR_CHECK_KERNEL -#define PK_ERROR_CHECK_KERNEL 1 + #define PK_ERROR_CHECK_KERNEL 1 #endif /// Define the time interval type, which must be an unsigned type of a size @@ -236,22 +166,22 @@ /// overridden by the application. #ifndef PK_TIME_INTERVAL_TYPE -#define PK_TIME_INTERVAL_TYPE uint64_t + #define PK_TIME_INTERVAL_TYPE uint64_t #endif /// Provide support for the PkTimer APIs in addition to the default /// initerrupt APIs. This definition can be overridden by the application. #ifndef PK_TIMER_SUPPORT -#define PK_TIMER_SUPPORT 1 + #define PK_TIMER_SUPPORT 1 #endif /// Provide support for the all PK APIs. Thread support requires/implies /// support for time services and semaphores. This definition can be -/// overridden by the application. +/// overridden by the application. #ifndef PK_THREAD_SUPPORT -#define PK_THREAD_SUPPORT 1 + #define PK_THREAD_SUPPORT 1 #endif /// Control the level of stack checking. @@ -259,7 +189,7 @@ /// This definition can be overriden by the application. /// /// 0 : No stack prepatterning or checking is made for thread and kernel -/// stacks. +/// stacks. /// /// 1 : Kernel interrupt stacks are prepatterned during /// \c pk_initialize(). Thread stacks are prepatterned during @@ -270,9 +200,9 @@ /// interrupt processing. The maximum utilization is stored in /// the thread data structure. The kernel will panic if stack overflow is /// detected. Stack utilization is not computed for the idle thread. - + #ifndef PK_STACK_CHECK -#define PK_STACK_CHECK 1 + #define PK_STACK_CHECK 1 #endif /// A hook for main() @@ -283,7 +213,7 @@ /// pk_app_cfg.h. The PK_MAIN_HOOK will run on the stack of main(). #ifndef PK_MAIN_HOOK -#define PK_MAIN_HOOK do {} while (0) + #define PK_MAIN_HOOK do {} while (0) #endif /// A hook for pk_start_threads() @@ -291,31 +221,35 @@ /// This hook macro is expanded in the call-tree of pk_start_threads() before /// threads are actually started. The application can redefine this hook /// macro in (or in headers referred to in) the application header -/// pk_app_cfg.h. +/// pk_app_cfg.h. /// /// The PK_START_THREADS_HOOK runs as a pseudo-interrupt handler on the /// kernel stack, with external interrupts disabled. #ifndef PK_START_THREADS_HOOK -#define PK_START_THREADS_HOOK do {} while (0) + #define PK_START_THREADS_HOOK do {} while (0) #endif /// The maximum value of the \c PkTimebase type. #define PK_TIMEBASE_MAX ((PkTimebase)-1) +/// The minimum count the DEC counter can have so as to not overrun PK +/// with DEC interrupts. +#define PK_DEC_MIN 32 + /// A special value that specifies that the timebase will not be reset during /// pk_init(). #define PK_TIMEBASE_CONTINUES PK_TIMEBASE_MAX /// By convention, a timeout value indicating 'no waiting' in a call of \c -/// pk_semaphore_pend(). +/// pk_semaphore_pend(). #define PK_NO_WAIT 0 /// By convention, a timeout value indicating 'wait forever' in a call of \c -/// pk_semaphore_pend(). +/// pk_semaphore_pend(). #define PK_WAIT_FOREVER ((PkInterval)-1) @@ -375,17 +309,31 @@ #define PK_NANOSECONDS(n) ( (PkInterval)( ( ((PK_BASE_FREQ_MHZ<<10)/1000) * (n) ) >> 10) ) #endif +/// Enable PK application tracing for latency measurments +#ifndef PK_TRACE_PERF_ENABLE + #define PK_TRACE_PERF_ENABLE 0 +#endif /// Enable PK application tracing (enabled by default) #ifndef PK_TRACE_ENABLE #define PK_TRACE_ENABLE 1 #endif +/// Enable PK ctrl (enabled by default) +#ifndef PK_TRACE_CTRL_ENABLE + #define PK_TRACE_CTRL_ENABLE 1 +#endif + /// Enable PK crit (disabled by default) #ifndef PK_TRACE_CRIT_ENABLE #define PK_TRACE_CRIT_ENABLE 0 #endif +/// Enable PK ckpt (disabled by default) +#ifndef PK_TRACE_CKPT_ENABLE + #define PK_TRACE_CKPT_ENABLE 0 +#endif + /// Enable Debug suppress (disabled by default) // a.k.a. enabled means turn off PK_TRACE(), but keep crit trace #ifndef PK_TRACE_DBG_SUPPRESS @@ -401,23 +349,34 @@ // override any other trace settings #if !PK_TRACE_ENABLE #undef PK_TRACE_DBG_SUPPRESS + #undef PK_TRACE_CTRL_ENABLE #undef PK_TRACE_CRIT_ENABLE + #undef PK_TRACE_CKPT_ENABLE #define PK_TRACE_DBG_SUPPRESS 1 + #define PK_TRACE_CTRL_ENABLE 0 #define PK_TRACE_CRIT_ENABLE 0 + #define PK_TRACE_CKPT_ENABLE 0 #endif -// PK TRACE enabled & PK CRIT enabled implies all tracing on. -// PK TRACE enabled & PK DBUG disabled implies PK CRIT INFO tracing only. -// PK TRACE enable & pK CRIT INFO disabled && PK DBUG disabled implies +// PK TRACE enabled implies all default tracing on. +// PK TRACE enabled & PK CKPT DEBUG disabled implies PK CRIT INFO and CTRL ERROR tracing only. +// PK TRACE enabled & PK CKPT DEBUG and CRIT INFO disabled implies PK CTRL ERROR tracing only. +// PK TRACE enabled & PK CRIT INFO disabled && PK DEBUG disabled && PK ERROR disabled implies // PK TRACE disabled -#if PK_TRACE_ENABLE && PK_TRACE_DBG_SUPPRESS && !PK_TRACE_CRIT_ENABLE +#if PK_TRACE_ENABLE && PK_TRACE_DBG_SUPPRESS && !PK_TRACE_CRIT_ENABLE && !PK_TRACE_CKPT_ENABLE && !PK_TRACE_CTRL_ENABLE #undef PK_TRACE_ENABLE #define PK_TRACE_ENABLE 0 #endif //Application trace macros +#if !PK_TRACE_PERF_ENABLE + #define PK_TRACE_PERF(...) +#else + #define PK_TRACE_PERF(...) PKTRACE(__VA_ARGS__) +#endif + #if PK_TRACE_DBG_SUPPRESS #define PK_TRACE(...) #define PK_TRACE_BIN(str, bufp, buf_size) @@ -426,12 +385,24 @@ #define PK_TRACE_BIN(str, bufp, buf_size) PKTRACE_BIN(str, bufp, buf_size) #endif +#if !PK_TRACE_CTRL_ENABLE + #define PK_TRACE_ERR(...) +#else + #define PK_TRACE_ERR(...) PKTRACE(__VA_ARGS__) +#endif + #if !PK_TRACE_CRIT_ENABLE #define PK_TRACE_INF(...) #else #define PK_TRACE_INF(...) PKTRACE(__VA_ARGS__) #endif +#if !PK_TRACE_CKPT_ENABLE + #define PK_TRACE_DBG(...) +#else + #define PK_TRACE_DBG(...) PKTRACE(__VA_ARGS__) +#endif + //Kernel trace macros #if !PK_KERNEL_TRACE_ENABLE #define PK_KERN_TRACE(...) @@ -445,9 +416,9 @@ /// Add a string to the trace buffer with an optional register holding a 16bit value /// WARNING: This calls a c function which may clobber any of the volatile registers #if (PK_TRACE_SUPPORT && PK_TIMER_SUPPORT) -#define PK_TRACE_ASM16(...) TRACE_ASM_HELPER16(VARG_COUNT(__VA_ARGS__), __VA_ARGS__) + #define PK_TRACE_ASM16(...) TRACE_ASM_HELPER16(VARG_COUNT(__VA_ARGS__), __VA_ARGS__) #else -#define PK_TRACE_ASM16(...) + #define PK_TRACE_ASM16(...) #endif /* PK_TRACE_SUPPORT */ /// The following macros are helper macros for tracing. They should not be called @@ -456,6 +427,7 @@ #define VARG_COUNT(...) VARG_COUNT_HELPER(, ##__VA_ARGS__, 7, 6, 5, 4, 3, 2, 1, 0) #ifdef __ASSEMBLER__ +// *INDENT-OFF* #define TRACE_ASM_HELPER16_CALL(count, ...) TINY_TRACE_ASM ## count (__VA_ARGS__) #define TRACE_ASM_HELPER16(count, ...) TRACE_ASM_HELPER16_CALL(count, __VA_ARGS__) @@ -484,7 +456,8 @@ oris %r3, %r3, \hash16 bl pk_trace_tiny .endm - + +// *INDENT-ON* #endif /*__ASSEMBLER__*/ @@ -522,7 +495,8 @@ typedef PK_TIME_INTERVAL_TYPE PkInterval; #include "pk_port_types.h" -typedef struct { +typedef struct +{ /// A priority queue of threads pending on the semaphore. PkThreadQueue pending_threads; @@ -543,8 +517,8 @@ typedef struct { /// arrays of semaphores. #define PK_SEMAPHORE_INITIALIZATION(_initial_count, _max_count) \ {.pending_threads = 0, \ - .count = (_initial_count), \ - .max_count = (_max_count)} + .count = (_initial_count), \ + .max_count = (_max_count)} /// Declare and initialize a semaphore @@ -563,19 +537,19 @@ typedef struct { #define PKTRACE2(str, parm0) \ ((sizeof(parm0) <= 2)? \ - pk_trace_tiny(HASH_ARG_COMBO(str, parm0)): \ - pk_trace_big(HASH_ARG_COMBO(str, 1), ((uint64_t)parm0) << 32, 0)) + pk_trace_tiny(HASH_ARG_COMBO(str, parm0)): \ + pk_trace_big(HASH_ARG_COMBO(str, 1), ((uint64_t)parm0) << 32, 0)) #define PKTRACE3(str, parm0, parm1) \ - pk_trace_big(HASH_ARG_COMBO(str, 2), ((((uint64_t)parm0) << 32) | parm1), 0) + pk_trace_big(HASH_ARG_COMBO(str, 2), ((((uint64_t)parm0) << 32) | parm1), 0) #define PKTRACE4(str, parm0, parm1, parm2) \ - pk_trace_big(HASH_ARG_COMBO(str, 3), ((((uint64_t)parm0) << 32) | parm1),\ - ((uint64_t)parm2) << 32 ) - + pk_trace_big(HASH_ARG_COMBO(str, 3), ((((uint64_t)parm0) << 32) | parm1),\ + ((uint64_t)parm2) << 32 ) + #define PKTRACE5(str, parm0, parm1, parm2, parm3) \ - pk_trace_big(HASH_ARG_COMBO(str, 4), ((((uint64_t)parm0) << 32) | parm1),\ - ((((uint64_t)parm2) << 32) | parm3) ) + pk_trace_big(HASH_ARG_COMBO(str, 4), ((((uint64_t)parm0) << 32) | parm1),\ + ((((uint64_t)parm2) << 32) | parm3) ) #define PKTRACE6(...) pk_trace_tiny() //will fail at compile time #define PKTRACE7(...) pk_trace_tiny() //will fail at compile time @@ -586,7 +560,7 @@ typedef struct { #if (PK_TRACE_SUPPORT && PK_TIMER_SUPPORT) #define PKTRACE(...) PKTRACE_HELPER(VARG_COUNT(__VA_ARGS__), __VA_ARGS__) #define PKTRACE_BIN(str, bufp, buf_size) \ - pk_trace_binary(((buf_size < 255)? HASH_ARG_COMBO(str, buf_size): HASH_ARG_COMBO(str, 255)), bufp) + pk_trace_binary(((buf_size < 255)? HASH_ARG_COMBO(str, buf_size): HASH_ARG_COMBO(str, 255)), bufp) #else #define PKTRACE(...) #define PKTRACE_BIN(str, bufp, buf_size) @@ -602,7 +576,8 @@ typedef struct { /// initial 'data member' of the structure. This allows a pointer to a queue /// element to be cast to a pointer to an PkDeque and vice-versa. -typedef struct PkDeque { +typedef struct PkDeque +{ /// Pointer to the head or the next element in a deque. /// @@ -621,7 +596,7 @@ typedef struct PkDeque { } PkDeque; -typedef void (*PkTimerCallback)(void *); +typedef void (*PkTimerCallback)(void*); #define PK_TIMER_CALLBACK(callback) void callback(void *) @@ -629,13 +604,14 @@ struct PkTimer; /// The PK timer object -typedef struct PkTimer { +typedef struct PkTimer +{ /// The time queue management pointers /// /// This pointer container is defined as the first element of the /// structure to allow the PkTimer to be cast to an PkDeque and - /// vice-versa. + /// vice-versa. PkDeque deque; /// The absolute timeout of the timer. @@ -647,26 +623,27 @@ typedef struct PkTimer { /// timeouts this field is initialized to __pk_thread_timeout(). PkTimerCallback callback; - /// Private data passed to the callback. + /// Private data passed to the callback. /// /// For PK thread timers used to implement Sleep and semaphore pend this /// field is initialized to a pointer to the thread. - void *arg; + void* arg; } PkTimer; // Threads -typedef void (*PkThreadRoutine)(void *arg); +typedef void (*PkThreadRoutine)(void* arg); #define PK_THREAD_ROUTINE(f) void f(void *arg); -typedef struct { +typedef struct +{ /// Stack pointer saved during context switches. Assembler code expects /// this to always be at address offset 0 from the thread pointer. - PkAddress saved_stack_pointer; + PkAddress saved_stack_pointer; /// This is 1 past the last valid byte address of the thread stack. /// Assembler code expects this to always be at address offset (sizeof @@ -679,8 +656,8 @@ typedef struct { PkAddress stack_base; /// If the thread is blocked on a semaphore, then this is the semaphore the - /// thread is blocked on. - PkSemaphore *semaphore; + /// thread is blocked on. + PkSemaphore* semaphore; /// The thread priority. PkThreadPriority priority; @@ -698,24 +675,25 @@ typedef struct { } PkThread; -typedef void (*PkBhHandler)(void *); +typedef void (*PkBhHandler)(void*); #define PK_BH_HANDLER(handler) void handler(void *) -typedef struct { +typedef struct +{ /// The bottom half queue management pointers /// /// This pointer container is defined as the first element of the /// structure to allow the PkBottomHalf to be cast to a PkDeque and - /// vice-versa. + /// vice-versa. PkDeque deque; /// The bottom half handler PkBhHandler bh_handler; - /// Private data passed to the handler. - void *arg; + /// Private data passed to the handler. + void* arg; } PkBottomHalf; @@ -748,45 +726,45 @@ pk_timebase_get(void); // Timer APIs -int -pk_timer_create(PkTimer *timer, - PkTimerCallback callback, - void *arg); +int +pk_timer_create(PkTimer* timer, + PkTimerCallback callback, + void* arg); -int -pk_timer_schedule(PkTimer *timer, - PkInterval interval); +int +pk_timer_schedule(PkTimer* timer, + PkInterval interval); -int -pk_timer_cancel(PkTimer *timer); +int +pk_timer_cancel(PkTimer* timer); -int -pk_timer_info_get(PkTimer *timer, - PkTimebase *timeout, - int *active); +int +pk_timer_info_get(PkTimer* timer, + PkTimebase* timeout, + int* active); // Thread APIs int -pk_thread_create(PkThread *thread, - PkThreadRoutine thread_routine, - void *arg, - PkAddress stack, - size_t stack_size, - PkThreadPriority priority); +pk_thread_create(PkThread* thread, + PkThreadRoutine thread_routine, + void* arg, + PkAddress stack, + size_t stack_size, + PkThreadPriority priority); int pk_start_threads(void); int -pk_thread_resume(PkThread *thread); +pk_thread_resume(PkThread* thread); int -pk_thread_suspend(PkThread *thread); +pk_thread_suspend(PkThread* thread); int -pk_thread_delete(PkThread *thread); +pk_thread_delete(PkThread* thread); int pk_complete(void); @@ -795,19 +773,19 @@ int pk_sleep(PkInterval interval); int -pk_thread_info_get(PkThread *thread, - PkThreadState *state, - PkThreadPriority *priority, - int *runnable); +pk_thread_info_get(PkThread* thread, + PkThreadState* state, + PkThreadPriority* priority, + int* runnable); -int -pk_thread_priority_change(PkThread *thread, - PkThreadPriority new_priority, - PkThreadPriority *old_priority); +int +pk_thread_priority_change(PkThread* thread, + PkThreadPriority new_priority, + PkThreadPriority* old_priority); int pk_thread_at_priority(PkThreadPriority priority, - PkThread **thread); + PkThread** thread); int pk_thread_priority_swap(PkThread* thread_a, PkThread* thread_b); @@ -816,29 +794,29 @@ pk_thread_priority_swap(PkThread* thread_a, PkThread* thread_b); // Semaphore APIs int -pk_semaphore_create(PkSemaphore *semaphore, - PkSemaphoreCount initial_count, - PkSemaphoreCount max_count); +pk_semaphore_create(PkSemaphore* semaphore, + PkSemaphoreCount initial_count, + PkSemaphoreCount max_count); int -pk_semaphore_post(PkSemaphore *semaphore); +pk_semaphore_post(PkSemaphore* semaphore); int -pk_semaphore_pend(PkSemaphore *semaphore, - PkInterval timeout); +pk_semaphore_pend(PkSemaphore* semaphore, + PkInterval timeout); int -pk_semaphore_release_all(PkSemaphore *semaphore); +pk_semaphore_release_all(PkSemaphore* semaphore); int -pk_semaphore_info_get(PkSemaphore *semaphore, - PkSemaphoreCount *count, - int *pending); +pk_semaphore_info_get(PkSemaphore* semaphore, + PkSemaphoreCount* count, + int* pending); void -pk_semaphore_post_handler(void *arg, - PkIrqId irq); +pk_semaphore_post_handler(void* arg, + PkIrqId irq); // Misc. APIs @@ -847,26 +825,26 @@ pk_halt() __attribute__ ((noreturn)); // Deque APIs -int -pk_deque_sentinel_create(PkDeque *deque); +int +pk_deque_sentinel_create(PkDeque* deque); #define PK_DEQUE_SENTINEL_INIT(dq_addr) \ -{\ - .next = dq_addr, \ - .previous = dq_addr \ -} + {\ + .next = dq_addr, \ + .previous = dq_addr \ + } #define PK_DEQUE_SENTINEL_STATIC_CREATE(deque) \ PkDeque deque = PK_DEQUE_SENTINEL_INIT(&deque) -int -pk_deque_element_create(PkDeque *element); +int +pk_deque_element_create(PkDeque* element); #define PK_DEQUE_ELEMENT_INIT() \ -{\ - .next = 0, \ - .previous = 0 \ -} + {\ + .next = 0, \ + .previous = 0 \ + } #define PK_DEQUE_ELEMENT_STATIC_CREATE(deque) \ PkDeque deque = PK_DEQUE_ELEMENT_INIT() @@ -879,8 +857,8 @@ pk_deque_element_create(PkDeque *element); /// /// \retval 1 The PkDeque is empty -static inline int -pk_deque_is_empty(PkDeque *deque) +static inline int +pk_deque_is_empty(PkDeque* deque) { return (deque == deque->next); } @@ -894,8 +872,8 @@ pk_deque_is_empty(PkDeque *deque) /// /// \retval 1 The element is currently enqueued -static inline int -pk_deque_is_queued(PkDeque *element) +static inline int +pk_deque_is_queued(PkDeque* element) { return (element->next != 0); } @@ -910,8 +888,8 @@ pk_deque_is_queued(PkDeque *element) /// It is an error to call this API on an element that is already enqueued, /// but the API does not check for this error. -static inline void -pk_deque_push_back(PkDeque *deque, PkDeque *element) +static inline void +pk_deque_push_back(PkDeque* deque, PkDeque* element) { deque->previous->next = element; element->previous = deque->previous; @@ -922,22 +900,22 @@ pk_deque_push_back(PkDeque *deque, PkDeque *element) /// Push an element at the head of a deque (LIFO order) /// -/// \param deque The sentinel node of a deque +/// \param deque The sentinel node of a deque /// /// \param element Typically the PkDeque object of a queable structure /// /// It is an error to call this API on an element that is already enqueued, /// but the API does not check for this error. -static inline void -pk_deque_push_front(PkDeque *deque, PkDeque *element) +static inline void +pk_deque_push_front(PkDeque* deque, PkDeque* element) { deque->next->previous = element; element->next = deque->next; element->previous = deque; deque->next = element; } - + /// Pop an element from the head of a deque /// /// \param deque The sentinel node of a deque @@ -949,15 +927,18 @@ pk_deque_push_front(PkDeque *deque, PkDeque *element) // The cast of 'head' is used to remove the 'volatile' attribute. -static inline PkDeque * -pk_deque_pop_front(PkDeque *deque) +static inline PkDeque* +pk_deque_pop_front(PkDeque* deque) { - PkDeque *head; + PkDeque* head; - if (pk_deque_is_empty(deque)) { + if (pk_deque_is_empty(deque)) + { return 0; - } else { - head = (PkDeque *)(deque->next); + } + else + { + head = (PkDeque*)(deque->next); deque->next = head->next; deque->next->previous = deque; head->next = 0; @@ -974,7 +955,7 @@ pk_deque_pop_front(PkDeque *deque) /// enqueued, but the API does not check for this error. static inline void -pk_deque_delete(PkDeque *element) +pk_deque_delete(PkDeque* element) { element->previous->next = element->next; element->next->previous = element->previous; @@ -986,20 +967,25 @@ pk_deque_delete(PkDeque *element) extern PkDeque _pk_bh_queue; static inline void -pk_bh_schedule(PkBottomHalf *bottom_half) +pk_bh_schedule(PkBottomHalf* bottom_half) { - pk_deque_push_back(&_pk_bh_queue, (PkDeque *)bottom_half); + if(!pk_deque_is_queued((PkDeque*)bottom_half)) + { + pk_deque_push_back(&_pk_bh_queue, (PkDeque*)bottom_half); + } } #define PK_BH_INIT(_handler, _arg) \ -{\ - .deque = PK_DEQUE_ELEMENT_INIT(), \ - .bh_handler = _handler, \ - .arg = _arg \ -} + {\ + .deque = PK_DEQUE_ELEMENT_INIT(), \ + .bh_handler = _handler, \ + .arg = _arg \ + } #define PK_BH_STATIC_CREATE(bh_name, handler, arg) \ -PkBottomHalf bh_name = PK_BH_INIT(handler, arg) + PkBottomHalf bh_name __attribute__((section (".sdata"))) = \ + PK_BH_INIT(handler, arg) + //Trace function prototypes @@ -1013,7 +999,7 @@ void pk_trace_set_timebase(PkTimebase timebase); /// Cast a pointer to another type, in a way that won't cause warnings #define PK_CAST_POINTER(t, p) ((t)((PkAddress)(p))) - + // Static Assert Macro for Compile time assertions. // - This macro can be used both inside and outside of a function. // - A value of false will cause the ASSERT to produce this error @@ -1040,7 +1026,7 @@ void pk_trace_set_timebase(PkTimebase timebase); /// PK follows the Unix convention that a successful call of an API returns 0 /// (PK_OK), but returns a negative code in the event of failure, or to /// provide further information. The error codes are all defined as manifest -/// constants. +/// constants. /// /// Some negative codes returned by PK APIs are not considered errors. These /// conditions are always checked, never cause a panic if they occur, and diff --git a/src/ppe/pk/kernel/pk_init.c b/src/ppe/pk/kernel/pk_init.c index 835a87b..5b3b0e3 100644 --- a/src/ppe/pk/kernel/pk_init.c +++ b/src/ppe/pk/kernel/pk_init.c @@ -5,7 +5,7 @@ /* */ /* OpenPOWER OnChipController Project */ /* */ -/* Contributors Listed Below - COPYRIGHT 2015,2016 */ +/* Contributors Listed Below - COPYRIGHT 2015,2017 */ /* [+] International Business Machines Corp. */ /* */ /* */ @@ -52,35 +52,41 @@ uint8_t __pk_timebase_rshift = 32; void pk_set_timebase_rshift(uint32_t timebase_freq_hz) { - //Use 1.0 scale if less than halfway between 1.0 and 1.25 - if(timebase_freq_hz <= (PK_BASE_FREQ_HZ + (PK_BASE_FREQ_HZ >> 3))) + //Use 1.0 scale if less than or equal to 1.0625 * base frequency + if(timebase_freq_hz <= (PK_BASE_FREQ_HZ + (PK_BASE_FREQ_HZ >> 4))) { __pk_timebase_rshift = 32; } - //use 1.25 scale if less than halfway between 1.25 and 1.5 + //use 1.125 scale if between 1.0625 and 1.1875 * base frequency + else if(timebase_freq_hz <= (PK_BASE_FREQ_HZ + (PK_BASE_FREQ_HZ >> 4) + (PK_BASE_FREQ_HZ >> 3))) + { + __pk_timebase_rshift = 3; + } + + //use 1.25 scale if between 1,1875 and 1.375 * base frequency else if(timebase_freq_hz <= (PK_BASE_FREQ_HZ + (PK_BASE_FREQ_HZ >> 3) + (PK_BASE_FREQ_HZ >> 2))) { __pk_timebase_rshift = 2; } - //use 1.5 scale if less than halfway between 1.5 and 2.0 + //use 1.5 scale if between 1.375 and 1.75 * base frequency else if(timebase_freq_hz <= (PK_BASE_FREQ_HZ + (PK_BASE_FREQ_HZ >> 2) + (PK_BASE_FREQ_HZ >> 1))) { __pk_timebase_rshift = 1; } - //use 2.0 scale if greater than 1.5 + //use 2.0 scale if greater than 1.75 * base frequency else { __pk_timebase_rshift = 0; } } -/// Initialize PK. +/// Initialize PK. /// /// \param kernel_stack A stack area for interrupt and bottom-half handlers. /// /// \param kernel_stack_size The size (in bytes) of the stack area for -/// interrupt and bottom-half handlers. +/// interrupt and bottom-half handlers. /// /// \param initial_timebase The initial value of the PK timebase. /// If the argument is given as the special value \c PK_TIMEBASE_CONTINUES, then the @@ -95,7 +101,7 @@ void pk_set_timebase_rshift(uint32_t timebase_freq_hz) /// /// \retval 0 Successful completion /// -/// \retval -PK_INVALID_ARGUMENT_INIT A stack pointer is 0 or is given +/// \retval -PK_INVALID_ARGUMENT_INIT A stack pointer is 0 or is given /// a 0 size. /// /// \retval -PK_STACK_OVERFLOW One or both stacks are not large enough to @@ -105,12 +111,15 @@ void pk_set_timebase_rshift(uint32_t timebase_freq_hz) // variables. In debugging sessions using RAM-resident PK images it is // assumed that the processor may be reset at any time, so we always need to // reset everything at initialization. +#if PK_TRACE_SUPPORT + extern PkTimer g_pk_trace_timer __attribute__((section (".sdata"))); +#endif int pk_initialize(PkAddress kernel_stack, - size_t kernel_stack_size, - PkTimebase initial_timebase, - uint32_t timebase_frequency_hz) + size_t kernel_stack_size, + PkTimebase initial_timebase, + uint32_t timebase_frequency_hz) { int rc; @@ -129,6 +138,8 @@ pk_initialize(PkAddress kernel_stack, //timebase frequency (versus what was hardcoded) pk_set_timebase_rshift(timebase_frequency_hz); + __pk_kernel_stack_limit = kernel_stack; + rc = __pk_stack_init(&kernel_stack, &kernel_stack_size); if (rc) @@ -149,8 +160,6 @@ pk_initialize(PkAddress kernel_stack, __pk_time_queue.next_timeout = PK_TIMEBASE_MAX; #if PK_TRACE_SUPPORT -extern PkTimer g_pk_trace_timer; -extern PkTraceBuffer g_pk_trace_buf; //set the trace timebase HZ g_pk_trace_buf.hz = timebase_frequency_hz; diff --git a/src/ppe/pk/kernel/pk_kernel.h b/src/ppe/pk/kernel/pk_kernel.h index aa49f9f..53ddb59 100644 --- a/src/ppe/pk/kernel/pk_kernel.h +++ b/src/ppe/pk/kernel/pk_kernel.h @@ -5,7 +5,7 @@ /* */ /* OpenPOWER OnChipController Project */ /* */ -/* Contributors Listed Below - COPYRIGHT 2015,2016 */ +/* Contributors Listed Below - COPYRIGHT 2015,2017 */ /* [+] International Business Machines Corp. */ /* */ /* */ @@ -34,19 +34,19 @@ /// we should try it. #ifdef __PK_CORE_C__ -#define IF__PK_CORE_C__(x) x -#define UNLESS__PK_CORE_C__(x) + #define IF__PK_CORE_C__(x) x + #define UNLESS__PK_CORE_C__(x) #else -#define IF__PK_CORE_C__(x) -#define UNLESS__PK_CORE_C__(x) x + #define IF__PK_CORE_C__(x) + #define UNLESS__PK_CORE_C__(x) x #endif #if PK_MINIMIZE_KERNEL_CODE_SPACE -#define IF_PK_MINIMIZE_KERNEL_CODE_SPACE(x) x -#define UNLESS_PK_MINIMIZE_KERNEL_CODE_SPACE(x) + #define IF_PK_MINIMIZE_KERNEL_CODE_SPACE(x) x + #define UNLESS_PK_MINIMIZE_KERNEL_CODE_SPACE(x) #else -#define IF_PK_MINIMIZE_KERNEL_CODE_SPACE(x) -#define UNLESS_PK_MINIMIZE_KERNEL_CODE_SPACE(x) x + #define IF_PK_MINIMIZE_KERNEL_CODE_SPACE(x) + #define UNLESS_PK_MINIMIZE_KERNEL_CODE_SPACE(x) x #endif @@ -60,12 +60,16 @@ volatile PkAddress __pk_saved_sp; /// The kernel stack; constant once defined by the call of -/// pk_initialize(). +/// pk_initialize(). UNLESS__PK_CORE_C__(extern) volatile PkAddress __pk_kernel_stack; +UNLESS__PK_CORE_C__(extern) +volatile +PkAddress __pk_kernel_stack_limit; + /// This is the run queue - the queue of mapped runnable tasks. UNLESS__PK_CORE_C__(extern) volatile @@ -74,7 +78,7 @@ PkThreadQueue __pk_run_queue; /// This flag is set by \c __pk_schedule() if a new highest-priority thread /// becomes runnable during an interrupt handler. The context switch will /// take place at the end of interrupt processing, and the -/// interrupt handling code will clear the flag. +/// interrupt handling code will clear the flag. UNLESS__PK_CORE_C__(extern) volatile @@ -88,11 +92,11 @@ int __pk_delayed_switch; /// - After pk_initialize() but prior to pk_start_threads() /// /// - After pk_start_threads(), when no threads are runnable. In this case -/// the NULL (0) value indicates that the PK idle thread is 'running'. +/// the NULL (0) value indicates that the PK idle thread is 'running'. /// /// - After pk_start_threads(), when the current (non-idle) thread has -/// completed or been deleted. -/// +/// completed or been deleted. +/// /// If \a __pk_current_thread == 0 then there is no requirement to save any /// register state on a context switch, either because the PK idle thread has /// no permanent context, or because any thread context on the kernel stack is @@ -116,15 +120,15 @@ PkThread* __pk_current_thread; /// interrupts. /// /// \a __pk_next_thread may be NULL (0) under the following -/// conditions: +/// conditions: /// /// - After pk_initialize() but prior to pk_start_threads(), assuming no /// threads have been made runnable. /// /// - After pk_start_threads(), when no threads are runnable. In this case /// the NULL (0) value indicates that the PK idle thread is the next thread -/// to 'run'. -/// +/// to 'run'. +/// /// If \a __pk_next_thread == 0 then there is no requirement to restore /// any register state on a context switch, because the PK idle thread has /// no permanent context. @@ -163,14 +167,15 @@ size_t __pk_kernel_stack_size; UNLESS__PK_CORE_C__(extern) volatile -PkThread* __pk_priority_map[PK_THREADS + 1]; +PkThread* __pk_priority_map[PK_THREADS + 1] __attribute__ ((section (".sdata"))); /// The PK time queue structure /// /// This structure is defined for use by the kernel, however applications /// could also use this structure to define their own time queues. -typedef struct { +typedef struct +{ /// A sentinel node for the time queue. /// @@ -200,7 +205,7 @@ typedef struct { } PkTimeQueue; UNLESS__PK_CORE_C__(extern) -PkTimeQueue __pk_time_queue; +PkTimeQueue __pk_time_queue __attribute__ ((section (".sdata"))); /// Return a pointer to the PkThread object of the currently running thread, /// or NULL (0) if PK is idle or has not been started. @@ -210,10 +215,10 @@ PkTimeQueue __pk_time_queue; /// does not (must not) use this API. UNLESS__PK_CORE_C__(extern) -inline PkThread * +inline PkThread* pk_current(void) { - return (PkThread *)__pk_current_thread; + return (PkThread*)__pk_current_thread; } /// Schedule the next timeout in a machine-specific way. @@ -228,15 +233,26 @@ PK_TIMER_CALLBACK(__pk_thread_timeout); /// Generic stack initialization. Portable. int -__pk_stack_init(PkAddress *stack, - size_t *size); +__pk_stack_init(PkAddress* stack, + size_t* size); + +void +__pk_stack_check(uint32_t stack_base, uint32_t stack_limit); + +#define PK_KERNEL_STACK_CHECK() __pk_stack_check(__pk_kernel_stack, __pk_kernel_stack_limit) + +#define PK_THREAD_STACK_CHECK() \ + { \ + PkThread* thread = (PkThread*)__pk_current_thread; \ + if (thread) __pk_stack_check(thread->stack_base, thread->stack_limit); \ + } /// Machine-specific thread context initialization. -void -__pk_thread_context_initialize(PkThread *thread, - PkThreadRoutine thread_routine, - void *arg); +void +__pk_thread_context_initialize(PkThread* thread, + PkThreadRoutine thread_routine, + void* arg); /// Machine specific resumption of __pk_next_thread at __pk_next_priority /// without saving the current context. @@ -245,11 +261,11 @@ __pk_next_thread_resume(void); /// Schedule a timer in the time queue. Portable. void -__pk_timer_schedule(PkTimer *timer); +__pk_timer_schedule(PkTimer* timer); /// Remove a timer from the time queue. Portable. int -__pk_timer_cancel(PkTimer *timer); +__pk_timer_cancel(PkTimer* timer); void __pk_schedule(void); @@ -258,7 +274,7 @@ __pk_schedule(void); // Call the application main(). Portable. void -__pk_main(int argc, char **argv); +__pk_main(int argc, char** argv); #endif /* __ASSEMBLER__ */ diff --git a/src/ppe/pk/kernel/pk_stack_init.c b/src/ppe/pk/kernel/pk_stack_init.c index c76b50f..28a1a3f 100644 --- a/src/ppe/pk/kernel/pk_stack_init.c +++ b/src/ppe/pk/kernel/pk_stack_init.c @@ -5,7 +5,7 @@ /* */ /* OpenPOWER OnChipController Project */ /* */ -/* Contributors Listed Below - COPYRIGHT 2015,2016 */ +/* Contributors Listed Below - COPYRIGHT 2015,2017 */ /* [+] International Business Machines Corp. */ /* */ /* */ @@ -36,8 +36,8 @@ #include "pk.h" -/// Initialize a stack area. -/// +/// Initialize a stack area. +/// /// \param stack A pointer to the smallest legal address of the stack. The /// stack address is modified as the stack is aligned and initialized. /// @@ -48,17 +48,18 @@ /// PK makes no assumptions about size or alignment of the area provided as a /// stack, and carefully aligns and initializes the stack. Regardless of how /// the stack grows, the \a stack parameter is considered to be the lowest -/// legal address of the stack. +/// legal address of the stack. int -__pk_stack_init(PkAddress *stack, - size_t *size) +__pk_stack_init(PkAddress* stack, + size_t* size) { PkAddress mask; size_t excess, i, count; - PK_STACK_TYPE *p; + PK_STACK_TYPE* p; - if (PK_STACK_DIRECTION < 0) { + if (PK_STACK_DIRECTION < 0) + { // Stacks grow down. The initial stack pointer is set to just above // the last allocated stack address. This is legal for pre-decrement @@ -69,7 +70,8 @@ __pk_stack_init(PkAddress *stack, *stack += *size; - if (!PK_STACK_PRE_DECREMENT) { + if (!PK_STACK_PRE_DECREMENT) + { *stack -= sizeof(PK_STACK_TYPE); *size -= sizeof(PK_STACK_TYPE); } @@ -80,13 +82,19 @@ __pk_stack_init(PkAddress *stack, *size -= excess; *size = (*size / sizeof(PK_STACK_TYPE)) * sizeof(PK_STACK_TYPE); - if (PK_STACK_CHECK) { - p = (PK_STACK_TYPE *)(*stack); + if (PK_STACK_CHECK) + { + p = (PK_STACK_TYPE*)(*stack); count = *size / sizeof(PK_STACK_TYPE); - for (i = 0; i < count; i++) { - if (PK_STACK_PRE_DECREMENT) { + + for (i = 0; i < count; i++) + { + if (PK_STACK_PRE_DECREMENT) + { *(--p) = PK_STACK_PATTERN; - } else { + } + else + { *(p--) = PK_STACK_PATTERN; } } @@ -94,7 +102,9 @@ __pk_stack_init(PkAddress *stack, __pk_stack_create_initial_frame(stack, size); - } else { + } + else + { PK_PANIC(PK_UNIMPLEMENTED); } @@ -102,3 +112,15 @@ __pk_stack_init(PkAddress *stack, return PK_OK; } + +void __pk_stack_check(uint32_t stack_base, uint32_t stack_limit) +{ + uint32_t stack_addr; + asm volatile ("mr %0, 1" : "=r" (stack_addr) : :); + + if(stack_addr > stack_base || stack_addr < stack_limit) + { + PK_PANIC(PK_STACK_OVERFLOW); + } +} + |

