Ejemplo n.º 1
0
void *dos_getmaxlockedmem(int *size)
{
	__dpmi_free_mem_info	meminfo;
	__dpmi_meminfo			info;
	int						working_size;
	void					*working_memory;
	int						last_locked;
	int						extra, 	i, j, allocsize;
	static char				*msg = "Locking data...";
	int						m, n;
	byte					*x;
 
// first lock all the current executing image so the locked count will
// be accurate.  It doesn't hurt to lock the memory multiple times
	last_locked = __djgpp_selector_limit + 1;
	info.size = last_locked - 4096;
	info.address = __djgpp_base_address + 4096;

	if (lockmem)
	{
		if(__dpmi_lock_linear_region(&info))
		{
			Sys_Error ("Lock of current memory at 0x%lx for %ldKb failed!\n",
						info.address, info.size/1024);
		}
	}

	__dpmi_get_free_memory_information(&meminfo);

	if (!win95)		/* Not windows or earlier than Win95 */
	{
		working_size = meminfo.maximum_locked_page_allocation_in_pages * 4096;
	}
	else
	{
		working_size = meminfo.largest_available_free_block_in_bytes -
				LEAVE_FOR_CACHE;
	}

	working_size &= ~0xffff;		/* Round down to 64K */
	working_size += 0x10000;

	do
	{
		working_size -= 0x10000;		/* Decrease 64K and try again */
		working_memory = sbrk(working_size);
	} while (working_memory == (void *)-1);

	extra = 0xfffc - ((unsigned)sbrk(0) & 0xffff);

	if (extra > 0)
	{
		sbrk(extra);
		working_size += extra;
	}

// now grab the memory
	info.address = last_locked + __djgpp_base_address;

	if (!win95)
	{
	    info.size = __djgpp_selector_limit + 1 - last_locked;

		while (info.size > 0 && __dpmi_lock_linear_region(&info))
		{
			info.size -= 0x1000;
			working_size -= 0x1000;
			sbrk(-0x1000);
		}
	}
	else
	{			/* Win95 section */
		j = COM_CheckParm("-winmem");

		if (standard_quake)
			minmem = MINIMUM_WIN_MEMORY;
		else
			minmem = MINIMUM_WIN_MEMORY_LEVELPAK;

		if (j)
		{
			allocsize = ((int)(Q_atoi(com_argv[j+1]))) * 0x100000 +
					LOCKED_FOR_MALLOC;

			if (allocsize < (minmem + LOCKED_FOR_MALLOC))
				allocsize = minmem + LOCKED_FOR_MALLOC;
		}
		else
		{
			allocsize = minmem + LOCKED_FOR_MALLOC;
		}

		if (!lockmem)
		{
		// we won't lock, just sbrk the memory
			info.size = allocsize;
			goto UpdateSbrk;
		}

		// lock the memory down
		write (STDOUT, msg, strlen (msg));

		for (j=allocsize ; j>(minmem + LOCKED_FOR_MALLOC) ;
			 j -= 0x100000)
		{
			info.size = j;
	
			if (!__dpmi_lock_linear_region(&info))
				goto Locked;
	
			write (STDOUT, ".", 1);
		}

	// finally, try with the absolute minimum amount
		for (i=0 ; i<10 ; i++)
		{
			info.size = minmem + LOCKED_FOR_MALLOC;

			if (!__dpmi_lock_linear_region(&info))
				goto Locked;
		}

		Sys_Error ("Can't lock memory; %d Mb lockable RAM required. "
				   "Try shrinking smartdrv.", info.size / 0x100000);

Locked:

UpdateSbrk:

		info.address += info.size;
		info.address -= __djgpp_base_address + 4; // ending point, malloc align
		working_size = info.address - (int)working_memory;
		sbrk(info.address-(int)sbrk(0));		// negative adjustment
	}


	if (lockunlockmem)
	{
		__dpmi_unlock_linear_region (&info);
		printf ("Locked and unlocked %d Mb data\n", working_size / 0x100000);
	}
	else if (lockmem)
	{
		printf ("Locked %d Mb data\n", working_size / 0x100000);
	}
	else
	{
		printf ("Allocated %d Mb data\n", working_size / 0x100000);
	}

// touch all the memory to make sure it's there. The 16-page skip is to
// keep Win 95 from thinking we're trying to page ourselves in (we are
// doing that, of course, but there's no reason we shouldn't)
	x = (byte *)working_memory;

	for (n=0 ; n<4 ; n++)
	{
		for (m=0 ; m<(working_size - 16 * 0x1000) ; m += 4)
		{
			sys_checksum += *(int *)&x[m];
			sys_checksum += *(int *)&x[m + 16 * 0x1000];
		}
	}

// give some of what we locked back for malloc before returning.  Done
// by cheating and passing a negative value to sbrk
	working_size -= LOCKED_FOR_MALLOC;
	sbrk( -(LOCKED_FOR_MALLOC));
	*size = working_size;
	return working_memory;
}
extern uint64_t
tuklib_physmem(void)
{
	uint64_t ret = 0;

#if defined(_WIN32) || defined(__CYGWIN__)
	if ((GetVersion() & 0xFF) >= 5) {
		// Windows 2000 and later have GlobalMemoryStatusEx() which
		// supports reporting values greater than 4 GiB. To keep the
		// code working also on older Windows versions, use
		// GlobalMemoryStatusEx() conditionally.
		HMODULE kernel32 = GetModuleHandle("kernel32.dll");
		if (kernel32 != NULL) {
			BOOL (WINAPI *gmse)(LPMEMORYSTATUSEX) = GetProcAddress(
					kernel32, "GlobalMemoryStatusEx");
			if (gmse != NULL) {
				MEMORYSTATUSEX meminfo;
				meminfo.dwLength = sizeof(meminfo);
				if (gmse(&meminfo))
					ret = meminfo.ullTotalPhys;
			}
		}
	}

	if (ret == 0) {
		// GlobalMemoryStatus() is supported by Windows 95 and later,
		// so it is fine to link against it unconditionally. Note that
		// GlobalMemoryStatus() has no return value.
		MEMORYSTATUS meminfo;
		meminfo.dwLength = sizeof(meminfo);
		GlobalMemoryStatus(&meminfo);
		ret = meminfo.dwTotalPhys;
	}

#elif defined(__OS2__)
	unsigned long mem;
	if (DosQuerySysInfo(QSV_TOTPHYSMEM, QSV_TOTPHYSMEM,
			&mem, sizeof(mem)) == 0)
		ret = mem;

#elif defined(__DJGPP__)
	__dpmi_free_mem_info meminfo;
	if (__dpmi_get_free_memory_information(&meminfo) == 0
			&& meminfo.total_number_of_physical_pages
				!= (unsigned long)-1)
		ret = (uint64_t)meminfo.total_number_of_physical_pages * 4096;

#elif defined(__VMS)
	int vms_mem;
	int val = SYI$_MEMSIZE;
	if (LIB$GETSYI(&val, &vms_mem, 0, 0, 0, 0) == SS$_NORMAL)
		ret = (uint64_t)vms_mem * 8192;

#elif defined(AMIGA) || defined(__AROS__)
	ret = AvailMem(MEMF_TOTAL);

#elif defined(TUKLIB_PHYSMEM_AIX)
	ret = _system_configuration.physmem;

#elif defined(TUKLIB_PHYSMEM_SYSCONF)
	const long pagesize = sysconf(_SC_PAGESIZE);
	const long pages = sysconf(_SC_PHYS_PAGES);
	if (pagesize != -1 && pages != -1)
		// According to docs, pagesize * pages can overflow.
		// Simple case is 32-bit box with 4 GiB or more RAM,
		// which may report exactly 4 GiB of RAM, and "long"
		// being 32-bit will overflow. Casting to uint64_t
		// hopefully avoids overflows in the near future.
		ret = (uint64_t)pagesize * (uint64_t)pages;

#elif defined(TUKLIB_PHYSMEM_SYSCTL)
	int name[2] = {
		CTL_HW,
#ifdef HW_PHYSMEM64
		HW_PHYSMEM64
#else
		HW_PHYSMEM
#endif
	};
	union {
		uint32_t u32;
		uint64_t u64;
	} mem;
	size_t mem_ptr_size = sizeof(mem.u64);
	if (sysctl(name, 2, &mem.u64, &mem_ptr_size, NULL, 0) != -1) {
		// IIRC, 64-bit "return value" is possible on some 64-bit
		// BSD systems even with HW_PHYSMEM (instead of HW_PHYSMEM64),
		// so support both.
		if (mem_ptr_size == sizeof(mem.u64))
			ret = mem.u64;
		else if (mem_ptr_size == sizeof(mem.u32))
			ret = mem.u32;
	}

#elif defined(TUKLIB_PHYSMEM_GETSYSINFO)
	// Docs are unclear if "start" is needed, but it doesn't hurt
	// much to have it.
	int memkb;
	int start = 0;
	if (getsysinfo(GSI_PHYSMEM, (caddr_t)&memkb, sizeof(memkb), &start)
			!= -1)
		ret = (uint64_t)memkb * 1024;

#elif defined(TUKLIB_PHYSMEM_PSTAT_GETSTATIC)
	struct pst_static pst;
	if (pstat_getstatic(&pst, sizeof(pst), 1, 0) != -1)
		ret = (uint64_t)pst.physical_memory * (uint64_t)pst.page_size;

#elif defined(TUKLIB_PHYSMEM_GETINVENT_R)
	inv_state_t *st = NULL;
	if (setinvent_r(&st) != -1) {
		inventory_t *i;
		while ((i = getinvent_r(st)) != NULL) {
			if (i->inv_class == INV_MEMORY
					&& i->inv_type == INV_MAIN_MB) {
				ret = (uint64_t)i->inv_state << 20;
				break;
			}
		}

		endinvent_r(st);
	}

#elif defined(TUKLIB_PHYSMEM_SYSINFO)
	struct sysinfo si;
	if (sysinfo(&si) == 0)
		ret = (uint64_t)si.totalram * si.mem_unit;
#endif

	return ret;
}