summaryrefslogtreecommitdiffstats
path: root/sys/i386
diff options
context:
space:
mode:
authoriwasaki <iwasaki@FreeBSD.org>2002-11-09 21:17:41 +0000
committeriwasaki <iwasaki@FreeBSD.org>2002-11-09 21:17:41 +0000
commiteec4b9c40a8bec683ef40f79b724cd2f6f213d1c (patch)
tree79c4e5e3a90b391243f451ae3754087f9c3d1f67 /sys/i386
parent619c6ab9fc1fe3c3b41e1401e11210692b226388 (diff)
downloadFreeBSD-src-eec4b9c40a8bec683ef40f79b724cd2f6f213d1c.zip
FreeBSD-src-eec4b9c40a8bec683ef40f79b724cd2f6f213d1c.tar.gz
Add a new loader tunable, hw.hasbrokenint12, to indicate that BIOS
has broken int 12H. If hw.hasbrokenint12="1" in loader environment, kernel never use BIOS INT 12 call to determine base memory size. Otherwise, kernel use INT 12 in old behaviour. This should fix kernel panic problem caused by 1.544 changes. MFC after: 1 day
Diffstat (limited to 'sys/i386')
-rw-r--r--sys/i386/i386/machdep.c124
1 files changed, 78 insertions, 46 deletions
diff --git a/sys/i386/i386/machdep.c b/sys/i386/i386/machdep.c
index 4e09e32..181463e 100644
--- a/sys/i386/i386/machdep.c
+++ b/sys/i386/i386/machdep.c
@@ -1467,6 +1467,7 @@ static void
getmemsize(int first)
{
int i, physmap_idx, pa_indx;
+ int hasbrokenint12;
u_int basemem, extmem;
struct vm86frame vmf;
struct vm86context vmc;
@@ -1475,11 +1476,66 @@ getmemsize(int first)
char *cp;
struct bios_smap *smap;
+ hasbrokenint12 = 0;
+ TUNABLE_INT_FETCH("hw.hasbrokenint12", &hasbrokenint12);
bzero(&vmf, sizeof(struct vm86frame));
bzero(physmap, sizeof(physmap));
basemem = 0;
/*
+ * Some newer BIOSes has broken INT 12H implementation which cause
+ * kernel panic immediately. In this case, we need to scan SMAP
+ * with INT 15:E820 first, then determine base memory size.
+ */
+ if (hasbrokenint12) {
+ goto int15e820;
+ }
+
+ /*
+ * Perform "base memory" related probes & setup
+ */
+ vm86_intcall(0x12, &vmf);
+ basemem = vmf.vmf_ax;
+ if (basemem > 640) {
+ printf("Preposterous BIOS basemem of %uK, truncating to 640K\n",
+ basemem);
+ basemem = 640;
+ }
+
+ /*
+ * XXX if biosbasemem is now < 640, there is a `hole'
+ * between the end of base memory and the start of
+ * ISA memory. The hole may be empty or it may
+ * contain BIOS code or data. Map it read/write so
+ * that the BIOS can write to it. (Memory from 0 to
+ * the physical end of the kernel is mapped read-only
+ * to begin with and then parts of it are remapped.
+ * The parts that aren't remapped form holes that
+ * remain read-only and are unused by the kernel.
+ * The base memory area is below the physical end of
+ * the kernel and right now forms a read-only hole.
+ * The part of it from PAGE_SIZE to
+ * (trunc_page(biosbasemem * 1024) - 1) will be
+ * remapped and used by the kernel later.)
+ *
+ * This code is similar to the code used in
+ * pmap_mapdev, but since no memory needs to be
+ * allocated we simply change the mapping.
+ */
+ for (pa = trunc_page(basemem * 1024);
+ pa < ISA_HOLE_START; pa += PAGE_SIZE)
+ pmap_kenter(KERNBASE + pa, pa);
+
+ /*
+ * if basemem != 640, map pages r/w into vm86 page table so
+ * that the bios can scribble on it.
+ */
+ pte = (pt_entry_t *)vm86paddr;
+ for (i = basemem / 4; i < 160; i++)
+ pte[i] = (i << PAGE_SHIFT) | PG_V | PG_RW | PG_U;
+
+int15e820:
+ /*
* map page 1 R/W into the kernel page table so we can use it
* as a buffer. The kernel will unmap this page later.
*/
@@ -1547,58 +1603,34 @@ next_run: ;
} while (vmf.vmf_ebx != 0);
/*
- * Perform "base memory" related probes & setup
+ * Perform "base memory" related probes & setup based on SMAP
*/
- for (i = 0; i <= physmap_idx; i += 2) {
- if (physmap[i] == 0x00000000) {
- basemem = physmap[i + 1] / 1024;
- break;
+ if (basemem == 0) {
+ for (i = 0; i <= physmap_idx; i += 2) {
+ if (physmap[i] == 0x00000000) {
+ basemem = physmap[i + 1] / 1024;
+ break;
+ }
}
- }
- /* Fall back to the old compatibility function for base memory */
- if (basemem == 0) {
- vm86_intcall(0x12, &vmf);
- basemem = vmf.vmf_ax;
- }
+ if (basemem == 0) {
+ basemem = 640;
+ }
- if (basemem > 640) {
- printf("Preposterous BIOS basemem of %uK, truncating to 640K\n",
- basemem);
- basemem = 640;
- }
+ if (basemem > 640) {
+ printf("Preposterous BIOS basemem of %uK, truncating to 640K\n",
+ basemem);
+ basemem = 640;
+ }
- /*
- * XXX if biosbasemem is now < 640, there is a `hole'
- * between the end of base memory and the start of
- * ISA memory. The hole may be empty or it may
- * contain BIOS code or data. Map it read/write so
- * that the BIOS can write to it. (Memory from 0 to
- * the physical end of the kernel is mapped read-only
- * to begin with and then parts of it are remapped.
- * The parts that aren't remapped form holes that
- * remain read-only and are unused by the kernel.
- * The base memory area is below the physical end of
- * the kernel and right now forms a read-only hole.
- * The part of it from PAGE_SIZE to
- * (trunc_page(biosbasemem * 1024) - 1) will be
- * remapped and used by the kernel later.)
- *
- * This code is similar to the code used in
- * pmap_mapdev, but since no memory needs to be
- * allocated we simply change the mapping.
- */
- for (pa = trunc_page(basemem * 1024);
- pa < ISA_HOLE_START; pa += PAGE_SIZE)
- pmap_kenter(KERNBASE + pa, pa);
+ for (pa = trunc_page(basemem * 1024);
+ pa < ISA_HOLE_START; pa += PAGE_SIZE)
+ pmap_kenter(KERNBASE + pa, pa);
- /*
- * if basemem != 640, map pages r/w into vm86 page table so
- * that the bios can scribble on it.
- */
- pte = (pt_entry_t *)vm86paddr;
- for (i = basemem / 4; i < 160; i++)
- pte[i] = (i << PAGE_SHIFT) | PG_V | PG_RW | PG_U;
+ pte = (pt_entry_t *)vm86paddr;
+ for (i = basemem / 4; i < 160; i++)
+ pte[i] = (i << PAGE_SHIFT) | PG_V | PG_RW | PG_U;
+ }
if (physmap[1] != 0)
goto physmap_done;
OpenPOWER on IntegriCloud