added ability to select memory block size configurable (#25)

very large memory configurations require large memory block (or very large amount of blocks)
This commit is contained in:
Stanislav Shwartsman 2022-07-30 13:56:09 +03:00 committed by GitHub
parent 8afd14972e
commit e32d536abe
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 74 additions and 46 deletions

View File

@ -358,8 +358,14 @@ cpu: cpuid_limit_winnt=0
# memory pool. You will be warned (by FATAL PANIC) in case guest already
# used all allocated host memory and wants more.
#
# BLOCK_SIZE:
# Memory block size select granularity of host memory allocation. Very
# large memory configurations might requre larger memory blocks which
# configurations with small memory might want memory block smaller.
# Default memory block size is 128K.
#
#=======================================================================
memory: guest=512, host=256
memory: guest=512, host=256, block_size=512
#=======================================================================
# ROMIMAGE:

View File

@ -816,6 +816,15 @@ void bx_init_options()
host_ramsize->set_ask_format("Enter host memory size (MB): [%d] ");
ram->set_options(ram->SERIES_ASK);
bx_param_num_c *mem_block_size = new bx_param_num_c(ram,
"block_size",
"Memory block granularity (kilobytes)",
"Granularity of host memory allocation",
4, 8192,
128);
mem_block_size->set_ask_format("Enter memory block size (KB): [%d] ");
ram->set_options(ram->SERIES_ASK);
path = new bx_param_filename_c(rom,
"file",
"ROM BIOS image",
@ -2793,6 +2802,8 @@ static int parse_line_formatted(const char *context, int num_params, char *param
SIM->get_param_num(BXPN_HOST_MEM_SIZE)->set(atol(&params[i][5]));
} else if (!strncmp(params[i], "guest=", 6)) {
SIM->get_param_num(BXPN_MEM_SIZE)->set(atol(&params[i][6]));
} else if (!strncmp(params[i], "block_size=", 11)) {
SIM->get_param_num(BXPN_MEM_BLOCK_SIZE)->set(atol(&params[i][11]));
} else {
PARSE_ERR(("%s: memory directive malformed.", context));
}

View File

@ -1330,7 +1330,10 @@ void bx_init_hardware()
// do not allocate more host memory than needed for emulation of guest RAM
if (memSize < hostMemSize) hostMemSize = memSize;
BX_MEM(0)->init_memory(memSize, hostMemSize);
bx_param_num_c *bxp_memblock_size = SIM->get_param_num(BXPN_MEM_BLOCK_SIZE);
Bit32u memBlockSize = bxp_memblock_size->get64() * 1024;
BX_MEM(0)->init_memory(memSize, hostMemSize, memBlockSize);
// First load the system BIOS (VGABIOS loading moved to the vga code)
BX_MEM(0)->load_ROM(SIM->get_param_string(BXPN_ROM_PATH)->getptr(),

View File

@ -93,6 +93,7 @@ private:
bool smram_restricted;
Bit64u len, allocated; // could be > 4G
Bit32u block_size; // individual block size, must be power of 2
Bit8u *actual_vector;
Bit8u *vector; // aligned correctly
Bit8u **blocks;
@ -121,9 +122,9 @@ public:
BX_MEM_C();
~BX_MEM_C();
BX_MEM_SMF Bit8u* get_vector(bx_phy_address addr);
BX_MEM_SMF void init_memory(Bit64u guest, Bit64u host);
BX_MEM_SMF void init_memory(Bit64u guest, Bit64u host, Bit32u block_size);
BX_MEM_SMF void cleanup_memory(void);
BX_MEM_SMF Bit8u* get_vector(bx_phy_address addr);
BX_MEM_SMF void enable_smram(bool enable, bool restricted);
BX_MEM_SMF void disable_smram(void);
@ -182,9 +183,6 @@ public:
BOCHSAPI extern BX_MEM_C bx_mem;
// must be power of two
#define BX_MEM_BLOCK_LEN (128*1024) /* 128K blocks */
/*
BX_CPP_INLINE Bit8u* BX_MEM_C::get_vector(bx_phy_address addr)
{
@ -192,19 +190,6 @@ BX_CPP_INLINE Bit8u* BX_MEM_C::get_vector(bx_phy_address addr)
}
*/
BX_CPP_INLINE Bit8u* BX_MEM_C::get_vector(bx_phy_address addr)
{
Bit32u block = (Bit32u)(addr / BX_MEM_BLOCK_LEN);
#if (BX_LARGE_RAMFILE)
if (!BX_MEM_THIS blocks[block] || (BX_MEM_THIS blocks[block] == BX_MEM_THIS swapped_out))
#else
if (!BX_MEM_THIS blocks[block])
#endif
allocate_block(block);
return BX_MEM_THIS blocks[block] + (Bit32u)(addr & (BX_MEM_BLOCK_LEN-1));
}
BX_CPP_INLINE Bit64u BX_MEM_C::get_memory_len(void)
{
return (BX_MEM_THIS len);

View File

@ -2,7 +2,7 @@
// $Id$
/////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2001-2020 The Bochs Project
// Copyright (C) 2001-2022 The Bochs Project
//
// I/O memory handlers API Copyright (C) 2003 by Frank Cornelis
//
@ -28,6 +28,12 @@
#include "iodev/iodev.h"
#define LOG_THIS BX_MEM(0)->
// block size must be power of two
BX_CPP_INLINE bool is_power_of_2(Bit64u x)
{
return (x & (x - 1)) == 0;
}
// alignment of memory vector, must be a power of 2
#define BX_MEM_VECTOR_ALIGN 4096
#define BX_MEM_HANDLERS ((BX_CONST64(1) << BX_PHY_ADDRESS_WIDTH) >> 20) /* one per megabyte */
@ -92,16 +98,18 @@ BX_MEM_C::~BX_MEM_C()
cleanup_memory();
}
void BX_MEM_C::init_memory(Bit64u guest, Bit64u host)
void BX_MEM_C::init_memory(Bit64u guest, Bit64u host, Bit32u block_size)
{
unsigned i, idx;
BX_DEBUG(("Init $Id$"));
// accept only memory size which is multiply of 1M
BX_ASSERT((host & 0xfffff) == 0);
BX_ASSERT((guest & 0xfffff) == 0);
if (! is_power_of_2(block_size)) {
BX_PANIC(("Block size %d is not power of two !", block_size));
}
if (BX_MEM_THIS actual_vector != NULL) {
BX_INFO(("freeing existing memory vector"));
delete [] BX_MEM_THIS actual_vector;
@ -110,8 +118,8 @@ void BX_MEM_C::init_memory(Bit64u guest, Bit64u host)
BX_MEM_THIS blocks = NULL;
}
BX_MEM_THIS vector = alloc_vector_aligned(host + BIOSROMSZ + EXROMSIZE + 4096, BX_MEM_VECTOR_ALIGN);
BX_INFO(("allocated memory at %p. after alignment, vector=%p",
BX_MEM_THIS actual_vector, BX_MEM_THIS vector));
BX_INFO(("allocated memory at %p. after alignment, vector=%p, block_size = %dK",
BX_MEM_THIS actual_vector, BX_MEM_THIS vector, block_size/1024));
BX_MEM_THIS len = guest;
BX_MEM_THIS allocated = host;
@ -119,17 +127,18 @@ void BX_MEM_C::init_memory(Bit64u guest, Bit64u host)
BX_MEM_THIS bogus = &BX_MEM_THIS vector[host + BIOSROMSZ + EXROMSIZE];
memset(BX_MEM_THIS rom, 0xff, BIOSROMSZ + EXROMSIZE + 4096);
BX_MEM_THIS block_size = block_size;
// block must be large enough to fit num_blocks in 32-bit
BX_ASSERT((BX_MEM_THIS len / BX_MEM_BLOCK_LEN) <= 0xffffffff);
BX_ASSERT((BX_MEM_THIS len / BX_MEM_THIS block_size) <= 0xffffffff);
Bit32u num_blocks = (Bit32u)(BX_MEM_THIS len / BX_MEM_BLOCK_LEN);
Bit32u num_blocks = (Bit32u)(BX_MEM_THIS len / BX_MEM_THIS block_size);
BX_INFO(("%.2fMB", (float)(BX_MEM_THIS len / (1024.0*1024.0))));
BX_INFO(("mem block size = 0x%08x, blocks=%u", BX_MEM_BLOCK_LEN, num_blocks));
BX_INFO(("mem block size = 0x%08x, blocks=%u", BX_MEM_THIS block_size, num_blocks));
BX_MEM_THIS blocks = new Bit8u* [num_blocks];
if (0) {
// all guest memory is allocated, just map it
for (idx = 0; idx < num_blocks; idx++) {
BX_MEM_THIS blocks[idx] = BX_MEM_THIS vector + (idx * BX_MEM_BLOCK_LEN);
BX_MEM_THIS blocks[idx] = BX_MEM_THIS vector + (idx * BX_MEM_THIS block_size);
}
BX_MEM_THIS used_blocks = num_blocks;
}
@ -166,16 +175,29 @@ void BX_MEM_C::init_memory(Bit64u guest, Bit64u host)
BX_MEM_THIS register_state();
}
Bit8u* BX_MEM_C::get_vector(bx_phy_address addr)
{
Bit32u block = (Bit32u)(addr / BX_MEM_THIS block_size);
#if (BX_LARGE_RAMFILE)
if (!BX_MEM_THIS blocks[block] || (BX_MEM_THIS blocks[block] == BX_MEM_THIS swapped_out))
#else
if (!BX_MEM_THIS blocks[block])
#endif
allocate_block(block);
return BX_MEM_THIS blocks[block] + (Bit32u)(addr & (BX_MEM_THIS block_size-1));
}
#if BX_LARGE_RAMFILE
void BX_MEM_C::read_block(Bit32u block)
{
const Bit64u block_address = ((Bit64u)block)*BX_MEM_BLOCK_LEN;
const Bit64u block_address = Bit64u(block) * BX_MEM_THIS block_size;
if (fseeko64(BX_MEM_THIS overflow_file, block_address, SEEK_SET))
BX_PANIC(("FATAL ERROR: Could not seek to 0x" FMT_LL "x in memory overflow file!", block_address));
// We could legitimately get an EOF condition if we are reading the last bit of memory.ram
if ((fread(BX_MEM_THIS blocks[block], BX_MEM_BLOCK_LEN, 1, BX_MEM_THIS overflow_file) != 1) &&
if ((fread(BX_MEM_THIS blocks[block], BX_MEM_THIS block_size, 1, BX_MEM_THIS overflow_file) != 1) &&
(!feof(BX_MEM_THIS overflow_file)))
BX_PANIC(("FATAL ERROR: Could not read from 0x" FMT_LL "x in memory overflow file!", block_address));
}
@ -183,7 +205,7 @@ void BX_MEM_C::read_block(Bit32u block)
void BX_MEM_C::allocate_block(Bit32u block)
{
const Bit32u max_blocks = (Bit32u)(BX_MEM_THIS allocated / BX_MEM_BLOCK_LEN);
const Bit32u max_blocks = (Bit32u)(BX_MEM_THIS allocated / BX_MEM_THIS block_size);
#if BX_LARGE_RAMFILE
/*
@ -198,7 +220,7 @@ void BX_MEM_C::allocate_block(Bit32u block)
do {
do {
// Wrap if necessary
if (++(BX_MEM_THIS next_swapout_idx)==((BX_MEM_THIS len)/BX_MEM_BLOCK_LEN))
if (++(BX_MEM_THIS next_swapout_idx)==((BX_MEM_THIS len)/BX_MEM_THIS block_size))
BX_MEM_THIS next_swapout_idx = 0;
if (BX_MEM_THIS next_swapout_idx == original_replacement_block)
BX_PANIC(("FATAL ERROR: Insufficient working RAM, all blocks are currently used for TLB entries!"));
@ -207,13 +229,13 @@ void BX_MEM_C::allocate_block(Bit32u block)
used_for_tlb = false;
// tlb buffer check loop
const Bit8u* buffer_end = buffer+BX_MEM_BLOCK_LEN;
const Bit8u* buffer_end = buffer+BX_MEM_THIS block_size;
// Don't replace it if any CPU is using it as a TLB entry
for (int i=0; i<BX_SMP_PROCESSORS && !used_for_tlb;i++)
used_for_tlb = BX_CPU(i)->check_addr_in_tlb_buffers(buffer, buffer_end);
} while (used_for_tlb);
// Flush the block to be replaced
bx_phy_address address = ((bx_phy_address)BX_MEM_THIS next_swapout_idx)*BX_MEM_BLOCK_LEN;
bx_phy_address address = bx_phy_address(BX_MEM_THIS next_swapout_idx) * BX_MEM_THIS block_size;
// Create overflow file if it does not currently exist.
if (!BX_MEM_THIS overflow_file) {
BX_MEM_THIS overflow_file = tmpfile64();
@ -223,7 +245,7 @@ void BX_MEM_C::allocate_block(Bit32u block)
// Write swapped out block
if (fseeko64(BX_MEM_THIS overflow_file, address, SEEK_SET))
BX_PANIC(("FATAL ERROR: Could not seek to 0x" FMT_PHY_ADDRX " in overflow file!", address));
if (1 != fwrite (BX_MEM_THIS blocks[BX_MEM_THIS next_swapout_idx], BX_MEM_BLOCK_LEN, 1, BX_MEM_THIS overflow_file))
if (1 != fwrite (BX_MEM_THIS blocks[BX_MEM_THIS next_swapout_idx], BX_MEM_THIS block_size, 1, BX_MEM_THIS overflow_file))
BX_PANIC(("FATAL ERROR: Could not write at 0x" FMT_PHY_ADDRX " in overflow file!", address));
// Mark swapped out block
BX_MEM_THIS blocks[BX_MEM_THIS next_swapout_idx] = BX_MEM_C::swapped_out;
@ -232,7 +254,7 @@ void BX_MEM_C::allocate_block(Bit32u block)
BX_DEBUG(("allocate_block: block=0x%x, replaced 0x%x", block, BX_MEM_THIS next_swapout_idx));
}
else {
BX_MEM_THIS blocks[block] = BX_MEM_THIS vector + (BX_MEM_THIS used_blocks++ * BX_MEM_BLOCK_LEN);
BX_MEM_THIS blocks[block] = BX_MEM_THIS vector + (BX_MEM_THIS used_blocks++ * BX_MEM_THIS block_size);
BX_DEBUG(("allocate_block: block=0x%x used 0x%x of 0x%x",
block, BX_MEM_THIS used_blocks, max_blocks));
}
@ -242,7 +264,7 @@ void BX_MEM_C::allocate_block(Bit32u block)
BX_PANIC(("FATAL ERROR: all available memory is already allocated !"));
}
else {
BX_MEM_THIS blocks[block] = BX_MEM_THIS vector + (BX_MEM_THIS used_blocks * BX_MEM_BLOCK_LEN);
BX_MEM_THIS blocks[block] = BX_MEM_THIS vector + (BX_MEM_THIS used_blocks * BX_MEM_THIS block_size);
BX_MEM_THIS used_blocks++;
}
BX_DEBUG(("allocate_block: used_blocks=0x%x of 0x%x", BX_MEM_THIS used_blocks, max_blocks));
@ -253,13 +275,13 @@ void BX_MEM_C::allocate_block(Bit32u block)
// The blocks in RAM must also be flushed to the save file.
void ramfile_save_handler(void *devptr, FILE *fp)
{
for (Bit32u idx = 0; idx < (BX_MEM(0)->len / BX_MEM_BLOCK_LEN); idx++) {
for (Bit32u idx = 0; idx < (BX_MEM(0)->len / BX_MEM_THIS block_size); idx++) {
if ((BX_MEM(0)->blocks[idx]) && (BX_MEM(0)->blocks[idx] != BX_MEM(0)->swapped_out))
{
bx_phy_address address = ((bx_phy_address)idx)*BX_MEM_BLOCK_LEN;
bx_phy_address address = bx_phy_address(idx) * BX_MEM_THIS block_size;
if (fseeko64(fp, address, SEEK_SET))
BX_PANIC(("FATAL ERROR: Could not seek to 0x" FMT_PHY_ADDRX " in overflow file!", address));
if (1 != fwrite (BX_MEM(0)->blocks[idx], BX_MEM_BLOCK_LEN, 1, fp))
if (1 != fwrite (BX_MEM(0)->blocks[idx], BX_MEM_THIS block_size, 1, fp))
BX_PANIC(("FATAL ERROR: Could not write at 0x" FMT_PHY_ADDRX " in overflow file!", address));
}
}
@ -281,8 +303,8 @@ Bit64s memory_param_save_handler(void *devptr, bx_param_c *param)
#endif
// Return the block offset into the array
Bit32u val = (Bit32u) (BX_MEM(0)->blocks[blk_index] - BX_MEM(0)->vector);
if ((val & (BX_MEM_BLOCK_LEN-1)) == 0)
return val / BX_MEM_BLOCK_LEN;
if ((val & (BX_MEM_THIS block_size-1)) == 0)
return val / BX_MEM_THIS block_size;
}
return -1;
}
@ -302,7 +324,7 @@ void memory_param_restore_handler(void *devptr, bx_param_c *param, Bit64s val)
BX_MEM(0)->blocks[blk_index] = NULL;
return;
}
BX_MEM(0)->blocks[blk_index] = BX_MEM(0)->vector + val * BX_MEM_BLOCK_LEN;
BX_MEM(0)->blocks[blk_index] = BX_MEM(0)->vector + val * BX_MEM_THIS block_size;
#if BX_LARGE_RAMFILE
BX_MEM(0)->read_block(blk_index);
#endif
@ -314,7 +336,7 @@ void BX_MEM_C::register_state()
char param_name[15];
bx_list_c *list = new bx_list_c(SIM->get_bochs_root(), "memory", "Memory State");
Bit32u num_blocks = (Bit32u)(BX_MEM_THIS len / BX_MEM_BLOCK_LEN);
Bit32u num_blocks = (Bit32u)(BX_MEM_THIS len / BX_MEM_THIS block_size);
#if BX_LARGE_RAMFILE
bx_shadow_filedata_c *ramfile = new bx_shadow_filedata_c(list, "ram", &(BX_MEM_THIS overflow_file));
ramfile->set_sr_handlers(this, ramfile_save_handler, (filedata_restore_handler)NULL);

View File

@ -81,6 +81,7 @@
#define BXPN_CPUID_SMAP "cpuid.smap"
#define BXPN_MEM_SIZE "memory.standard.ram.size"
#define BXPN_HOST_MEM_SIZE "memory.standard.ram.host_size"
#define BXPN_MEM_BLOCK_SIZE "memory.standard.ram.block_size"
#define BXPN_ROMIMAGE "memory.standard.rom"
#define BXPN_ROM_PATH "memory.standard.rom.file"
#define BXPN_ROM_ADDRESS "memory.standard.rom.address"