/* * 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 #include #include #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->offset_low + ((uint32_t)idt_entry->offset_high << 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 */