181ad8388SMartin Matuska /////////////////////////////////////////////////////////////////////////////// 281ad8388SMartin Matuska // 381ad8388SMartin Matuska /// \file tuklib_physmem.c 481ad8388SMartin Matuska /// \brief Get the amount of physical memory 581ad8388SMartin Matuska // 681ad8388SMartin Matuska // Author: Lasse Collin 781ad8388SMartin Matuska // 881ad8388SMartin Matuska // This file has been put into the public domain. 981ad8388SMartin Matuska // You can do whatever you want with this file. 1081ad8388SMartin Matuska // 1181ad8388SMartin Matuska /////////////////////////////////////////////////////////////////////////////// 1281ad8388SMartin Matuska 1381ad8388SMartin Matuska #include "tuklib_physmem.h" 1481ad8388SMartin Matuska 1581ad8388SMartin Matuska // We want to use Windows-specific code on Cygwin, which also has memory 1681ad8388SMartin Matuska // information available via sysconf(), but on Cygwin 1.5 and older it 1781ad8388SMartin Matuska // gives wrong results (from our point of view). 1881ad8388SMartin Matuska #if defined(_WIN32) || defined(__CYGWIN__) 1981ad8388SMartin Matuska # ifndef _WIN32_WINNT 2081ad8388SMartin Matuska # define _WIN32_WINNT 0x0500 2181ad8388SMartin Matuska # endif 2281ad8388SMartin Matuska # include <windows.h> 2381ad8388SMartin Matuska 2481ad8388SMartin Matuska #elif defined(__OS2__) 2581ad8388SMartin Matuska # define INCL_DOSMISC 2681ad8388SMartin Matuska # include <os2.h> 2781ad8388SMartin Matuska 2881ad8388SMartin Matuska #elif defined(__DJGPP__) 2981ad8388SMartin Matuska # include <dpmi.h> 3081ad8388SMartin Matuska 3181ad8388SMartin Matuska #elif defined(__VMS) 3281ad8388SMartin Matuska # include <lib$routines.h> 3381ad8388SMartin Matuska # include <syidef.h> 3481ad8388SMartin Matuska # include <ssdef.h> 3581ad8388SMartin Matuska 3653200025SRui Paulo #elif defined(AMIGA) || defined(__AROS__) 3753200025SRui Paulo # define __USE_INLINE__ 3853200025SRui Paulo # include <proto/exec.h> 3953200025SRui Paulo 40*fe50a38eSXin LI #elif defined(__QNX__) 41*fe50a38eSXin LI # include <sys/syspage.h> 42*fe50a38eSXin LI # include <string.h> 43*fe50a38eSXin LI 44e0f0e66dSMartin Matuska #elif defined(TUKLIB_PHYSMEM_AIX) 45e0f0e66dSMartin Matuska # include <sys/systemcfg.h> 46e0f0e66dSMartin Matuska 4781ad8388SMartin Matuska #elif defined(TUKLIB_PHYSMEM_SYSCONF) 4881ad8388SMartin Matuska # include <unistd.h> 4981ad8388SMartin Matuska 5081ad8388SMartin Matuska #elif defined(TUKLIB_PHYSMEM_SYSCTL) 5181ad8388SMartin Matuska # ifdef HAVE_SYS_PARAM_H 5281ad8388SMartin Matuska # include <sys/param.h> 5381ad8388SMartin Matuska # endif 5481ad8388SMartin Matuska # include <sys/sysctl.h> 5581ad8388SMartin Matuska 56e0f0e66dSMartin Matuska // Tru64 57e0f0e66dSMartin Matuska #elif defined(TUKLIB_PHYSMEM_GETSYSINFO) 58e0f0e66dSMartin Matuska # include <sys/sysinfo.h> 59e0f0e66dSMartin Matuska # include <machine/hal_sysinfo.h> 60e0f0e66dSMartin Matuska 61e0f0e66dSMartin Matuska // HP-UX 62e0f0e66dSMartin Matuska #elif defined(TUKLIB_PHYSMEM_PSTAT_GETSTATIC) 63e0f0e66dSMartin Matuska # include <sys/param.h> 64e0f0e66dSMartin Matuska # include <sys/pstat.h> 65e0f0e66dSMartin Matuska 6681ad8388SMartin Matuska // IRIX 6781ad8388SMartin Matuska #elif defined(TUKLIB_PHYSMEM_GETINVENT_R) 6881ad8388SMartin Matuska # include <invent.h> 6981ad8388SMartin Matuska 7081ad8388SMartin Matuska // This sysinfo() is Linux-specific. 7181ad8388SMartin Matuska #elif defined(TUKLIB_PHYSMEM_SYSINFO) 7281ad8388SMartin Matuska # include <sys/sysinfo.h> 7381ad8388SMartin Matuska #endif 7481ad8388SMartin Matuska 7581ad8388SMartin Matuska 7681ad8388SMartin Matuska extern uint64_t 7781ad8388SMartin Matuska tuklib_physmem(void) 7881ad8388SMartin Matuska { 7981ad8388SMartin Matuska uint64_t ret = 0; 8081ad8388SMartin Matuska 8181ad8388SMartin Matuska #if defined(_WIN32) || defined(__CYGWIN__) 8281ad8388SMartin Matuska if ((GetVersion() & 0xFF) >= 5) { 8381ad8388SMartin Matuska // Windows 2000 and later have GlobalMemoryStatusEx() which 8481ad8388SMartin Matuska // supports reporting values greater than 4 GiB. To keep the 8581ad8388SMartin Matuska // code working also on older Windows versions, use 8681ad8388SMartin Matuska // GlobalMemoryStatusEx() conditionally. 8781ad8388SMartin Matuska HMODULE kernel32 = GetModuleHandle("kernel32.dll"); 8881ad8388SMartin Matuska if (kernel32 != NULL) { 8981ad8388SMartin Matuska BOOL (WINAPI *gmse)(LPMEMORYSTATUSEX) = GetProcAddress( 9081ad8388SMartin Matuska kernel32, "GlobalMemoryStatusEx"); 9181ad8388SMartin Matuska if (gmse != NULL) { 9281ad8388SMartin Matuska MEMORYSTATUSEX meminfo; 9381ad8388SMartin Matuska meminfo.dwLength = sizeof(meminfo); 9481ad8388SMartin Matuska if (gmse(&meminfo)) 9581ad8388SMartin Matuska ret = meminfo.ullTotalPhys; 9681ad8388SMartin Matuska } 9781ad8388SMartin Matuska } 9881ad8388SMartin Matuska } 9981ad8388SMartin Matuska 10081ad8388SMartin Matuska if (ret == 0) { 10181ad8388SMartin Matuska // GlobalMemoryStatus() is supported by Windows 95 and later, 10281ad8388SMartin Matuska // so it is fine to link against it unconditionally. Note that 10381ad8388SMartin Matuska // GlobalMemoryStatus() has no return value. 10481ad8388SMartin Matuska MEMORYSTATUS meminfo; 10581ad8388SMartin Matuska meminfo.dwLength = sizeof(meminfo); 10681ad8388SMartin Matuska GlobalMemoryStatus(&meminfo); 10781ad8388SMartin Matuska ret = meminfo.dwTotalPhys; 10881ad8388SMartin Matuska } 10981ad8388SMartin Matuska 11081ad8388SMartin Matuska #elif defined(__OS2__) 11181ad8388SMartin Matuska unsigned long mem; 11281ad8388SMartin Matuska if (DosQuerySysInfo(QSV_TOTPHYSMEM, QSV_TOTPHYSMEM, 11381ad8388SMartin Matuska &mem, sizeof(mem)) == 0) 11481ad8388SMartin Matuska ret = mem; 11581ad8388SMartin Matuska 11681ad8388SMartin Matuska #elif defined(__DJGPP__) 11781ad8388SMartin Matuska __dpmi_free_mem_info meminfo; 11881ad8388SMartin Matuska if (__dpmi_get_free_memory_information(&meminfo) == 0 11981ad8388SMartin Matuska && meminfo.total_number_of_physical_pages 12081ad8388SMartin Matuska != (unsigned long)-1) 12181ad8388SMartin Matuska ret = (uint64_t)meminfo.total_number_of_physical_pages * 4096; 12281ad8388SMartin Matuska 12381ad8388SMartin Matuska #elif defined(__VMS) 12481ad8388SMartin Matuska int vms_mem; 12581ad8388SMartin Matuska int val = SYI$_MEMSIZE; 12681ad8388SMartin Matuska if (LIB$GETSYI(&val, &vms_mem, 0, 0, 0, 0) == SS$_NORMAL) 12781ad8388SMartin Matuska ret = (uint64_t)vms_mem * 8192; 12881ad8388SMartin Matuska 12953200025SRui Paulo #elif defined(AMIGA) || defined(__AROS__) 13053200025SRui Paulo ret = AvailMem(MEMF_TOTAL); 13153200025SRui Paulo 132*fe50a38eSXin LI #elif defined(__QNX__) 133*fe50a38eSXin LI const struct asinfo_entry *entries = SYSPAGE_ENTRY(asinfo); 134*fe50a38eSXin LI size_t count = SYSPAGE_ENTRY_SIZE(asinfo) / sizeof(struct asinfo_entry); 135*fe50a38eSXin LI const char *strings = SYSPAGE_ENTRY(strings)->data; 136*fe50a38eSXin LI 137*fe50a38eSXin LI for (size_t i = 0; i < count; ++i) 138*fe50a38eSXin LI if (strcmp(strings + entries[i].name, "ram") == 0) 139*fe50a38eSXin LI ret += entries[i].end - entries[i].start + 1; 140*fe50a38eSXin LI 141e0f0e66dSMartin Matuska #elif defined(TUKLIB_PHYSMEM_AIX) 142e0f0e66dSMartin Matuska ret = _system_configuration.physmem; 143e0f0e66dSMartin Matuska 14481ad8388SMartin Matuska #elif defined(TUKLIB_PHYSMEM_SYSCONF) 14581ad8388SMartin Matuska const long pagesize = sysconf(_SC_PAGESIZE); 14681ad8388SMartin Matuska const long pages = sysconf(_SC_PHYS_PAGES); 147e0f0e66dSMartin Matuska if (pagesize != -1 && pages != -1) 14881ad8388SMartin Matuska // According to docs, pagesize * pages can overflow. 14981ad8388SMartin Matuska // Simple case is 32-bit box with 4 GiB or more RAM, 15081ad8388SMartin Matuska // which may report exactly 4 GiB of RAM, and "long" 15181ad8388SMartin Matuska // being 32-bit will overflow. Casting to uint64_t 15281ad8388SMartin Matuska // hopefully avoids overflows in the near future. 15381ad8388SMartin Matuska ret = (uint64_t)pagesize * (uint64_t)pages; 15481ad8388SMartin Matuska 15581ad8388SMartin Matuska #elif defined(TUKLIB_PHYSMEM_SYSCTL) 15681ad8388SMartin Matuska int name[2] = { 15781ad8388SMartin Matuska CTL_HW, 15881ad8388SMartin Matuska #ifdef HW_PHYSMEM64 15981ad8388SMartin Matuska HW_PHYSMEM64 16081ad8388SMartin Matuska #else 16181ad8388SMartin Matuska HW_PHYSMEM 16281ad8388SMartin Matuska #endif 16381ad8388SMartin Matuska }; 16481ad8388SMartin Matuska union { 16581ad8388SMartin Matuska uint32_t u32; 16681ad8388SMartin Matuska uint64_t u64; 16781ad8388SMartin Matuska } mem; 16881ad8388SMartin Matuska size_t mem_ptr_size = sizeof(mem.u64); 16981ad8388SMartin Matuska if (sysctl(name, 2, &mem.u64, &mem_ptr_size, NULL, 0) != -1) { 17081ad8388SMartin Matuska // IIRC, 64-bit "return value" is possible on some 64-bit 17181ad8388SMartin Matuska // BSD systems even with HW_PHYSMEM (instead of HW_PHYSMEM64), 17281ad8388SMartin Matuska // so support both. 17381ad8388SMartin Matuska if (mem_ptr_size == sizeof(mem.u64)) 17481ad8388SMartin Matuska ret = mem.u64; 17581ad8388SMartin Matuska else if (mem_ptr_size == sizeof(mem.u32)) 17681ad8388SMartin Matuska ret = mem.u32; 17781ad8388SMartin Matuska } 17881ad8388SMartin Matuska 179e0f0e66dSMartin Matuska #elif defined(TUKLIB_PHYSMEM_GETSYSINFO) 180e0f0e66dSMartin Matuska // Docs are unclear if "start" is needed, but it doesn't hurt 181e0f0e66dSMartin Matuska // much to have it. 182e0f0e66dSMartin Matuska int memkb; 183e0f0e66dSMartin Matuska int start = 0; 184e0f0e66dSMartin Matuska if (getsysinfo(GSI_PHYSMEM, (caddr_t)&memkb, sizeof(memkb), &start) 185e0f0e66dSMartin Matuska != -1) 186e0f0e66dSMartin Matuska ret = (uint64_t)memkb * 1024; 187e0f0e66dSMartin Matuska 188e0f0e66dSMartin Matuska #elif defined(TUKLIB_PHYSMEM_PSTAT_GETSTATIC) 189e0f0e66dSMartin Matuska struct pst_static pst; 190e0f0e66dSMartin Matuska if (pstat_getstatic(&pst, sizeof(pst), 1, 0) != -1) 191e0f0e66dSMartin Matuska ret = (uint64_t)pst.physical_memory * (uint64_t)pst.page_size; 192e0f0e66dSMartin Matuska 19381ad8388SMartin Matuska #elif defined(TUKLIB_PHYSMEM_GETINVENT_R) 19481ad8388SMartin Matuska inv_state_t *st = NULL; 19581ad8388SMartin Matuska if (setinvent_r(&st) != -1) { 19681ad8388SMartin Matuska inventory_t *i; 19781ad8388SMartin Matuska while ((i = getinvent_r(st)) != NULL) { 19881ad8388SMartin Matuska if (i->inv_class == INV_MEMORY 19981ad8388SMartin Matuska && i->inv_type == INV_MAIN_MB) { 20081ad8388SMartin Matuska ret = (uint64_t)i->inv_state << 20; 20181ad8388SMartin Matuska break; 20281ad8388SMartin Matuska } 20381ad8388SMartin Matuska } 20481ad8388SMartin Matuska 20581ad8388SMartin Matuska endinvent_r(st); 20681ad8388SMartin Matuska } 20781ad8388SMartin Matuska 20881ad8388SMartin Matuska #elif defined(TUKLIB_PHYSMEM_SYSINFO) 20981ad8388SMartin Matuska struct sysinfo si; 21081ad8388SMartin Matuska if (sysinfo(&si) == 0) 21181ad8388SMartin Matuska ret = (uint64_t)si.totalram * si.mem_unit; 21281ad8388SMartin Matuska #endif 21381ad8388SMartin Matuska 21481ad8388SMartin Matuska return ret; 21581ad8388SMartin Matuska } 216