xref: /dflybsd-src/contrib/xz/src/common/tuklib_physmem.c (revision 46a2189dd86b644c3a76ac281d84b4182fd66b95)
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