nes-proj/cpu/x86/init/common/interrupt.h
Michael LeMay 3908253038 x86: Add support for (paging-based) protection domains
This patch implements a simple, lightweight form of protection domains
using a pluggable framework.  Currently, the following plugin is
available:

 - Flat memory model with paging.

The overall goal of a protection domain implementation within this
framework is to define a set of resources that should be accessible to
each protection domain and to prevent that protection domain from
accessing other resources.  The details of each implementation of
protection domains may differ substantially, but they should all be
guided by the principle of least privilege.  However, that idealized
principle is balanced against the practical objectives of limiting the
number of relatively time-consuming context switches and minimizing
changes to existing code.

For additional information, please refer to cpu/x86/mm/README.md.

This patch also causes the C compiler to be used as the default linker
and assembler.
2016-03-21 17:18:06 -07:00

149 lines
7.1 KiB
C

/*
* Copyright (C) 2015, Intel Corporation. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* 3. Neither the name of the copyright holder nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
* OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef INTERRUPT_H
#define INTERRUPT_H
#include <stdint.h>
#include "gdt-layout.h"
#include "idt.h"
struct interrupt_context {
/* The general-purpose register values are saved by the pushal instruction in
* the interrupt dispatcher. Having access to these saved values may be
* useful in some future interrupt or exception handler, and saving and later
* restoring them also enables the ISR to freely overwrite the EAX, ECX, and
* EDX registers as is permitted by the cdecl calling convention.
*/
uint32_t edi;
uint32_t esi;
uint32_t ebp;
uint32_t esp;
uint32_t ebx;
uint32_t edx;
uint32_t ecx;
uint32_t eax;
/* These two values are pushed on the stack by the CPU when it delivers an
* exception with an associated error code. Currently, only the double fault
* handler accepts this structure as a parameter, and that type of exception
* does have an associated error code.
*/
uint32_t error_code;
uint32_t eip;
/* The CPU pushes additional values beyond these on the stack, specifically
* the code segment descriptor and flags. If a privilege-level change occurs
* during delivery, the CPU additionally pushes the stack pointer and stack
* segment descriptor.
*/
};
#define ISR_STUB(label_str, has_error_code, handler_str, exc) \
"jmp 2f\n\t" \
".align 4\n\t" \
label_str ":\n\t" \
" pushal\n\t" \
PROT_DOMAINS_ENTER_ISR(exc) \
" call " handler_str "\n\t" \
PROT_DOMAINS_LEAVE_ISR(exc) \
" popal\n\t" \
" .if " #has_error_code "\n\t" \
" add $4, %%esp\n\t" \
" .endif\n\t" \
" iret\n\t" \
"2:\n\t"
/* Helper macro to register interrupt handler function.
*
* num: Interrupt number (0-255)
* has_error_code: 0 if interrupt doesn't push error code onto the
* stack. Otherwise, set this argument to 1.
* handler: Pointer to function that should be called once the
* interrupt is raised. In case has_error_code == 0
* the function prototype should be the following:
* void handler(void)
* Otherwise, it should be:
* void handler(struct interrupt_context context)
* exc: 0 if this is an interrupt, which should be handled
* at the interrupt privilege level. 1 if this is an
* exception, which should be handled at the
* exception privilege level.
* dpl: Privilege level for IDT descriptor, which is the
* numerically-highest privilege level that can
* generate this interrupt with a software interrupt
* instruction.
*
* Since there is no easy way to write an Interrupt Service Routines
* (ISR) in C (for further information on this, see [1]), we provide
* this helper macro. It basically provides an assembly trampoline
* to a C function (handler parameter) which, indeed, handles the
* interrupt.
*
* [1] http://wiki.osdev.org/Interrupt_Service_Routines
*/
#define SET_INT_EXC_HANDLER(num, has_error_code, handler, exc, dpl) \
do { \
__asm__ __volatile__ ( \
"pushl %[_dpl_]\n\t" \
"pushl %[_cs_]\n\t" \
"pushl $1f\n\t" \
"pushl %[_isr_num_]\n\t" \
"call idt_set_intr_gate_desc\n\t" \
"add $16, %%esp\n\t" \
ISR_STUB("1", has_error_code, "%P[_handler_]", exc) \
: \
: [_isr_num_] "g" (num), \
[_handler_] "i" (handler), \
[_cs_] "i" (exc ? GDT_SEL_CODE_EXC : GDT_SEL_CODE_INT), \
[_dpl_] "i" (dpl) \
/* the invocation of idt_set_intr_gate_desc may clobber */ \
/* the caller-saved registers: */ \
: "eax", "ecx", "edx" \
); \
} while (0)
#define SET_INTERRUPT_HANDLER(num, has_error_code, handler) \
SET_INT_EXC_HANDLER(num, has_error_code, handler, 0, PRIV_LVL_INT)
#define SET_EXCEPTION_HANDLER(num, has_error_code, handler) \
SET_INT_EXC_HANDLER(num, has_error_code, handler, 1, PRIV_LVL_EXC)
/* Disable maskable hardware interrupts */
#define DISABLE_IRQ() \
do { \
__asm__ ("cli"); \
} while (0)
/* Enable maskable hardware interrupts */
#define ENABLE_IRQ() \
do { \
__asm__ ("sti"); \
} while (0)
#endif /* INTERRUPT_H */