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.
This commit is contained in:
parent
b0de416682
commit
3908253038
48 changed files with 3558 additions and 295 deletions
|
@ -29,45 +29,15 @@
|
|||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
#include "gdt.h"
|
||||
#include "gdt-layout.h"
|
||||
#include "helpers.h"
|
||||
#include "prot-domains.h"
|
||||
#include "segmentation.h"
|
||||
|
||||
#define NUM_DESC 3
|
||||
|
||||
#define GDT_IDX_NULL 0
|
||||
#define GDT_IDX_CODE 1
|
||||
#define GDT_IDX_DATA 2
|
||||
|
||||
/* All code in the x86 port of Contiki runs at ring (privilege) level 0 */
|
||||
#define PRIV_LVL 0
|
||||
|
||||
/* Compute GDT selector from descriptor index and requested privilege level */
|
||||
#define GDT_SEL(IDX, RPL) (((IDX) << 3) | (RPL))
|
||||
|
||||
#define GDT_SEL_NULL GDT_SEL(GDT_IDX_NULL, 0)
|
||||
#define GDT_SEL_CODE GDT_SEL(GDT_IDX_CODE, PRIV_LVL)
|
||||
#define GDT_SEL_DATA GDT_SEL(GDT_IDX_DATA, PRIV_LVL)
|
||||
|
||||
/* Each define here is for a specific flag in the descriptor. Refer to Intel
|
||||
* Combined Manual (Intel 64 and IA-32 Architectures Software Developer's
|
||||
* Manual), Vol. 3, Section 3.4.5 for a description of each flag.
|
||||
*/
|
||||
#define SEG_DESCTYPE(x) ((x) << 0x04) /* Descriptor type (0 for system, 1 for code/data) */
|
||||
#define SEG_PRES(x) ((x) << 0x07) /* Present */
|
||||
#define SEG_SAVL(x) ((x) << 0x0C) /* Available for system use */
|
||||
#define SEG_LONG(x) ((x) << 0x0D) /* Long mode */
|
||||
#define SEG_SIZE(x) ((x) << 0x0E) /* Size (0 for 16-bit, 1 for 32) */
|
||||
#define SEG_GRAN(x) ((x) << 0x0F) /* Granularity (0 for 1B - 1MB, 1 for 4KB - 4GB) */
|
||||
#define SEG_PRIV(x) (((x) & 0x03) << 0x05) /* Set privilege level (0 - 3) */
|
||||
|
||||
#define SEG_DATA_RDWR 0x02 /* Read/Write */
|
||||
#define SEG_CODE_EXRD 0x0A /* Execute/Read */
|
||||
|
||||
#define GDT_CODE_PL0 SEG_DESCTYPE(1) | SEG_PRES(1) | SEG_SAVL(0) | \
|
||||
SEG_LONG(0) | SEG_SIZE(1) | SEG_GRAN(1) | \
|
||||
SEG_PRIV(0) | SEG_CODE_EXRD
|
||||
|
||||
#define GDT_DATA_PL0 SEG_DESCTYPE(1) | SEG_PRES(1) | SEG_SAVL(0) | \
|
||||
SEG_LONG(0) | SEG_SIZE(1) | SEG_GRAN(1) | \
|
||||
SEG_PRIV(0) | SEG_DATA_RDWR
|
||||
#define GDT_MEM_PL0 (SEG_DESCTYPE_NSYS | SEG_GRAN_PAGE)
|
||||
#define GDT_CODE_PL0 (GDT_MEM_PL0 | SEG_TYPE_CODE_EXRD)
|
||||
#define GDT_DATA_PL0 (GDT_MEM_PL0 | SEG_TYPE_DATA_RDWR)
|
||||
|
||||
typedef struct gdtr
|
||||
{
|
||||
|
@ -75,41 +45,53 @@ typedef struct gdtr
|
|||
uint32_t base;
|
||||
} __attribute__((packed)) gdtr_t;
|
||||
|
||||
typedef uint64_t segment_desc_t;
|
||||
|
||||
/* From Intel Combined Manual, Vol. 3 , Section 3.5.1: The base addresses of
|
||||
* the GDT should be aligned on an eight-byte boundary to yield the best
|
||||
* processor performance.
|
||||
*/
|
||||
static segment_desc_t gdt[NUM_DESC] __attribute__ ((aligned (8)));
|
||||
segment_desc_t __attribute__ ((aligned(8))) ATTR_BSS_GDT_START
|
||||
gdt[GDT_NUM_FIXED_DESC];
|
||||
|
||||
static void
|
||||
set_descriptor(unsigned int index, uint32_t base, uint32_t limit, uint16_t flag)
|
||||
#define GDT_LEN \
|
||||
((((uintptr_t)&_ebss_gdt_addr) - \
|
||||
(uintptr_t)gdt)/sizeof(segment_desc_t))
|
||||
|
||||
/*---------------------------------------------------------------------------*/
|
||||
static void ATTR_CODE_BOOT
|
||||
set_descriptor(unsigned int index,
|
||||
uint32_t base,
|
||||
uint32_t len,
|
||||
uint16_t flag)
|
||||
{
|
||||
segment_desc_t descriptor;
|
||||
|
||||
if (index >= NUM_DESC)
|
||||
return;
|
||||
if(GDT_LEN <= index) {
|
||||
halt();
|
||||
}
|
||||
|
||||
/* Create the high 32 bit segment */
|
||||
descriptor = limit & 0x000F0000; /* set limit bits 19:16 */
|
||||
descriptor |= (flag << 8) & 0x00F0FF00; /* set type, p, dpl, s, g, d/b, l and avl fields */
|
||||
descriptor |= (base >> 16) & 0x000000FF; /* set base bits 23:16 */
|
||||
descriptor |= base & 0xFF000000; /* set base bits 31:24 */
|
||||
|
||||
/* Shift by 32 to allow for low part of segment */
|
||||
descriptor <<= 32;
|
||||
|
||||
/* Create the low 32 bit segment */
|
||||
descriptor |= base << 16; /* set base bits 15:0 */
|
||||
descriptor |= limit & 0x0000FFFF; /* set limit bits 15:0 */
|
||||
segment_desc_init(&descriptor, base, len, flag);
|
||||
|
||||
/* Save descriptor into gdt */
|
||||
gdt[index] = descriptor;
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
||||
void
|
||||
gdt_copy_desc_change_dpl(unsigned int dest_idx,
|
||||
unsigned int src_idx,
|
||||
unsigned dpl)
|
||||
{
|
||||
segment_desc_t desc;
|
||||
|
||||
if((GDT_LEN <= dest_idx) || (GDT_LEN <= src_idx)) {
|
||||
halt();
|
||||
}
|
||||
|
||||
/* This function initializes the Global Offset Table. For simplicity, the
|
||||
desc = gdt[src_idx];
|
||||
SEG_SET_FLAG(desc, DPL, dpl);
|
||||
gdt[dest_idx] = desc;
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
||||
/* This function initializes the Global Descriptor Table. For simplicity, the
|
||||
* memory is organized following the flat model. Thus, memory appears to
|
||||
* Contiki as a single continuous address space. Code, data, and stack
|
||||
* are all contained in this address space (so called linear address space).
|
||||
|
@ -120,29 +102,35 @@ gdt_init(void)
|
|||
gdtr_t gdtr;
|
||||
|
||||
/* Initialize gdtr structure */
|
||||
gdtr.limit = sizeof(segment_desc_t) * NUM_DESC - 1;
|
||||
gdtr.limit = sizeof(segment_desc_t) * GDT_LEN - 1;
|
||||
gdtr.base = (uint32_t) &gdt;
|
||||
|
||||
/* Initialize descriptors */
|
||||
set_descriptor(GDT_IDX_NULL, 0, 0, 0);
|
||||
set_descriptor(GDT_IDX_CODE, 0, 0x0FFFFF, GDT_CODE_PL0);
|
||||
set_descriptor(GDT_IDX_DATA, 0, 0x0FFFFF, GDT_DATA_PL0);
|
||||
set_descriptor(GDT_IDX_CODE_FLAT, 0, 0x100000, GDT_CODE_PL0);
|
||||
set_descriptor(GDT_IDX_DATA_FLAT, 0, 0x100000, GDT_DATA_PL0);
|
||||
|
||||
/* Load GDTR register and update segment registers.
|
||||
*
|
||||
* CS register cannot be changed directly. For that reason, we do a far jump.
|
||||
*/
|
||||
__asm__ ("lgdt %[_gdtr_]\n\t"
|
||||
"jmp %[_cs_], $1f\n\t"
|
||||
"1:\n\t"
|
||||
"mov %[_ds_], %%ds\n\t"
|
||||
"mov %[_ds_], %%ss\n\t"
|
||||
"mov %[_ds_], %%es\n\t"
|
||||
"mov %[_ds_], %%fs\n\t"
|
||||
"mov %[_ds_], %%gs\n\t"
|
||||
:
|
||||
: [_gdtr_] "m" (gdtr),
|
||||
[_cs_] "i" (GDT_SEL_CODE),
|
||||
[_ds_] "r" (GDT_SEL_DATA)
|
||||
);
|
||||
/* Load GDTR */
|
||||
__asm__ __volatile__ ("lgdt %0" :: "m" (gdtr));
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
||||
void
|
||||
gdt_insert(unsigned int idx, segment_desc_t desc)
|
||||
{
|
||||
if(GDT_LEN <= idx) {
|
||||
halt();
|
||||
}
|
||||
|
||||
gdt[idx] = desc;
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
||||
void
|
||||
gdt_lookup(unsigned int idx, segment_desc_t *desc)
|
||||
{
|
||||
if((GDT_LEN <= idx) || (desc == NULL)) {
|
||||
halt();
|
||||
}
|
||||
|
||||
*desc = gdt[idx];
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue