1557 lines
53 KiB
C
1557 lines
53 KiB
C
/*
|
|
* The file implements main user interface functiothat
|
|
* sets up the vIDT ISRs.
|
|
* Copyright (c) 2014, Intel Corporation.
|
|
*
|
|
* This program is free software; you can redistribute it and/or modify it
|
|
* under the terms and conditions of the GNU General Public License,
|
|
* version 2, as published by the Free Software Foundation.
|
|
*
|
|
* This program is distributed in the hope it will be useful, but WITHOUT
|
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
|
* more details.
|
|
*/
|
|
#ifdef APP_MODE
|
|
#include <stdio.h>
|
|
#include <stdint.h>
|
|
#include <stdlib.h>
|
|
#else
|
|
#include <linux/spinlock.h>
|
|
#include <linux/module.h>
|
|
#include <linux/kernel.h>
|
|
#include <asm/uaccess.h>
|
|
#include <linux/smp.h>
|
|
#include <linux/slab.h>
|
|
#include "include/vmm_hsym.h"
|
|
#include "include/vmm_hsym_common.h"
|
|
#include "include/vidt_ioctl.h"
|
|
#include "include/types.h"
|
|
#include "include/arch72.h"
|
|
#include <linux/mm.h>
|
|
#include <linux/sched.h>
|
|
#include <linux/notifier.h>
|
|
#include <linux/list.h>
|
|
#include <linux/cpu.h>
|
|
#include <linux/fs.h>
|
|
#endif
|
|
#define ALIGN_DATA_SECT(x) __attribute__ ((aligned (4096), section (x)))
|
|
#define DATA_SECT(x) __attribute__ ((section (x)))
|
|
#define ALIGN_CODE_SECT(x) __attribute__ ((aligned (4096), section (x), noinline))
|
|
|
|
//#define STRINGIFY(str) (#str)
|
|
int setup_vidt(void);
|
|
void restore_os_idt(void);
|
|
#define EENTER_VECTOR 29
|
|
#define ERESUME_VECTOR 30
|
|
#define EEXIT_VECTOR 31
|
|
#define MAX_VIEW_NUM 16
|
|
#define PRINT_ALWAYS 1
|
|
#define PRINT_DEBUG 0
|
|
#define KdPrint(flag, x) if (flag) { printk x; }
|
|
#define SECS_SCV_UNTRUSTED (0xDDBBAACCDDBBAACC)
|
|
|
|
#define ADD_REGION(map, start, npages, patch, npatches, nbytes) \
|
|
do { \
|
|
uint32_t n = map.n_regions; \
|
|
map.region[n].start_gva = (unsigned long) (start); \
|
|
map.region[n].n_pages = (npages); \
|
|
map.region[n].n_bytes = (nbytes); \
|
|
map.region[n].patch_info = (unsigned long)(patch); \
|
|
map.region[n].n_patches = (npatches); \
|
|
map.n_regions++; \
|
|
} while(0)
|
|
|
|
#ifdef __x86_64__
|
|
#define MOV_OPCODE_SIZE (0x2)
|
|
#else
|
|
#define MOV_OPCODE_SIZE (0x1)
|
|
#endif //end of !__x86_64__
|
|
|
|
#define ADD_SECS_PATCH(patch_id, str, idx) \
|
|
do { \
|
|
str##_offset = (unsigned long)str##_secs_patch##patch_id - (unsigned long)str; \
|
|
str##_patch[idx].val = (unsigned long)secs_ptr; \
|
|
str##_patch[idx].offset = str##_offset + MOV_OPCODE_SIZE; \
|
|
str##_patch[idx].type = PATCH_TYPE_SECS_PTR; \
|
|
} while(0)
|
|
|
|
#define REGION_SIZE(region) ((unsigned long)region##_end - (unsigned long)region)
|
|
|
|
#define VIDT_SUCCESS (0)
|
|
#define VIDT_FAIL (-1)
|
|
|
|
#define SAFE_FREE(ptr) \
|
|
do { \
|
|
if (ptr) { \
|
|
kfree(ptr); \
|
|
ptr = NULL; \
|
|
} \
|
|
} while (0)
|
|
|
|
#ifndef APP_MODE
|
|
bool set_page_exec(unsigned long address)
|
|
{
|
|
unsigned int level;
|
|
pte_t* pte;
|
|
|
|
pte = lookup_address((unsigned long)address, &level);
|
|
|
|
if (pte) {
|
|
KdPrint(PRINT_ALWAYS, ("pte data 0x%llx \n", pte_val(*pte)));
|
|
|
|
if (pte_val(*pte) & _PAGE_NX) {
|
|
KdPrint(PRINT_ALWAYS, ("page is NX \n"));
|
|
pte->pte &= ~_PAGE_NX;
|
|
//VT??? Don't we need to do TLB flush here (invlpg()
|
|
//and probably TLB shootdown)
|
|
} else {
|
|
KdPrint(PRINT_ALWAYS, ("page is X \n"));
|
|
}
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
typedef struct {
|
|
uint16 limit;
|
|
uint32 base;
|
|
} __attribute__((packed)) IA32_GDTR, IA32_IDTR, IA32_LDTR;
|
|
|
|
typedef struct {
|
|
uint32 OffsetLow :16; // Offset bits 15..0
|
|
uint32 Selector :16; // Selector
|
|
uint32 Reserved_0:8; // Reserved
|
|
uint32 GateType :5; // Gate Type. See #defines above
|
|
uint32 dpl :2;
|
|
uint32 present :1;
|
|
uint32 OffsetHigh:16; // Offset bits 31..16
|
|
} __attribute__((packed)) IA32_IDT_GATE_DESCRIPTOR;
|
|
|
|
typedef struct {
|
|
uint32 addr_orig;
|
|
uint32 addr_vidt;
|
|
} __attribute__((packed)) IA32_IDT_REDIRECT_TABLE;
|
|
|
|
typedef struct {
|
|
uint64 addr_orig;
|
|
uint64 addr_vidt;
|
|
} __attribute__((packed)) IA32e_IDT_REDIRECT_TABLE;
|
|
|
|
typedef struct {
|
|
uint32 OffsetLow :16; // Offset bits 15..0
|
|
uint32 Selector :16; // Selector
|
|
uint32 ist_index :3; //IST index
|
|
uint32 reserved1 :5;
|
|
uint32 GateType :4; // Gate Type. See #defines above
|
|
uint32 reserved2 :1;
|
|
uint32 dpl :2;
|
|
uint32 present :1;
|
|
uint32 OffsetMid :16; // Offset bits 31..16
|
|
uint32 OffsetHigh:32; // Offset bits 31..16
|
|
uint32 reserved3 :32; // Offset bits 31..16
|
|
} __attribute__((packed)) IA32e_IDT_GATE_DESCRIPTOR;
|
|
|
|
typedef struct {
|
|
uint16 limit;
|
|
uint64 base;
|
|
} __attribute__((packed)) IA32e_GDTR, IA32e_IDTR, IA32e_LDTR;
|
|
|
|
typedef struct {
|
|
struct {
|
|
uint32 limit_15_00 : 16;
|
|
uint32 base_address_15_00 : 16;
|
|
} lo;
|
|
struct {
|
|
uint32 base_address_23_16 : 8;
|
|
uint32 accessed : 1;
|
|
uint32 readable : 1;
|
|
uint32 conforming : 1;
|
|
uint32 mbo_11 : 1; // Must Be One
|
|
uint32 mbo_12 : 1; // Must Be One
|
|
uint32 dpl : 2; // Descriptor Privilege Level
|
|
uint32 present : 1;
|
|
uint32 limit_19_16 : 4;
|
|
uint32 avl : 1; // Available to software
|
|
uint32 mbz_21 : 1; // Must Be Zero
|
|
uint32 default_size : 1; // 0 = 16-bit segment; 1 = 32-bit segment
|
|
uint32 granularity : 1;
|
|
uint32 base_address_31_24 : 8;
|
|
} hi;
|
|
} __attribute__((packed)) IA32_CODE_SEGMENT_DESCRIPTOR;
|
|
|
|
typedef struct {
|
|
uint32 vep_max; //ptr
|
|
uint32 vep_tos; //ptr
|
|
uint32 redirect_size;
|
|
#ifdef __x86_64__
|
|
uint64 redirect_addr; //ptr
|
|
IA32e_IDTR os_idtr;
|
|
#else
|
|
uint32 redirect_addr; //ptr
|
|
IA32_IDTR os_idtr;
|
|
#endif
|
|
} __attribute__((packed)) PER_CORE_STATE;
|
|
|
|
typedef struct {
|
|
uint32 per_cpu_vidt_start;
|
|
uint32 per_cpu_vidt_end;
|
|
uint32 per_cpu_vidt_stub_start;
|
|
uint32 per_cpu_vidt_stub_end;
|
|
uint32 per_cpu_test_code_start;
|
|
uint32 per_cpu_test_code_end;
|
|
} __attribute__((packed)) PER_CORE_VIDT_STATE;
|
|
|
|
struct vidt_priv_data{
|
|
unsigned long int pid;
|
|
unsigned long int viewid;
|
|
unsigned long int magic;
|
|
};
|
|
|
|
struct view_list {
|
|
struct vidt_priv_data view_data;
|
|
struct list_head list;
|
|
};
|
|
|
|
#define VIDT_PRIV_MAGIC (unsigned long int)0xABCDEF12
|
|
|
|
#define MAX_CORES 8
|
|
|
|
PER_CORE_VIDT_STATE core_vidt_state[MAX_CORES] DATA_SECT(".vidtd");
|
|
PER_CORE_STATE core_state[MAX_CORES] DATA_SECT(".vidtd");
|
|
#ifdef __x86_64__
|
|
IA32e_IDT_REDIRECT_TABLE redirect[MAX_CORES][256] DATA_SECT(".vidtd");
|
|
#else
|
|
IA32_IDT_REDIRECT_TABLE redirect[MAX_CORES][256] DATA_SECT(".vidtd");
|
|
#endif
|
|
uint64 ptr_core_state DATA_SECT(".vidtd") = 1; //initialize before use in vidt_setup
|
|
uint64 secs_la ALIGN_DATA_SECT(".vidtd") = 0x0; //alloc and init during vidt setup
|
|
|
|
|
|
#ifdef __x86_64__
|
|
extern inline int cpuid_asm64(uint32_t leaf, uint32_t b_val, uint64_t c,
|
|
uint64_t d, uint64_t S, uint64_t D);
|
|
#else
|
|
extern inline int cpuid_asm(uint32_t leaf, uint32_t b_val, uint32_t c,
|
|
uint32_t d, uint32_t S, uint32_t D);
|
|
#endif
|
|
|
|
|
|
int map_pid_viewId(void *priv_data, struct entry_pid_viewid view_new);
|
|
int unmap_pid_viewId(void *priv_data, struct entry_pid_viewid view_entry);
|
|
int clean_ta_view(void *priv_data);
|
|
void clean_view_map_list(struct file *file);
|
|
|
|
int init_view_map_list(struct file *file)
|
|
{
|
|
if (!file)
|
|
return VIDT_FAIL;
|
|
struct view_list *pfd_view_map =
|
|
(struct view_list*) kmalloc(sizeof(struct view_list), GFP_KERNEL);
|
|
if(pfd_view_map == NULL)
|
|
return VIDT_FAIL;
|
|
INIT_LIST_HEAD(&pfd_view_map->list);
|
|
file->private_data = (void *)pfd_view_map;
|
|
|
|
return VIDT_SUCCESS;
|
|
}
|
|
|
|
void clean_view_map_list(struct file *file)
|
|
{
|
|
if (file->private_data)
|
|
kfree(file->private_data);
|
|
file->private_data = NULL;
|
|
}
|
|
|
|
int clean_ta_view(void *priv_data)
|
|
{
|
|
struct view_list *temp_head = NULL;
|
|
struct view_list *pos=NULL;
|
|
struct view_list *temp_node=NULL;
|
|
temp_head = (struct view_list*) priv_data;
|
|
if(temp_head == NULL) {
|
|
return VIDT_FAIL;
|
|
}
|
|
list_for_each_entry_safe(pos, temp_node,&temp_head->list,list){
|
|
if((pos->view_data.magic == VIDT_PRIV_MAGIC)){
|
|
#ifdef __x86_64__
|
|
cpuid_asm64(SL_CMD_HSEC_REMOVE_VIEW, 0, 0,pos->view_data.viewid, 0, 0);
|
|
#else
|
|
cpuid_asm(SL_CMD_HSEC_REMOVE_VIEW, 0, 0,pos->view_data.viewid, 0, 0);
|
|
#endif
|
|
list_del(&pos->list);
|
|
kfree(pos);
|
|
}
|
|
else {
|
|
printk("MAGIC 0x%lx doesn't match 0x%lx\n", pos->view_data.magic, VIDT_PRIV_MAGIC);
|
|
}
|
|
}
|
|
|
|
return VIDT_SUCCESS;
|
|
}
|
|
|
|
|
|
int unmap_pid_viewId(void *priv_data, struct entry_pid_viewid view_entry)
|
|
{
|
|
struct view_list *temp_head = NULL,*pos=NULL,*temp_node=NULL;
|
|
|
|
temp_head = (struct view_list*) priv_data;
|
|
if(temp_head == NULL) {
|
|
printk(KERN_INFO "nothing there to clean here unmap_pid_viewId!!\n");
|
|
return VIDT_FAIL;
|
|
}
|
|
list_for_each_entry_safe(pos,temp_node,&(temp_head->list),list){
|
|
if((pos->view_data.magic == VIDT_PRIV_MAGIC) &&
|
|
pos->view_data.viewid == view_entry.viewid && pos->view_data.pid == view_entry.pid) {
|
|
list_del(&pos->list);
|
|
kfree(pos);
|
|
return VIDT_SUCCESS;
|
|
}
|
|
}
|
|
return VIDT_FAIL;
|
|
}
|
|
|
|
int map_pid_viewId(void *priv_data, struct entry_pid_viewid view_new)
|
|
{
|
|
struct view_list *temp_head= NULL,*temp_node = NULL;
|
|
temp_head = (struct view_list *)priv_data;
|
|
temp_node = (struct view_list*) kmalloc(sizeof(struct view_list), GFP_KERNEL);
|
|
if(temp_node == NULL)
|
|
return VIDT_FAIL;
|
|
temp_node->view_data.pid = view_new.pid;
|
|
temp_node->view_data.viewid = view_new.viewid;
|
|
temp_node->view_data.magic = VIDT_PRIV_MAGIC;
|
|
INIT_LIST_HEAD(&temp_node->list);
|
|
|
|
list_add(&(temp_node->list),&(temp_head->list));
|
|
|
|
return VIDT_SUCCESS;
|
|
}
|
|
|
|
#if !defined(__x86_64__)
|
|
static void ia32_read_idtr(void *p_descriptor)
|
|
{
|
|
asm (
|
|
"sidt %0\n"
|
|
: "=m" (*(IA32_IDTR*)p_descriptor)
|
|
);
|
|
}
|
|
|
|
void ia32_load_idtr(void *p_descriptor)
|
|
{
|
|
__asm__ (
|
|
"cli\n"
|
|
"lidt %0\n"
|
|
"sti\n"
|
|
:
|
|
: "m" (*(IA32_IDTR*)p_descriptor)
|
|
);
|
|
}
|
|
|
|
static inline void ia32_read_gdtr(void *p_descriptor)
|
|
{
|
|
__asm__ (
|
|
"sgdt %0\n"
|
|
: "=m" (*(IA32_GDTR*)p_descriptor)
|
|
);
|
|
}
|
|
|
|
static inline void ia32_read_ldtr(void *p_descriptor)
|
|
{
|
|
__asm__ (
|
|
"sldt %0\n"
|
|
: "=m" (*(IA32_LDTR*)p_descriptor)
|
|
);
|
|
}
|
|
#else
|
|
static inline void ia32e_load_idtr(void *p_descriptor)
|
|
{
|
|
__asm__ (
|
|
"cli\n"
|
|
"lidt %0\n"
|
|
"sti\n"
|
|
:
|
|
: "m" (*(IA32e_IDTR*)p_descriptor)
|
|
);
|
|
}
|
|
static inline void ia32e_read_gdtr(void *p_descriptor)
|
|
{
|
|
__asm__ (
|
|
"sgdt %0\n"
|
|
: "=m" (*(IA32e_GDTR*)p_descriptor)
|
|
);
|
|
}
|
|
|
|
static inline void ia32e_read_ldtr(void *p_descriptor)
|
|
{
|
|
__asm__ (
|
|
"sldt %0\n"
|
|
: "=m" (*(IA32e_LDTR*)p_descriptor)
|
|
);
|
|
}
|
|
|
|
static void ia32e_read_idtr(void *p_descriptor)
|
|
{
|
|
asm (
|
|
"sidt %0\n"
|
|
: "=m" (*(IA32e_IDTR*)p_descriptor)
|
|
);
|
|
}
|
|
#endif
|
|
|
|
#define IA32_IDT_GATE_TYPE_TASK 0x5
|
|
#define IA32_IDT_GATE_TYPE_INTERRUPT_16 0x86
|
|
#define IA32_IDT_GATE_TYPE_TRAP_16 0x87
|
|
#define IA32_IDT_GATE_TYPE_INTERRUPT_DPL0_32 0x8E
|
|
#define IA32_IDT_GATE_TYPE_TRAP_32 0x8F
|
|
#define IA32_DPL3 0x3
|
|
#define IA32_GATE_TYPE_INTR 0xE
|
|
|
|
#if !defined(__x86_64__)
|
|
void print_ldt(void* x)
|
|
{
|
|
uint32 *pTab;
|
|
uint16 i;
|
|
uint32 base;
|
|
uint16 limit;
|
|
IA32_LDTR ldtr;
|
|
|
|
ia32_read_ldtr(&ldtr);
|
|
base = ldtr.base;
|
|
limit = ldtr.limit;
|
|
KdPrint(PRINT_ALWAYS, ("LDT BASE = 0x%x LDT LIMIT = 0x%x \n",
|
|
(uint32) base, (uint32) limit));
|
|
pTab = (uint32 *) base;
|
|
for (i = 0; i < (limit+1) / sizeof(IA32_CODE_SEGMENT_DESCRIPTOR); ++i)
|
|
{
|
|
KdPrint(PRINT_DEBUG, ("0x%x 0x%x 0x%x \n",
|
|
(uint32)i, pTab[i*2], pTab[i*2+1]));
|
|
}
|
|
}
|
|
|
|
void print_gdt(void* x)
|
|
{
|
|
uint32 *pTab;
|
|
uint16 i;
|
|
uint32 base;
|
|
uint16 limit;
|
|
IA32_GDTR gdtr;
|
|
|
|
ia32_read_gdtr(&gdtr);
|
|
base = gdtr.base;
|
|
limit = gdtr.limit;
|
|
|
|
KdPrint(PRINT_ALWAYS, ("GDT BASE = 0x%x GDT LIMIT = 0x%x \n",
|
|
(uint32) base, (uint32) limit));
|
|
|
|
pTab = (uint32 *) base;
|
|
|
|
for (i = 0; i < (limit+1) / sizeof(IA32_CODE_SEGMENT_DESCRIPTOR); ++i)
|
|
{
|
|
KdPrint(PRINT_DEBUG, ("0x%x 0x%x 0x%x \n",
|
|
(uint32)i, pTab[i*2], pTab[i*2+1]));
|
|
}
|
|
}
|
|
#endif // end of !__x86_64__
|
|
#endif // end of !APP_MODE
|
|
|
|
unsigned int isr_size = 0;
|
|
extern void MyHandler_non_arch_end(void);
|
|
extern void MyHandler(void);
|
|
extern void MyHandler_arch_end(void);
|
|
|
|
#define NUM_AEX_CODE_PATCHES 6
|
|
extern void test_code_cpuindex(void);
|
|
extern void test_code_ptr_core_state_patch(void);
|
|
extern void test_code_secs_patch1(void);
|
|
extern void test_code_secs_patch2(void);
|
|
extern void test_code_cmp_patch(void);
|
|
extern void test_code_exit_page_patch(void);
|
|
extern void test_code(void);
|
|
|
|
#define NUM_EXIT_CODE_PATCHES 4
|
|
extern void exit_code_cpuindex(void);
|
|
extern void exit_code_cmp_patch(void);
|
|
extern void exit_code_secs_patch1(void);
|
|
extern void exit_code_exit_page_patch(void);
|
|
extern void exit_code(void);
|
|
|
|
#define NUM_ENT_RES_CODE_PATCHES 10
|
|
extern void enter_eresume_code_cpuindex(void);
|
|
extern void enter_eresume_code_cmp_patch1(void);
|
|
extern void enter_eresume_code_cmp_patch2(void);
|
|
extern void enter_eresume_code_secs_patch1(void);
|
|
extern void enter_eresume_code_secs_patch2(void);
|
|
extern void enter_eresume_code_secs_patch3(void);
|
|
extern void enter_eresume_code_secs_patch4(void);
|
|
extern void enter_eresume_code_secs_patch5(void);
|
|
extern void enter_eresume_code_secs_patch6(void);
|
|
extern void enter_eresume_code_enter_page_patch(void);
|
|
extern void enter_eresume_code(void);
|
|
|
|
extern void test_code_end(void);
|
|
extern void exit_code_end(void);
|
|
extern void enter_eresume_code_end(void);
|
|
extern void vidt_stub_patch_val0(void);
|
|
extern void vidt_stub_patch_callee0(void);
|
|
extern void begin_vidt_stub0(void);
|
|
|
|
#ifdef APP_MODE
|
|
int get_vidt_code_pages(uint8_t **vidt_buf, uint32_t *vidt_size)
|
|
{
|
|
|
|
void* per_cpu_vidt_stub = NULL;
|
|
void* per_cpu_test_code = NULL;
|
|
void* per_cpu_exit_code = NULL;
|
|
void* per_cpu_enter_eresume_code = NULL;
|
|
void *code_buf = NULL;
|
|
|
|
uint32_t size_stub = 0, size_tc = 0, size_exitc = 0, tmp_size = 0;
|
|
uint32_t size_enter_eresumec = 0, size_total = 0;
|
|
uint32_t off = 0;
|
|
int i, ret = 0;
|
|
|
|
// --------------------------------------------------------
|
|
// Step1: Do allocations for different flows
|
|
// --------------------------------------------------------
|
|
//alloc and clear pages for per_cpu_vidt_stub (MyHandler)
|
|
isr_size = ((unsigned int)MyHandler_non_arch_end -
|
|
(unsigned int)MyHandler_arch_end);
|
|
per_cpu_vidt_stub = calloc(1, isr_size*256);
|
|
if (per_cpu_vidt_stub == NULL) {
|
|
printf("%s:%d: Failed allocating memory\n", __func__, __LINE__);
|
|
ret = -1;
|
|
goto exit_vidt_code_pages;
|
|
}
|
|
size_stub += isr_size*256;
|
|
|
|
//alloc and clear pages for AEX Exit stub code
|
|
tmp_size = REGION_SIZE(test_code);
|
|
per_cpu_test_code = calloc(1, tmp_size);
|
|
if (per_cpu_test_code == NULL) {
|
|
printf("%s:%d: Failed allocating memory\n", __func__, __LINE__);
|
|
ret = -1;
|
|
goto exit_vidt_code_pages;
|
|
}
|
|
size_tc = tmp_size;
|
|
|
|
//alloc and clear pages for sync exit stub code
|
|
tmp_size = REGION_SIZE(exit_code);
|
|
per_cpu_exit_code = calloc(1, tmp_size);
|
|
if (per_cpu_exit_code == NULL) {
|
|
printf("%s:%d: Failed allocating memory\n", __func__, __LINE__);
|
|
ret = -1;
|
|
goto exit_vidt_code_pages;
|
|
}
|
|
size_exitc = tmp_size;
|
|
|
|
//alloc and clear pages for enter/resume stub code
|
|
tmp_size = REGION_SIZE(enter_eresume_code);
|
|
per_cpu_enter_eresume_code = calloc(1, tmp_size);
|
|
if (per_cpu_enter_eresume_code == NULL) {
|
|
printf("%s:%d: Failed allocating memory\n", __func__, __LINE__);
|
|
ret = -1;
|
|
goto exit_vidt_code_pages;
|
|
}
|
|
size_enter_eresumec = tmp_size;
|
|
|
|
// --------------------------------------------------------
|
|
// Step2: Copy the code pages of flows individually
|
|
// --------------------------------------------------------
|
|
memcpy((char*)((unsigned int)per_cpu_vidt_stub),
|
|
(char*)MyHandler, isr_size*21);
|
|
//copy non-arch handlers 21-255
|
|
for (i=21; i<256; i++) {
|
|
memcpy( (char*)((unsigned int)per_cpu_vidt_stub + (isr_size*i)),
|
|
(char*)MyHandler_arch_end, isr_size);
|
|
}
|
|
|
|
memcpy( (char*)((unsigned int)per_cpu_test_code),
|
|
(char*)test_code, (unsigned int)test_code_end -
|
|
(unsigned int)test_code);
|
|
|
|
|
|
memcpy( (char*)((unsigned int)per_cpu_enter_eresume_code),
|
|
(char*)enter_eresume_code, (unsigned int)enter_eresume_code_end -
|
|
(unsigned int)enter_eresume_code);
|
|
|
|
memcpy( (char*)((unsigned int)per_cpu_exit_code),
|
|
(char*)exit_code, (unsigned int)exit_code_end -
|
|
(unsigned int)exit_code);
|
|
|
|
|
|
// --------------------------------------------------------
|
|
// Step3: Concatenate all the code pages into 1 memory chunk
|
|
// --------------------------------------------------------
|
|
size_total = size_stub + size_tc + size_exitc + size_enter_eresumec;
|
|
code_buf = calloc(1, size_total);
|
|
if (!code_buf) {
|
|
printf("%s:%d: Failed allocating memory\n", __func__, __LINE__);
|
|
ret = -1;
|
|
size_total = 0;
|
|
goto exit_vidt_code_pages;
|
|
}
|
|
|
|
memcpy(code_buf + off, (char *)per_cpu_test_code, size_tc);
|
|
off += size_tc;
|
|
printf("size tc = %lu\n", size_tc);
|
|
memcpy(code_buf + off, (char *)per_cpu_enter_eresume_code, size_enter_eresumec);
|
|
off += size_enter_eresumec;
|
|
printf("size enter_eresume= %lu\n", size_enter_eresumec);
|
|
memcpy(code_buf + off, (char *)per_cpu_exit_code, size_exitc);
|
|
off += size_exitc;
|
|
printf("size exit code = %lu\n", size_exitc);
|
|
memcpy(code_buf + off, (char *)per_cpu_vidt_stub, size_stub);
|
|
off += size_stub;
|
|
printf("size stub = %lu\n", size_stub);
|
|
|
|
exit_vidt_code_pages:
|
|
// --------------------------------------------------------
|
|
// Step4: Free memory for individual flows
|
|
// --------------------------------------------------------
|
|
if (per_cpu_vidt_stub)
|
|
free(per_cpu_vidt_stub);
|
|
if (per_cpu_test_code)
|
|
free(per_cpu_test_code);
|
|
if (per_cpu_enter_eresume_code)
|
|
free(per_cpu_enter_eresume_code);
|
|
if (per_cpu_exit_code)
|
|
free(per_cpu_exit_code);
|
|
|
|
// --------------------------------------------------------
|
|
// Step5: Return buffer and size
|
|
// --------------------------------------------------------
|
|
*vidt_buf = code_buf;
|
|
*vidt_size = size_total;
|
|
|
|
return ret;
|
|
}
|
|
|
|
void free_vidt_code_pages(void *buf)
|
|
{
|
|
if (buf)
|
|
free(buf);
|
|
}
|
|
#else
|
|
|
|
void print_idt(void *desc)
|
|
{
|
|
int i;
|
|
|
|
#ifdef __x86_64__
|
|
IA32e_IDT_GATE_DESCRIPTOR *Idt = (IA32e_IDT_GATE_DESCRIPTOR *)desc;
|
|
#else
|
|
IA32_IDT_GATE_DESCRIPTOR *Idt = (IA32_IDT_GATE_DESCRIPTOR *)desc;
|
|
#endif
|
|
|
|
for (i = 0 ; i < 256 ; i++)
|
|
{
|
|
KdPrint(PRINT_DEBUG, ("Gate Type 0x%x Selector:Address 0x%x:0x%llx \n",
|
|
Idt[i].GateType,
|
|
Idt[i].Selector,
|
|
#ifdef __x86_64__
|
|
((uint64_t)Idt[i].OffsetHigh << 32) | (Idt[i].OffsetMid << 16) | (Idt[i].OffsetLow) ));
|
|
#else
|
|
(Idt[i].OffsetHigh << 16) | (Idt[i].OffsetLow)));
|
|
#endif
|
|
}
|
|
|
|
}
|
|
|
|
|
|
void read_idt(uint32 cpuindex, uint64 codebase, void *desc)
|
|
{
|
|
int i;
|
|
|
|
#ifdef __x86_64__
|
|
IA32e_IDT_GATE_DESCRIPTOR *Idt = (IA32e_IDT_GATE_DESCRIPTOR *)desc;
|
|
#else
|
|
IA32_IDT_GATE_DESCRIPTOR *Idt = (IA32_IDT_GATE_DESCRIPTOR *)desc;
|
|
#endif
|
|
|
|
for (i = 0 ; i < 256 ; i++)
|
|
{
|
|
#ifdef __x86_64__
|
|
|
|
redirect[cpuindex][i].addr_orig =
|
|
(((uint64_t)Idt[i].OffsetHigh << 32) |
|
|
((uint64_t)Idt[i].OffsetMid << 16) |
|
|
(Idt[i].OffsetLow));
|
|
#else
|
|
redirect[cpuindex][i].addr_orig =
|
|
(Idt[i].OffsetHigh << 16) | (Idt[i].OffsetLow);
|
|
#endif
|
|
redirect[cpuindex][i].addr_vidt = (unsigned long)codebase + isr_size * i;
|
|
|
|
KdPrint(PRINT_DEBUG, ("Gate Type 0x%x Selector:Address 0x%x:0x%llx ",
|
|
Idt[i].GateType,
|
|
Idt[i].Selector,
|
|
redirect[cpuindex][i].addr_orig));
|
|
KdPrint(PRINT_DEBUG, ("Redirect Address 0x%llx ",
|
|
redirect[cpuindex][i].addr_vidt));
|
|
}
|
|
|
|
}
|
|
|
|
void InstallExceptionHandler(void *desc,
|
|
uint32 ExceptionIndex, uint64 HandlerAddr, uint32 GateType, uint32 dpl)
|
|
{
|
|
#ifdef __x86_64__
|
|
IA32e_IDT_GATE_DESCRIPTOR *Idt = (IA32e_IDT_GATE_DESCRIPTOR*)desc;
|
|
#else
|
|
IA32_IDT_GATE_DESCRIPTOR *Idt = (IA32_IDT_GATE_DESCRIPTOR*)desc;
|
|
#endif
|
|
if (!desc)
|
|
return;
|
|
//assuming Idt ptr is valid
|
|
#ifdef __x86_64__
|
|
Idt[ExceptionIndex].OffsetLow = HandlerAddr & 0xFFFF;
|
|
Idt[ExceptionIndex].OffsetMid = ((HandlerAddr >> 16 ) & 0xFFFF);
|
|
Idt[ExceptionIndex].OffsetHigh = ((HandlerAddr >> 32 ) & 0xFFFFFFFF);
|
|
#else
|
|
Idt[ExceptionIndex].OffsetLow = HandlerAddr & 0xFFFF;
|
|
Idt[ExceptionIndex].OffsetHigh = HandlerAddr >> 16;
|
|
#endif
|
|
Idt[ExceptionIndex].GateType = GateType;
|
|
Idt[ExceptionIndex].dpl = dpl;
|
|
}
|
|
|
|
void update_vidt(uint32 cpuindex, void *desc)
|
|
{
|
|
int i;
|
|
#ifdef __x86_64__
|
|
IA32e_IDT_GATE_DESCRIPTOR* Idt = (IA32e_IDT_GATE_DESCRIPTOR*) desc;
|
|
#else
|
|
IA32_IDT_GATE_DESCRIPTOR *Idt = (IA32_IDT_GATE_DESCRIPTOR *)desc;
|
|
#endif
|
|
|
|
for (i = 0 ; i < 256 ; i++)
|
|
{
|
|
//check for gate type - only if intr/trap gate then install handler
|
|
//for task gate - point to original selector in gdt/ldt
|
|
if (IA32_IDT_GATE_TYPE_TASK == Idt[i].GateType)
|
|
{
|
|
KdPrint(PRINT_DEBUG, ("Gate Type - task gate - skipping "));
|
|
continue;
|
|
}
|
|
|
|
InstallExceptionHandler((void *)Idt, i, redirect[cpuindex][i].addr_vidt,
|
|
Idt[i].GateType, Idt[i].dpl);
|
|
|
|
KdPrint(PRINT_DEBUG, ("Gate Type 0x%x Selector:Address 0x%x:0x%llx ",
|
|
Idt[i].GateType, Idt[i].Selector,
|
|
#ifdef __x86_64__
|
|
((uint64_t)Idt[i].OffsetHigh << 32) | ((uint64_t)Idt[i].OffsetMid << 16) | (Idt[i].OffsetLow) ));
|
|
#else
|
|
(Idt[i].OffsetHigh << 16) | (Idt[i].OffsetLow) ));
|
|
#endif
|
|
KdPrint(PRINT_DEBUG, ("original Address 0x%llx\n",
|
|
redirect[cpuindex][i].addr_orig));
|
|
}
|
|
}
|
|
|
|
void update_vidt_special_handlers(uint32 cpuindex, void *param)
|
|
{
|
|
#ifdef __x86_64__
|
|
IA32e_IDT_GATE_DESCRIPTOR *Idt = (IA32e_IDT_GATE_DESCRIPTOR *)param;
|
|
#else
|
|
IA32_IDT_GATE_DESCRIPTOR *Idt = (IA32_IDT_GATE_DESCRIPTOR *)param;
|
|
#endif
|
|
|
|
int i=EENTER_VECTOR;
|
|
|
|
InstallExceptionHandler((void *)Idt,
|
|
i, redirect[cpuindex][i].addr_vidt,
|
|
IA32_GATE_TYPE_INTR, IA32_DPL3);
|
|
|
|
KdPrint(PRINT_ALWAYS, ("Gate Type 0x%x Selector:Address 0x%x:0x%llx \n",
|
|
Idt[i].GateType, Idt[i].Selector,
|
|
#ifdef __x86_64__
|
|
((uint64_t)Idt[i].OffsetHigh << 32) | ((uint64_t)Idt[i].OffsetMid << 16) | (Idt[i].OffsetLow) ));
|
|
#else
|
|
(Idt[i].OffsetHigh << 16) | (Idt[i].OffsetLow) ));
|
|
#endif
|
|
|
|
KdPrint(PRINT_ALWAYS, ("original Address 0x%llx \n",
|
|
redirect[cpuindex][i].addr_orig));
|
|
|
|
i=EEXIT_VECTOR;
|
|
|
|
InstallExceptionHandler((void *)Idt,
|
|
i, redirect[cpuindex][i].addr_vidt,
|
|
IA32_GATE_TYPE_INTR, IA32_DPL3);
|
|
KdPrint(PRINT_DEBUG, ("Gate Type 0x%x Selector:Address 0x%x:0x%llx\n",
|
|
Idt[i].GateType, Idt[i].Selector,
|
|
#ifdef __x86_64__
|
|
((uint64_t)Idt[i].OffsetHigh << 32) | ((uint64_t)Idt[i].OffsetMid << 16) | (Idt[i].OffsetLow) ));
|
|
#else
|
|
(Idt[i].OffsetHigh << 16) | (Idt[i].OffsetLow) ));
|
|
#endif
|
|
KdPrint(PRINT_DEBUG, ("original Address 0x%llx \n",
|
|
redirect[cpuindex][i].addr_orig));
|
|
|
|
i=ERESUME_VECTOR;
|
|
InstallExceptionHandler((void *)Idt,
|
|
i, redirect[cpuindex][i].addr_vidt,
|
|
IA32_GATE_TYPE_INTR, IA32_DPL3);
|
|
KdPrint(PRINT_DEBUG, ("Gate Type 0x%x Selector:Address 0x%x:0x%llx\n",
|
|
Idt[i].GateType, Idt[i].Selector,
|
|
#ifdef __x86_64__
|
|
((uint64_t)Idt[i].OffsetHigh << 32) | ((uint64_t)Idt[i].OffsetMid << 16) | (Idt[i].OffsetLow) ));
|
|
#else
|
|
(Idt[i].OffsetHigh << 16) | (Idt[i].OffsetLow) ));
|
|
#endif
|
|
KdPrint(PRINT_DEBUG, ("original Address 0x%llx \n",
|
|
redirect[cpuindex][i].addr_orig));
|
|
}
|
|
|
|
void restore_os_idt(void)
|
|
{
|
|
uint32 cpuindex;
|
|
get_online_cpus();
|
|
for_each_online_cpu(cpuindex) {
|
|
#ifdef __x86_64__
|
|
smp_call_function_single(cpuindex, ia32e_load_idtr,
|
|
&core_state[cpuindex].os_idtr, 1);
|
|
#else
|
|
smp_call_function_single(cpuindex, ia32_load_idtr,
|
|
&core_state[cpuindex].os_idtr, 1);
|
|
#endif
|
|
}
|
|
put_online_cpus();
|
|
}
|
|
|
|
typedef void (*segment_reg_func_t)(void *desc);
|
|
|
|
#define NUM_STACK_PAGES 8
|
|
|
|
int setup_vidt(void)
|
|
{
|
|
void* vidt = NULL;
|
|
unsigned int page_offset = 0;
|
|
|
|
#ifdef __x86_64__
|
|
IA32e_IDT_GATE_DESCRIPTOR* vidt_start, *idt_start;
|
|
IA32e_IDTR Idtr;
|
|
#else
|
|
IA32_IDT_GATE_DESCRIPTOR* vidt_start, *idt_start;
|
|
IA32_IDTR Idtr;
|
|
#endif
|
|
void* per_cpu_vidt_stub = NULL;
|
|
void* per_cpu_test_code = NULL;
|
|
void* per_cpu_exit_code = NULL;
|
|
void* per_cpu_enter_eresume_code = NULL;
|
|
void* per_cpu_r0stack_pages = NULL;
|
|
void* per_cpu_enter_page = NULL;
|
|
void* per_cpu_exit_page = NULL;
|
|
uint32 cpuindex = 0;
|
|
unsigned int ActiveProcessors = 0;
|
|
unsigned int i = 0;
|
|
|
|
unsigned int test_code_offset = 0;
|
|
unsigned int enter_eresume_code_offset = 0;
|
|
unsigned int exit_code_offset = 0;
|
|
unsigned int region_size = 0;
|
|
hsec_sl_param_t sl_info;
|
|
|
|
char* redirect_ptr = NULL;
|
|
secs_t *secs_ptr = NULL;
|
|
|
|
memset(&sl_info, 0, sizeof(hsec_sl_param_t));
|
|
|
|
printk("setup_vidt loaded at %p\n", (void *)setup_vidt);
|
|
secs_la = (uint64)kmalloc(0x1000, GFP_KERNEL); //1 page for SECS la
|
|
if(secs_la == NULL)
|
|
{
|
|
KdPrint(PRINT_ALWAYS,("kmalloc failed %s: %d\n", __func__, __LINE__));
|
|
return SL_EUNKNOWN;
|
|
}
|
|
printk("secs gva at %p\n", (void*) secs_la);
|
|
secs_ptr = (secs_t*)secs_la;
|
|
//Temp setup of SECS is no longer needed.
|
|
//But keeping it here, as these numbers serve as magic
|
|
//numbers while debugging.
|
|
/*setup psuedo SECS for view 0 -- note this is for test*/
|
|
memset((char*)secs_ptr, 0, 0x1000);
|
|
secs_ptr->scv = SECS_SCV_UNTRUSTED;
|
|
//secs_ptr->size = 4096;
|
|
secs_ptr->size = 0x6A000;
|
|
secs_ptr->base = 0; /*fill in for testing with simple app*/
|
|
secs_ptr->ssa_frame_size = 1; //1 page
|
|
|
|
#ifdef __x86_64__
|
|
sl_info.secs_gva = (uint64_t)secs_ptr;
|
|
#else
|
|
sl_info.secs_gva = (uint32_t)secs_ptr;
|
|
#endif
|
|
KdPrint(PRINT_ALWAYS, ("Registering sl global info 0x%llx\n",
|
|
sl_info.secs_gva));
|
|
reg_sl_global_info(&sl_info);
|
|
|
|
//allocate redirect table from non-pageable memory
|
|
#ifdef __x86_64__
|
|
redirect_ptr = kmalloc(sizeof(IA32e_IDT_REDIRECT_TABLE) * 256 * MAX_CORES,
|
|
GFP_KERNEL);
|
|
#else
|
|
redirect_ptr = kmalloc(sizeof(IA32_IDT_REDIRECT_TABLE) * 256 * MAX_CORES,
|
|
GFP_KERNEL);
|
|
#endif
|
|
if(redirect_ptr == NULL)
|
|
{
|
|
KdPrint(PRINT_ALWAYS,("kmalloc failed %s: %d\n", __func__, __LINE__));
|
|
SAFE_FREE(secs_ptr);
|
|
return SL_EUNKNOWN;
|
|
}
|
|
|
|
//allocate ptr_core_state from non-pageable memory
|
|
ptr_core_state = (unsigned long) kmalloc(sizeof(PER_CORE_STATE) * MAX_CORES, GFP_KERNEL);
|
|
|
|
if(ptr_core_state == NULL)
|
|
{
|
|
KdPrint(PRINT_ALWAYS,("kmalloc failed %s: %d\n", __func__, __LINE__));
|
|
SAFE_FREE(secs_ptr);
|
|
SAFE_FREE(redirect_ptr);
|
|
return SL_EUNKNOWN;
|
|
}
|
|
memset((char*)ptr_core_state, 0, sizeof(PER_CORE_STATE) * MAX_CORES);
|
|
|
|
ActiveProcessors = NR_CPUS;
|
|
KdPrint(PRINT_DEBUG, ("ActiveProcessors = %x \n",ActiveProcessors));
|
|
|
|
cpuindex = 0;
|
|
get_online_cpus();
|
|
for_each_online_cpu(cpuindex) {
|
|
hsec_vIDT_param_t vIDT_info;
|
|
hsec_map_t region_map;
|
|
unsigned int n_stub_patches = 0;
|
|
segment_reg_func_t read_gdtr_fp, read_idtr_fp, read_ldtr_fp;
|
|
#ifdef __x86_64__
|
|
IA32e_LDTR ldtr;
|
|
IA32e_GDTR gdtr;
|
|
IA32e_IDTR idtr;
|
|
IA32e_IDTR idt_desc;
|
|
#else
|
|
IA32_LDTR ldtr;
|
|
IA32_GDTR gdtr;
|
|
IA32_IDTR idtr;
|
|
IA32_IDTR idt_desc;
|
|
#endif
|
|
hsec_patch_info_t *stub_patch, *test_code_patch, *enter_eresume_code_patch, *exit_code_patch;
|
|
|
|
test_code_patch=stub_patch=enter_eresume_code_patch=exit_code_patch = NULL;
|
|
|
|
KdPrint(PRINT_ALWAYS, ("======cpuindex = 0x%x ========\n", cpuindex));
|
|
|
|
//FIXME - these values should be per logical processor
|
|
//update psuedo secs cached gdtr, idtr, ldtr
|
|
#ifdef __x86_64__
|
|
read_gdtr_fp = ia32e_read_gdtr;
|
|
read_idtr_fp = ia32e_read_idtr;
|
|
read_ldtr_fp = ia32e_read_ldtr;
|
|
#else
|
|
read_gdtr_fp = ia32_read_gdtr;
|
|
read_idtr_fp = ia32_read_idtr;
|
|
read_ldtr_fp = ia32_read_ldtr;
|
|
#endif
|
|
|
|
smp_call_function_single(cpuindex, read_gdtr_fp, (void *)&gdtr, 1);
|
|
|
|
secs_ptr->pcd[cpuindex].gdtr = gdtr.base;
|
|
|
|
smp_call_function_single(cpuindex, read_ldtr_fp, (void *)&ldtr, 1);
|
|
secs_ptr->pcd[cpuindex].ldtr = ldtr.base;
|
|
|
|
smp_call_function_single(cpuindex, read_idtr_fp, (void *)&idtr, 1);
|
|
|
|
secs_ptr->pcd[cpuindex].idtr = idtr.base;
|
|
|
|
//alloc and clear page for this cpus vidt
|
|
vidt = kmalloc(0x1000, GFP_KERNEL); //1 page
|
|
if(vidt == NULL)
|
|
{
|
|
KdPrint(PRINT_ALWAYS,("kmalloc failed %s: %d\n", __func__, __LINE__));
|
|
goto fail_msg;
|
|
}
|
|
|
|
//alloc and clear pages for per_cpu_vidt_stub (MyHandler)
|
|
isr_size = ((unsigned long)MyHandler_non_arch_end -
|
|
(unsigned long)MyHandler_arch_end);
|
|
per_cpu_vidt_stub = kmalloc(isr_size*256, GFP_KERNEL);
|
|
if(per_cpu_vidt_stub == NULL)
|
|
{
|
|
KdPrint(PRINT_ALWAYS,("kmalloc failed %s: %d\n", __func__, __LINE__));
|
|
goto fail_msg;
|
|
}
|
|
//alloc and clear pages for AEX Exit stub code
|
|
if (((unsigned long)test_code_end - (unsigned long)test_code)<0x1000) {
|
|
per_cpu_test_code = kmalloc(0x1000, GFP_KERNEL);
|
|
} else {
|
|
per_cpu_test_code = kmalloc((unsigned long)test_code_end -
|
|
(unsigned long)test_code, GFP_KERNEL);
|
|
}
|
|
if(per_cpu_test_code == NULL)
|
|
{
|
|
KdPrint(PRINT_ALWAYS,("kmalloc failed %s: %d\n", __func__, __LINE__));
|
|
goto fail_msg;
|
|
}
|
|
//alloc and clear pages for sync exit stub code
|
|
if (((unsigned long)exit_code_end - (unsigned long)exit_code)<0x1000) {
|
|
per_cpu_exit_code = kmalloc(0x1000, GFP_KERNEL);
|
|
}
|
|
else {
|
|
per_cpu_exit_code = kmalloc((unsigned long)exit_code_end -
|
|
(unsigned long)exit_code, GFP_KERNEL);
|
|
}
|
|
if(per_cpu_exit_code == NULL)
|
|
{
|
|
KdPrint(PRINT_ALWAYS,("kmalloc failed %s: %d\n", __func__, __LINE__));
|
|
goto fail_msg;
|
|
}
|
|
//alloc and clear pages for enter/resume stub code
|
|
if (((unsigned long)enter_eresume_code_end -
|
|
(unsigned long)enter_eresume_code)<0x1000) {
|
|
per_cpu_enter_eresume_code = kmalloc(0x1000, GFP_KERNEL);
|
|
}
|
|
else {
|
|
per_cpu_enter_eresume_code = kmalloc((unsigned long)enter_eresume_code_end -
|
|
(unsigned long)enter_eresume_code, GFP_KERNEL);
|
|
}
|
|
|
|
if(per_cpu_enter_eresume_code == NULL)
|
|
{
|
|
KdPrint(PRINT_ALWAYS,("kmalloc failed %s: %d\n", __func__, __LINE__));
|
|
goto fail_msg;
|
|
}
|
|
|
|
printk("allocating per cpu thread r0 stack pages \n");
|
|
per_cpu_r0stack_pages = kmalloc(0x1000*NUM_STACK_PAGES, GFP_KERNEL);
|
|
if(per_cpu_r0stack_pages == NULL)
|
|
{
|
|
KdPrint(PRINT_ALWAYS,("kmalloc failed %s: %d\n", __func__, __LINE__));
|
|
goto fail_msg;
|
|
}
|
|
per_cpu_enter_page = kmalloc(0x1000, GFP_KERNEL);
|
|
if(per_cpu_enter_page == NULL)
|
|
{
|
|
KdPrint(PRINT_ALWAYS,("kmalloc failed %s: %d\n", __func__, __LINE__));
|
|
goto fail_msg;
|
|
}
|
|
per_cpu_exit_page = kmalloc(0x1000, GFP_KERNEL);
|
|
if(per_cpu_exit_page == NULL)
|
|
{
|
|
KdPrint(PRINT_ALWAYS,("kmalloc failed %s: %d\n", __func__, __LINE__));
|
|
goto fail_msg;
|
|
}
|
|
|
|
//if any kmalloc failed goto fail_msg
|
|
if ((!vidt) || (!per_cpu_vidt_stub) || (!per_cpu_test_code)
|
|
|| (!per_cpu_exit_code) || (!per_cpu_enter_eresume_code)
|
|
|| (!per_cpu_r0stack_pages)
|
|
|| (!per_cpu_enter_page) || (!per_cpu_exit_page))
|
|
goto fail_msg;
|
|
|
|
#ifdef __x86_64__
|
|
|
|
KdPrint(PRINT_ALWAYS, ("vidt is at 0x%llx\n", (uint64)vidt));
|
|
KdPrint(PRINT_ALWAYS, ("per_cpu_vidt_stub is at 0x%llx size 0x%x\n",
|
|
(uint64)per_cpu_vidt_stub, isr_size*256));
|
|
KdPrint(PRINT_ALWAYS, ("per_cpu_test_code is at 0x%llx \n",
|
|
(uint64)per_cpu_test_code));
|
|
KdPrint(PRINT_ALWAYS, ("per_cpu_exit_code is at 0x%llx \n",
|
|
(uint64)per_cpu_exit_code));
|
|
KdPrint(PRINT_ALWAYS, ("per_cpu_enter_eresume_code is at 0x%llx \n",
|
|
(uint64)per_cpu_enter_eresume_code));
|
|
KdPrint(PRINT_ALWAYS, ("per_cpu_r0stack_pages start at 0x%llx \n",
|
|
(uint64)per_cpu_r0stack_pages));
|
|
KdPrint(PRINT_ALWAYS, ("per_cpu_enter_pages start at 0x%llx \n",
|
|
(uint64)per_cpu_enter_page));
|
|
KdPrint(PRINT_ALWAYS, ("per_cpu_exit_page start at 0x%llx \n",
|
|
(uint64)per_cpu_exit_page));
|
|
#else
|
|
|
|
KdPrint(PRINT_ALWAYS, ("vidt is at 0x%x\n", (uint32)vidt));
|
|
KdPrint(PRINT_ALWAYS, ("per_cpu_vidt_stub is at 0x%x size 0x%x\n",
|
|
(uint32)per_cpu_vidt_stub, isr_size*256));
|
|
KdPrint(PRINT_ALWAYS, ("per_cpu_test_code is at 0x%x \n",
|
|
(uint32)per_cpu_test_code));
|
|
KdPrint(PRINT_ALWAYS, ("per_cpu_exit_code is at 0x%x \n",
|
|
(uint32)per_cpu_exit_code));
|
|
KdPrint(PRINT_ALWAYS, ("per_cpu_enter_eresume_code is at 0x%x \n",
|
|
(uint32)per_cpu_enter_eresume_code));
|
|
KdPrint(PRINT_ALWAYS, ("per_cpu_r0stack_pages start at 0x%lx \n",
|
|
(uint32)per_cpu_r0stack_pages));
|
|
KdPrint(PRINT_ALWAYS, ("per_cpu_enter_pages start at 0x%lx \n",
|
|
(uint32)per_cpu_enter_page));
|
|
KdPrint(PRINT_ALWAYS, ("per_cpu_exit_page start at 0x%lx \n",
|
|
(uint32)per_cpu_exit_page));
|
|
#endif
|
|
KdPrint(PRINT_ALWAYS, ("==============\n"));
|
|
|
|
memset(vidt, 0, 0x1000);
|
|
memset( per_cpu_vidt_stub, 0, isr_size*256);
|
|
memset( per_cpu_test_code, 0,
|
|
(unsigned long)test_code_end - (unsigned long)test_code);
|
|
memset( per_cpu_exit_code, 0,
|
|
(unsigned long)exit_code_end - (unsigned long)exit_code);
|
|
memset( per_cpu_enter_eresume_code, 0,
|
|
(unsigned long)enter_eresume_code_end -
|
|
(unsigned long)enter_eresume_code);
|
|
memset(®ion_map, 0, sizeof(region_map));
|
|
memset(&vIDT_info, 0, sizeof(vIDT_info));
|
|
//copy handler code
|
|
//copy architechural handlers 0-20
|
|
memcpy((char*)((unsigned long)per_cpu_vidt_stub),
|
|
(char*)MyHandler, isr_size*21);
|
|
//copy non-arch handlers 21-255
|
|
for (i=21; i<256; i++) {
|
|
memcpy( (char*)((unsigned long)per_cpu_vidt_stub + (isr_size*i)),
|
|
(char*)MyHandler_arch_end, isr_size);
|
|
}
|
|
|
|
//--------setup aex flow--------------
|
|
//copy main body of exit stub code
|
|
memcpy( (char*)((unsigned long)per_cpu_test_code),
|
|
(char*)test_code, (unsigned long)test_code_end -
|
|
(unsigned long)test_code);
|
|
|
|
|
|
// 6 patches - cpuindex, ptr_core_state, 2 secs ptr, secs scv, exit_page
|
|
test_code_patch =
|
|
(hsec_patch_info_t *)kmalloc(NUM_AEX_CODE_PATCHES * sizeof(hsec_patch_info_t),
|
|
GFP_KERNEL);
|
|
if(test_code_patch == NULL)
|
|
{
|
|
KdPrint(PRINT_ALWAYS,("kmalloc failed %s: %d\n", __func__, __LINE__));
|
|
goto fail_msg;
|
|
}
|
|
//patch per cpu test code with core id
|
|
test_code_offset = (unsigned long)test_code_cpuindex -
|
|
(unsigned long)test_code;
|
|
#if 0
|
|
memcpy( (char*)((unsigned long)per_cpu_test_code +
|
|
test_code_offset + 0x1),
|
|
(char*)&cpuindex, sizeof(unsigned long));
|
|
#endif
|
|
|
|
test_code_patch[0].val = (unsigned long)cpuindex;
|
|
test_code_patch[0].offset = test_code_offset + MOV_OPCODE_SIZE;
|
|
test_code_patch[0].type = PATCH_TYPE_CORE_ID;
|
|
|
|
|
|
//patch per cpu test code with secs
|
|
ADD_SECS_PATCH(1, test_code, 1);
|
|
|
|
//patch per cpu test code with ptr_core_state
|
|
test_code_offset = (unsigned long)test_code_ptr_core_state_patch -
|
|
(unsigned long)test_code;
|
|
#if 0
|
|
memcpy( (char*)((unsigned long)per_cpu_test_code +
|
|
test_code_offset + 0x1),
|
|
(char*)&ptr_core_state, sizeof(unsigned long));
|
|
#endif
|
|
|
|
test_code_patch[2].val = (unsigned long)ptr_core_state;
|
|
test_code_patch[2].offset = test_code_offset + MOV_OPCODE_SIZE;
|
|
test_code_patch[2].type = PATCH_TYPE_CORE_STATE_PTR;
|
|
|
|
|
|
test_code_offset = (unsigned long)test_code_cmp_patch -
|
|
(unsigned long)test_code;
|
|
|
|
test_code_patch[3].val = (unsigned long)~0x0; //special value to signify that hypersim should patch by itself.
|
|
test_code_patch[3].offset = test_code_offset + MOV_OPCODE_SIZE;
|
|
test_code_patch[3].type = PATCH_TYPE_SECS_SCV;
|
|
|
|
ADD_SECS_PATCH(2, test_code, 4);
|
|
|
|
/*FIXME noticed that the data values were being type-casted to
|
|
unsigned long which will cause issues - must replace with #def
|
|
data_type to adjust for 32 bit and 64 bit*/
|
|
|
|
test_code_offset = (unsigned long)test_code_exit_page_patch -
|
|
(unsigned long)test_code;
|
|
test_code_patch[5].val = (unsigned long)per_cpu_exit_page;
|
|
test_code_patch[5].offset = test_code_offset + MOV_OPCODE_SIZE;
|
|
test_code_patch[5].type = PATCH_TYPE_EXIT_PAGE;
|
|
|
|
region_size = REGION_SIZE(test_code);
|
|
ADD_REGION(region_map, per_cpu_test_code,1,
|
|
test_code_patch, NUM_AEX_CODE_PATCHES, region_size);
|
|
|
|
set_page_exec((unsigned long)per_cpu_test_code);
|
|
|
|
//--------setup entry flow--------------
|
|
memcpy( (char*)((unsigned long)per_cpu_enter_eresume_code),
|
|
(char*)enter_eresume_code, (unsigned long)enter_eresume_code_end -
|
|
(unsigned long)enter_eresume_code);
|
|
|
|
|
|
enter_eresume_code_patch =
|
|
(hsec_patch_info_t *)kmalloc(NUM_ENT_RES_CODE_PATCHES * sizeof(hsec_patch_info_t),
|
|
GFP_KERNEL);
|
|
if(enter_eresume_code_patch == NULL)
|
|
{
|
|
KdPrint(PRINT_ALWAYS,("kmalloc failed %s: %d\n", __func__, __LINE__));
|
|
goto fail_msg;
|
|
}
|
|
//patch per cpu enter code with core id
|
|
enter_eresume_code_offset = (unsigned long)enter_eresume_code_cpuindex -
|
|
(unsigned long)enter_eresume_code;
|
|
#if 0
|
|
memcpy( (char*)((unsigned long)per_cpu_enter_eresume_code +
|
|
enter_eresume_code_offset + 0x1),
|
|
(char*)&cpuindex, sizeof(unsigned long));
|
|
#endif
|
|
enter_eresume_code_patch[0].val = (unsigned long)cpuindex;
|
|
enter_eresume_code_patch[0].offset = enter_eresume_code_offset + MOV_OPCODE_SIZE;
|
|
enter_eresume_code_patch[0].type = PATCH_TYPE_CORE_ID;
|
|
|
|
enter_eresume_code_offset = (unsigned long)enter_eresume_code_cmp_patch1 -
|
|
(unsigned long)enter_eresume_code;
|
|
enter_eresume_code_patch[1].val = (unsigned long)~0x0;
|
|
enter_eresume_code_patch[1].offset = enter_eresume_code_offset + MOV_OPCODE_SIZE;
|
|
enter_eresume_code_patch[1].type = PATCH_TYPE_SECS_SCV_UN;
|
|
|
|
|
|
enter_eresume_code_offset = (unsigned long)enter_eresume_code_cmp_patch2 -
|
|
(unsigned long)enter_eresume_code;
|
|
enter_eresume_code_patch[2].val = (unsigned long)~0x0;
|
|
enter_eresume_code_patch[2].offset = enter_eresume_code_offset + MOV_OPCODE_SIZE;
|
|
enter_eresume_code_patch[2].type = PATCH_TYPE_SECS_SCV;
|
|
|
|
ADD_SECS_PATCH(1, enter_eresume_code, 3);
|
|
ADD_SECS_PATCH(2, enter_eresume_code, 4);
|
|
ADD_SECS_PATCH(3, enter_eresume_code, 5);
|
|
ADD_SECS_PATCH(4, enter_eresume_code, 6);
|
|
ADD_SECS_PATCH(5, enter_eresume_code, 7);
|
|
ADD_SECS_PATCH(6, enter_eresume_code, 8);
|
|
|
|
enter_eresume_code_offset = (unsigned long)enter_eresume_code_enter_page_patch -
|
|
(unsigned long)enter_eresume_code;
|
|
enter_eresume_code_patch[9].val = (unsigned long)per_cpu_enter_page;
|
|
enter_eresume_code_patch[9].offset = enter_eresume_code_offset + MOV_OPCODE_SIZE;
|
|
enter_eresume_code_patch[9].type = PATCH_TYPE_ENTER_PAGE;
|
|
|
|
region_size = REGION_SIZE(enter_eresume_code);
|
|
ADD_REGION(region_map, per_cpu_enter_eresume_code, 1,
|
|
enter_eresume_code_patch, NUM_ENT_RES_CODE_PATCHES, region_size);
|
|
set_page_exec((unsigned long)per_cpu_enter_eresume_code);
|
|
|
|
//--------setup exit flow--------------
|
|
memcpy( (char*)((unsigned long)per_cpu_exit_code),
|
|
(char*)exit_code, (unsigned long)exit_code_end -
|
|
(unsigned long)exit_code);
|
|
|
|
exit_code_patch =
|
|
(hsec_patch_info_t *)kmalloc(NUM_EXIT_CODE_PATCHES * sizeof(hsec_patch_info_t),
|
|
GFP_KERNEL);
|
|
if(exit_code_patch == NULL)
|
|
{
|
|
KdPrint(PRINT_ALWAYS,("kmalloc failed %s: %d\n", __func__, __LINE__));
|
|
goto fail_msg;
|
|
}
|
|
//patch per cpu exit code with core id
|
|
exit_code_offset = (unsigned long)exit_code_cpuindex -
|
|
(unsigned long)exit_code;
|
|
#if 0
|
|
memcpy( (char*)((unsigned long)per_cpu_exit_code +
|
|
exit_code_offset + 0x1),
|
|
(char*)&cpuindex, sizeof(unsigned long));
|
|
#endif
|
|
exit_code_patch[0].val = (unsigned long)cpuindex;
|
|
exit_code_patch[0].offset = exit_code_offset + MOV_OPCODE_SIZE;
|
|
exit_code_patch[0].type = PATCH_TYPE_CORE_ID;
|
|
|
|
exit_code_offset = (unsigned long)exit_code_cmp_patch -
|
|
(unsigned long)exit_code;
|
|
exit_code_patch[1].val = (unsigned long)~0x0;
|
|
exit_code_patch[1].offset = exit_code_offset + MOV_OPCODE_SIZE;
|
|
exit_code_patch[1].type = PATCH_TYPE_SECS_SCV;
|
|
|
|
ADD_SECS_PATCH(1, exit_code, 2);
|
|
|
|
exit_code_offset = (unsigned long)exit_code_exit_page_patch -
|
|
(unsigned long)exit_code;
|
|
exit_code_patch[3].val = (unsigned long)per_cpu_exit_page;
|
|
exit_code_patch[3].offset = exit_code_offset + MOV_OPCODE_SIZE;
|
|
exit_code_patch[3].type = PATCH_TYPE_EXIT_PAGE;
|
|
|
|
region_size = REGION_SIZE(exit_code);
|
|
ADD_REGION(region_map, per_cpu_exit_code, 1,
|
|
exit_code_patch, NUM_EXIT_CODE_PATCHES, region_size);
|
|
set_page_exec((unsigned long)per_cpu_exit_code);
|
|
|
|
//prepare vidt per core
|
|
core_state[cpuindex].os_idtr = idtr;
|
|
// smp_call_function_single(cpuindex, print_gdt, NULL, 0);
|
|
|
|
KdPrint(PRINT_DEBUG, ("==============\n"));
|
|
|
|
KdPrint(PRINT_ALWAYS, ("CPU %x IDT lim is 0x%hx\n",
|
|
cpuindex, idtr.limit));
|
|
KdPrint(PRINT_ALWAYS, ("CPU %x IDT base is 0x%llx\n",
|
|
cpuindex, idtr.base));
|
|
KdPrint(PRINT_ALWAYS, ("==============\n"));
|
|
|
|
#ifdef __x86_64__
|
|
idt_start = (IA32e_IDT_GATE_DESCRIPTOR*)idtr.base;
|
|
#else
|
|
idt_start = (IA32_IDT_GATE_DESCRIPTOR*)idtr.base;
|
|
#endif
|
|
//print_idt(idt_start);
|
|
KdPrint(PRINT_DEBUG, ("==============\n"));
|
|
|
|
page_offset = (unsigned long)idtr.base & 0x00000FFF;
|
|
if (idtr.limit > 0x1000) {
|
|
KdPrint(PRINT_ALWAYS, ("Cannot copy idt into vidt memory\n"));
|
|
goto fail_msg;
|
|
}
|
|
memcpy( (char*)((unsigned long)vidt+page_offset),
|
|
(char*)idtr.base, idtr.limit+1);
|
|
|
|
#ifdef __x86_64__
|
|
vidt_start = (IA32e_IDT_GATE_DESCRIPTOR*)((unsigned long)vidt+page_offset);
|
|
#else
|
|
vidt_start = (IA32_IDT_GATE_DESCRIPTOR*)((unsigned long)vidt+page_offset);
|
|
#endif
|
|
|
|
|
|
//save os orig handlers and update our
|
|
//handlers in cpu specific redirect table
|
|
read_idt(cpuindex, (unsigned long)per_cpu_vidt_stub, (void *)idt_start);
|
|
KdPrint(PRINT_DEBUG, ("==============\n"));
|
|
|
|
update_vidt(cpuindex, (void *)vidt_start);
|
|
update_vidt_special_handlers(cpuindex, (void *)vidt_start);
|
|
|
|
//print_idt(vidt_start);
|
|
KdPrint(PRINT_DEBUG, ("==============\n"));
|
|
|
|
//patch vidt handler code with vector numbers for non-arch handlers
|
|
//from 21 to 255 and for all isrs patch vidt handler code with
|
|
//entrypoint of per cpu test code
|
|
|
|
// Per vector, vector# and handler code address is patched
|
|
stub_patch = (hsec_patch_info_t *)kmalloc(256*2* sizeof(hsec_patch_info_t),
|
|
GFP_KERNEL);
|
|
if(stub_patch == NULL)
|
|
{
|
|
KdPrint(PRINT_ALWAYS,("kmalloc failed %s: %d\n", __func__, __LINE__));
|
|
goto fail_msg;
|
|
}
|
|
//VT: TODO - the following code needs change in offsets
|
|
//(0x7 and 0xF need to be changed for 64 bit)
|
|
// TODO: Check if stub_patch is non null
|
|
for (i = 0 ; i < 256 ; i++)
|
|
{
|
|
// Fist record patch info for patching the vector #
|
|
stub_patch[i*2].val = i;
|
|
stub_patch[i*2].offset = i*isr_size +
|
|
(unsigned long)vidt_stub_patch_val0 -
|
|
(unsigned long)MyHandler +
|
|
MOV_OPCODE_SIZE;
|
|
stub_patch[i*2].type = PATCH_TYPE_IDT_VECTOR;
|
|
|
|
// Now record patch info for patching the stub handler address
|
|
stub_patch[i*2+1].offset = i*isr_size +
|
|
(unsigned long)vidt_stub_patch_callee0 -
|
|
(unsigned long)MyHandler + MOV_OPCODE_SIZE;
|
|
stub_patch[i*2+1].type = PATCH_TYPE_REGION_ADDR;
|
|
switch (i) {
|
|
case EENTER_VECTOR:
|
|
case ERESUME_VECTOR:
|
|
stub_patch[i*2+1].val = (unsigned long)per_cpu_enter_eresume_code;
|
|
break;
|
|
case EEXIT_VECTOR:
|
|
stub_patch[i*2+1].val = (unsigned long)per_cpu_exit_code;
|
|
break;
|
|
default:
|
|
stub_patch[i*2+1].val = (unsigned long)per_cpu_test_code;
|
|
break;
|
|
}
|
|
n_stub_patches += 2;
|
|
}
|
|
|
|
//copy redirect table into non-pageable memory
|
|
//note must be done before core_state redirect_addr set
|
|
#ifdef __x86_64__
|
|
memcpy((char*)redirect_ptr + (cpuindex * 256 * sizeof(IA32e_IDT_REDIRECT_TABLE)),
|
|
(char*)redirect[cpuindex],
|
|
256 * sizeof(IA32e_IDT_REDIRECT_TABLE));
|
|
|
|
core_state[cpuindex].redirect_addr =(unsigned long)(redirect_ptr +
|
|
(cpuindex * 256 * sizeof(IA32e_IDT_REDIRECT_TABLE)));
|
|
//(unsigned long)redirect[cpuindex];
|
|
core_state[cpuindex].redirect_size = sizeof(IA32e_IDT_REDIRECT_TABLE) * 256;
|
|
core_state[cpuindex].vep_max = 0; //unused remove
|
|
core_state[cpuindex].vep_tos = 0; //unused remove
|
|
|
|
#else
|
|
memcpy((char*)redirect_ptr + (cpuindex * 256 * sizeof(IA32_IDT_REDIRECT_TABLE)),
|
|
(char*)redirect[cpuindex],
|
|
256 * sizeof(IA32_IDT_REDIRECT_TABLE));
|
|
|
|
core_state[cpuindex].redirect_addr =(unsigned long)(redirect_ptr +
|
|
(cpuindex * 256 * sizeof(IA32_IDT_REDIRECT_TABLE)));
|
|
//(unsigned long)redirect[cpuindex];
|
|
core_state[cpuindex].redirect_size = sizeof(IA32_IDT_REDIRECT_TABLE) * 256;
|
|
core_state[cpuindex].vep_max = 0; //unused remove
|
|
core_state[cpuindex].vep_tos = 0; //unused remove
|
|
|
|
#endif
|
|
KdPrint(PRINT_ALWAYS, ("core state %d = 0x%x 0x%x 0x%lx 0x%llx\n", cpuindex,
|
|
core_state[cpuindex].vep_max,
|
|
core_state[cpuindex].vep_tos,
|
|
core_state[cpuindex].redirect_size,
|
|
core_state[cpuindex].redirect_addr));
|
|
|
|
/* Note - must be done before IDT modified - copy per core state to
|
|
* non-pageable memory */
|
|
memcpy( (char*)ptr_core_state,
|
|
(char*)core_state,
|
|
sizeof(PER_CORE_STATE) * MAX_CORES);
|
|
|
|
|
|
//set up complete - now we can modify IDT via driver or hypervisor
|
|
|
|
#ifdef __x86_64__
|
|
Idtr.base = (uint64)(vidt_start);
|
|
Idtr.limit = sizeof(IA32e_IDT_GATE_DESCRIPTOR) * 256 - 1;
|
|
#else
|
|
Idtr.base = (uint32)(vidt_start);
|
|
Idtr.limit = sizeof(IA32_IDT_GATE_DESCRIPTOR) * 256 - 1;
|
|
#endif
|
|
// smp_call_function_single(cpuindex, ia32_load_idtr, &Idtr, 1);
|
|
|
|
// Test register vIDT with VIDT stub only...
|
|
// TBD: Add other regions as well in this.
|
|
ADD_REGION(region_map, per_cpu_vidt_stub, ((isr_size*256)>>12)+1,
|
|
stub_patch, n_stub_patches, (isr_size*256));
|
|
i = 0;
|
|
while ((per_cpu_vidt_stub + i*0x1000) <
|
|
(per_cpu_vidt_stub + (isr_size*256))) {
|
|
set_page_exec((unsigned long)(per_cpu_vidt_stub + i*0x1000));
|
|
i++;
|
|
}
|
|
|
|
#ifdef __x86_64__
|
|
vIDT_info.vIDT_base = (uint64_t)Idtr.base;
|
|
#else
|
|
vIDT_info.vIDT_base = (uint32_t)Idtr.base;
|
|
#endif
|
|
vIDT_info.vIDT_limit = Idtr.limit;
|
|
vIDT_info.cpu = cpuindex;
|
|
vIDT_info.map = region_map;
|
|
KdPrint(PRINT_ALWAYS, ("Registering vIDT for cpu %d\n", cpuindex));
|
|
KdPrint(PRINT_ALWAYS, ("Number of patches = 0x%x\n",
|
|
vIDT_info.map.region[0].n_patches));
|
|
KdPrint(PRINT_ALWAYS, ("Creating XO mapping for 0x%llx, n_pages = 0x%x\n",
|
|
region_map.region[0].start_gva, region_map.region[0].n_pages));
|
|
|
|
vIDT_info.r0stack_num_pages = (uint16_t)NUM_STACK_PAGES;
|
|
#ifdef __x86_64__
|
|
vIDT_info.r0stack_gva_tos = (uint64_t)(per_cpu_r0stack_pages + (NUM_STACK_PAGES*0x1000) -1);
|
|
vIDT_info.r0_enter_page = (uint64_t)(per_cpu_enter_page);
|
|
vIDT_info.r0_exit_page = (uint64_t)(per_cpu_exit_page);
|
|
vIDT_info.enter_eresume_code = (uint64_t) (per_cpu_enter_eresume_code);
|
|
vIDT_info.exit_code = (uint64_t) (per_cpu_exit_code);
|
|
vIDT_info.async_exit_code = (uint64_t) (per_cpu_test_code);
|
|
#else
|
|
vIDT_info.r0stack_gva_tos = (uint32_t)(per_cpu_r0stack_pages + (NUM_STACK_PAGES*0x1000) -1);
|
|
vIDT_info.r0_enter_page = (uint32_t)(per_cpu_enter_page);
|
|
vIDT_info.r0_exit_page = (uint32_t)(per_cpu_exit_page);
|
|
vIDT_info.enter_eresume_code = (uint32_t) (per_cpu_enter_eresume_code);
|
|
vIDT_info.exit_code = (uint32_t) (per_cpu_exit_code);
|
|
vIDT_info.async_exit_code = (uint32_t) (per_cpu_test_code);
|
|
#endif
|
|
|
|
KdPrint(PRINT_ALWAYS, ("num r0 stack pages are 0x%x\n", vIDT_info.r0stack_num_pages));
|
|
KdPrint(PRINT_ALWAYS, ("r0 stack tos is at 0x%llx\n", vIDT_info.r0stack_gva_tos));
|
|
|
|
// WARNING - Here, we are calling reg_vIDT on the cpu for which
|
|
// we want to change the IDT. This reduces crashes seen in MP
|
|
// environment. If possible, we should try to remove this restriction
|
|
// and make hypervisor change IDT on the desired cpu.
|
|
// Note that last argument to the smp_single* function is 1 here as
|
|
// we want the reg_VIDT to finish before proceeding. The reason is
|
|
// that the hypercall makes some pages XO and if we don't wait here,
|
|
// there is a race where somebody could write to the pages after they
|
|
// have been marked XO by the hypersim but before the EPTs are disabled.
|
|
// That can cause EPT write violation.
|
|
smp_call_function_single(cpuindex, reg_vIDT, (void*)&vIDT_info, 1);
|
|
|
|
KdPrint(PRINT_ALWAYS, ("finished registering vidt for cpu %u, running on cpu %d\n", cpuindex, smp_processor_id()));
|
|
//verify
|
|
#ifdef __x86_64__
|
|
smp_call_function_single(cpuindex, ia32e_read_idtr, &idt_desc, 1);
|
|
#else
|
|
smp_call_function_single(cpuindex, ia32_read_idtr, &idt_desc, 1);
|
|
#endif
|
|
// smp_call_function_single(cpuindex, print_gdt, NULL, 0);
|
|
// smp_call_function_single(cpuindex, print_ldt, NULL, 0);
|
|
|
|
KdPrint(PRINT_ALWAYS, ("CPU %x IDT lim is 0x%hx\n", cpuindex, idt_desc.limit));
|
|
KdPrint(PRINT_ALWAYS, ("CPU %x IDT base is 0x%llx\n", cpuindex, idt_desc.base));
|
|
KdPrint(PRINT_ALWAYS, ("==============\n"));
|
|
|
|
#ifdef __x86_64__
|
|
idt_start = (IA32e_IDT_GATE_DESCRIPTOR*)idt_desc.base;
|
|
#else
|
|
idt_start = (IA32_IDT_GATE_DESCRIPTOR*)idt_desc.base;
|
|
#endif
|
|
//print_idt(idt_start);
|
|
KdPrint(PRINT_DEBUG, ("==============\n"));
|
|
|
|
core_vidt_state[cpuindex].per_cpu_vidt_start =
|
|
(unsigned long)vidt;
|
|
core_vidt_state[cpuindex].per_cpu_vidt_end =
|
|
(unsigned long)vidt + 0x1000 - 1;
|
|
core_vidt_state[cpuindex].per_cpu_vidt_stub_start =
|
|
(unsigned long)per_cpu_vidt_stub;
|
|
core_vidt_state[cpuindex].per_cpu_vidt_stub_end =
|
|
(unsigned long)per_cpu_vidt_stub + (isr_size * 256) - 1;
|
|
core_vidt_state[cpuindex].per_cpu_test_code_start =
|
|
(unsigned long)per_cpu_test_code;
|
|
core_vidt_state[cpuindex].per_cpu_test_code_end =
|
|
(unsigned long)per_cpu_test_code + ((unsigned long)test_code_end -
|
|
(unsigned long)test_code) - 1;
|
|
|
|
// For test only - after XO permission, enabling this code should cause
|
|
// write protection violation in the hypersim.
|
|
#if 0
|
|
memcpy( (char*)((unsigned long)per_cpu_vidt_stub + EENTER_VECTOR * isr_size + 0xF),
|
|
(char*)(unsigned long)&per_cpu_enter_eresume_code,
|
|
sizeof(unsigned long));
|
|
#endif
|
|
|
|
//////////////////////////////////////////////////////////
|
|
//for UP debug uncomment break
|
|
//break;
|
|
//////////////////////////////////////////////////////////
|
|
}
|
|
put_online_cpus();
|
|
goto end_success;
|
|
|
|
fail_msg:
|
|
put_online_cpus();
|
|
KdPrint(PRINT_ALWAYS, ("some allocation failed\n"));
|
|
SAFE_FREE(per_cpu_vidt_stub);
|
|
SAFE_FREE(per_cpu_test_code);
|
|
SAFE_FREE(per_cpu_exit_code);
|
|
SAFE_FREE(per_cpu_enter_eresume_code);
|
|
SAFE_FREE(per_cpu_r0stack_pages);
|
|
SAFE_FREE(per_cpu_enter_page);
|
|
SAFE_FREE(per_cpu_exit_page);
|
|
SAFE_FREE(vidt);
|
|
SAFE_FREE(secs_ptr);
|
|
SAFE_FREE(redirect_ptr);
|
|
SAFE_FREE(ptr_core_state);
|
|
return SL_EUNKNOWN;
|
|
|
|
end_success:
|
|
return SL_SUCCESS;
|
|
}
|
|
#endif // end of !APP_MODE
|
|
|