diff --git a/include/mem.h b/include/mem.h index d7415a325..8d99e2054 100644 --- a/include/mem.h +++ b/include/mem.h @@ -58,6 +58,8 @@ bool MEM_ReAllocatePages(MemHandle & handle,Bitu pages,bo MemHandle MEM_NextHandle(MemHandle handle); MemHandle MEM_NextHandleAt(MemHandle handle,Bitu where); +uint32_t MEM_HardwareAllocate(const char *name,uint32_t sz); + /* The following six functions are used everywhere in the end so these should be changed for Working on big or little endian machines diff --git a/include/voodoo.h b/include/voodoo.h index 02eabf72d..40b67c061 100644 --- a/include/voodoo.h +++ b/include/voodoo.h @@ -22,13 +22,16 @@ #define VOODOO_INITIAL_LFB 0xd0000000 +#define VOODOO_LFB_SIZE 0x01000000 /* VOODOO_PAGES == 4096 (4096 << 12) 16MB size must be a power of 2 */ +#define VOODOO_LFB_ALIGNMASK ( ~(VOODOO_LFB_SIZE - 1u) ) /* 16MB align */ #define VOODOO_REG_PAGES 1024 #define VOODOO_LFB_PAGES 1024 #define VOODOO_TEX_PAGES 2048 -#define VOODOO_PAGES (VOODOO_REG_PAGES+VOODOO_LFB_PAGES+VOODOO_TEX_PAGES) +#define VOODOO_PAGES (VOODOO_REG_PAGES+VOODOO_LFB_PAGES+VOODOO_TEX_PAGES) +static_assert( VOODOO_LFB_ALIGNMASK == 0xFF000000ul, "Voodoo LFB error" ); -#define VOODOO_EMU_TYPE_OFF 0 +#define VOODOO_EMU_TYPE_OFF 0 #define VOODOO_EMU_TYPE_SOFTWARE 1 #define VOODOO_EMU_TYPE_ACCELERATED 2 diff --git a/src/hardware/memory.cpp b/src/hardware/memory.cpp index 8c60b0d54..a9bb101fd 100644 --- a/src/hardware/memory.cpp +++ b/src/hardware/memory.cpp @@ -30,6 +30,7 @@ #include "programs.h" #include "zipfile.h" #include "regs.h" +#include "bitop.h" #ifndef WIN32 # include # include @@ -200,6 +201,7 @@ static struct MemoryBlock { uint32_t mem_alias_pagemask = 0; uint32_t mem_alias_pagemask_active = 0; uint32_t address_bits = 0; + uint32_t hw_next_assign = 0; } memory; uint32_t MEM_get_address_bits() { @@ -1890,6 +1892,27 @@ void MEM_InitCallouts(void) { MEM_callouts[MEM_callouts_index(MEM_TYPE_MB)].resize(64); } +uint32_t MEM_HardwareAllocate(const char *name,uint32_t sz) { + uint32_t assign = 0; + + if (sz != 0ul && bitop::ispowerof2(sz)) { + if (memory.hw_next_assign < 0xFE000000ul) { + memory.hw_next_assign += sz - 1ul; + memory.hw_next_assign &= ~(sz - 1ul); + } + if (memory.hw_next_assign < 0xFE000000ul) { + assign = memory.hw_next_assign; + memory.hw_next_assign += sz; + LOG(LOG_MISC,LOG_DEBUG)("Device '%s' assigned address 0x%lx-0x%lx which it may treat as minimum\n",name,(unsigned long)assign,(unsigned long)assign+(unsigned long)sz-1ul); + } + } + + if (assign == 0) + LOG(LOG_MISC,LOG_DEBUG)("Unable to assign device '%s' a physical address of size 0x%lx\n",name,(unsigned long)sz); + + return assign; +} + void Init_RAM() { Section_prop * section=static_cast(control->GetSection("dosbox")); Bitu i; @@ -1936,6 +1959,15 @@ void Init_RAM() { { Bitu maxsz; + /* Leave 128MB of space at the top for the BIOS, S3 VGA, and Voodoo 3Dfx emulation. + * There was a known bug 2024/12/21 where setting the maximum memory size and installing + * Windows XP caused problems because XP would try to use the Voodoo 3Dfx MMIO as memory + * when enabled at 0xD0000000. + * + * BIOS: Given the 512KB at the top, including for ACPI structures + * PC-98 PEGC framebuffer: 512KB below BIOS + * S3 LFB and MMIO: 32MB at 32MB alignment + * Voodoo 3Dfx: 16MB at 16MB alignment */ if (sizeof(void*) > 4) // 64-bit address space maxsz = (Bitu)(3968ul * 1024ul); // 3.9GB (up to 0xF8000000) else @@ -1949,6 +1981,8 @@ void Init_RAM() { LOG_MSG("Final %lu\n",(unsigned long)memsizekb); } memory.reported_pages = memory.pages = memsizekb/4; + memory.hw_next_assign = memory.pages << 12ul; + LOG(LOG_MISC,LOG_DEBUG)("Hardware assignment will begin at 0x%lx",(unsigned long)memory.hw_next_assign); // FIXME: Hopefully our refactoring will remove the need for this hack /* if the config file asks for less than 1MB of memory diff --git a/src/hardware/pci_bus.cpp b/src/hardware/pci_bus.cpp index e27451281..8265a2fb1 100644 --- a/src/hardware/pci_bus.cpp +++ b/src/hardware/pci_bus.cpp @@ -248,12 +248,12 @@ public: void config_write(uint8_t regnum,Bitu iolen,uint32_t value) override { if (iolen == 1) { - const unsigned char mask = config_writemask[regnum]; - const unsigned char nmask = ~mask; + const unsigned char mask = config_writemask[regnum]; + const unsigned char nmask = ~mask; /* configuration write masks apply here as well */ config[regnum] = - ((unsigned char)value & mask) + + ((unsigned char)value & mask) + (config[regnum] & nmask); switch (regnum) { /* FIXME: I hope I ported this right --J.C. */ diff --git a/src/hardware/vga.cpp b/src/hardware/vga.cpp index 2df906b6a..9d8c809f8 100644 --- a/src/hardware/vga.cpp +++ b/src/hardware/vga.cpp @@ -708,6 +708,8 @@ bool has_pcibus_enable(void); uint32_t MEM_get_address_bits(); uint32_t GetReportedVideoMemorySize(void); +static uint32_t assigned_lfb = 0; + void VGA_Reset(Section*) { // All non-PC98 video-related config settings are now in the [video] section @@ -749,9 +751,9 @@ void VGA_Reset(Section*) { lfb_default = true; } - /* no farther than 32MB below the top */ - if (S3_LFB_BASE > 0xFE000000UL) - S3_LFB_BASE = 0xFE000000UL; + /* no farther than 64MB below the top, do not overlap the BIOS */ + if (S3_LFB_BASE > 0xFC000000UL) + S3_LFB_BASE = 0xFC000000UL; /* if the user WANTS the base address to be PCI misaligned, then turn off PCI VGA emulation */ if (enable_pci_vga && has_pcibus_enable() && (S3_LFB_BASE & 0x1FFFFFFul)) { @@ -768,21 +770,26 @@ void VGA_Reset(Section*) { enable_pci_vga = false; } - /* must not overlap system RAM */ + /* must not overlap system RAM or other devices */ if (S3_LFB_BASE < (MEM_TotalPages()*4096)) S3_LFB_BASE = (MEM_TotalPages()*4096); + if (S3_LFB_BASE < assigned_lfb) + S3_LFB_BASE = assigned_lfb; if (enable_pci_vga && has_pcibus_enable()) { /* must be 32MB aligned (PCI) */ - S3_LFB_BASE += 0x0FFFFFFUL; + S3_LFB_BASE += 0x1FFFFFFUL; S3_LFB_BASE &= ~0x1FFFFFFUL; } else { /* must be 64KB aligned (ISA) */ - S3_LFB_BASE += 0x7FFFUL; + S3_LFB_BASE += 0xFFFFUL; S3_LFB_BASE &= ~0xFFFFUL; } + /* sanity check */ + if (S3_LFB_BASE >= 0xFE000000UL) E_Exit("S3 LFB base 0x%lx would overlap BIOS",(unsigned long)S3_LFB_BASE); + /* if the constraints we imposed make it impossible to maintain the alignment required for PCI, * then just switch off PCI VGA emulation. */ if (IS_VGA_ARCH && enable_pci_vga && has_pcibus_enable()) { @@ -1663,6 +1670,12 @@ void VGA_Init() { LOG(LOG_MISC,LOG_DEBUG)("Initializing VGA"); LOG(LOG_MISC,LOG_DEBUG)("Render scaler maximum resolution is %u x %u",SCALER_MAXWIDTH,SCALER_MAXHEIGHT); + /* the purpose of this is so that, if everything is crammed up at the top to make room for system RAM, the S3 and 3Dfx do not conflict */ + if (IS_VGA_ARCH && svgaCard != SVGA_None) + assigned_lfb = MEM_HardwareAllocate("VGA",32ul << 20ul/*32MB*/); + else + LOG(LOG_MISC,LOG_DEBUG)("Emulation does not require allocating or assigning any LFB"); + VGA_TweakUserVsyncOffset(0.0f); for (i=0;i<256;i++) { diff --git a/src/hardware/voodoo.cpp b/src/hardware/voodoo.cpp index ca0e66db7..89f23f86b 100644 --- a/src/hardware/voodoo.cpp +++ b/src/hardware/voodoo.cpp @@ -37,6 +37,7 @@ class VOODOO; static VOODOO* voodoo_dev; +static uint32_t assigned_lfb = 0; static uint32_t voodoo_current_lfb=(VOODOO_INITIAL_LFB&0xffff0000); static bool voodoo_pci_enabled = false; @@ -127,7 +128,10 @@ public: break; } - if (needs_pci_device) PCI_AddSST_Device((Bitu)card_type); + if (needs_pci_device) { + LOG(LOG_MISC,LOG_DEBUG)("Voodoo 3Dfx LFB at 0x%lx",(unsigned long)voodoo_current_lfb); + PCI_AddSST_Device((Bitu)card_type); + } } ~VOODOO(){ @@ -197,7 +201,7 @@ void VOODOO_PCI_Enable(bool enable) { void VOODOO_PCI_SetLFB(uint32_t lfbaddr) { - lfbaddr &= 0xFFFF0000UL; + lfbaddr &= VOODOO_LFB_ALIGNMASK; if (lfbaddr == voodoo_current_lfb) return; @@ -232,7 +236,18 @@ void VOODOO_Destroy(Section* /*sec*/) { void VOODOO_OnPowerOn(Section* /*sec*/) { if (voodoo_dev == NULL) { voodoo_pci_enabled = true; - voodoo_current_lfb=(VOODOO_INITIAL_LFB&0xffff0000); + + voodoo_current_lfb = VOODOO_INITIAL_LFB & VOODOO_LFB_ALIGNMASK; + + /* must not overlap system RAM */ + if (voodoo_current_lfb < (MEM_TotalPages()*4096)) + voodoo_current_lfb = (MEM_TotalPages()*4096); + if (voodoo_current_lfb < assigned_lfb) + voodoo_current_lfb = assigned_lfb; + + voodoo_current_lfb += ~VOODOO_LFB_ALIGNMASK; /* round up */ + voodoo_current_lfb &= VOODOO_LFB_ALIGNMASK; + voodoo_dev = new VOODOO(control->GetSection("voodoo")); voodoo_lfb_cb_init(); @@ -242,6 +257,9 @@ void VOODOO_OnPowerOn(Section* /*sec*/) { void VOODOO_Init() { LOG(LOG_MISC,LOG_DEBUG)("Initializing Voodoo/3DFX emulation"); + /* the purpose of this is so that, if everything is crammed up at the top to make room for system RAM, the S3 and 3Dfx do not conflict */ + assigned_lfb = MEM_HardwareAllocate("Voodoo 3Dfx",16ul << 20ul/*16MB*/); + AddExitFunction(AddExitFunctionFuncPair(VOODOO_Destroy),true); AddVMEventFunction(VM_EVENT_POWERON,AddVMEventFunctionFuncPair(VOODOO_OnPowerOn)); } diff --git a/src/ints/bios.cpp b/src/ints/bios.cpp index 372f6c390..e888840dd 100644 --- a/src/ints/bios.cpp +++ b/src/ints/bios.cpp @@ -9726,7 +9726,7 @@ private: bios_has_exec_vga_bios = false; LOG(LOG_MISC,LOG_DEBUG)("BIOS: executing POST routine"); - if (ACPI_REGION_SIZE != 0) { + if (ACPI_REGION_SIZE != 0 && !IS_PC98_ARCH) { // place it just below the mirror of the BIOS at FFFF0000 ACPI_BASE = 0xFFFF0000 - ACPI_REGION_SIZE;