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 40fe50a38eSXin LI #elif defined(__QNX__) 41fe50a38eSXin LI # include <sys/syspage.h> 42fe50a38eSXin LI # include <string.h> 43fe50a38eSXin 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 76*c917796cSXin LI // With GCC >= 8.1 with -Wextra and Clang >= 13 with -Wcast-function-type 77*c917796cSXin LI // will warn about the Windows-specific code. 78*c917796cSXin LI #if defined(__has_warning) 79*c917796cSXin LI # if __has_warning("-Wcast-function-type") 80*c917796cSXin LI # define CAN_DISABLE_WCAST_FUNCTION_TYPE 1 81*c917796cSXin LI # endif 82*c917796cSXin LI #elif TUKLIB_GNUC_REQ(8,1) 83*c917796cSXin LI # define CAN_DISABLE_WCAST_FUNCTION_TYPE 1 84*c917796cSXin LI #endif 85*c917796cSXin LI 86*c917796cSXin LI 8781ad8388SMartin Matuska extern uint64_t 8881ad8388SMartin Matuska tuklib_physmem(void) 8981ad8388SMartin Matuska { 9081ad8388SMartin Matuska uint64_t ret = 0; 9181ad8388SMartin Matuska 9281ad8388SMartin Matuska #if defined(_WIN32) || defined(__CYGWIN__) 9381ad8388SMartin Matuska if ((GetVersion() & 0xFF) >= 5) { 9481ad8388SMartin Matuska // Windows 2000 and later have GlobalMemoryStatusEx() which 9581ad8388SMartin Matuska // supports reporting values greater than 4 GiB. To keep the 9681ad8388SMartin Matuska // code working also on older Windows versions, use 9781ad8388SMartin Matuska // GlobalMemoryStatusEx() conditionally. 989e6bbe47SXin LI HMODULE kernel32 = GetModuleHandle(TEXT("kernel32.dll")); 9981ad8388SMartin Matuska if (kernel32 != NULL) { 1001456f0f9SXin LI typedef BOOL (WINAPI *gmse_type)(LPMEMORYSTATUSEX); 101*c917796cSXin LI #ifdef CAN_DISABLE_WCAST_FUNCTION_TYPE 102*c917796cSXin LI # pragma GCC diagnostic push 103*c917796cSXin LI # pragma GCC diagnostic ignored "-Wcast-function-type" 104*c917796cSXin LI #endif 1051456f0f9SXin LI gmse_type gmse = (gmse_type)GetProcAddress( 10681ad8388SMartin Matuska kernel32, "GlobalMemoryStatusEx"); 107*c917796cSXin LI #ifdef CAN_DISABLE_WCAST_FUNCTION_TYPE 108*c917796cSXin LI # pragma GCC diagnostic pop 109*c917796cSXin LI #endif 11081ad8388SMartin Matuska if (gmse != NULL) { 11181ad8388SMartin Matuska MEMORYSTATUSEX meminfo; 11281ad8388SMartin Matuska meminfo.dwLength = sizeof(meminfo); 11381ad8388SMartin Matuska if (gmse(&meminfo)) 11481ad8388SMartin Matuska ret = meminfo.ullTotalPhys; 11581ad8388SMartin Matuska } 11681ad8388SMartin Matuska } 11781ad8388SMartin Matuska } 11881ad8388SMartin Matuska 11981ad8388SMartin Matuska if (ret == 0) { 12081ad8388SMartin Matuska // GlobalMemoryStatus() is supported by Windows 95 and later, 12181ad8388SMartin Matuska // so it is fine to link against it unconditionally. Note that 12281ad8388SMartin Matuska // GlobalMemoryStatus() has no return value. 12381ad8388SMartin Matuska MEMORYSTATUS meminfo; 12481ad8388SMartin Matuska meminfo.dwLength = sizeof(meminfo); 12581ad8388SMartin Matuska GlobalMemoryStatus(&meminfo); 12681ad8388SMartin Matuska ret = meminfo.dwTotalPhys; 12781ad8388SMartin Matuska } 12881ad8388SMartin Matuska 12981ad8388SMartin Matuska #elif defined(__OS2__) 13081ad8388SMartin Matuska unsigned long mem; 13181ad8388SMartin Matuska if (DosQuerySysInfo(QSV_TOTPHYSMEM, QSV_TOTPHYSMEM, 13281ad8388SMartin Matuska &mem, sizeof(mem)) == 0) 13381ad8388SMartin Matuska ret = mem; 13481ad8388SMartin Matuska 13581ad8388SMartin Matuska #elif defined(__DJGPP__) 13681ad8388SMartin Matuska __dpmi_free_mem_info meminfo; 13781ad8388SMartin Matuska if (__dpmi_get_free_memory_information(&meminfo) == 0 13881ad8388SMartin Matuska && meminfo.total_number_of_physical_pages 13981ad8388SMartin Matuska != (unsigned long)-1) 14081ad8388SMartin Matuska ret = (uint64_t)meminfo.total_number_of_physical_pages * 4096; 14181ad8388SMartin Matuska 14281ad8388SMartin Matuska #elif defined(__VMS) 14381ad8388SMartin Matuska int vms_mem; 14481ad8388SMartin Matuska int val = SYI$_MEMSIZE; 14581ad8388SMartin Matuska if (LIB$GETSYI(&val, &vms_mem, 0, 0, 0, 0) == SS$_NORMAL) 14681ad8388SMartin Matuska ret = (uint64_t)vms_mem * 8192; 14781ad8388SMartin Matuska 14853200025SRui Paulo #elif defined(AMIGA) || defined(__AROS__) 14953200025SRui Paulo ret = AvailMem(MEMF_TOTAL); 15053200025SRui Paulo 151fe50a38eSXin LI #elif defined(__QNX__) 152fe50a38eSXin LI const struct asinfo_entry *entries = SYSPAGE_ENTRY(asinfo); 153fe50a38eSXin LI size_t count = SYSPAGE_ENTRY_SIZE(asinfo) / sizeof(struct asinfo_entry); 154fe50a38eSXin LI const char *strings = SYSPAGE_ENTRY(strings)->data; 155fe50a38eSXin LI 156fe50a38eSXin LI for (size_t i = 0; i < count; ++i) 157fe50a38eSXin LI if (strcmp(strings + entries[i].name, "ram") == 0) 158fe50a38eSXin LI ret += entries[i].end - entries[i].start + 1; 159fe50a38eSXin LI 160e0f0e66dSMartin Matuska #elif defined(TUKLIB_PHYSMEM_AIX) 161e0f0e66dSMartin Matuska ret = _system_configuration.physmem; 162e0f0e66dSMartin Matuska 16381ad8388SMartin Matuska #elif defined(TUKLIB_PHYSMEM_SYSCONF) 16481ad8388SMartin Matuska const long pagesize = sysconf(_SC_PAGESIZE); 16581ad8388SMartin Matuska const long pages = sysconf(_SC_PHYS_PAGES); 166f99e4a2dSXin LI if (pagesize != -1 && pages != -1) 16781ad8388SMartin Matuska // According to docs, pagesize * pages can overflow. 16881ad8388SMartin Matuska // Simple case is 32-bit box with 4 GiB or more RAM, 16981ad8388SMartin Matuska // which may report exactly 4 GiB of RAM, and "long" 17081ad8388SMartin Matuska // being 32-bit will overflow. Casting to uint64_t 17181ad8388SMartin Matuska // hopefully avoids overflows in the near future. 17281ad8388SMartin Matuska ret = (uint64_t)pagesize * (uint64_t)pages; 17381ad8388SMartin Matuska 17481ad8388SMartin Matuska #elif defined(TUKLIB_PHYSMEM_SYSCTL) 17581ad8388SMartin Matuska int name[2] = { 17681ad8388SMartin Matuska CTL_HW, 17781ad8388SMartin Matuska #ifdef HW_PHYSMEM64 17881ad8388SMartin Matuska HW_PHYSMEM64 17981ad8388SMartin Matuska #else 18081ad8388SMartin Matuska HW_PHYSMEM 18181ad8388SMartin Matuska #endif 18281ad8388SMartin Matuska }; 18381ad8388SMartin Matuska union { 18481ad8388SMartin Matuska uint32_t u32; 18581ad8388SMartin Matuska uint64_t u64; 18681ad8388SMartin Matuska } mem; 18781ad8388SMartin Matuska size_t mem_ptr_size = sizeof(mem.u64); 18881ad8388SMartin Matuska if (sysctl(name, 2, &mem.u64, &mem_ptr_size, NULL, 0) != -1) { 18981ad8388SMartin Matuska // IIRC, 64-bit "return value" is possible on some 64-bit 19081ad8388SMartin Matuska // BSD systems even with HW_PHYSMEM (instead of HW_PHYSMEM64), 19181ad8388SMartin Matuska // so support both. 19281ad8388SMartin Matuska if (mem_ptr_size == sizeof(mem.u64)) 19381ad8388SMartin Matuska ret = mem.u64; 19481ad8388SMartin Matuska else if (mem_ptr_size == sizeof(mem.u32)) 19581ad8388SMartin Matuska ret = mem.u32; 19681ad8388SMartin Matuska } 19781ad8388SMartin Matuska 198e0f0e66dSMartin Matuska #elif defined(TUKLIB_PHYSMEM_GETSYSINFO) 199e0f0e66dSMartin Matuska // Docs are unclear if "start" is needed, but it doesn't hurt 200e0f0e66dSMartin Matuska // much to have it. 201e0f0e66dSMartin Matuska int memkb; 202e0f0e66dSMartin Matuska int start = 0; 203e0f0e66dSMartin Matuska if (getsysinfo(GSI_PHYSMEM, (caddr_t)&memkb, sizeof(memkb), &start) 204e0f0e66dSMartin Matuska != -1) 205e0f0e66dSMartin Matuska ret = (uint64_t)memkb * 1024; 206e0f0e66dSMartin Matuska 207e0f0e66dSMartin Matuska #elif defined(TUKLIB_PHYSMEM_PSTAT_GETSTATIC) 208e0f0e66dSMartin Matuska struct pst_static pst; 209e0f0e66dSMartin Matuska if (pstat_getstatic(&pst, sizeof(pst), 1, 0) != -1) 210e0f0e66dSMartin Matuska ret = (uint64_t)pst.physical_memory * (uint64_t)pst.page_size; 211e0f0e66dSMartin Matuska 21281ad8388SMartin Matuska #elif defined(TUKLIB_PHYSMEM_GETINVENT_R) 21381ad8388SMartin Matuska inv_state_t *st = NULL; 21481ad8388SMartin Matuska if (setinvent_r(&st) != -1) { 21581ad8388SMartin Matuska inventory_t *i; 21681ad8388SMartin Matuska while ((i = getinvent_r(st)) != NULL) { 21781ad8388SMartin Matuska if (i->inv_class == INV_MEMORY 21881ad8388SMartin Matuska && i->inv_type == INV_MAIN_MB) { 21981ad8388SMartin Matuska ret = (uint64_t)i->inv_state << 20; 22081ad8388SMartin Matuska break; 22181ad8388SMartin Matuska } 22281ad8388SMartin Matuska } 22381ad8388SMartin Matuska 22481ad8388SMartin Matuska endinvent_r(st); 22581ad8388SMartin Matuska } 22681ad8388SMartin Matuska 22781ad8388SMartin Matuska #elif defined(TUKLIB_PHYSMEM_SYSINFO) 22881ad8388SMartin Matuska struct sysinfo si; 22981ad8388SMartin Matuska if (sysinfo(&si) == 0) 23081ad8388SMartin Matuska ret = (uint64_t)si.totalram * si.mem_unit; 23181ad8388SMartin Matuska #endif 23281ad8388SMartin Matuska 23381ad8388SMartin Matuska return ret; 23481ad8388SMartin Matuska } 235