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