From: Bhavana Nagendra <bnagendr@redhat.com> Subject: Re: [RHEL5.1 PATCH : Fix AMD-64 AGP aperture validation Date: Thu, 17 May 2007 10:36:07 -0400 Bugzilla: 236826 Message-Id: <464C6857.9030603@redhat.com> Changelog: [agp] Fix AMD-64 AGP aperture validation >>This fix is needed if RHEL5 defaults to CONFIG_DISCONTIGMEM and a quick >>look at .config looks like it does. Though the default memory mapping in >>RHEL5 is sparse, >>the patch is useful for those who prefer to use discongtiguous memory -- >>checked with Don Z. >> >>Under CONFIG_DISCONTIGMEM, assuming that a !pfn_valid() implies all >>subsequent pfn-s are also invalid is wrong. Thus replace this by >>explicitly checking against the E820 map. >> >>Upstream status: Patch has been accepted. >>Upstream path: http://lkml.org/lkml/2007/3/29/39 >> --- linux-2.6.18.x86_64/drivers/char/agp/amd64-agp.c.agporig 2007-05-17 09:47:53.000000000 -0400 +++ linux-2.6.18.x86_64/drivers/char/agp/amd64-agp.c 2007-05-17 10:14:57.000000000 -0400 @@ -15,6 +15,7 @@ #include <linux/mmzone.h> #include <asm/page.h> /* PAGE_SIZE */ #include <asm/k8.h> +#include <asm/e820.h> #include "agp.h" /* PTE bits. */ @@ -252,7 +253,6 @@ static struct agp_bridge_driver amd_8151 /* Some basic sanity checks for the aperture. */ static int __devinit aperture_valid(u64 aper, u32 size) { - u32 pfn, c; if (aper == 0) { printk(KERN_ERR PFX "No aperture\n"); return 0; @@ -265,14 +265,9 @@ static int __devinit aperture_valid(u64 printk(KERN_ERR PFX "Aperture out of bounds\n"); return 0; } - pfn = aper >> PAGE_SHIFT; - for (c = 0; c < size/PAGE_SIZE; c++) { - if (!pfn_valid(pfn + c)) - break; - if (!PageReserved(pfn_to_page(pfn + c))) { - printk(KERN_ERR PFX "Aperture pointing to RAM\n"); - return 0; - } + if (e820_any_mapped(aper, aper + size, E820_RAM)) { + printk(KERN_ERR PFX "Aperture pointing to RAM\n"); + return 0; } /* Request the Aperture. This catches cases when someone else --- linux-2.6.18.x86_64/arch/x86_64/kernel/e820.c.agporig 2007-05-17 09:54:50.000000000 -0400 +++ linux-2.6.18.x86_64/arch/x86_64/kernel/e820.c 2007-05-16 16:08:35.000000000 -0400 @@ -94,7 +94,7 @@ static inline int bad_addr(unsigned long * This function checks if any part of the range <start,end> is mapped * with type. */ -int __meminit +int e820_any_mapped(unsigned long start, unsigned long end, unsigned type) { int i; @@ -108,6 +108,7 @@ e820_any_mapped(unsigned long start, uns } return 0; } +EXPORT_SYMBOL_GPL(e820_any_mapped); /* * This function checks if the entire range <start,end> is mapped with type. --- linux-2.6.18.x86_64/arch/i386/kernel/setup-xen.c.agporig 2007-05-17 10:09:07.000000000 -0400 +++ linux-2.6.18.x86_64/arch/i386/kernel/setup-xen.c 2007-05-17 10:30:13.000000000 -0400 @@ -395,6 +395,25 @@ EXPORT_SYMBOL(phys_to_machine_mapping); start_info_t *xen_start_info; EXPORT_SYMBOL(xen_start_info); +/* + * This function checks if any part of the range <start,end> is mapped + * with type. + */ +int +e820_any_mapped(u64 start, u64 end, unsigned type) +{ + int i; + for (i = 0; i < e820.nr_map; i++) { + const struct e820entry *ei = &e820.map[i]; + if (type && ei->type != type) + continue; + if (ei->addr >= end || ei->addr + ei->size <= start) + continue; + return 1; + } + return 0; +} + void __init add_memory_region(unsigned long long start, unsigned long long size, int type) { --- linux-2.6.18.x86_64/arch/i386/kernel/setup.c.agporig 2007-05-17 09:54:09.000000000 -0400 +++ linux-2.6.18.x86_64/arch/i386/kernel/setup.c 2007-05-17 09:53:13.000000000 -0400 @@ -409,6 +409,26 @@ static void __init limit_regions(unsigne } } +/* + * This function checks if any part of the range <start,end> is mapped + * with type. + */ +int +e820_any_mapped(u64 start, u64 end, unsigned type) +{ + int i; + for (i = 0; i < e820.nr_map; i++) { + const struct e820entry *ei = &e820.map[i]; + if (type && ei->type != type) + continue; + if (ei->addr >= end || ei->addr + ei->size <= start) + continue; + return 1; + } + return 0; +} +EXPORT_SYMBOL_GPL(e820_any_mapped); + void __init add_memory_region(unsigned long long start, unsigned long long size, int type) { diff -urN ../kernel-2.6.18/linux-2.6.18.i686/include/asm-i386/e820.h linux-2.6.18.i686/include/asm-i386/e820.h --- ../kernel-2.6.18/linux-2.6.18.i686/include/asm-i386/e820.h 2006-09-19 23:42:06.000000000 -0400 +++ linux-2.6.18.i686/include/asm-i386/e820.h 2007-06-22 03:04:38.000000000 -0400 @@ -36,6 +36,7 @@ extern struct e820map e820; +extern int e820_any_mapped(u64 start, u64 end, unsigned type); extern int e820_all_mapped(unsigned long start, unsigned long end, unsigned type);