--- system/cpuinfo.c +++ system/cpuinfo.c @@ -846,6 +846,12 @@ default: // Unknown processor - make a guess at the family. switch (cpuid_info.version.family) { + case 3: + cpu_model = "386-class CPU (unknown)"; + break; + case 4: + cpu_model = "486-class CPU (unknown)"; + break; case 5: cpu_model = "586-class CPU (unknown)"; break; --- system/cpuid.c +++ system/cpuid.c @@ -8,6 +8,27 @@ #include #include "cpuid.h" +#include "config.h" + +#define AC_BIT (1<<18) +#define CPUID_BIT (1<<21) +static inline int has_cpuid(int bits) +{ + int eax, edx; + __asm__ __volatile__( + "pushfl\n\t" + "popl %0\n\t" + "movl %0,%1\n\t" + "xorl %2,%0\n\t" + "pushl %0\n\t" + "popfl\n\t" + "pushfl\n\t" + "popl %0\n\t" + "pushl %1\n\t" + "popfl\n\t" + "xorl %1,%0":"=a" (eax),"=d" (edx):"c" (bits)); + return eax; +} //------------------------------------------------------------------------------ // Public Variables @@ -24,6 +45,15 @@ uint32_t reg[4]; char *p, *q; + switch (has_cpuid(AC_BIT|CPUID_BIT)) { + case 0: + cpuid_info.version.family = 3; + return; + case AC_BIT: + cpuid_info.version.family = 4; + return; + } + // Get the max standard cpuid & vendor ID. cpuid(0x0, 0, &cpuid_info.max_cpuid, --- boot/setup.S +++ boot/setup.S @@ -100,6 +100,29 @@ .long 0x10 do_setup: + + # Check cpuid support + + pushfl + popw %dx + popw %ax + xorb $0x20, %al # toggle CPUID feature bit (21) + pushw %ax + pushw %dx + popfl + pushfl + popw %dx + popw %ax + xorb %dl, %al + and $0x20, %al + jz 1f + pushw $0x1000 + popw %ds + movb $0xa8, %al # testb $imm %al opcode + movw %ax, patch1 + movw %ax, patch2 +1: + # Reload the segment registers, except for the stack. movw %cs, %ax --- boot/startup32.S +++ boot/startup32.S @@ -105,6 +105,8 @@ # ...and check if the processor supports long mode. +patch1: + jmp 1f movl $0x80000000, %eax # check if function 0x80000001 is available pushl %ebx # ebx is overwritten by cpuid cpuid @@ -198,6 +200,8 @@ # Enable PAE if supported. +patch2: + jmp 1f pushl %ebx # ebx is overwritten by cpuid movl $0x00000001, %eax # test the PAE flag cpuid --- system/cache.h +++ system/cache.h @@ -1,6 +1,7 @@ // SPDX-License-Identifier: GPL-2.0 #ifndef CACHE_H #define CACHE_H +#include "cpuid.h" /** * \file * @@ -26,6 +27,7 @@ : "rax", "memory" ); #else + if (cpuid_info.version.family >= 4) __asm__ __volatile__ ("\t" "movl %%cr0, %%eax \n\t" "orl $0x40000000, %%eax \n\t" /* Set CD */ @@ -53,6 +55,7 @@ : "rax", "memory" ); #else + // if (cpuid_info.version.family >= 4) __asm__ __volatile__ ("\t" "movl %%cr0, %%eax \n\t" "andl $0x9fffffff, %%eax \n\t" /* Clear CD and NW */ @@ -69,6 +72,7 @@ */ static inline void cache_flush(void) { + if (cpuid_info.version.family >= 4) __asm__ __volatile__ ("\t" "wbinvd\n" : /* no outputs */ --- app/main.c +++ app/main.c @@ -75,6 +75,7 @@ static volatile int init_state = 0; +static uintptr_t low_load_limit = LOW_LOAD_LIMIT; static uintptr_t low_load_addr; static uintptr_t high_load_addr; @@ -205,6 +206,9 @@ cpuid_init(); + if (cpuid_info.version.family <= 4) // down to 1MB memory size support + low_load_limit = SIZE_C(256,KB); // must be a multiple of the page size + // Nothing before this should access the boot parameters, in case they are located above 4GB. // This is the first region we map, so it is guaranteed not to fail. boot_params_addr = map_region(boot_params_addr, sizeof(boot_params_t), true); @@ -284,8 +288,8 @@ size_t program_size = (_stacks - _start) + BSP_STACK_SIZE + (num_enabled_cpus - 1) * AP_STACK_SIZE; - bool load_addr_ok = set_load_addr(& low_load_addr, program_size, 0x1000, LOW_LOAD_LIMIT) - && set_load_addr(&high_load_addr, program_size, LOW_LOAD_LIMIT, HIGH_LOAD_LIMIT); + bool load_addr_ok = set_load_addr(& low_load_addr, program_size, 0x1000, low_load_limit) + && set_load_addr(&high_load_addr, program_size, low_load_limit, HIGH_LOAD_LIMIT); trace(0, "program size %ikB", (int)(program_size / 1024)); trace(0, " low_load_addr %0*x", 2*sizeof(uintptr_t), low_load_addr); @@ -422,7 +426,7 @@ // Relocation may disrupt the test. window_num = 1; } - if (window_num == 0 && pm_limit_lower >= LOW_LOAD_LIMIT) { + if (window_num == 0 && pm_limit_lower >= low_load_limit) { // Avoid unnecessary relocation. window_num = 1; } @@ -445,10 +449,10 @@ switch (window_num) { case 0: window_start = 0; - window_end = (LOW_LOAD_LIMIT >> PAGE_SHIFT); + window_end = (low_load_limit >> PAGE_SHIFT); break; case 1: - window_start = (LOW_LOAD_LIMIT >> PAGE_SHIFT); + window_start = (low_load_limit >> PAGE_SHIFT); window_end = VM_WINDOW_SIZE; break; default: --- lib/unistd.c +++ lib/unistd.c @@ -5,10 +5,17 @@ #include "cpuinfo.h" #include "tsc.h" +#include "io.h" #include "unistd.h" //------------------------------------------------------------------------------ +// Constants +//------------------------------------------------------------------------------ + +#define PIT_TICKS_50mS 59659 // PIT clock is 1.193182MHz + +//------------------------------------------------------------------------------ // Public Functions //------------------------------------------------------------------------------ @@ -22,9 +29,14 @@ __builtin_ia32_pause(); } while ((get_tsc() - t0) < cycles); } else { - // This will be highly inaccurate, but should give at least the requested delay. - volatile uint64_t count = (uint64_t)usec * 1000; + volatile uint64_t count = (uint64_t)usec / 50000; while (count > 0) { + // Use PIT Timer + outb((inb(0x61) & ~0x02) | 0x01, 0x61); + outb(0xb0, 0x43); + outb(PIT_TICKS_50mS & 0xff, 0x42); + outb(PIT_TICKS_50mS >> 8, 0x42); + while ((inb(0x61) & 0x20) == 0); count--; } }