zephyr/arch/x86/core/dynamic.c

111 lines
3.2 KiB
C
Raw Normal View History

x86: remove dynamically generated IRQ and exception code We are interested in supporting some XIP x86 platforms which are unable to fetch CPU instructions from system RAM. This requires refactoring our dynamic IRQ/exc code which currently synthesizes assembly language instructions to create IRQ stubs on-the-fly. Instead, a new approach is taken. Given that the configuration at build time specifies the number of required stubs, use this to generate a build time a set of tiny stub functions which simply push a 'stub id' and then call common dynamic interrupt code. The handler function and handler argument is saved in a table keyed by this stub id. CONFIG_EOI_HANDLER_SUPPORTED removed, the code hasn't been conditionally compiled for some time and in all cases we call _loapic_eoi() when finished with an interrupt. Some other out-of-date verbiage in comments related to supporting non-APIC removed. Previously, when dynamic exceptions were created a pointer would be passed in by the caller reserving ram for the stub code. Since this is no longer feasible, two new Kconfig options have been added. CONFIG_NUM_DYNAMIC_EXC_STUBS and CONFIG_NUM_DYNAMIC_EXC_NO_ERR_STUBS control how many stubs are created for exceptions that push an error code, and no error code, respectively. SW Interrupts are no longer triggered by "int <vector>" hard-coded assembly instructions. Instead this is done by sending a self-directed inter-processor interrupt from the LOAPIC, using a new API loapic_int_vect_trigger(). In this way we get rid of dynamically generated code in irq_test_common.h. All interrupts call _loapic_eoi() when finished, since this is now the right thing to do for all IRQs, including SW interrupts. _irq_handler_set() for x86 no longer requires the old function pointer to be supplied. Change-Id: I78993d3d00dd153c9051c518b417cce8d3acee9e Signed-off-by: Andrew Boie <andrew.p.boie@intel.com>
2015-10-20 05:10:53 +08:00
/*
* Copyright (c) 2015 Intel Corporation
*
* 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.
*/
/**
* @file common dynamic irq/exception-relation functions for IA-32 arch
*/
#include <nanokernel.h>
#include <arch/cpu.h>
#include <nano_private.h>
#if ALL_DYN_STUBS > 0
/**
* @brief Allocate dynamic interrupt stub
*
* @param sp Pointer to integer tracking stub allocation
* @param limit Max number of stubs to allow
* @return index of the first available element of the STUB array or -1
* if all elements are used
*/
int _stub_alloc(unsigned int *sp, unsigned int limit)
{
int rv, key;
key = irq_lock();
if (*sp == limit) {
rv = -1;
} else {
rv = (*sp)++;
}
irq_unlock(key);
return rv;
}
/**
* @brief Get the memory address of an unused dynamic IRQ or exception stub
*
* We generate at build time a set of dynamic stubs which push
* a stub index onto the stack for use as an argument by
* common handling code. These don't each have individual labels,
* but it's possible to compute an offset to any particular one
*
* @param stub_idx Stub number to fetch the corresponding stub function
* @param base_ptr Memory location in ROM where stubs begin
* @return Pointer to the stub code to install into the IDT
*/
void *_get_dynamic_stub(int stub_idx, void *base_ptr)
{
uint32_t offset;
/*
* Because we want the sizes of the stubs to be consisent and minimized,
* stubs are grouped into blocks, each containing a push and subsequent
* 2-byte jump instruction to the end of the block, which then contains
* a larger jump instruction to common dynamic IRQ handling code
*/
offset = (stub_idx * DYN_STUB_SIZE) + ((stub_idx / DYN_STUB_PER_BLOCK) *
DYN_STUB_JMP_SIZE);
return (void *)((uint32_t)base_ptr + offset);
}
/**
* @brief Map an IRQ/exception vector back to the corresponding stub index
*
* This is used to fetch a reference to a stub when all we have is the IRQ
* vector.
*
* @param IRQ vector as installed in the IDT
* @return stub index
*/
uint8_t _stub_idx_from_vector(int vector)
{
IDT_ENTRY *idt_entry;
uint8_t *stub_addr;
/*
* We need to do a reverse map from the vector number to the stub
* index. Look in the IDT for the provided vector and find the memory
* address of the handler function, which should be one of
* the dynamic stubs
*/
idt_entry = (IDT_ENTRY *)(_idt_base_address + (vector << 3));
stub_addr = (uint8_t *)((uint32_t)idt_entry->lowOffset +
((uint32_t)idt_entry->hiOffset << 16));
/*
* Return the specific byte in the handler code which contains
* the stub index, the argument to the initial push operation
*/
return stub_addr[DYN_STUB_IDX_OFFSET];
}
#endif /* ALL_DYN_STUBS */