⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 mtrr.c

📁 Linux内核源代码 为压缩文件 是<<Linux内核>>一书中的源代码
💻 C
📖 第 1 页 / 共 5 页
字号:
    /*  Restore MTRRdefType  */    if ( mtrr_if == MTRR_IF_INTEL ) {	/* Intel (P6) standard MTRRs */	wrmsr (MTRRdefType_MSR, ctxt->deftype_lo, ctxt->deftype_hi);    } else {	/* Cyrix ARRs - everything else was excluded at the top */	setCx86 (CX86_CCR3, ctxt->ccr3);    }    /*  Enable caches  */    asm volatile ("movl  %%cr0, %0\n\t"		  "andl  $0xbfffffff, %0\n\t"		  "movl  %0, %%cr0\n\t"		  : "=r" (tmp) : : "memory");    /*  Restore value of CR4  */    if ( test_bit(X86_FEATURE_PGE, &boot_cpu_data.x86_capability) )	asm volatile ("movl  %0, %%cr4"		      : : "r" (ctxt->cr4val) : "memory");    /*  Re-enable interrupts locally (if enabled previously)  */    __restore_flags (ctxt->flags);}   /*  End Function set_mtrr_done  *//*  This function returns the number of variable MTRRs  */static unsigned int get_num_var_ranges (void){    unsigned long config, dummy;    switch ( mtrr_if )    {    case MTRR_IF_INTEL:	rdmsr (MTRRcap_MSR, config, dummy);	return (config & 0xff);    case MTRR_IF_AMD_K6:	return 2;    case MTRR_IF_CYRIX_ARR:	return 8;    case MTRR_IF_CENTAUR_MCR:	return 8;    default:	return 0;    }}   /*  End Function get_num_var_ranges  *//*  Returns non-zero if we have the write-combining memory type  */static int have_wrcomb (void){    unsigned long config, dummy;    switch ( mtrr_if )    {    case MTRR_IF_INTEL:	rdmsr (MTRRcap_MSR, config, dummy);	return (config & (1<<10));	return 1;    case MTRR_IF_AMD_K6:    case MTRR_IF_CENTAUR_MCR:    case MTRR_IF_CYRIX_ARR:	return 1;    default:	return 0;    }}   /*  End Function have_wrcomb  */static u32 size_or_mask, size_and_mask;static void intel_get_mtrr (unsigned int reg, unsigned long *base,			    unsigned long *size, mtrr_type *type){    unsigned long mask_lo, mask_hi, base_lo, base_hi;    rdmsr (MTRRphysMask_MSR(reg), mask_lo, mask_hi);    if ( (mask_lo & 0x800) == 0 )    {	/*  Invalid (i.e. free) range  */	*base = 0;	*size = 0;	*type = 0;	return;    }    rdmsr(MTRRphysBase_MSR(reg), base_lo, base_hi);    /* Work out the shifted address mask. */    mask_lo = size_or_mask | mask_hi << (32 - PAGE_SHIFT)		| mask_lo >> PAGE_SHIFT;    /* This works correctly if size is a power of two, i.e. a       contiguous range. */     *size = -mask_lo;     *base = base_hi << (32 - PAGE_SHIFT) | base_lo >> PAGE_SHIFT;     *type = base_lo & 0xff;}   /*  End Function intel_get_mtrr  */static void cyrix_get_arr (unsigned int reg, unsigned long *base,			   unsigned long *size, mtrr_type *type){    unsigned long flags;    unsigned char arr, ccr3, rcr, shift;    arr = CX86_ARR_BASE + (reg << 1) + reg; /* avoid multiplication by 3 */    /* Save flags and disable interrupts */    __save_flags (flags); __cli ();    ccr3 = getCx86 (CX86_CCR3);    setCx86 (CX86_CCR3, (ccr3 & 0x0f) | 0x10);		/* enable MAPEN */    ((unsigned char *) base)[3]  = getCx86 (arr);    ((unsigned char *) base)[2]  = getCx86 (arr+1);    ((unsigned char *) base)[1]  = getCx86 (arr+2);    rcr = getCx86(CX86_RCR_BASE + reg);    setCx86 (CX86_CCR3, ccr3);				/* disable MAPEN */    /* Enable interrupts if it was enabled previously */    __restore_flags (flags);    shift = ((unsigned char *) base)[1] & 0x0f;    *base >>= PAGE_SHIFT;    /* Power of two, at least 4K on ARR0-ARR6, 256K on ARR7     * Note: shift==0xf means 4G, this is unsupported.     */    if (shift)      *size = (reg < 7 ? 0x1UL : 0x40UL) << shift;    else      *size = 0;    /* Bit 0 is Cache Enable on ARR7, Cache Disable on ARR0-ARR6 */    if (reg < 7)    {	switch (rcr)	{	  case  1: *type = MTRR_TYPE_UNCACHABLE; break;	  case  8: *type = MTRR_TYPE_WRBACK;     break;	  case  9: *type = MTRR_TYPE_WRCOMB;     break;	  case 24:	  default: *type = MTRR_TYPE_WRTHROUGH;  break;	}    } else    {	switch (rcr)	{	  case  0: *type = MTRR_TYPE_UNCACHABLE; break;	  case  8: *type = MTRR_TYPE_WRCOMB;     break;	  case  9: *type = MTRR_TYPE_WRBACK;     break;	  case 25:	  default: *type = MTRR_TYPE_WRTHROUGH;  break;	}    }}   /*  End Function cyrix_get_arr  */static void amd_get_mtrr (unsigned int reg, unsigned long *base,			  unsigned long *size, mtrr_type *type){    unsigned long low, high;    rdmsr (0xC0000085, low, high);    /*  Upper dword is region 1, lower is region 0  */    if (reg == 1) low = high;    /*  The base masks off on the right alignment  */    *base = (low & 0xFFFE0000) >> PAGE_SHIFT;    *type = 0;    if (low & 1) *type = MTRR_TYPE_UNCACHABLE;    if (low & 2) *type = MTRR_TYPE_WRCOMB;    if ( !(low & 3) )    {	*size = 0;	return;    }    /*     *	This needs a little explaining. The size is stored as an     *	inverted mask of bits of 128K granularity 15 bits long offset     *	2 bits     *     *	So to get a size we do invert the mask and add 1 to the lowest     *	mask bit (4 as its 2 bits in). This gives us a size we then shift     *	to turn into 128K blocks     *     *	eg		111 1111 1111 1100      is 512K     *     *	invert		000 0000 0000 0011     *	+1		000 0000 0000 0100     *	*128K	...     */    low = (~low) & 0x1FFFC;    *size = (low + 4) << (15 - PAGE_SHIFT);    return;}   /*  End Function amd_get_mtrr  */static struct{    unsigned long high;    unsigned long low;} centaur_mcr[8];static void centaur_get_mcr (unsigned int reg, unsigned long *base,			     unsigned long *size, mtrr_type *type){    *base = centaur_mcr[reg].high >> PAGE_SHIFT;    *size = -(centaur_mcr[reg].low & 0xfffff000) >> PAGE_SHIFT;    *type = MTRR_TYPE_WRCOMB;	/*  If it is there, it is write-combining  */}   /*  End Function centaur_get_mcr  */static void (*get_mtrr) (unsigned int reg, unsigned long *base,			 unsigned long *size, mtrr_type *type);static void intel_set_mtrr_up (unsigned int reg, unsigned long base,			       unsigned long size, mtrr_type type, int do_safe)/*  [SUMMARY] Set variable MTRR register on the local CPU.    <reg> The register to set.    <base> The base address of the region.    <size> The size of the region. If this is 0 the region is disabled.    <type> The type of the region.    <do_safe> If TRUE, do the change safely. If FALSE, safety measures should    be done externally.    [RETURNS] Nothing.*/{    struct set_mtrr_context ctxt;    if (do_safe) set_mtrr_prepare (&ctxt);    if (size == 0)    {	/* The invalid bit is kept in the mask, so we simply clear the	   relevant mask register to disable a range. */	wrmsr (MTRRphysMask_MSR (reg), 0, 0);    }    else    {	wrmsr (MTRRphysBase_MSR (reg), base << PAGE_SHIFT | type,		(base & size_and_mask) >> (32 - PAGE_SHIFT));	wrmsr (MTRRphysMask_MSR (reg), -size << PAGE_SHIFT | 0x800,		(-size & size_and_mask) >> (32 - PAGE_SHIFT));    }    if (do_safe) set_mtrr_done (&ctxt);}   /*  End Function intel_set_mtrr_up  */static void cyrix_set_arr_up (unsigned int reg, unsigned long base,			      unsigned long size, mtrr_type type, int do_safe){    struct set_mtrr_context ctxt;    unsigned char arr, arr_type, arr_size;    arr = CX86_ARR_BASE + (reg << 1) + reg; /* avoid multiplication by 3 */    /* count down from 32M (ARR0-ARR6) or from 2G (ARR7) */    if (reg >= 7)	size >>= 6;    size &= 0x7fff; /* make sure arr_size <= 14 */    for(arr_size = 0; size; arr_size++, size >>= 1);    if (reg<7)    {	switch (type) {	  case MTRR_TYPE_UNCACHABLE:	arr_type =  1; break;	  case MTRR_TYPE_WRCOMB:		arr_type =  9; break;	  case MTRR_TYPE_WRTHROUGH:	arr_type = 24; break;	  default:			arr_type =  8; break;	}    }    else    {	switch (type)	{	  case MTRR_TYPE_UNCACHABLE:	arr_type =  0; break;	  case MTRR_TYPE_WRCOMB:		arr_type =  8; break;	  case MTRR_TYPE_WRTHROUGH:	arr_type = 25; break;	  default:			arr_type =  9; break;	}    }    if (do_safe) set_mtrr_prepare (&ctxt);    base <<= PAGE_SHIFT;    setCx86(arr,    ((unsigned char *) &base)[3]);    setCx86(arr+1,  ((unsigned char *) &base)[2]);    setCx86(arr+2, (((unsigned char *) &base)[1]) | arr_size);    setCx86(CX86_RCR_BASE + reg, arr_type);    if (do_safe) set_mtrr_done (&ctxt);}   /*  End Function cyrix_set_arr_up  */static void amd_set_mtrr_up (unsigned int reg, unsigned long base,			     unsigned long size, mtrr_type type, int do_safe)/*  [SUMMARY] Set variable MTRR register on the local CPU.    <reg> The register to set.    <base> The base address of the region.    <size> The size of the region. If this is 0 the region is disabled.    <type> The type of the region.    <do_safe> If TRUE, do the change safely. If FALSE, safety measures should    be done externally.    [RETURNS] Nothing.*/{    u32 regs[2];    struct set_mtrr_context ctxt;    if (do_safe) set_mtrr_prepare (&ctxt);    /*     *	Low is MTRR0 , High MTRR 1     */    rdmsr (0xC0000085, regs[0], regs[1]);    /*     *	Blank to disable     */    if (size == 0)	regs[reg] = 0;    else	/* Set the register to the base, the type (off by one) and an	   inverted bitmask of the size The size is the only odd	   bit. We are fed say 512K We invert this and we get 111 1111	   1111 1011 but if you subtract one and invert you get the   	   desired 111 1111 1111 1100 mask	   But ~(x - 1) == ~x + 1 == -x. Two's complement rocks!  */	regs[reg] = (-size>>(15-PAGE_SHIFT) & 0x0001FFFC)				| (base<<PAGE_SHIFT) | (type+1);    /*     *	The writeback rule is quite specific. See the manual. Its     *	disable local interrupts, write back the cache, set the mtrr     */    __asm__ __volatile__ ("wbinvd" : : : "memory");    wrmsr (0xC0000085, regs[0], regs[1]);    if (do_safe) set_mtrr_done (&ctxt);}   /*  End Function amd_set_mtrr_up  */static void centaur_set_mcr_up (unsigned int reg, unsigned long base,				unsigned long size, mtrr_type type,				int do_safe){    struct set_mtrr_context ctxt;    unsigned long low, high;    if (do_safe) set_mtrr_prepare( &ctxt );    if (size == 0)    {        /*  Disable  */        high = low = 0;    }    else    {	high = base << PAGE_SHIFT;	low = -size << PAGE_SHIFT | 0x1f; /* only support write-combining... */    }    centaur_mcr[reg].high = high;    centaur_mcr[reg].low = low;    wrmsr (0x110 + reg, low, high);    if (do_safe) set_mtrr_done( &ctxt );}   /*  End Function centaur_set_mtrr_up  */static void (*set_mtrr_up) (unsigned int reg, unsigned long base,			    unsigned long size, mtrr_type type,			    int do_safe);#ifdef CONFIG_SMPstruct mtrr_var_range{    unsigned long base_lo;    unsigned long base_hi;    unsigned long mask_lo;    unsigned long mask_hi;};/*  Get the MSR pair relating to a var range  */static void __init get_mtrr_var_range (unsigned int index,					   struct mtrr_var_range *vr){    rdmsr (MTRRphysBase_MSR (index), vr->base_lo, vr->base_hi);    rdmsr (MTRRphysMask_MSR (index), vr->mask_lo, vr->mask_hi);}   /*  End Function get_mtrr_var_range  *//*  Set the MSR pair relating to a var range. Returns TRUE if    changes are made  */static int __init set_mtrr_var_range_testing (unsigned int index,						  struct mtrr_var_range *vr){    unsigned int lo, hi;    int changed = FALSE;    rdmsr(MTRRphysBase_MSR(index), lo, hi);    if ( (vr->base_lo & 0xfffff0ffUL) != (lo & 0xfffff0ffUL)	 || (vr->base_hi & 0xfUL) != (hi & 0xfUL) )    {	wrmsr (MTRRphysBase_MSR(index), vr->base_lo, vr->base_hi);	changed = TRUE;    }    rdmsr (MTRRphysMask_MSR(index), lo, hi);    if ( (vr->mask_lo & 0xfffff800UL) != (lo & 0xfffff800UL)	 || (vr->mask_hi & 0xfUL) != (hi & 0xfUL) )    {	wrmsr(MTRRphysMask_MSR(index), vr->mask_lo, vr->mask_hi);	changed = TRUE;    }    return changed;}   /*  End Function set_mtrr_var_range_testing  */static void __init get_fixed_ranges(mtrr_type *frs){    unsigned long *p = (unsigned long *)frs;    int i;    rdmsr(MTRRfix64K_00000_MSR, p[0], p[1]);    for (i = 0; i < 2; i++)	rdmsr(MTRRfix16K_80000_MSR + i, p[2 + i*2], p[3 + i*2]);    for (i = 0; i < 8; i++)	rdmsr(MTRRfix4K_C0000_MSR + i, p[6 + i*2], p[7 + i*2]);}   /*  End Function get_fixed_ranges  */static int __init set_fixed_ranges_testing(mtrr_type *frs){

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -