diff options
Diffstat (limited to 'sys')
-rw-r--r-- | sys/amd64/amd64/machdep.c | 124 | ||||
-rw-r--r-- | sys/i386/i386/machdep.c | 124 |
2 files changed, 156 insertions, 92 deletions
diff --git a/sys/amd64/amd64/machdep.c b/sys/amd64/amd64/machdep.c index 4e09e32..181463e 100644 --- a/sys/amd64/amd64/machdep.c +++ b/sys/amd64/amd64/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; 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; |