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
This commit is contained in:
Mitsuru IWASAKI 2002-11-09 21:17:41 +00:00
parent f41b3be72e
commit 2be7d43928
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=106707
2 changed files with 162 additions and 98 deletions

View File

@ -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,10 +1476,65 @@ 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,59 +1603,35 @@ 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;
}
}
/* Fall back to the old compatibility function for base memory */
if (basemem == 0) {
vm86_intcall(0x12, &vmf);
basemem = vmf.vmf_ax;
for (i = 0; i <= physmap_idx; i += 2) {
if (physmap[i] == 0x00000000) {
basemem = physmap[i + 1] / 1024;
break;
}
}
if (basemem == 0) {
basemem = 640;
}
if (basemem > 640) {
printf("Preposterous BIOS basemem of %uK, truncating to 640K\n",
basemem);
basemem = 640;
}
for (pa = trunc_page(basemem * 1024);
pa < ISA_HOLE_START; pa += PAGE_SIZE)
pmap_kenter(KERNBASE + pa, pa);
pte = (pt_entry_t *)vm86paddr;
for (i = basemem / 4; i < 160; i++)
pte[i] = (i << PAGE_SHIFT) | PG_V | PG_RW | PG_U;
}
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;
if (physmap[1] != 0)
goto physmap_done;

View File

@ -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,10 +1476,65 @@ 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,59 +1603,35 @@ 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;
}
}
/* Fall back to the old compatibility function for base memory */
if (basemem == 0) {
vm86_intcall(0x12, &vmf);
basemem = vmf.vmf_ax;
for (i = 0; i <= physmap_idx; i += 2) {
if (physmap[i] == 0x00000000) {
basemem = physmap[i + 1] / 1024;
break;
}
}
if (basemem == 0) {
basemem = 640;
}
if (basemem > 640) {
printf("Preposterous BIOS basemem of %uK, truncating to 640K\n",
basemem);
basemem = 640;
}
for (pa = trunc_page(basemem * 1024);
pa < ISA_HOLE_START; pa += PAGE_SIZE)
pmap_kenter(KERNBASE + pa, pa);
pte = (pt_entry_t *)vm86paddr;
for (i = basemem / 4; i < 160; i++)
pte[i] = (i << PAGE_SHIFT) | PG_V | PG_RW | PG_U;
}
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;
if (physmap[1] != 0)
goto physmap_done;