mirror of
https://github.com/FreeRTOS/FreeRTOS-Kernel.git
synced 2026-01-22 01:30:31 -05:00
Adding support for Xen for x86 (32bit and 64bit)
This commit is contained in:
parent
14b30f209f
commit
dd83fb7347
21 changed files with 6421 additions and 0 deletions
627
portable/GCC/XEN_x86/IA32/port.c
Normal file
627
portable/GCC/XEN_x86/IA32/port.c
Normal file
|
|
@ -0,0 +1,627 @@
|
|||
/*
|
||||
* FreeRTOS Kernel <DEVELOPMENT BRANCH>
|
||||
* Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||
*
|
||||
* SPDX-License-Identifier: MIT
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
* this software and associated documentation files (the "Software"), to deal in
|
||||
* the Software without restriction, including without limitation the rights to
|
||||
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
||||
* the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
* subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
* https://www.FreeRTOS.org
|
||||
* https://github.com/FreeRTOS
|
||||
*
|
||||
*/
|
||||
|
||||
/* Standard includes. */
|
||||
#include <limits.h>
|
||||
|
||||
/* Scheduler includes. */
|
||||
#include "FreeRTOS.h"
|
||||
#include "task.h"
|
||||
#include "io.h"
|
||||
#include "ioapic.h"
|
||||
#include "stdio.h"
|
||||
#include "IRQ.h"
|
||||
|
||||
|
||||
#if ( configUSE_PORT_OPTIMISED_TASK_SELECTION == 1 )
|
||||
/* Check the configuration. */
|
||||
#if ( configMAX_PRIORITIES > 32 )
|
||||
#error configUSE_PORT_OPTIMISED_TASK_SELECTION can only be set to 1 when configMAX_PRIORITIES is less than or equal to 32. It is very rare that a system requires more than 10 to 15 difference priorities as tasks that share a priority will time slice.
|
||||
#endif
|
||||
#endif /* configUSE_PORT_OPTIMISED_TASK_SELECTION */
|
||||
|
||||
#if ( ( configMAX_API_CALL_INTERRUPT_PRIORITY > portMAX_PRIORITY ) || ( configMAX_API_CALL_INTERRUPT_PRIORITY < 2 ) )
|
||||
#error configMAX_API_CALL_INTERRUPT_PRIORITY must be between 2 and 15
|
||||
#endif
|
||||
|
||||
#if ( ( configSUPPORT_FPU == 1 ) && ( configSUPPORT_DYNAMIC_ALLOCATION == 0 ) )
|
||||
#error configSUPPORT_DYNAMIC_ALLOCATION must be set to 1 to use this port with an FPU
|
||||
#endif
|
||||
|
||||
/* A critical section is exited when the critical section nesting count reaches
|
||||
* this value. */
|
||||
#define portNO_CRITICAL_NESTING ( ( uint32_t ) 0 )
|
||||
|
||||
/* Tasks are not created with a floating point context, but can be given a
|
||||
* floating point context after they have been created. A variable is stored as
|
||||
* part of the tasks context that holds portNO_FLOATING_POINT_CONTEXT if the task
|
||||
* does not have an FPU context, or any other value if the task does have an FPU
|
||||
* context. */
|
||||
#define portNO_FLOATING_POINT_CONTEXT ( ( StackType_t ) 0 )
|
||||
|
||||
/* Only the IF bit is set so tasks start with interrupts enabled. */
|
||||
#define portINITIAL_EFLAGS ( 0x200UL )
|
||||
|
||||
/* Error interrupts are at the highest priority vectors. */
|
||||
#define portAPIC_LVT_ERROR_VECTOR ( 0xfe )
|
||||
#define portAPIC_SPURIOUS_INT_VECTOR ( 0xff )
|
||||
#define portAPIC_DEBUG_SERIAL_INT_VECTOR ( 0x24 )
|
||||
|
||||
/* EFLAGS bits. */
|
||||
#define portEFLAGS_IF ( 0x200UL )
|
||||
|
||||
/* FPU context size if FSAVE is used. */
|
||||
#define portFPU_CONTEXT_SIZE_BYTES 108
|
||||
|
||||
/* The expected size of each entry in the IDT. Used to check structure packing
|
||||
* is set correctly. */
|
||||
#define portEXPECTED_IDT_ENTRY_SIZE 8
|
||||
|
||||
/* Default flags setting for entries in the IDT. */
|
||||
#define portIDT_FLAGS ( 0x8E )
|
||||
|
||||
/* This is the lowest possible ISR vector available to application code. */
|
||||
#define portAPIC_MIN_ALLOWABLE_VECTOR ( 0x20 )
|
||||
|
||||
/* If configASSERT() is defined then the system stack is filled with this value
|
||||
* to allow for a crude stack overflow check. */
|
||||
#define portSTACK_WORD ( 0xecececec )
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
/*
|
||||
* Starts the first task executing.
|
||||
*/
|
||||
extern void vPortStartFirstTask( void );
|
||||
|
||||
/*
|
||||
* Used to catch tasks that attempt to return from their implementing function.
|
||||
*/
|
||||
static void prvTaskExitError( void );
|
||||
|
||||
/*
|
||||
* Complete one descriptor in the IDT.
|
||||
*/
|
||||
static void prvSetInterruptGate( uint8_t ucNumber,
|
||||
ISR_Handler_t pxHandlerFunction,
|
||||
uint8_t ucFlags );
|
||||
|
||||
/*
|
||||
* The default handler installed in each IDT position.
|
||||
*/
|
||||
extern void vPortCentralInterruptWrapper( void );
|
||||
|
||||
/*
|
||||
* Handler for portYIELD().
|
||||
*/
|
||||
extern void vPortYieldCall( void );
|
||||
|
||||
/*
|
||||
* Configure the APIC to generate the RTOS tick.
|
||||
*/
|
||||
static void prvSetupLAPIC( void );
|
||||
|
||||
/*
|
||||
* Tick interrupt handler.
|
||||
*/
|
||||
extern void vPortTimerHandler( void );
|
||||
extern void vPortIRQHandler( void );
|
||||
extern void vHypervisorCallback( void );
|
||||
extern void vSCIHandler( void );
|
||||
extern void vTestInterruptHandler( void );
|
||||
void enable_sci(void);
|
||||
void init_time(void);
|
||||
|
||||
/*
|
||||
* Check an interrupt vector is not too high, too low, in use by FreeRTOS, or
|
||||
* already in use by the application.
|
||||
*/
|
||||
static BaseType_t prvCheckValidityOfVectorNumber( uint32_t ulVectorNumber );
|
||||
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
/* A variable is used to keep track of the critical section nesting. This
|
||||
* variable must be initialised to a non zero value to ensure interrupts don't
|
||||
* inadvertently become unmasked before the scheduler starts. It is set to zero
|
||||
* before the first task starts executing. */
|
||||
volatile uint32_t ulCriticalNesting = 9999UL;
|
||||
|
||||
/* A structure used to map the various fields of an IDT entry into separate
|
||||
* structure members. */
|
||||
struct IDTEntry
|
||||
{
|
||||
uint16_t usISRLow; /* Low 16 bits of handler address. */
|
||||
uint16_t usSegmentSelector; /* Flat model means this is not changed. */
|
||||
uint8_t ucZero; /* Must be set to zero. */
|
||||
uint8_t ucFlags; /* Flags for this entry. */
|
||||
uint16_t usISRHigh; /* High 16 bits of handler address. */
|
||||
}
|
||||
__attribute__( ( packed ) );
|
||||
typedef struct IDTEntry IDTEntry_t;
|
||||
|
||||
|
||||
/* Use to pass the location of the IDT to the CPU. */
|
||||
struct IDTPointer
|
||||
{
|
||||
uint16_t usTableLimit;
|
||||
uint32_t ulTableBase; /* The address of the first entry in xInterruptDescriptorTable. */
|
||||
}
|
||||
__attribute__( ( __packed__ ) );
|
||||
typedef struct IDTPointer IDTPointer_t;
|
||||
|
||||
/* The IDT itself. */
|
||||
static __attribute__( ( aligned( 32 ) ) ) IDTEntry_t xInterruptDescriptorTable[ portNUM_VECTORS ];
|
||||
|
||||
#if ( configUSE_COMMON_INTERRUPT_ENTRY_POINT == 1 )
|
||||
|
||||
/* A table in which application defined interrupt handlers are stored. These
|
||||
* are called by the central interrupt handler if a common interrupt entry
|
||||
* point it used. */
|
||||
static ISR_Handler_t xInterruptHandlerTable[ portNUM_VECTORS ] = { NULL };
|
||||
|
||||
#endif /* configUSE_COMMON_INTERRUPT_ENTRY_POINT */
|
||||
|
||||
#if ( configSUPPORT_FPU == 1 )
|
||||
|
||||
/* Saved as part of the task context. If pucPortTaskFPUContextBuffer is NULL
|
||||
* then the task does not have an FPU context. If pucPortTaskFPUContextBuffer is
|
||||
* not NULL then it points to a buffer into which the FPU context can be saved. */
|
||||
uint8_t * pucPortTaskFPUContextBuffer __attribute__( ( used ) ) = pdFALSE;
|
||||
|
||||
#endif /* configSUPPORT_FPU */
|
||||
|
||||
/* The stack used by interrupt handlers. */
|
||||
static uint32_t ulSystemStack[ configISR_STACK_SIZE ] __attribute__( ( used ) ) = { 0 };
|
||||
|
||||
/* Don't use the very top of the system stack so the return address
|
||||
* appears as 0 if the debugger tries to unwind the stack. */
|
||||
volatile uint32_t ulTopOfSystemStack __attribute__( ( used ) ) = ( uint32_t ) &( ulSystemStack[ configISR_STACK_SIZE - 5 ] );
|
||||
|
||||
/* If a yield is requested from an interrupt or from a critical section then
|
||||
* the yield is not performed immediately, and ulPortYieldPending is set to pdTRUE
|
||||
* instead to indicate the yield should be performed at the end of the interrupt
|
||||
* when the critical section is exited. */
|
||||
volatile uint32_t ulPortYieldPending __attribute__( ( used ) ) = pdFALSE;
|
||||
volatile uint32_t schedStart __attribute__( ( used ) ) = pdFALSE;
|
||||
|
||||
/* Counts the interrupt nesting depth. Used to know when to switch to the
|
||||
* interrupt/system stack and when to save/restore a complete context. */
|
||||
volatile uint32_t ulInterruptNesting __attribute__( ( used ) ) = 0;
|
||||
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
/*
|
||||
* See header file for description.
|
||||
*/
|
||||
StackType_t * pxPortInitialiseStack( StackType_t *pxTopOfStack,
|
||||
TaskFunction_t pxCode,
|
||||
void * pvParameters )
|
||||
{
|
||||
uint32_t ulCodeSegment;
|
||||
|
||||
/* Setup the initial stack as expected by the portFREERTOS_INTERRUPT_EXIT macro. */
|
||||
|
||||
*pxTopOfStack = 0x00;
|
||||
pxTopOfStack--;
|
||||
*pxTopOfStack = 0x00;
|
||||
pxTopOfStack--;
|
||||
|
||||
/* Parameters first. */
|
||||
*pxTopOfStack = ( StackType_t ) pvParameters;
|
||||
pxTopOfStack--;
|
||||
|
||||
/* There is nothing to return to so assert if attempting to use the return
|
||||
* address. */
|
||||
*pxTopOfStack = ( StackType_t ) prvTaskExitError;
|
||||
pxTopOfStack--;
|
||||
|
||||
/* iret used to start the task pops up to here. */
|
||||
*pxTopOfStack = portINITIAL_EFLAGS;
|
||||
pxTopOfStack--;
|
||||
|
||||
/* CS */
|
||||
__asm volatile ( "movl %%cs, %0" : "=r" ( ulCodeSegment ) );
|
||||
*pxTopOfStack = ulCodeSegment;
|
||||
pxTopOfStack--;
|
||||
|
||||
/* First instruction in the task. */
|
||||
*pxTopOfStack = ( StackType_t ) pxCode;
|
||||
pxTopOfStack--;
|
||||
|
||||
/* General purpose registers as expected by a POPA instruction. */
|
||||
*pxTopOfStack = 0xEA;
|
||||
pxTopOfStack--;
|
||||
|
||||
*pxTopOfStack = 0xEC;
|
||||
pxTopOfStack--;
|
||||
|
||||
*pxTopOfStack = 0xED1; /* EDX */
|
||||
pxTopOfStack--;
|
||||
|
||||
*pxTopOfStack = 0xEB1; /* EBX */
|
||||
pxTopOfStack--;
|
||||
|
||||
/* Hole for ESP. */
|
||||
pxTopOfStack--;
|
||||
|
||||
*pxTopOfStack = 0x00; /* EBP */
|
||||
pxTopOfStack--;
|
||||
|
||||
*pxTopOfStack = 0xE5; /* ESI */
|
||||
pxTopOfStack--;
|
||||
|
||||
*pxTopOfStack = 0xeeeeeeee; /* EDI */
|
||||
|
||||
#if ( configSUPPORT_FPU == 1 )
|
||||
{
|
||||
pxTopOfStack--;
|
||||
|
||||
/* Buffer for FPU context, which is initialised to NULL as tasks are not
|
||||
* created with an FPU context. */
|
||||
*pxTopOfStack = portNO_FLOATING_POINT_CONTEXT;
|
||||
}
|
||||
#endif /* configSUPPORT_FPU */
|
||||
|
||||
return pxTopOfStack;
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
static void prvSetInterruptGate( uint8_t ucNumber,
|
||||
ISR_Handler_t pxHandlerFunction,
|
||||
uint8_t ucFlags )
|
||||
{
|
||||
uint16_t usCodeSegment;
|
||||
uint32_t ulBase = ( uint32_t ) pxHandlerFunction;
|
||||
|
||||
xInterruptDescriptorTable[ ucNumber ].usISRLow = ( uint16_t ) ( ulBase & USHRT_MAX );
|
||||
xInterruptDescriptorTable[ ucNumber ].usISRHigh = ( uint16_t ) ( ( ulBase >> 16UL ) & USHRT_MAX );
|
||||
|
||||
/* When the flat model is used the CS will never change. */
|
||||
__asm volatile ( "mov %%cs, %0" : "=r" ( usCodeSegment ) );
|
||||
xInterruptDescriptorTable[ ucNumber ].usSegmentSelector = usCodeSegment;
|
||||
xInterruptDescriptorTable[ ucNumber ].ucZero = 0;
|
||||
xInterruptDescriptorTable[ ucNumber ].ucFlags = ucFlags | 0x60;
|
||||
}
|
||||
|
||||
/*-----------------------------------------------------------*/
|
||||
#define PIC1 0x20
|
||||
#define PIC2 0xA0
|
||||
#define PIC1_COMMAND PIC1
|
||||
#define PIC1_DATA (PIC1+1)
|
||||
#define PIC2_COMMAND PIC2
|
||||
#define PIC2_DATA (PIC2+1)
|
||||
void vPortSetupIDT( void )
|
||||
{
|
||||
extern void vPortAPICErrorHandlerWrapper( void );
|
||||
extern void vPortAPICSpuriousHandler( void );
|
||||
|
||||
// Disable interrupts from 8259
|
||||
outb(PIC1_COMMAND, 0x21);
|
||||
outb(PIC1_DATA, 0xFF);
|
||||
outb(PIC1_COMMAND, 0x22);
|
||||
outb(PIC1_DATA, 0xFF);
|
||||
uint32_t ulNum;
|
||||
IDTPointer_t xIDT;
|
||||
#if ( configUSE_COMMON_INTERRUPT_ENTRY_POINT == 1 )
|
||||
{
|
||||
for( ulNum = 0; ulNum < portNUM_VECTORS; ulNum++ )
|
||||
{
|
||||
/* If a handler has not already been installed on this vector. */
|
||||
if( ( xInterruptDescriptorTable[ ulNum ].usISRLow == 0x00 ) && ( xInterruptDescriptorTable[ ulNum ].usISRHigh == 0x00 ) )
|
||||
{
|
||||
prvSetInterruptGate( ( uint8_t ) ulNum, vPortCentralInterruptWrapper, portIDT_FLAGS );
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif /* configUSE_COMMON_INTERRUPT_ENTRY_POINT */
|
||||
|
||||
/* Install APIC timer ISR vector. */
|
||||
prvSetInterruptGate( ( uint8_t ) 50, vPortTimerHandler, portIDT_FLAGS );
|
||||
|
||||
/* Install API error handler. */
|
||||
prvSetInterruptGate( ( uint8_t ) portAPIC_LVT_ERROR_VECTOR, vPortAPICErrorHandlerWrapper, portIDT_FLAGS );
|
||||
|
||||
/* Install Yield handler. */
|
||||
prvSetInterruptGate( ( uint8_t ) portAPIC_YIELD_INT_VECTOR, vPortYieldCall, portIDT_FLAGS );
|
||||
|
||||
/* Install spurious interrupt vector. */
|
||||
prvSetInterruptGate( ( uint8_t ) portAPIC_SPURIOUS_INT_VECTOR, vPortAPICSpuriousHandler, portIDT_FLAGS );
|
||||
|
||||
/* Install Vector for Debug Serial Port */
|
||||
prvSetInterruptGate( ( uint8_t ) portAPIC_DEBUG_SERIAL_INT_VECTOR, vPortIRQHandler, portIDT_FLAGS );
|
||||
prvSetInterruptGate( ( uint8_t ) 37, vHypervisorCallback, portIDT_FLAGS );
|
||||
prvSetInterruptGate( ( uint8_t ) 41, vSCIHandler, portIDT_FLAGS );
|
||||
prvSetInterruptGate( ( uint8_t ) 96, vTestInterruptHandler, portIDT_FLAGS );
|
||||
|
||||
/* Set IDT address. */
|
||||
xIDT.ulTableBase = ( uint32_t ) xInterruptDescriptorTable;
|
||||
xIDT.usTableLimit = sizeof( xInterruptDescriptorTable ) - 1;
|
||||
|
||||
/* Set IDT in CPU. */
|
||||
__asm volatile ( "lidt %0" ::"m" ( xIDT ) );
|
||||
//__asm volatile ("ltr %w0" :: "rm" (7 * 8));
|
||||
|
||||
|
||||
prvSetupLAPIC();
|
||||
set_ioapic_irq_mask(portAPIC_DEBUG_SERIAL_INT_VECTOR-0x20,0);
|
||||
set_ioapic_irq_mask(portAPIC_TIMER_INT_VECTOR-0x20,0);
|
||||
enable_sci();
|
||||
portENABLE_INTERRUPTS();
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
static void prvTaskExitError( void )
|
||||
{
|
||||
/* A function that implements a task must not exit or attempt to return to
|
||||
* its caller as there is nothing to return to. If a task wants to exit it
|
||||
* should instead call vTaskDelete( NULL ).
|
||||
*
|
||||
* Artificially force an assert() to be triggered if configASSERT() is
|
||||
* defined, then stop here so application writers can catch the error. */
|
||||
configASSERT( ulCriticalNesting == ~0UL );
|
||||
portDISABLE_INTERRUPTS();
|
||||
|
||||
for( ; ; )
|
||||
{
|
||||
}
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
static void prvSetupLAPIC( void )
|
||||
{
|
||||
extern void vPortAPICErrorHandlerWrapper( void );
|
||||
extern void vPortAPICSpuriousHandler( void );
|
||||
|
||||
/* Initialise LAPIC to a well known state. */
|
||||
portAPIC_LDR = 0xFFFFFFFF;
|
||||
portAPIC_LDR = ( ( portAPIC_LDR & 0x00FFFFFF ) | 0x00000001 );
|
||||
portAPIC_LVT_TIMER = portAPIC_DISABLE;
|
||||
portAPIC_LVT_PERF = portAPIC_NMI;
|
||||
portAPIC_LVT_LINT0 = portAPIC_DISABLE;
|
||||
portAPIC_LVT_LINT1 = portAPIC_DISABLE;
|
||||
portAPIC_TASK_PRIORITY = 0;
|
||||
|
||||
/* Enable the APIC, mapping the spurious interrupt at the same time. */
|
||||
portAPIC_SPURIOUS_INT = portAPIC_SPURIOUS_INT_VECTOR | portAPIC_ENABLE_BIT;
|
||||
|
||||
/* Set timer error vector. */
|
||||
portAPIC_LVT_ERROR = portAPIC_LVT_ERROR_VECTOR;
|
||||
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
BaseType_t xPortStartScheduler( void )
|
||||
{
|
||||
BaseType_t xWord;
|
||||
|
||||
/* Some versions of GCC require the -mno-ms-bitfields command line option
|
||||
* for packing to work. */
|
||||
configASSERT( sizeof( struct IDTEntry ) == portEXPECTED_IDT_ENTRY_SIZE );
|
||||
|
||||
/* Fill part of the system stack with a known value to help detect stack
|
||||
* overflow. A few zeros are left so GDB doesn't get confused unwinding
|
||||
* the stack. */
|
||||
for( xWord = 0; xWord < configISR_STACK_SIZE - 20; xWord++ )
|
||||
{
|
||||
ulSystemStack[ xWord ] = portSTACK_WORD;
|
||||
}
|
||||
|
||||
/* Initialise Interrupt Descriptor Table (IDT). */
|
||||
vPortSetupIDT();
|
||||
|
||||
init_time();
|
||||
|
||||
|
||||
/* Make sure the stack used by interrupts is aligned. */
|
||||
ulTopOfSystemStack &= ~portBYTE_ALIGNMENT_MASK;
|
||||
ulCriticalNesting = 0;
|
||||
|
||||
|
||||
/* Should not return from the following function as the scheduler will then
|
||||
* be executing the tasks. */
|
||||
vPortStartFirstTask();
|
||||
|
||||
return 0;
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
void vPortEndScheduler( void )
|
||||
{
|
||||
/* Not implemented in ports where there is nothing to return to.
|
||||
* Artificially force an assert. */
|
||||
configASSERT( ulCriticalNesting == 1000UL );
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
void vPortEnterCritical( void )
|
||||
{
|
||||
if( ulCriticalNesting == 0 )
|
||||
{
|
||||
#if ( configMAX_API_CALL_INTERRUPT_PRIORITY == portMAX_PRIORITY )
|
||||
{
|
||||
__asm volatile ( "cli" );
|
||||
}
|
||||
#else
|
||||
{
|
||||
portAPIC_TASK_PRIORITY = portMAX_API_CALL_PRIORITY;
|
||||
configASSERT( portAPIC_TASK_PRIORITY == portMAX_API_CALL_PRIORITY );
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
/* Now that interrupts are disabled, ulCriticalNesting can be accessed
|
||||
* directly. Increment ulCriticalNesting to keep a count of how many times
|
||||
* portENTER_CRITICAL() has been called. */
|
||||
ulCriticalNesting++;
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
void vPortExitCritical( void )
|
||||
{
|
||||
if( ulCriticalNesting > portNO_CRITICAL_NESTING )
|
||||
{
|
||||
/* Decrement the nesting count as the critical section is being
|
||||
* exited. */
|
||||
ulCriticalNesting--;
|
||||
|
||||
/* If the nesting level has reached zero then all interrupt
|
||||
* priorities must be re-enabled. */
|
||||
if( ulCriticalNesting == portNO_CRITICAL_NESTING )
|
||||
{
|
||||
/* Critical nesting has reached zero so all interrupt priorities
|
||||
* should be unmasked. */
|
||||
#if ( configMAX_API_CALL_INTERRUPT_PRIORITY == portMAX_PRIORITY )
|
||||
{
|
||||
__asm volatile ( "sti" );
|
||||
}
|
||||
#else
|
||||
{
|
||||
portAPIC_TASK_PRIORITY = 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* If a yield was pended from within the critical section then
|
||||
* perform the yield now. */
|
||||
if( ulPortYieldPending != pdFALSE )
|
||||
{
|
||||
ulPortYieldPending = pdFALSE;
|
||||
__asm volatile ( portYIELD_INTERRUPT );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
uint32_t ulPortSetInterruptMask( void )
|
||||
{
|
||||
volatile uint32_t ulOriginalMask;
|
||||
|
||||
/* Set mask to max syscall priority. */
|
||||
#if ( configMAX_API_CALL_INTERRUPT_PRIORITY == portMAX_PRIORITY )
|
||||
{
|
||||
/* Return whether interrupts were already enabled or not. Pop adjusts
|
||||
* the stack first. */
|
||||
__asm volatile ( "pushf \t\n"
|
||||
"pop %0 \t\n"
|
||||
"cli "
|
||||
: "=rm" ( ulOriginalMask )::"memory" );
|
||||
|
||||
ulOriginalMask &= portEFLAGS_IF;
|
||||
}
|
||||
#else
|
||||
{
|
||||
/* Return original mask. */
|
||||
ulOriginalMask = portAPIC_TASK_PRIORITY;
|
||||
portAPIC_TASK_PRIORITY = portMAX_API_CALL_PRIORITY;
|
||||
configASSERT( portAPIC_TASK_PRIORITY == portMAX_API_CALL_PRIORITY );
|
||||
}
|
||||
#endif /* if ( configMAX_API_CALL_INTERRUPT_PRIORITY == portMAX_PRIORITY ) */
|
||||
|
||||
return ulOriginalMask;
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
void vPortClearInterruptMask( uint32_t ulNewMaskValue )
|
||||
{
|
||||
#if ( configMAX_API_CALL_INTERRUPT_PRIORITY == portMAX_PRIORITY )
|
||||
{
|
||||
if( ulNewMaskValue != pdFALSE )
|
||||
{
|
||||
__asm volatile ( "sti" );
|
||||
}
|
||||
}
|
||||
#else
|
||||
{
|
||||
portAPIC_TASK_PRIORITY = ulNewMaskValue;
|
||||
configASSERT( portAPIC_TASK_PRIORITY == ulNewMaskValue );
|
||||
}
|
||||
#endif /* if ( configMAX_API_CALL_INTERRUPT_PRIORITY == portMAX_PRIORITY ) */
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
#if ( configSUPPORT_FPU == 1 )
|
||||
|
||||
void vPortTaskUsesFPU( void )
|
||||
{
|
||||
/* A task is registering the fact that it needs an FPU context. Allocate a
|
||||
* buffer into which the context can be saved. */
|
||||
pucPortTaskFPUContextBuffer = ( uint8_t * ) pvPortMalloc( portFPU_CONTEXT_SIZE_BYTES );
|
||||
configASSERT( pucPortTaskFPUContextBuffer );
|
||||
|
||||
/* Initialise the floating point registers. */
|
||||
__asm volatile ( "fninit" );
|
||||
}
|
||||
|
||||
#endif /* configSUPPORT_FPU */
|
||||
|
||||
void (*test_irq_handler)(void) = NULL;
|
||||
void process_test_interrupt() {
|
||||
if (test_irq_handler) test_irq_handler();
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
void vPortAPICErrorHandler( void )
|
||||
{
|
||||
/* Variable to hold the APIC error status for viewing in the debugger. */
|
||||
volatile uint32_t ulErrorStatus = 0;
|
||||
|
||||
portAPIC_ERROR_STATUS = 0;
|
||||
ulErrorStatus = portAPIC_ERROR_STATUS;
|
||||
( void ) ulErrorStatus;
|
||||
|
||||
/* Force an assert. */
|
||||
configASSERT( ulCriticalNesting == ~0UL );
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
#if ( configUSE_COMMON_INTERRUPT_ENTRY_POINT == 1 )
|
||||
|
||||
void vPortCentralInterruptHandler( uint32_t ulVector )
|
||||
{
|
||||
if( ulVector < portNUM_VECTORS )
|
||||
{
|
||||
uint32_t irq = ulVector - 0x20;
|
||||
INT_HANDLER irq_handler = get_int_handler(irq);
|
||||
if (irq_handler != NULL) {
|
||||
irq_handler();
|
||||
}
|
||||
}
|
||||
/* Check for a system stack overflow. */
|
||||
configASSERT( ulSystemStack[ 10 ] == portSTACK_WORD );
|
||||
configASSERT( ulSystemStack[ 12 ] == portSTACK_WORD );
|
||||
configASSERT( ulSystemStack[ 14 ] == portSTACK_WORD );
|
||||
}
|
||||
|
||||
#endif /* configUSE_COMMON_INTERRUPT_ENTRY_POINT */
|
||||
/*-----------------------------------------------------------*/
|
||||
void vGenerateYieldInterrupt( void )
|
||||
{
|
||||
__asm volatile ( portYIELD_INTERRUPT );
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
int vHaltCPU(void)
|
||||
{
|
||||
__asm volatile ("hlt");
|
||||
return 1;
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue