void *dos_getmaxlockedmem(int *size) { __dpmi_free_mem_info meminfo; __dpmi_meminfo info; int working_size; void *working_memory; int last_locked; int extra, i, j, allocsize; static char *msg = "Locking data..."; int m, n; byte *x; // first lock all the current executing image so the locked count will // be accurate. It doesn't hurt to lock the memory multiple times last_locked = __djgpp_selector_limit + 1; info.size = last_locked - 4096; info.address = __djgpp_base_address + 4096; if (lockmem) { if(__dpmi_lock_linear_region(&info)) { Sys_Error ("Lock of current memory at 0x%lx for %ldKb failed!\n", info.address, info.size/1024); } } __dpmi_get_free_memory_information(&meminfo); if (!win95) /* Not windows or earlier than Win95 */ { working_size = meminfo.maximum_locked_page_allocation_in_pages * 4096; } else { working_size = meminfo.largest_available_free_block_in_bytes - LEAVE_FOR_CACHE; } working_size &= ~0xffff; /* Round down to 64K */ working_size += 0x10000; do { working_size -= 0x10000; /* Decrease 64K and try again */ working_memory = sbrk(working_size); } while (working_memory == (void *)-1); extra = 0xfffc - ((unsigned)sbrk(0) & 0xffff); if (extra > 0) { sbrk(extra); working_size += extra; } // now grab the memory info.address = last_locked + __djgpp_base_address; if (!win95) { info.size = __djgpp_selector_limit + 1 - last_locked; while (info.size > 0 && __dpmi_lock_linear_region(&info)) { info.size -= 0x1000; working_size -= 0x1000; sbrk(-0x1000); } } else { /* Win95 section */ j = COM_CheckParm("-winmem"); if (standard_quake) minmem = MINIMUM_WIN_MEMORY; else minmem = MINIMUM_WIN_MEMORY_LEVELPAK; if (j) { allocsize = ((int)(Q_atoi(com_argv[j+1]))) * 0x100000 + LOCKED_FOR_MALLOC; if (allocsize < (minmem + LOCKED_FOR_MALLOC)) allocsize = minmem + LOCKED_FOR_MALLOC; } else { allocsize = minmem + LOCKED_FOR_MALLOC; } if (!lockmem) { // we won't lock, just sbrk the memory info.size = allocsize; goto UpdateSbrk; } // lock the memory down write (STDOUT, msg, strlen (msg)); for (j=allocsize ; j>(minmem + LOCKED_FOR_MALLOC) ; j -= 0x100000) { info.size = j; if (!__dpmi_lock_linear_region(&info)) goto Locked; write (STDOUT, ".", 1); } // finally, try with the absolute minimum amount for (i=0 ; i<10 ; i++) { info.size = minmem + LOCKED_FOR_MALLOC; if (!__dpmi_lock_linear_region(&info)) goto Locked; } Sys_Error ("Can't lock memory; %d Mb lockable RAM required. " "Try shrinking smartdrv.", info.size / 0x100000); Locked: UpdateSbrk: info.address += info.size; info.address -= __djgpp_base_address + 4; // ending point, malloc align working_size = info.address - (int)working_memory; sbrk(info.address-(int)sbrk(0)); // negative adjustment } if (lockunlockmem) { __dpmi_unlock_linear_region (&info); printf ("Locked and unlocked %d Mb data\n", working_size / 0x100000); } else if (lockmem) { printf ("Locked %d Mb data\n", working_size / 0x100000); } else { printf ("Allocated %d Mb data\n", working_size / 0x100000); } // touch all the memory to make sure it's there. The 16-page skip is to // keep Win 95 from thinking we're trying to page ourselves in (we are // doing that, of course, but there's no reason we shouldn't) x = (byte *)working_memory; for (n=0 ; n<4 ; n++) { for (m=0 ; m<(working_size - 16 * 0x1000) ; m += 4) { sys_checksum += *(int *)&x[m]; sys_checksum += *(int *)&x[m + 16 * 0x1000]; } } // give some of what we locked back for malloc before returning. Done // by cheating and passing a negative value to sbrk working_size -= LOCKED_FOR_MALLOC; sbrk( -(LOCKED_FOR_MALLOC)); *size = working_size; return working_memory; }
extern uint64_t tuklib_physmem(void) { uint64_t ret = 0; #if defined(_WIN32) || defined(__CYGWIN__) if ((GetVersion() & 0xFF) >= 5) { // Windows 2000 and later have GlobalMemoryStatusEx() which // supports reporting values greater than 4 GiB. To keep the // code working also on older Windows versions, use // GlobalMemoryStatusEx() conditionally. HMODULE kernel32 = GetModuleHandle("kernel32.dll"); if (kernel32 != NULL) { BOOL (WINAPI *gmse)(LPMEMORYSTATUSEX) = GetProcAddress( kernel32, "GlobalMemoryStatusEx"); if (gmse != NULL) { MEMORYSTATUSEX meminfo; meminfo.dwLength = sizeof(meminfo); if (gmse(&meminfo)) ret = meminfo.ullTotalPhys; } } } if (ret == 0) { // GlobalMemoryStatus() is supported by Windows 95 and later, // so it is fine to link against it unconditionally. Note that // GlobalMemoryStatus() has no return value. MEMORYSTATUS meminfo; meminfo.dwLength = sizeof(meminfo); GlobalMemoryStatus(&meminfo); ret = meminfo.dwTotalPhys; } #elif defined(__OS2__) unsigned long mem; if (DosQuerySysInfo(QSV_TOTPHYSMEM, QSV_TOTPHYSMEM, &mem, sizeof(mem)) == 0) ret = mem; #elif defined(__DJGPP__) __dpmi_free_mem_info meminfo; if (__dpmi_get_free_memory_information(&meminfo) == 0 && meminfo.total_number_of_physical_pages != (unsigned long)-1) ret = (uint64_t)meminfo.total_number_of_physical_pages * 4096; #elif defined(__VMS) int vms_mem; int val = SYI$_MEMSIZE; if (LIB$GETSYI(&val, &vms_mem, 0, 0, 0, 0) == SS$_NORMAL) ret = (uint64_t)vms_mem * 8192; #elif defined(AMIGA) || defined(__AROS__) ret = AvailMem(MEMF_TOTAL); #elif defined(TUKLIB_PHYSMEM_AIX) ret = _system_configuration.physmem; #elif defined(TUKLIB_PHYSMEM_SYSCONF) const long pagesize = sysconf(_SC_PAGESIZE); const long pages = sysconf(_SC_PHYS_PAGES); if (pagesize != -1 && pages != -1) // According to docs, pagesize * pages can overflow. // Simple case is 32-bit box with 4 GiB or more RAM, // which may report exactly 4 GiB of RAM, and "long" // being 32-bit will overflow. Casting to uint64_t // hopefully avoids overflows in the near future. ret = (uint64_t)pagesize * (uint64_t)pages; #elif defined(TUKLIB_PHYSMEM_SYSCTL) int name[2] = { CTL_HW, #ifdef HW_PHYSMEM64 HW_PHYSMEM64 #else HW_PHYSMEM #endif }; union { uint32_t u32; uint64_t u64; } mem; size_t mem_ptr_size = sizeof(mem.u64); if (sysctl(name, 2, &mem.u64, &mem_ptr_size, NULL, 0) != -1) { // IIRC, 64-bit "return value" is possible on some 64-bit // BSD systems even with HW_PHYSMEM (instead of HW_PHYSMEM64), // so support both. if (mem_ptr_size == sizeof(mem.u64)) ret = mem.u64; else if (mem_ptr_size == sizeof(mem.u32)) ret = mem.u32; } #elif defined(TUKLIB_PHYSMEM_GETSYSINFO) // Docs are unclear if "start" is needed, but it doesn't hurt // much to have it. int memkb; int start = 0; if (getsysinfo(GSI_PHYSMEM, (caddr_t)&memkb, sizeof(memkb), &start) != -1) ret = (uint64_t)memkb * 1024; #elif defined(TUKLIB_PHYSMEM_PSTAT_GETSTATIC) struct pst_static pst; if (pstat_getstatic(&pst, sizeof(pst), 1, 0) != -1) ret = (uint64_t)pst.physical_memory * (uint64_t)pst.page_size; #elif defined(TUKLIB_PHYSMEM_GETINVENT_R) inv_state_t *st = NULL; if (setinvent_r(&st) != -1) { inventory_t *i; while ((i = getinvent_r(st)) != NULL) { if (i->inv_class == INV_MEMORY && i->inv_type == INV_MAIN_MB) { ret = (uint64_t)i->inv_state << 20; break; } } endinvent_r(st); } #elif defined(TUKLIB_PHYSMEM_SYSINFO) struct sysinfo si; if (sysinfo(&si) == 0) ret = (uint64_t)si.totalram * si.mem_unit; #endif return ret; }