From 93f39ea88a7456358256c4a72ba4ee43ba266155 Mon Sep 17 00:00:00 2001 From: David Malone Date: Sun, 15 Sep 2002 15:07:55 +0000 Subject: [PATCH] Some BIOSs are using MTRR values that are only documented under NDA to control the mapping of things like the ACPI and APM into memory. The problem is that starting X changes these values, so if something was using the bits of BIOS mapped into memory (say ACPI or APM), then next time they access this memory the machine would hang. This patch refuse to change MTRR values it doesn't understand, unless a new "force" option is given. This means X doesn't change them by accident but someone can override that if they really want to. PR: 28418 Tested by: Christopher Masto , David Bushong , Santos MFC after: 1 week --- sys/amd64/amd64/amd64_mem.c | 11 +++++++++++ sys/i386/i386/i686_mem.c | 11 +++++++++++ sys/i386/i386/k6_mem.c | 2 +- sys/sys/memrange.h | 1 + usr.sbin/memcontrol/memcontrol.8 | 3 ++- usr.sbin/memcontrol/memcontrol.c | 1 + 6 files changed, 27 insertions(+), 2 deletions(-) diff --git a/sys/amd64/amd64/amd64_mem.c b/sys/amd64/amd64/amd64_mem.c index 7704f47dca2c..672e63fbe00a 100644 --- a/sys/amd64/amd64/amd64_mem.c +++ b/sys/amd64/amd64/amd64_mem.c @@ -392,6 +392,13 @@ i686_mrsetlow(struct mem_range_softc *sc, struct mem_range_desc *mrd, int *arg) ((last_md = i686_mtrrfixsearch(sc, mrd->mr_base + mrd->mr_len - 1)) == NULL)) return(EINVAL); + /* check we aren't doing something risky */ + if (!(mrd->mr_flags & MDF_FORCE)) + for (curr_md = first_md; curr_md <= last_md; curr_md++) { + if ((curr_md->mr_flags & MDF_ATTRMASK) == MDF_UNKNOWN) + return (EACCES); + } + /* set flags, clear set-by-firmware flag */ for (curr_md = first_md; curr_md <= last_md; curr_md++) { curr_md->mr_flags = mrcopyflags(curr_md->mr_flags & ~MDF_FIRMWARE, mrd->mr_flags); @@ -431,6 +438,10 @@ i686_mrsetvariable(struct mem_range_softc *sc, struct mem_range_desc *mrd, int * /* whoops, owned by someone */ if (curr_md->mr_flags & MDF_BUSY) return(EBUSY); + /* check we aren't doing something risky */ + if (!(mrd->mr_flags & MDF_FORCE) && + ((curr_md->mr_flags & MDF_ATTRMASK) == MDF_UNKNOWN)) + return (EACCES); /* Ok, just hijack this entry */ free_md = curr_md; break; diff --git a/sys/i386/i386/i686_mem.c b/sys/i386/i386/i686_mem.c index 7704f47dca2c..672e63fbe00a 100644 --- a/sys/i386/i386/i686_mem.c +++ b/sys/i386/i386/i686_mem.c @@ -392,6 +392,13 @@ i686_mrsetlow(struct mem_range_softc *sc, struct mem_range_desc *mrd, int *arg) ((last_md = i686_mtrrfixsearch(sc, mrd->mr_base + mrd->mr_len - 1)) == NULL)) return(EINVAL); + /* check we aren't doing something risky */ + if (!(mrd->mr_flags & MDF_FORCE)) + for (curr_md = first_md; curr_md <= last_md; curr_md++) { + if ((curr_md->mr_flags & MDF_ATTRMASK) == MDF_UNKNOWN) + return (EACCES); + } + /* set flags, clear set-by-firmware flag */ for (curr_md = first_md; curr_md <= last_md; curr_md++) { curr_md->mr_flags = mrcopyflags(curr_md->mr_flags & ~MDF_FIRMWARE, mrd->mr_flags); @@ -431,6 +438,10 @@ i686_mrsetvariable(struct mem_range_softc *sc, struct mem_range_desc *mrd, int * /* whoops, owned by someone */ if (curr_md->mr_flags & MDF_BUSY) return(EBUSY); + /* check we aren't doing something risky */ + if (!(mrd->mr_flags & MDF_FORCE) && + ((curr_md->mr_flags & MDF_ATTRMASK) == MDF_UNKNOWN)) + return (EACCES); /* Ok, just hijack this entry */ free_md = curr_md; break; diff --git a/sys/i386/i386/k6_mem.c b/sys/i386/i386/k6_mem.c index 00f9b7ff07ef..7065b98902f4 100644 --- a/sys/i386/i386/k6_mem.c +++ b/sys/i386/i386/k6_mem.c @@ -79,7 +79,7 @@ k6_mrmake(struct mem_range_desc *desc, u_int32_t *mtrr) { return EINVAL; if (desc->mr_len < 131072 || !powerof2(desc->mr_len)) return EINVAL; - if (desc->mr_flags &~ (MDF_WRITECOMBINE|MDF_UNCACHEABLE)) + if (desc->mr_flags &~ (MDF_WRITECOMBINE|MDF_UNCACHEABLE|MDF_FORCE)) return EOPNOTSUPP; for (bit = ffs(desc->mr_len >> 17) - 1; bit < 15; bit++) diff --git a/sys/sys/memrange.h b/sys/sys/memrange.h index bd18f590b467..558ad31377e3 100644 --- a/sys/sys/memrange.h +++ b/sys/sys/memrange.h @@ -20,6 +20,7 @@ #define MDF_BOGUS (1<<28) /* we don't like it */ #define MDF_FIXACTIVE (1<<29) /* can't be turned off */ #define MDF_BUSY (1<<30) /* range is in use */ +#define MDF_FORCE (1<<31) /* force risky changes */ struct mem_range_desc { diff --git a/usr.sbin/memcontrol/memcontrol.8 b/usr.sbin/memcontrol/memcontrol.8 index 989eb16f2cf2..f9d24a83ff69 100644 --- a/usr.sbin/memcontrol/memcontrol.8 +++ b/usr.sbin/memcontrol/memcontrol.8 @@ -83,7 +83,8 @@ Length of memory range in bytes, power of 2 .It Fl o Ar owner Text identifier for this setting (7 char max) .It Ar attribute -Attributes applied to this range; one of +Attributes applied to this range; combinations of +.Ar force , .Ar uncacheable , .Ar write-combine , .Ar write-through , diff --git a/usr.sbin/memcontrol/memcontrol.c b/usr.sbin/memcontrol/memcontrol.c index 2554723733a9..9eb87197eaaa 100644 --- a/usr.sbin/memcontrol/memcontrol.c +++ b/usr.sbin/memcontrol/memcontrol.c @@ -50,6 +50,7 @@ struct {"write-through", MDF_WRITETHROUGH, MDF_SETTABLE}, {"write-back", MDF_WRITEBACK, MDF_SETTABLE}, {"write-protect", MDF_WRITEPROTECT, MDF_SETTABLE}, + {"force", MDF_FORCE, MDF_SETTABLE}, {"unknown", MDF_UNKNOWN, 0}, {"fixed-base", MDF_FIXBASE, 0}, {"fixed-length", MDF_FIXLEN, 0},