mirror of https://github.com/xemu-project/xemu.git
added generic physical memory dirty bit support
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@601 c046a42c-6fe2-441c-8c8c-71466251a162
This commit is contained in:
parent
ad08132319
commit
1ccde1cb94
20
cpu-all.h
20
cpu-all.h
|
@ -500,6 +500,7 @@ int cpu_inl(CPUState *env, int addr);
|
||||||
extern int phys_ram_size;
|
extern int phys_ram_size;
|
||||||
extern int phys_ram_fd;
|
extern int phys_ram_fd;
|
||||||
extern uint8_t *phys_ram_base;
|
extern uint8_t *phys_ram_base;
|
||||||
|
extern uint8_t *phys_ram_dirty;
|
||||||
|
|
||||||
/* physical memory access */
|
/* physical memory access */
|
||||||
#define IO_MEM_NB_ENTRIES 256
|
#define IO_MEM_NB_ENTRIES 256
|
||||||
|
@ -509,9 +510,11 @@ extern uint8_t *phys_ram_base;
|
||||||
#define IO_MEM_RAM (0 << IO_MEM_SHIFT) /* hardcoded offset */
|
#define IO_MEM_RAM (0 << IO_MEM_SHIFT) /* hardcoded offset */
|
||||||
#define IO_MEM_ROM (1 << IO_MEM_SHIFT) /* hardcoded offset */
|
#define IO_MEM_ROM (1 << IO_MEM_SHIFT) /* hardcoded offset */
|
||||||
#define IO_MEM_UNASSIGNED (2 << IO_MEM_SHIFT)
|
#define IO_MEM_UNASSIGNED (2 << IO_MEM_SHIFT)
|
||||||
#define IO_MEM_CODE (3 << IO_MEM_SHIFT)
|
#define IO_MEM_CODE (3 << IO_MEM_SHIFT) /* used internally, never use directly */
|
||||||
|
#define IO_MEM_NOTDIRTY (4 << IO_MEM_SHIFT) /* used internally, never use directly */
|
||||||
|
|
||||||
typedef void CPUWriteMemoryFunc(uint32_t addr, uint32_t value);
|
/* NOTE: vaddr is only used internally. Never use it except if you know what you do */
|
||||||
|
typedef void CPUWriteMemoryFunc(uint32_t addr, uint32_t value, uint32_t vaddr);
|
||||||
typedef uint32_t CPUReadMemoryFunc(uint32_t addr);
|
typedef uint32_t CPUReadMemoryFunc(uint32_t addr);
|
||||||
|
|
||||||
void cpu_register_physical_memory(unsigned long start_addr, unsigned long size,
|
void cpu_register_physical_memory(unsigned long start_addr, unsigned long size,
|
||||||
|
@ -525,6 +528,19 @@ void cpu_physical_memory_rw(CPUState *env, uint8_t *buf, target_ulong addr,
|
||||||
int cpu_memory_rw_debug(CPUState *env,
|
int cpu_memory_rw_debug(CPUState *env,
|
||||||
uint8_t *buf, target_ulong addr, int len, int is_write);
|
uint8_t *buf, target_ulong addr, int len, int is_write);
|
||||||
|
|
||||||
|
/* read dirty bit (return 0 or 1) */
|
||||||
|
static inline int cpu_physical_memory_is_dirty(target_ulong addr)
|
||||||
|
{
|
||||||
|
return phys_ram_dirty[addr >> TARGET_PAGE_BITS];
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void cpu_physical_memory_set_dirty(target_ulong addr)
|
||||||
|
{
|
||||||
|
phys_ram_dirty[addr >> TARGET_PAGE_BITS] = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
void cpu_physical_memory_reset_dirty(target_ulong start, target_ulong end);
|
||||||
|
|
||||||
/* gdb stub API */
|
/* gdb stub API */
|
||||||
extern int gdbstub_fd;
|
extern int gdbstub_fd;
|
||||||
CPUState *cpu_gdbstub_get_env(void *opaque);
|
CPUState *cpu_gdbstub_get_env(void *opaque);
|
||||||
|
|
|
@ -530,6 +530,8 @@ static inline target_ulong get_phys_addr_code(CPUState *env, target_ulong addr)
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
/* NOTE: this function can trigger an exception */
|
/* NOTE: this function can trigger an exception */
|
||||||
|
/* NOTE2: the returned address is not exactly the physical address: it
|
||||||
|
is the offset relative to phys_ram_base */
|
||||||
/* XXX: i386 target specific */
|
/* XXX: i386 target specific */
|
||||||
static inline target_ulong get_phys_addr_code(CPUState *env, target_ulong addr)
|
static inline target_ulong get_phys_addr_code(CPUState *env, target_ulong addr)
|
||||||
{
|
{
|
||||||
|
|
175
exec.c
175
exec.c
|
@ -59,6 +59,7 @@ uint8_t *code_gen_ptr;
|
||||||
int phys_ram_size;
|
int phys_ram_size;
|
||||||
int phys_ram_fd;
|
int phys_ram_fd;
|
||||||
uint8_t *phys_ram_base;
|
uint8_t *phys_ram_base;
|
||||||
|
uint8_t *phys_ram_dirty;
|
||||||
|
|
||||||
typedef struct PageDesc {
|
typedef struct PageDesc {
|
||||||
/* offset in memory of the page + io_index in the low 12 bits */
|
/* offset in memory of the page + io_index in the low 12 bits */
|
||||||
|
@ -162,7 +163,7 @@ static inline PageDesc *page_find(unsigned int index)
|
||||||
#if !defined(CONFIG_USER_ONLY)
|
#if !defined(CONFIG_USER_ONLY)
|
||||||
static void tlb_protect_code(CPUState *env, uint32_t addr);
|
static void tlb_protect_code(CPUState *env, uint32_t addr);
|
||||||
static void tlb_unprotect_code(CPUState *env, uint32_t addr);
|
static void tlb_unprotect_code(CPUState *env, uint32_t addr);
|
||||||
static void tlb_unprotect_code_phys(CPUState *env, uint32_t phys_addr);
|
static void tlb_unprotect_code_phys(CPUState *env, uint32_t phys_addr, target_ulong vaddr);
|
||||||
|
|
||||||
static inline VirtPageDesc *virt_page_find_alloc(unsigned int index)
|
static inline VirtPageDesc *virt_page_find_alloc(unsigned int index)
|
||||||
{
|
{
|
||||||
|
@ -528,8 +529,11 @@ static void build_page_bitmap(PageDesc *p)
|
||||||
|
|
||||||
/* invalidate all TBs which intersect with the target physical page
|
/* invalidate all TBs which intersect with the target physical page
|
||||||
starting in range [start;end[. NOTE: start and end must refer to
|
starting in range [start;end[. NOTE: start and end must refer to
|
||||||
the same physical page */
|
the same physical page. 'vaddr' is a virtual address referencing
|
||||||
static void tb_invalidate_phys_page_range(target_ulong start, target_ulong end)
|
the physical page of code. It is only used an a hint if there is no
|
||||||
|
code left. */
|
||||||
|
static void tb_invalidate_phys_page_range(target_ulong start, target_ulong end,
|
||||||
|
target_ulong vaddr)
|
||||||
{
|
{
|
||||||
int n;
|
int n;
|
||||||
PageDesc *p;
|
PageDesc *p;
|
||||||
|
@ -571,13 +575,13 @@ static void tb_invalidate_phys_page_range(target_ulong start, target_ulong end)
|
||||||
/* if no code remaining, no need to continue to use slow writes */
|
/* if no code remaining, no need to continue to use slow writes */
|
||||||
if (!p->first_tb) {
|
if (!p->first_tb) {
|
||||||
invalidate_page_bitmap(p);
|
invalidate_page_bitmap(p);
|
||||||
tlb_unprotect_code_phys(cpu_single_env, start);
|
tlb_unprotect_code_phys(cpu_single_env, start, vaddr);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
/* len must be <= 8 and start must be a multiple of len */
|
/* len must be <= 8 and start must be a multiple of len */
|
||||||
static inline void tb_invalidate_phys_page_fast(target_ulong start, int len)
|
static inline void tb_invalidate_phys_page_fast(target_ulong start, int len, target_ulong vaddr)
|
||||||
{
|
{
|
||||||
PageDesc *p;
|
PageDesc *p;
|
||||||
int offset, b;
|
int offset, b;
|
||||||
|
@ -592,7 +596,7 @@ static inline void tb_invalidate_phys_page_fast(target_ulong start, int len)
|
||||||
goto do_invalidate;
|
goto do_invalidate;
|
||||||
} else {
|
} else {
|
||||||
do_invalidate:
|
do_invalidate:
|
||||||
tb_invalidate_phys_page_range(start, start + len);
|
tb_invalidate_phys_page_range(start, start + len, vaddr);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1088,8 +1092,7 @@ static inline void tlb_protect_code1(CPUTLBEntry *tlb_entry, uint32_t addr)
|
||||||
(TARGET_PAGE_MASK | TLB_INVALID_MASK)) &&
|
(TARGET_PAGE_MASK | TLB_INVALID_MASK)) &&
|
||||||
(tlb_entry->address & ~TARGET_PAGE_MASK) != IO_MEM_CODE &&
|
(tlb_entry->address & ~TARGET_PAGE_MASK) != IO_MEM_CODE &&
|
||||||
(tlb_entry->address & ~TARGET_PAGE_MASK) != IO_MEM_ROM) {
|
(tlb_entry->address & ~TARGET_PAGE_MASK) != IO_MEM_ROM) {
|
||||||
tlb_entry->address |= IO_MEM_CODE;
|
tlb_entry->address = (tlb_entry->address & TARGET_PAGE_MASK) | IO_MEM_CODE;
|
||||||
tlb_entry->addend -= (unsigned long)phys_ram_base;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1116,8 +1119,7 @@ static inline void tlb_unprotect_code1(CPUTLBEntry *tlb_entry, uint32_t addr)
|
||||||
if (addr == (tlb_entry->address &
|
if (addr == (tlb_entry->address &
|
||||||
(TARGET_PAGE_MASK | TLB_INVALID_MASK)) &&
|
(TARGET_PAGE_MASK | TLB_INVALID_MASK)) &&
|
||||||
(tlb_entry->address & ~TARGET_PAGE_MASK) == IO_MEM_CODE) {
|
(tlb_entry->address & ~TARGET_PAGE_MASK) == IO_MEM_CODE) {
|
||||||
tlb_entry->address &= TARGET_PAGE_MASK;
|
tlb_entry->address = (tlb_entry->address & TARGET_PAGE_MASK) | IO_MEM_NOTDIRTY;
|
||||||
tlb_entry->addend += (unsigned long)phys_ram_base;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1138,23 +1140,84 @@ static inline void tlb_unprotect_code2(CPUTLBEntry *tlb_entry,
|
||||||
{
|
{
|
||||||
if ((tlb_entry->address & ~TARGET_PAGE_MASK) == IO_MEM_CODE &&
|
if ((tlb_entry->address & ~TARGET_PAGE_MASK) == IO_MEM_CODE &&
|
||||||
((tlb_entry->address & TARGET_PAGE_MASK) + tlb_entry->addend) == phys_addr) {
|
((tlb_entry->address & TARGET_PAGE_MASK) + tlb_entry->addend) == phys_addr) {
|
||||||
tlb_entry->address &= TARGET_PAGE_MASK;
|
tlb_entry->address = (tlb_entry->address & TARGET_PAGE_MASK) | IO_MEM_NOTDIRTY;
|
||||||
tlb_entry->addend += (unsigned long)phys_ram_base;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* update the TLB so that writes in physical page 'phys_addr' are no longer
|
/* update the TLB so that writes in physical page 'phys_addr' are no longer
|
||||||
tested self modifying code */
|
tested self modifying code */
|
||||||
/* XXX: find a way to improve it */
|
static void tlb_unprotect_code_phys(CPUState *env, uint32_t phys_addr, target_ulong vaddr)
|
||||||
static void tlb_unprotect_code_phys(CPUState *env, uint32_t phys_addr)
|
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
phys_addr &= TARGET_PAGE_MASK;
|
phys_addr &= TARGET_PAGE_MASK;
|
||||||
|
phys_addr += (long)phys_ram_base;
|
||||||
|
i = (vaddr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1);
|
||||||
|
tlb_unprotect_code2(&env->tlb_write[0][i], phys_addr);
|
||||||
|
tlb_unprotect_code2(&env->tlb_write[1][i], phys_addr);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void tlb_reset_dirty_range(CPUTLBEntry *tlb_entry,
|
||||||
|
unsigned long start, unsigned long length)
|
||||||
|
{
|
||||||
|
unsigned long addr;
|
||||||
|
if ((tlb_entry->address & ~TARGET_PAGE_MASK) == IO_MEM_RAM) {
|
||||||
|
addr = (tlb_entry->address & TARGET_PAGE_MASK) + tlb_entry->addend;
|
||||||
|
if ((addr - start) < length) {
|
||||||
|
tlb_entry->address = (tlb_entry->address & TARGET_PAGE_MASK) | IO_MEM_NOTDIRTY;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void cpu_physical_memory_reset_dirty(target_ulong start, target_ulong end)
|
||||||
|
{
|
||||||
|
CPUState *env;
|
||||||
|
target_ulong length;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
start &= TARGET_PAGE_MASK;
|
||||||
|
end = TARGET_PAGE_ALIGN(end);
|
||||||
|
|
||||||
|
length = end - start;
|
||||||
|
if (length == 0)
|
||||||
|
return;
|
||||||
|
memset(phys_ram_dirty + (start >> TARGET_PAGE_BITS), 0, length >> TARGET_PAGE_BITS);
|
||||||
|
|
||||||
|
env = cpu_single_env;
|
||||||
|
/* we modify the TLB cache so that the dirty bit will be set again
|
||||||
|
when accessing the range */
|
||||||
|
start += (unsigned long)phys_ram_base;
|
||||||
for(i = 0; i < CPU_TLB_SIZE; i++)
|
for(i = 0; i < CPU_TLB_SIZE; i++)
|
||||||
tlb_unprotect_code2(&env->tlb_write[0][i], phys_addr);
|
tlb_reset_dirty_range(&env->tlb_write[0][i], start, length);
|
||||||
for(i = 0; i < CPU_TLB_SIZE; i++)
|
for(i = 0; i < CPU_TLB_SIZE; i++)
|
||||||
tlb_unprotect_code2(&env->tlb_write[1][i], phys_addr);
|
tlb_reset_dirty_range(&env->tlb_write[1][i], start, length);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void tlb_set_dirty1(CPUTLBEntry *tlb_entry,
|
||||||
|
unsigned long start)
|
||||||
|
{
|
||||||
|
unsigned long addr;
|
||||||
|
if ((tlb_entry->address & ~TARGET_PAGE_MASK) == IO_MEM_NOTDIRTY) {
|
||||||
|
addr = (tlb_entry->address & TARGET_PAGE_MASK) + tlb_entry->addend;
|
||||||
|
if (addr == start) {
|
||||||
|
tlb_entry->address = (tlb_entry->address & TARGET_PAGE_MASK) | IO_MEM_RAM;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* update the TLB corresponding to virtual page vaddr and phys addr
|
||||||
|
addr so that it is no longer dirty */
|
||||||
|
static inline void tlb_set_dirty(unsigned long addr, target_ulong vaddr)
|
||||||
|
{
|
||||||
|
CPUState *env = cpu_single_env;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
phys_ram_dirty[(addr - (unsigned long)phys_ram_base) >> TARGET_PAGE_BITS] = 1;
|
||||||
|
|
||||||
|
addr &= TARGET_PAGE_MASK;
|
||||||
|
i = (vaddr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1);
|
||||||
|
tlb_set_dirty1(&env->tlb_write[0][i], addr);
|
||||||
|
tlb_set_dirty1(&env->tlb_write[1][i], addr);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* add a new TLB entry. At most one entry for a given virtual
|
/* add a new TLB entry. At most one entry for a given virtual
|
||||||
|
@ -1210,12 +1273,16 @@ int tlb_set_page(CPUState *env, uint32_t vaddr, uint32_t paddr, int prot,
|
||||||
if ((pd & ~TARGET_PAGE_MASK) == IO_MEM_ROM) {
|
if ((pd & ~TARGET_PAGE_MASK) == IO_MEM_ROM) {
|
||||||
/* ROM: access is ignored (same as unassigned) */
|
/* ROM: access is ignored (same as unassigned) */
|
||||||
env->tlb_write[is_user][index].address = vaddr | IO_MEM_ROM;
|
env->tlb_write[is_user][index].address = vaddr | IO_MEM_ROM;
|
||||||
env->tlb_write[is_user][index].addend = addend - (unsigned long)phys_ram_base;
|
env->tlb_write[is_user][index].addend = addend;
|
||||||
} else if (first_tb) {
|
} else if (first_tb) {
|
||||||
/* if code is present, we use a specific memory
|
/* if code is present, we use a specific memory
|
||||||
handler. It works only for physical memory access */
|
handler. It works only for physical memory access */
|
||||||
env->tlb_write[is_user][index].address = vaddr | IO_MEM_CODE;
|
env->tlb_write[is_user][index].address = vaddr | IO_MEM_CODE;
|
||||||
env->tlb_write[is_user][index].addend = addend - (unsigned long)phys_ram_base;
|
env->tlb_write[is_user][index].addend = addend;
|
||||||
|
} else if ((pd & ~TARGET_PAGE_MASK) == IO_MEM_RAM &&
|
||||||
|
!cpu_physical_memory_is_dirty(pd)) {
|
||||||
|
env->tlb_write[is_user][index].address = vaddr | IO_MEM_NOTDIRTY;
|
||||||
|
env->tlb_write[is_user][index].addend = addend;
|
||||||
} else {
|
} else {
|
||||||
env->tlb_write[is_user][index].address = address;
|
env->tlb_write[is_user][index].address = address;
|
||||||
env->tlb_write[is_user][index].addend = addend;
|
env->tlb_write[is_user][index].addend = addend;
|
||||||
|
@ -1446,6 +1513,10 @@ void page_unprotect_range(uint8_t *data, unsigned long data_size)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline void tlb_set_dirty(unsigned long addr, target_ulong vaddr)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
#endif /* defined(CONFIG_USER_ONLY) */
|
#endif /* defined(CONFIG_USER_ONLY) */
|
||||||
|
|
||||||
/* register physical memory. 'size' must be a multiple of the target
|
/* register physical memory. 'size' must be a multiple of the target
|
||||||
|
@ -1471,7 +1542,7 @@ static uint32_t unassigned_mem_readb(uint32_t addr)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void unassigned_mem_writeb(uint32_t addr, uint32_t val)
|
static void unassigned_mem_writeb(uint32_t addr, uint32_t val, uint32_t vaddr)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1490,28 +1561,40 @@ static CPUWriteMemoryFunc *unassigned_mem_write[3] = {
|
||||||
/* self modifying code support in soft mmu mode : writing to a page
|
/* self modifying code support in soft mmu mode : writing to a page
|
||||||
containing code comes to these functions */
|
containing code comes to these functions */
|
||||||
|
|
||||||
static void code_mem_writeb(uint32_t addr, uint32_t val)
|
static void code_mem_writeb(uint32_t addr, uint32_t val, uint32_t vaddr)
|
||||||
{
|
{
|
||||||
|
unsigned long phys_addr;
|
||||||
|
|
||||||
|
phys_addr = addr - (long)phys_ram_base;
|
||||||
#if !defined(CONFIG_USER_ONLY)
|
#if !defined(CONFIG_USER_ONLY)
|
||||||
tb_invalidate_phys_page_fast(addr, 1);
|
tb_invalidate_phys_page_fast(phys_addr, 1, vaddr);
|
||||||
#endif
|
#endif
|
||||||
stb_raw(phys_ram_base + addr, val);
|
stb_raw((uint8_t *)addr, val);
|
||||||
|
phys_ram_dirty[phys_addr >> TARGET_PAGE_BITS] = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void code_mem_writew(uint32_t addr, uint32_t val)
|
static void code_mem_writew(uint32_t addr, uint32_t val, uint32_t vaddr)
|
||||||
{
|
{
|
||||||
|
unsigned long phys_addr;
|
||||||
|
|
||||||
|
phys_addr = addr - (long)phys_ram_base;
|
||||||
#if !defined(CONFIG_USER_ONLY)
|
#if !defined(CONFIG_USER_ONLY)
|
||||||
tb_invalidate_phys_page_fast(addr, 2);
|
tb_invalidate_phys_page_fast(phys_addr, 2, vaddr);
|
||||||
#endif
|
#endif
|
||||||
stw_raw(phys_ram_base + addr, val);
|
stw_raw((uint8_t *)addr, val);
|
||||||
|
phys_ram_dirty[phys_addr >> TARGET_PAGE_BITS] = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void code_mem_writel(uint32_t addr, uint32_t val)
|
static void code_mem_writel(uint32_t addr, uint32_t val, uint32_t vaddr)
|
||||||
{
|
{
|
||||||
|
unsigned long phys_addr;
|
||||||
|
|
||||||
|
phys_addr = addr - (long)phys_ram_base;
|
||||||
#if !defined(CONFIG_USER_ONLY)
|
#if !defined(CONFIG_USER_ONLY)
|
||||||
tb_invalidate_phys_page_fast(addr, 4);
|
tb_invalidate_phys_page_fast(phys_addr, 4, vaddr);
|
||||||
#endif
|
#endif
|
||||||
stl_raw(phys_ram_base + addr, val);
|
stl_raw((uint8_t *)addr, val);
|
||||||
|
phys_ram_dirty[phys_addr >> TARGET_PAGE_BITS] = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static CPUReadMemoryFunc *code_mem_read[3] = {
|
static CPUReadMemoryFunc *code_mem_read[3] = {
|
||||||
|
@ -1526,12 +1609,40 @@ static CPUWriteMemoryFunc *code_mem_write[3] = {
|
||||||
code_mem_writel,
|
code_mem_writel,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static void notdirty_mem_writeb(uint32_t addr, uint32_t val, uint32_t vaddr)
|
||||||
|
{
|
||||||
|
stb_raw((uint8_t *)addr, val);
|
||||||
|
tlb_set_dirty(addr, vaddr);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void notdirty_mem_writew(uint32_t addr, uint32_t val, uint32_t vaddr)
|
||||||
|
{
|
||||||
|
stw_raw((uint8_t *)addr, val);
|
||||||
|
tlb_set_dirty(addr, vaddr);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void notdirty_mem_writel(uint32_t addr, uint32_t val, uint32_t vaddr)
|
||||||
|
{
|
||||||
|
stl_raw((uint8_t *)addr, val);
|
||||||
|
tlb_set_dirty(addr, vaddr);
|
||||||
|
}
|
||||||
|
|
||||||
|
static CPUWriteMemoryFunc *notdirty_mem_write[3] = {
|
||||||
|
notdirty_mem_writeb,
|
||||||
|
notdirty_mem_writew,
|
||||||
|
notdirty_mem_writel,
|
||||||
|
};
|
||||||
|
|
||||||
static void io_mem_init(void)
|
static void io_mem_init(void)
|
||||||
{
|
{
|
||||||
cpu_register_io_memory(IO_MEM_ROM >> IO_MEM_SHIFT, code_mem_read, unassigned_mem_write);
|
cpu_register_io_memory(IO_MEM_ROM >> IO_MEM_SHIFT, code_mem_read, unassigned_mem_write);
|
||||||
cpu_register_io_memory(IO_MEM_UNASSIGNED >> IO_MEM_SHIFT, unassigned_mem_read, unassigned_mem_write);
|
cpu_register_io_memory(IO_MEM_UNASSIGNED >> IO_MEM_SHIFT, unassigned_mem_read, unassigned_mem_write);
|
||||||
cpu_register_io_memory(IO_MEM_CODE >> IO_MEM_SHIFT, code_mem_read, code_mem_write);
|
cpu_register_io_memory(IO_MEM_CODE >> IO_MEM_SHIFT, code_mem_read, code_mem_write);
|
||||||
io_mem_nb = 4;
|
cpu_register_io_memory(IO_MEM_NOTDIRTY >> IO_MEM_SHIFT, code_mem_read, notdirty_mem_write);
|
||||||
|
io_mem_nb = 5;
|
||||||
|
|
||||||
|
/* alloc dirty bits array */
|
||||||
|
phys_ram_dirty = malloc(phys_ram_size >> TARGET_PAGE_BITS);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* mem_read and mem_write are arrays of functions containing the
|
/* mem_read and mem_write are arrays of functions containing the
|
||||||
|
@ -1620,17 +1731,17 @@ void cpu_physical_memory_rw(CPUState *env, uint8_t *buf, target_ulong addr,
|
||||||
if (l >= 4 && ((addr & 3) == 0)) {
|
if (l >= 4 && ((addr & 3) == 0)) {
|
||||||
/* 32 bit read access */
|
/* 32 bit read access */
|
||||||
val = ldl_raw(buf);
|
val = ldl_raw(buf);
|
||||||
io_mem_write[io_index][2](addr, val);
|
io_mem_write[io_index][2](addr, val, 0);
|
||||||
l = 4;
|
l = 4;
|
||||||
} else if (l >= 2 && ((addr & 1) == 0)) {
|
} else if (l >= 2 && ((addr & 1) == 0)) {
|
||||||
/* 16 bit read access */
|
/* 16 bit read access */
|
||||||
val = lduw_raw(buf);
|
val = lduw_raw(buf);
|
||||||
io_mem_write[io_index][1](addr, val);
|
io_mem_write[io_index][1](addr, val, 0);
|
||||||
l = 2;
|
l = 2;
|
||||||
} else {
|
} else {
|
||||||
/* 8 bit access */
|
/* 8 bit access */
|
||||||
val = ldub_raw(buf);
|
val = ldub_raw(buf);
|
||||||
io_mem_write[io_index][0](addr, val);
|
io_mem_write[io_index][0](addr, val, 0);
|
||||||
l = 1;
|
l = 1;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -76,14 +76,14 @@ static inline void glue(io_write, SUFFIX)(unsigned long physaddr,
|
||||||
|
|
||||||
index = (tlb_addr >> IO_MEM_SHIFT) & (IO_MEM_NB_ENTRIES - 1);
|
index = (tlb_addr >> IO_MEM_SHIFT) & (IO_MEM_NB_ENTRIES - 1);
|
||||||
#if SHIFT <= 2
|
#if SHIFT <= 2
|
||||||
io_mem_write[index][SHIFT](physaddr, val);
|
io_mem_write[index][SHIFT](physaddr, val, tlb_addr);
|
||||||
#else
|
#else
|
||||||
#ifdef TARGET_WORDS_BIGENDIAN
|
#ifdef TARGET_WORDS_BIGENDIAN
|
||||||
io_mem_write[index][2](physaddr, val >> 32);
|
io_mem_write[index][2](physaddr, val >> 32, tlb_addr);
|
||||||
io_mem_write[index][2](physaddr + 4, val);
|
io_mem_write[index][2](physaddr + 4, val, tlb_addr);
|
||||||
#else
|
#else
|
||||||
io_mem_write[index][2](physaddr, val);
|
io_mem_write[index][2](physaddr, val, tlb_addr);
|
||||||
io_mem_write[index][2](physaddr + 4, val >> 32);
|
io_mem_write[index][2](physaddr + 4, val >> 32, tlb_addr);
|
||||||
#endif
|
#endif
|
||||||
#endif /* SHIFT > 2 */
|
#endif /* SHIFT > 2 */
|
||||||
}
|
}
|
||||||
|
|
33
vl.c
33
vl.c
|
@ -233,6 +233,7 @@ int nographic;
|
||||||
int term_inited;
|
int term_inited;
|
||||||
int64_t ticks_per_sec;
|
int64_t ticks_per_sec;
|
||||||
int boot_device = 'c';
|
int boot_device = 'c';
|
||||||
|
static int ram_size;
|
||||||
|
|
||||||
/***********************************************************/
|
/***********************************************************/
|
||||||
/* x86 io ports */
|
/* x86 io ports */
|
||||||
|
@ -610,7 +611,7 @@ void cmos_init(void)
|
||||||
cmos_data[REG_EQUIPMENT_BYTE] |= 0x04; /* PS/2 mouse installed */
|
cmos_data[REG_EQUIPMENT_BYTE] |= 0x04; /* PS/2 mouse installed */
|
||||||
|
|
||||||
/* memory size */
|
/* memory size */
|
||||||
val = (phys_ram_size / 1024) - 1024;
|
val = (ram_size / 1024) - 1024;
|
||||||
if (val > 65535)
|
if (val > 65535)
|
||||||
val = 65535;
|
val = 65535;
|
||||||
cmos_data[0x17] = val;
|
cmos_data[0x17] = val;
|
||||||
|
@ -618,7 +619,7 @@ void cmos_init(void)
|
||||||
cmos_data[0x30] = val;
|
cmos_data[0x30] = val;
|
||||||
cmos_data[0x31] = val >> 8;
|
cmos_data[0x31] = val >> 8;
|
||||||
|
|
||||||
val = (phys_ram_size / 65536) - ((16 * 1024 * 1024) / 65536);
|
val = (ram_size / 65536) - ((16 * 1024 * 1024) / 65536);
|
||||||
if (val > 65535)
|
if (val > 65535)
|
||||||
val = 65535;
|
val = 65535;
|
||||||
cmos_data[0x34] = val;
|
cmos_data[0x34] = val;
|
||||||
|
@ -3312,7 +3313,7 @@ extern void __sigaction();
|
||||||
int main(int argc, char **argv)
|
int main(int argc, char **argv)
|
||||||
{
|
{
|
||||||
int c, ret, initrd_size, i, use_gdbstub, gdbstub_port, long_index;
|
int c, ret, initrd_size, i, use_gdbstub, gdbstub_port, long_index;
|
||||||
int snapshot, linux_boot, total_ram_size;
|
int snapshot, linux_boot;
|
||||||
#if defined (TARGET_I386)
|
#if defined (TARGET_I386)
|
||||||
struct linux_params *params;
|
struct linux_params *params;
|
||||||
#endif
|
#endif
|
||||||
|
@ -3331,7 +3332,7 @@ int main(int argc, char **argv)
|
||||||
fd_filename[i] = NULL;
|
fd_filename[i] = NULL;
|
||||||
for(i = 0; i < MAX_DISKS; i++)
|
for(i = 0; i < MAX_DISKS; i++)
|
||||||
hd_filename[i] = NULL;
|
hd_filename[i] = NULL;
|
||||||
phys_ram_size = 32 * 1024 * 1024;
|
ram_size = 32 * 1024 * 1024;
|
||||||
vga_ram_size = VGA_RAM_SIZE;
|
vga_ram_size = VGA_RAM_SIZE;
|
||||||
#if defined (TARGET_I386)
|
#if defined (TARGET_I386)
|
||||||
pstrcpy(network_script, sizeof(network_script), DEFAULT_NETWORK_SCRIPT);
|
pstrcpy(network_script, sizeof(network_script), DEFAULT_NETWORK_SCRIPT);
|
||||||
|
@ -3425,10 +3426,10 @@ int main(int argc, char **argv)
|
||||||
help();
|
help();
|
||||||
break;
|
break;
|
||||||
case 'm':
|
case 'm':
|
||||||
phys_ram_size = atoi(optarg) * 1024 * 1024;
|
ram_size = atoi(optarg) * 1024 * 1024;
|
||||||
if (phys_ram_size <= 0)
|
if (ram_size <= 0)
|
||||||
help();
|
help();
|
||||||
if (phys_ram_size > PHYS_RAM_MAX_SIZE) {
|
if (ram_size > PHYS_RAM_MAX_SIZE) {
|
||||||
fprintf(stderr, "qemu: at most %d MB RAM can be simulated\n",
|
fprintf(stderr, "qemu: at most %d MB RAM can be simulated\n",
|
||||||
PHYS_RAM_MAX_SIZE / (1024 * 1024));
|
PHYS_RAM_MAX_SIZE / (1024 * 1024));
|
||||||
exit(1);
|
exit(1);
|
||||||
|
@ -3489,10 +3490,10 @@ int main(int argc, char **argv)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* init the memory */
|
/* init the memory */
|
||||||
total_ram_size = phys_ram_size + vga_ram_size;
|
phys_ram_size = ram_size + vga_ram_size;
|
||||||
|
|
||||||
#ifdef CONFIG_SOFTMMU
|
#ifdef CONFIG_SOFTMMU
|
||||||
phys_ram_base = malloc(total_ram_size);
|
phys_ram_base = memalign(TARGET_PAGE_SIZE, phys_ram_size);
|
||||||
if (!phys_ram_base) {
|
if (!phys_ram_base) {
|
||||||
fprintf(stderr, "Could not allocate physical memory\n");
|
fprintf(stderr, "Could not allocate physical memory\n");
|
||||||
exit(1);
|
exit(1);
|
||||||
|
@ -3518,10 +3519,10 @@ int main(int argc, char **argv)
|
||||||
phys_ram_file);
|
phys_ram_file);
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
ftruncate(phys_ram_fd, total_ram_size);
|
ftruncate(phys_ram_fd, phys_ram_size);
|
||||||
unlink(phys_ram_file);
|
unlink(phys_ram_file);
|
||||||
phys_ram_base = mmap(get_mmap_addr(total_ram_size),
|
phys_ram_base = mmap(get_mmap_addr(phys_ram_size),
|
||||||
total_ram_size,
|
phys_ram_size,
|
||||||
PROT_WRITE | PROT_READ, MAP_SHARED | MAP_FIXED,
|
PROT_WRITE | PROT_READ, MAP_SHARED | MAP_FIXED,
|
||||||
phys_ram_fd, 0);
|
phys_ram_fd, 0);
|
||||||
if (phys_ram_base == MAP_FAILED) {
|
if (phys_ram_base == MAP_FAILED) {
|
||||||
|
@ -3551,7 +3552,7 @@ int main(int argc, char **argv)
|
||||||
init_ioports();
|
init_ioports();
|
||||||
|
|
||||||
/* allocate RAM */
|
/* allocate RAM */
|
||||||
cpu_register_physical_memory(0, phys_ram_size, 0);
|
cpu_register_physical_memory(0, ram_size, 0);
|
||||||
|
|
||||||
if (linux_boot) {
|
if (linux_boot) {
|
||||||
/* now we can load the kernel */
|
/* now we can load the kernel */
|
||||||
|
@ -3580,7 +3581,7 @@ int main(int argc, char **argv)
|
||||||
params->mount_root_rdonly = 0;
|
params->mount_root_rdonly = 0;
|
||||||
stw_raw(¶ms->cl_magic, 0xA33F);
|
stw_raw(¶ms->cl_magic, 0xA33F);
|
||||||
stw_raw(¶ms->cl_offset, params->commandline - (uint8_t *)params);
|
stw_raw(¶ms->cl_offset, params->commandline - (uint8_t *)params);
|
||||||
stl_raw(¶ms->alt_mem_k, (phys_ram_size / 1024) - 1024);
|
stl_raw(¶ms->alt_mem_k, (ram_size / 1024) - 1024);
|
||||||
pstrcat(params->commandline, sizeof(params->commandline), kernel_cmdline);
|
pstrcat(params->commandline, sizeof(params->commandline), kernel_cmdline);
|
||||||
params->loader_type = 0x01;
|
params->loader_type = 0x01;
|
||||||
if (initrd_size > 0) {
|
if (initrd_size > 0) {
|
||||||
|
@ -3617,7 +3618,7 @@ int main(int argc, char **argv)
|
||||||
env->regs[R_ESI] = KERNEL_PARAMS_ADDR;
|
env->regs[R_ESI] = KERNEL_PARAMS_ADDR;
|
||||||
env->eflags = 0x2;
|
env->eflags = 0x2;
|
||||||
#elif defined (TARGET_PPC)
|
#elif defined (TARGET_PPC)
|
||||||
PPC_init_hw(env, phys_ram_size, KERNEL_LOAD_ADDR, ret,
|
PPC_init_hw(env, ram_size, KERNEL_LOAD_ADDR, ret,
|
||||||
KERNEL_STACK_ADDR, boot_device);
|
KERNEL_STACK_ADDR, boot_device);
|
||||||
#endif
|
#endif
|
||||||
} else {
|
} else {
|
||||||
|
@ -3669,7 +3670,7 @@ int main(int argc, char **argv)
|
||||||
/* init basic PC hardware */
|
/* init basic PC hardware */
|
||||||
register_ioport_write(0x80, 1, ioport80_write, 1);
|
register_ioport_write(0x80, 1, ioport80_write, 1);
|
||||||
|
|
||||||
vga_initialize(ds, phys_ram_base + phys_ram_size, phys_ram_size,
|
vga_initialize(ds, phys_ram_base + ram_size, ram_size,
|
||||||
vga_ram_size);
|
vga_ram_size);
|
||||||
#if defined (TARGET_I386)
|
#if defined (TARGET_I386)
|
||||||
cmos_init();
|
cmos_init();
|
||||||
|
|
Loading…
Reference in New Issue