mirror of
https://github.com/xen-project/xen.git
synced 2026-10-29 18:50:05 +01:00
bitkeeper revision 1.1159.199.1 (41ab4412dnDymGEqZNhEzt67Yzgmxw)
MTRR support for privileged kernels. Should help our X-server support.
This commit is contained in:
1 parent
b582b9903a
commit
3ef3ee4b43
9 files changed
+282
-2
No files matched your search
@@ -138,6 +138,8 @@
|
||||
40f56238eczveJ86k_4hNxCLRQIF-g linux-2.6.9-xen-sparse/arch/xen/i386/kernel/Makefile
|
||||
40f56238rXVTJQKbBuXXLH52qEArcg linux-2.6.9-xen-sparse/arch/xen/i386/kernel/cpu/Makefile
|
||||
40f562385s4lr6Zg92gExe7UQ4A76Q linux-2.6.9-xen-sparse/arch/xen/i386/kernel/cpu/common.c
|
||||
41ab440bnpxZdWShZrGgM9pPaz5rmA linux-2.6.9-xen-sparse/arch/xen/i386/kernel/cpu/mtrr/Makefile
|
||||
41ab440bBKWz-aEOEojU4PAMXe3Ppg linux-2.6.9-xen-sparse/arch/xen/i386/kernel/cpu/mtrr/main.c
|
||||
40f56238XDtHSijkAFlbv1PT8Bhw_Q linux-2.6.9-xen-sparse/arch/xen/i386/kernel/entry.S
|
||||
40f56238bnvciAuyzAiMkdzGErYt1A linux-2.6.9-xen-sparse/arch/xen/i386/kernel/head.S
|
||||
40f58a0d31M2EkuPbG94ns_nOi0PVA linux-2.6.9-xen-sparse/arch/xen/i386/kernel/i386_ksyms.c
|
||||
|
||||
@@ -110,6 +110,7 @@ CONFIG_X86_CPUID=y
|
||||
# CONFIG_EDD is not set
|
||||
CONFIG_NOHIGHMEM=y
|
||||
# CONFIG_HIGHMEM4G is not set
|
||||
CONFIG_MTRR=y
|
||||
CONFIG_HAVE_DEC_LOCK=y
|
||||
# CONFIG_REGPARM is not set
|
||||
|
||||
|
||||
@@ -564,6 +564,11 @@ config HAVE_ARCH_BOOTMEM_NODE
|
||||
# low memory. Setting this option will put user-space page table
|
||||
# entries in high memory.
|
||||
|
||||
config MTRR
|
||||
bool
|
||||
depends on XEN_PRIVILEGED_GUEST
|
||||
default y
|
||||
|
||||
#config MTRR
|
||||
# bool "MTRR (Memory Type Range Register) support"
|
||||
# ---help---
|
||||
|
||||
@@ -18,7 +18,7 @@ c-obj-y += umc.o
|
||||
|
||||
#obj-$(CONFIG_X86_MCE) += ../../../../i386/kernel/cpu/mcheck/
|
||||
|
||||
#obj-$(CONFIG_MTRR) += ../../../../i386/kernel/cpu/mtrr/
|
||||
obj-$(CONFIG_MTRR) += mtrr/
|
||||
#obj-$(CONFIG_CPU_FREQ) += ../../../../i386/kernel/cpu/cpufreq/
|
||||
|
||||
c-link :=
|
||||
|
||||
@@ -0,0 +1,16 @@
|
||||
obj-y := main.o
|
||||
c-obj-y := if.o
|
||||
|
||||
c-link :=
|
||||
|
||||
$(patsubst %.o,$(obj)/%.c,$(c-obj-y) $(c-link)): $(obj)/mtrr.h
|
||||
@ln -fsn $(srctree)/arch/i386/kernel/cpu/mtrr/$(notdir $@) $@
|
||||
|
||||
$(patsubst %.o,$(obj)/%.c,$(obj-y)): $(obj)/mtrr.h
|
||||
|
||||
$(obj)/mtrr.h:
|
||||
@ln -fsn $(srctree)/arch/i386/kernel/cpu/mtrr/mtrr.h $@
|
||||
|
||||
obj-y += $(c-obj-y)
|
||||
|
||||
clean-files += $(patsubst %.o,%.c,$(c-obj-y) $(c-obj-) $(c-link))
|
||||
@@ -0,0 +1,165 @@
|
||||
#include <linux/init.h>
|
||||
#include <linux/proc_fs.h>
|
||||
#include <linux/ctype.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/seq_file.h>
|
||||
#include <asm/uaccess.h>
|
||||
|
||||
#include <asm/mtrr.h>
|
||||
#include "mtrr.h"
|
||||
|
||||
void generic_get_mtrr(unsigned int reg, unsigned long *base,
|
||||
unsigned int *size, mtrr_type * type)
|
||||
{
|
||||
dom0_op_t op;
|
||||
|
||||
op.cmd = DOM0_READ_MEMTYPE;
|
||||
op.u.read_memtype.reg = reg;
|
||||
(void)HYPERVISOR_dom0_op(&op);
|
||||
|
||||
*size = op.u.read_memtype.nr_pfns;
|
||||
*base = op.u.read_memtype.pfn;
|
||||
*type = op.u.read_memtype.type;
|
||||
}
|
||||
|
||||
struct mtrr_ops generic_mtrr_ops = {
|
||||
.use_intel_if = 1,
|
||||
.get = generic_get_mtrr,
|
||||
};
|
||||
|
||||
struct mtrr_ops *mtrr_if = &generic_mtrr_ops;
|
||||
unsigned int num_var_ranges;
|
||||
unsigned int *usage_table;
|
||||
|
||||
void __init set_num_var_ranges(void)
|
||||
{
|
||||
dom0_op_t op;
|
||||
|
||||
for (num_var_ranges = 0; ; num_var_ranges++) {
|
||||
op.cmd = DOM0_READ_MEMTYPE;
|
||||
op.u.read_memtype.reg = num_var_ranges;
|
||||
if (HYPERVISOR_dom0_op(&op) != 0)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void __init init_table(void)
|
||||
{
|
||||
int i, max;
|
||||
|
||||
max = num_var_ranges;
|
||||
if ((usage_table = kmalloc(max * sizeof *usage_table, GFP_KERNEL))
|
||||
== NULL) {
|
||||
printk(KERN_ERR "mtrr: could not allocate\n");
|
||||
return;
|
||||
}
|
||||
for (i = 0; i < max; i++)
|
||||
usage_table[i] = 0;
|
||||
}
|
||||
|
||||
int mtrr_add_page(unsigned long base, unsigned long size,
|
||||
unsigned int type, char increment)
|
||||
{
|
||||
int error;
|
||||
dom0_op_t op;
|
||||
|
||||
op.cmd = DOM0_ADD_MEMTYPE;
|
||||
op.u.add_memtype.pfn = base;
|
||||
op.u.add_memtype.nr_pfns = size;
|
||||
op.u.add_memtype.type = type;
|
||||
if ((error = HYPERVISOR_dom0_op(&op)))
|
||||
return error;
|
||||
|
||||
if (increment)
|
||||
++usage_table[op.u.add_memtype.reg];
|
||||
|
||||
return op.u.add_memtype.reg;
|
||||
}
|
||||
|
||||
int
|
||||
mtrr_add(unsigned long base, unsigned long size, unsigned int type,
|
||||
char increment)
|
||||
{
|
||||
if ((base & (PAGE_SIZE - 1)) || (size & (PAGE_SIZE - 1))) {
|
||||
printk(KERN_WARNING "mtrr: size and base must be multiples of 4 kiB\n");
|
||||
printk(KERN_DEBUG "mtrr: size: 0x%lx base: 0x%lx\n", size, base);
|
||||
return -EINVAL;
|
||||
}
|
||||
return mtrr_add_page(base >> PAGE_SHIFT, size >> PAGE_SHIFT, type,
|
||||
increment);
|
||||
}
|
||||
|
||||
int mtrr_del_page(int reg, unsigned long base, unsigned long size)
|
||||
{
|
||||
int i, max;
|
||||
mtrr_type ltype;
|
||||
unsigned long lbase;
|
||||
unsigned int lsize;
|
||||
int error = -EINVAL;
|
||||
dom0_op_t op;
|
||||
|
||||
max = num_var_ranges;
|
||||
if (reg < 0) {
|
||||
/* Search for existing MTRR */
|
||||
for (i = 0; i < max; ++i) {
|
||||
mtrr_if->get(i, &lbase, &lsize, <ype);
|
||||
if (lbase == base && lsize == size) {
|
||||
reg = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (reg < 0) {
|
||||
printk(KERN_DEBUG "mtrr: no MTRR for %lx000,%lx000 found\n", base,
|
||||
size);
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
if (usage_table[reg] < 1) {
|
||||
printk(KERN_WARNING "mtrr: reg: %d has count=0\n", reg);
|
||||
goto out;
|
||||
}
|
||||
if (--usage_table[reg] < 1) {
|
||||
op.cmd = DOM0_DEL_MEMTYPE;
|
||||
op.u.del_memtype.handle = 0;
|
||||
op.u.add_memtype.reg = reg;
|
||||
(void)HYPERVISOR_dom0_op(&op);
|
||||
}
|
||||
error = reg;
|
||||
out:
|
||||
return error;
|
||||
}
|
||||
|
||||
int
|
||||
mtrr_del(int reg, unsigned long base, unsigned long size)
|
||||
{
|
||||
if ((base & (PAGE_SIZE - 1)) || (size & (PAGE_SIZE - 1))) {
|
||||
printk(KERN_INFO "mtrr: size and base must be multiples of 4 kiB\n");
|
||||
printk(KERN_DEBUG "mtrr: size: 0x%lx base: 0x%lx\n", size, base);
|
||||
return -EINVAL;
|
||||
}
|
||||
return mtrr_del_page(reg, base >> PAGE_SHIFT, size >> PAGE_SHIFT);
|
||||
}
|
||||
|
||||
EXPORT_SYMBOL(mtrr_add);
|
||||
EXPORT_SYMBOL(mtrr_del);
|
||||
|
||||
static int __init mtrr_init(void)
|
||||
{
|
||||
struct cpuinfo_x86 *c = &boot_cpu_data;
|
||||
|
||||
if (!(xen_start_info.flags & SIF_PRIVILEGED))
|
||||
return -ENODEV;
|
||||
|
||||
if ((!cpu_has(c, X86_FEATURE_MTRR)) &&
|
||||
(!cpu_has(c, X86_FEATURE_K6_MTRR)) &&
|
||||
(!cpu_has(c, X86_FEATURE_CYRIX_ARR)) &&
|
||||
(!cpu_has(c, X86_FEATURE_CENTAUR_MCR)))
|
||||
return -ENODEV;
|
||||
|
||||
set_num_var_ranges();
|
||||
init_table();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
subsys_initcall(mtrr_init);
|
||||
@@ -28,8 +28,9 @@ void __init machine_specific_modify_cpu_capabilities(struct cpuinfo_x86 *c)
|
||||
clear_bit(X86_FEATURE_DE, c->x86_capability);
|
||||
clear_bit(X86_FEATURE_PSE, c->x86_capability);
|
||||
clear_bit(X86_FEATURE_PGE, c->x86_capability);
|
||||
clear_bit(X86_FEATURE_MTRR, c->x86_capability);
|
||||
clear_bit(X86_FEATURE_FXSR, c->x86_capability);
|
||||
if (!(xen_start_info.flags & SIF_PRIVILEGED))
|
||||
clear_bit(X86_FEATURE_MTRR, c->x86_capability);
|
||||
}
|
||||
|
||||
extern void hypervisor_callback(void);
|
||||
|
||||
@@ -21,6 +21,9 @@
|
||||
#include <asm/shadow.h>
|
||||
#include <public/sched_ctl.h>
|
||||
|
||||
#include <asm/mtrr.h>
|
||||
#include "mtrr/mtrr.h"
|
||||
|
||||
#define TRC_DOM0OP_ENTER_BASE 0x00020000
|
||||
#define TRC_DOM0OP_LEAVE_BASE 0x00030000
|
||||
|
||||
@@ -93,6 +96,40 @@ long arch_do_dom0_op(dom0_op_t *op, dom0_op_t *u_dom0_op)
|
||||
}
|
||||
break;
|
||||
|
||||
case DOM0_ADD_MEMTYPE:
|
||||
{
|
||||
ret = mtrr_add_page(
|
||||
op->u.add_memtype.pfn,
|
||||
op->u.add_memtype.nr_pfns,
|
||||
op->u.add_memtype.type,
|
||||
1);
|
||||
}
|
||||
break;
|
||||
|
||||
case DOM0_DEL_MEMTYPE:
|
||||
{
|
||||
ret = mtrr_del_page(op->u.del_memtype.reg, 0, 0);
|
||||
}
|
||||
break;
|
||||
|
||||
case DOM0_READ_MEMTYPE:
|
||||
{
|
||||
unsigned long pfn;
|
||||
unsigned int nr_pfns;
|
||||
mtrr_type type;
|
||||
|
||||
ret = -EINVAL;
|
||||
if ( op->u.read_memtype.reg < num_var_ranges )
|
||||
{
|
||||
mtrr_if->get(op->u.read_memtype.reg, &pfn, &nr_pfns, &type);
|
||||
(void)__put_user(pfn, &u_dom0_op->u.read_memtype.pfn);
|
||||
(void)__put_user(nr_pfns, &u_dom0_op->u.read_memtype.nr_pfns);
|
||||
(void)__put_user(type, &u_dom0_op->u.read_memtype.type);
|
||||
ret = 0;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
ret = -ENOSYS;
|
||||
|
||||
|
||||
@@ -336,6 +336,56 @@ typedef struct {
|
||||
u32 type; /* 8: vm_assist cmd */
|
||||
} PACKED dom0_setdomainvmassist_t; /* 12 bytes */
|
||||
|
||||
/*
|
||||
* Request memory range (@pfn, @pfn+@nr_pfns-1) to have type @type.
|
||||
* On x86, @type is an architecture-defined MTRR memory type.
|
||||
* On success, returns the MTRR that was used (@reg) and a handle that can
|
||||
* be passed to DOM0_DEL_MEMTYPE to accurately tear down the new setting.
|
||||
* (x86-specific).
|
||||
*/
|
||||
#define DOM0_ADD_MEMTYPE 31
|
||||
typedef struct {
|
||||
/* IN variables. */
|
||||
memory_t pfn; /* 0 */
|
||||
MEMORY_PADDING;
|
||||
memory_t nr_pfns; /* 8 */
|
||||
MEMORY_PADDING;
|
||||
u32 type; /* 16 */
|
||||
u32 __pad0;
|
||||
/* OUT variables. */
|
||||
u32 handle; /* 24 */
|
||||
u32 reg; /* 28 */
|
||||
} PACKED dom0_add_memtype_t; /* 32 bytes */
|
||||
|
||||
/*
|
||||
* Tear down an existing memory-range type. If @handle is remembered then it
|
||||
* should be passed in to accurately tear down the correct setting (in case
|
||||
* of overlapping memory regions with differing types). If it is not known
|
||||
* then @handle should be set to zero. In all cases @reg must be set.
|
||||
* (x86-specific).
|
||||
*/
|
||||
#define DOM0_DEL_MEMTYPE 32
|
||||
typedef struct {
|
||||
/* IN variables. */
|
||||
u32 handle; /* 0 */
|
||||
u32 reg; /* 4 */
|
||||
} PACKED dom0_del_memtype_t; /* 8 bytes */
|
||||
|
||||
/* Read current type of an MTRR (x86-specific). */
|
||||
#define DOM0_READ_MEMTYPE 33
|
||||
typedef struct {
|
||||
/* IN variables. */
|
||||
u32 reg; /* 0 */
|
||||
u32 __pad0;
|
||||
/* OUT variables. */
|
||||
memory_t pfn; /* 8 */
|
||||
MEMORY_PADDING;
|
||||
memory_t nr_pfns; /* 16 */
|
||||
MEMORY_PADDING;
|
||||
u32 type; /* 24 */
|
||||
u32 __pad1;
|
||||
} PACKED dom0_read_memtype_t; /* 32 bytes */
|
||||
|
||||
typedef struct {
|
||||
u32 cmd; /* 0 */
|
||||
u32 interface_version; /* 4 */ /* DOM0_INTERFACE_VERSION */
|
||||
@@ -366,6 +416,9 @@ typedef struct {
|
||||
dom0_setdomainmaxmem_t setdomainmaxmem;
|
||||
dom0_getpageframeinfo2_t getpageframeinfo2;
|
||||
dom0_setdomainvmassist_t setdomainvmassist;
|
||||
dom0_add_memtype_t add_memtype;
|
||||
dom0_del_memtype_t del_memtype;
|
||||
dom0_read_memtype_t read_memtype;
|
||||
} PACKED u;
|
||||
} PACKED dom0_op_t; /* 80 bytes */
|
||||
|
||||
|
||||