12940b44dSPeter Avalos ///////////////////////////////////////////////////////////////////////////////
22940b44dSPeter Avalos //
32940b44dSPeter Avalos /// \file tuklib_physmem.c
42940b44dSPeter Avalos /// \brief Get the amount of physical memory
52940b44dSPeter Avalos //
62940b44dSPeter Avalos // Author: Lasse Collin
72940b44dSPeter Avalos //
82940b44dSPeter Avalos // This file has been put into the public domain.
92940b44dSPeter Avalos // You can do whatever you want with this file.
102940b44dSPeter Avalos //
112940b44dSPeter Avalos ///////////////////////////////////////////////////////////////////////////////
122940b44dSPeter Avalos
132940b44dSPeter Avalos #include "tuklib_physmem.h"
142940b44dSPeter Avalos
152940b44dSPeter Avalos // We want to use Windows-specific code on Cygwin, which also has memory
162940b44dSPeter Avalos // information available via sysconf(), but on Cygwin 1.5 and older it
172940b44dSPeter Avalos // gives wrong results (from our point of view).
182940b44dSPeter Avalos #if defined(_WIN32) || defined(__CYGWIN__)
192940b44dSPeter Avalos # ifndef _WIN32_WINNT
202940b44dSPeter Avalos # define _WIN32_WINNT 0x0500
212940b44dSPeter Avalos # endif
222940b44dSPeter Avalos # include <windows.h>
232940b44dSPeter Avalos
242940b44dSPeter Avalos #elif defined(__OS2__)
252940b44dSPeter Avalos # define INCL_DOSMISC
262940b44dSPeter Avalos # include <os2.h>
272940b44dSPeter Avalos
282940b44dSPeter Avalos #elif defined(__DJGPP__)
292940b44dSPeter Avalos # include <dpmi.h>
302940b44dSPeter Avalos
312940b44dSPeter Avalos #elif defined(__VMS)
322940b44dSPeter Avalos # include <lib$routines.h>
332940b44dSPeter Avalos # include <syidef.h>
342940b44dSPeter Avalos # include <ssdef.h>
352940b44dSPeter Avalos
3615ab8c86SJohn Marino #elif defined(AMIGA) || defined(__AROS__)
3715ab8c86SJohn Marino # define __USE_INLINE__
3815ab8c86SJohn Marino # include <proto/exec.h>
3915ab8c86SJohn Marino
4015ab8c86SJohn Marino #elif defined(__QNX__)
4115ab8c86SJohn Marino # include <sys/syspage.h>
4215ab8c86SJohn Marino # include <string.h>
4315ab8c86SJohn Marino
442940b44dSPeter Avalos #elif defined(TUKLIB_PHYSMEM_AIX)
452940b44dSPeter Avalos # include <sys/systemcfg.h>
462940b44dSPeter Avalos
472940b44dSPeter Avalos #elif defined(TUKLIB_PHYSMEM_SYSCONF)
482940b44dSPeter Avalos # include <unistd.h>
492940b44dSPeter Avalos
502940b44dSPeter Avalos #elif defined(TUKLIB_PHYSMEM_SYSCTL)
512940b44dSPeter Avalos # ifdef HAVE_SYS_PARAM_H
522940b44dSPeter Avalos # include <sys/param.h>
532940b44dSPeter Avalos # endif
542940b44dSPeter Avalos # include <sys/sysctl.h>
552940b44dSPeter Avalos
562940b44dSPeter Avalos // Tru64
572940b44dSPeter Avalos #elif defined(TUKLIB_PHYSMEM_GETSYSINFO)
582940b44dSPeter Avalos # include <sys/sysinfo.h>
592940b44dSPeter Avalos # include <machine/hal_sysinfo.h>
602940b44dSPeter Avalos
612940b44dSPeter Avalos // HP-UX
622940b44dSPeter Avalos #elif defined(TUKLIB_PHYSMEM_PSTAT_GETSTATIC)
632940b44dSPeter Avalos # include <sys/param.h>
642940b44dSPeter Avalos # include <sys/pstat.h>
652940b44dSPeter Avalos
662940b44dSPeter Avalos // IRIX
672940b44dSPeter Avalos #elif defined(TUKLIB_PHYSMEM_GETINVENT_R)
682940b44dSPeter Avalos # include <invent.h>
692940b44dSPeter Avalos
702940b44dSPeter Avalos // This sysinfo() is Linux-specific.
712940b44dSPeter Avalos #elif defined(TUKLIB_PHYSMEM_SYSINFO)
722940b44dSPeter Avalos # include <sys/sysinfo.h>
732940b44dSPeter Avalos #endif
742940b44dSPeter Avalos
752940b44dSPeter Avalos
762940b44dSPeter Avalos extern uint64_t
tuklib_physmem(void)772940b44dSPeter Avalos tuklib_physmem(void)
782940b44dSPeter Avalos {
792940b44dSPeter Avalos uint64_t ret = 0;
802940b44dSPeter Avalos
812940b44dSPeter Avalos #if defined(_WIN32) || defined(__CYGWIN__)
822940b44dSPeter Avalos if ((GetVersion() & 0xFF) >= 5) {
832940b44dSPeter Avalos // Windows 2000 and later have GlobalMemoryStatusEx() which
842940b44dSPeter Avalos // supports reporting values greater than 4 GiB. To keep the
852940b44dSPeter Avalos // code working also on older Windows versions, use
862940b44dSPeter Avalos // GlobalMemoryStatusEx() conditionally.
872940b44dSPeter Avalos HMODULE kernel32 = GetModuleHandle("kernel32.dll");
882940b44dSPeter Avalos if (kernel32 != NULL) {
89*46a2189dSzrj typedef BOOL (WINAPI *gmse_type)(LPMEMORYSTATUSEX);
90*46a2189dSzrj gmse_type gmse = (gmse_type)GetProcAddress(
912940b44dSPeter Avalos kernel32, "GlobalMemoryStatusEx");
922940b44dSPeter Avalos if (gmse != NULL) {
932940b44dSPeter Avalos MEMORYSTATUSEX meminfo;
942940b44dSPeter Avalos meminfo.dwLength = sizeof(meminfo);
952940b44dSPeter Avalos if (gmse(&meminfo))
962940b44dSPeter Avalos ret = meminfo.ullTotalPhys;
972940b44dSPeter Avalos }
982940b44dSPeter Avalos }
992940b44dSPeter Avalos }
1002940b44dSPeter Avalos
1012940b44dSPeter Avalos if (ret == 0) {
1022940b44dSPeter Avalos // GlobalMemoryStatus() is supported by Windows 95 and later,
1032940b44dSPeter Avalos // so it is fine to link against it unconditionally. Note that
1042940b44dSPeter Avalos // GlobalMemoryStatus() has no return value.
1052940b44dSPeter Avalos MEMORYSTATUS meminfo;
1062940b44dSPeter Avalos meminfo.dwLength = sizeof(meminfo);
1072940b44dSPeter Avalos GlobalMemoryStatus(&meminfo);
1082940b44dSPeter Avalos ret = meminfo.dwTotalPhys;
1092940b44dSPeter Avalos }
1102940b44dSPeter Avalos
1112940b44dSPeter Avalos #elif defined(__OS2__)
1122940b44dSPeter Avalos unsigned long mem;
1132940b44dSPeter Avalos if (DosQuerySysInfo(QSV_TOTPHYSMEM, QSV_TOTPHYSMEM,
1142940b44dSPeter Avalos &mem, sizeof(mem)) == 0)
1152940b44dSPeter Avalos ret = mem;
1162940b44dSPeter Avalos
1172940b44dSPeter Avalos #elif defined(__DJGPP__)
1182940b44dSPeter Avalos __dpmi_free_mem_info meminfo;
1192940b44dSPeter Avalos if (__dpmi_get_free_memory_information(&meminfo) == 0
1202940b44dSPeter Avalos && meminfo.total_number_of_physical_pages
1212940b44dSPeter Avalos != (unsigned long)-1)
1222940b44dSPeter Avalos ret = (uint64_t)meminfo.total_number_of_physical_pages * 4096;
1232940b44dSPeter Avalos
1242940b44dSPeter Avalos #elif defined(__VMS)
1252940b44dSPeter Avalos int vms_mem;
1262940b44dSPeter Avalos int val = SYI$_MEMSIZE;
1272940b44dSPeter Avalos if (LIB$GETSYI(&val, &vms_mem, 0, 0, 0, 0) == SS$_NORMAL)
1282940b44dSPeter Avalos ret = (uint64_t)vms_mem * 8192;
1292940b44dSPeter Avalos
13015ab8c86SJohn Marino #elif defined(AMIGA) || defined(__AROS__)
13115ab8c86SJohn Marino ret = AvailMem(MEMF_TOTAL);
13215ab8c86SJohn Marino
13315ab8c86SJohn Marino #elif defined(__QNX__)
13415ab8c86SJohn Marino const struct asinfo_entry *entries = SYSPAGE_ENTRY(asinfo);
13515ab8c86SJohn Marino size_t count = SYSPAGE_ENTRY_SIZE(asinfo) / sizeof(struct asinfo_entry);
13615ab8c86SJohn Marino const char *strings = SYSPAGE_ENTRY(strings)->data;
13715ab8c86SJohn Marino
13815ab8c86SJohn Marino for (size_t i = 0; i < count; ++i)
13915ab8c86SJohn Marino if (strcmp(strings + entries[i].name, "ram") == 0)
14015ab8c86SJohn Marino ret += entries[i].end - entries[i].start + 1;
14115ab8c86SJohn Marino
1422940b44dSPeter Avalos #elif defined(TUKLIB_PHYSMEM_AIX)
1432940b44dSPeter Avalos ret = _system_configuration.physmem;
1442940b44dSPeter Avalos
1452940b44dSPeter Avalos #elif defined(TUKLIB_PHYSMEM_SYSCONF)
1462940b44dSPeter Avalos const long pagesize = sysconf(_SC_PAGESIZE);
1472940b44dSPeter Avalos const long pages = sysconf(_SC_PHYS_PAGES);
1482940b44dSPeter Avalos if (pagesize != -1 && pages != -1)
1492940b44dSPeter Avalos // According to docs, pagesize * pages can overflow.
1502940b44dSPeter Avalos // Simple case is 32-bit box with 4 GiB or more RAM,
1512940b44dSPeter Avalos // which may report exactly 4 GiB of RAM, and "long"
1522940b44dSPeter Avalos // being 32-bit will overflow. Casting to uint64_t
1532940b44dSPeter Avalos // hopefully avoids overflows in the near future.
1542940b44dSPeter Avalos ret = (uint64_t)pagesize * (uint64_t)pages;
1552940b44dSPeter Avalos
1562940b44dSPeter Avalos #elif defined(TUKLIB_PHYSMEM_SYSCTL)
1572940b44dSPeter Avalos int name[2] = {
1582940b44dSPeter Avalos CTL_HW,
1592940b44dSPeter Avalos #ifdef HW_PHYSMEM64
1602940b44dSPeter Avalos HW_PHYSMEM64
1612940b44dSPeter Avalos #else
1622940b44dSPeter Avalos HW_PHYSMEM
1632940b44dSPeter Avalos #endif
1642940b44dSPeter Avalos };
1652940b44dSPeter Avalos union {
1662940b44dSPeter Avalos uint32_t u32;
1672940b44dSPeter Avalos uint64_t u64;
1682940b44dSPeter Avalos } mem;
1692940b44dSPeter Avalos size_t mem_ptr_size = sizeof(mem.u64);
1702940b44dSPeter Avalos if (sysctl(name, 2, &mem.u64, &mem_ptr_size, NULL, 0) != -1) {
1712940b44dSPeter Avalos // IIRC, 64-bit "return value" is possible on some 64-bit
1722940b44dSPeter Avalos // BSD systems even with HW_PHYSMEM (instead of HW_PHYSMEM64),
1732940b44dSPeter Avalos // so support both.
1742940b44dSPeter Avalos if (mem_ptr_size == sizeof(mem.u64))
1752940b44dSPeter Avalos ret = mem.u64;
1762940b44dSPeter Avalos else if (mem_ptr_size == sizeof(mem.u32))
1772940b44dSPeter Avalos ret = mem.u32;
1782940b44dSPeter Avalos }
1792940b44dSPeter Avalos
1802940b44dSPeter Avalos #elif defined(TUKLIB_PHYSMEM_GETSYSINFO)
1812940b44dSPeter Avalos // Docs are unclear if "start" is needed, but it doesn't hurt
1822940b44dSPeter Avalos // much to have it.
1832940b44dSPeter Avalos int memkb;
1842940b44dSPeter Avalos int start = 0;
1852940b44dSPeter Avalos if (getsysinfo(GSI_PHYSMEM, (caddr_t)&memkb, sizeof(memkb), &start)
1862940b44dSPeter Avalos != -1)
1872940b44dSPeter Avalos ret = (uint64_t)memkb * 1024;
1882940b44dSPeter Avalos
1892940b44dSPeter Avalos #elif defined(TUKLIB_PHYSMEM_PSTAT_GETSTATIC)
1902940b44dSPeter Avalos struct pst_static pst;
1912940b44dSPeter Avalos if (pstat_getstatic(&pst, sizeof(pst), 1, 0) != -1)
1922940b44dSPeter Avalos ret = (uint64_t)pst.physical_memory * (uint64_t)pst.page_size;
1932940b44dSPeter Avalos
1942940b44dSPeter Avalos #elif defined(TUKLIB_PHYSMEM_GETINVENT_R)
1952940b44dSPeter Avalos inv_state_t *st = NULL;
1962940b44dSPeter Avalos if (setinvent_r(&st) != -1) {
1972940b44dSPeter Avalos inventory_t *i;
1982940b44dSPeter Avalos while ((i = getinvent_r(st)) != NULL) {
1992940b44dSPeter Avalos if (i->inv_class == INV_MEMORY
2002940b44dSPeter Avalos && i->inv_type == INV_MAIN_MB) {
2012940b44dSPeter Avalos ret = (uint64_t)i->inv_state << 20;
2022940b44dSPeter Avalos break;
2032940b44dSPeter Avalos }
2042940b44dSPeter Avalos }
2052940b44dSPeter Avalos
2062940b44dSPeter Avalos endinvent_r(st);
2072940b44dSPeter Avalos }
2082940b44dSPeter Avalos
2092940b44dSPeter Avalos #elif defined(TUKLIB_PHYSMEM_SYSINFO)
2102940b44dSPeter Avalos struct sysinfo si;
2112940b44dSPeter Avalos if (sysinfo(&si) == 0)
2122940b44dSPeter Avalos ret = (uint64_t)si.totalram * si.mem_unit;
2132940b44dSPeter Avalos #endif
2142940b44dSPeter Avalos
2152940b44dSPeter Avalos return ret;
2162940b44dSPeter Avalos }
217