aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBlue Swirl <blauwirbel@gmail.com>2010-12-11 18:56:27 +0000
committerBlue Swirl <blauwirbel@gmail.com>2010-12-11 18:56:27 +0000
commit1b3cba6e91ab55a158e49bc5398fd76e67c695a8 (patch)
tree75671d78f3812a4a0ec21fe4c96874d123242cd5
parentd65aaf3773e4be7ae97df9d867cbe9b36e2fb8a1 (diff)
downloadqemu-1b3cba6e91ab55a158e49bc5398fd76e67c695a8.zip
qemu-1b3cba6e91ab55a158e49bc5398fd76e67c695a8.tar.gz
qemu-1b3cba6e91ab55a158e49bc5398fd76e67c695a8.tar.bz2
monitor: implement x86 info mem for PAE and long modes
'info mem' didn't show correct information for PAE mode and x86_64 long mode. Fix by implementing the output for missing modes. Signed-off-by: Blue Swirl <blauwirbel@gmail.com>
-rw-r--r--monitor.c176
1 files changed, 164 insertions, 12 deletions
diff --git a/monitor.c b/monitor.c
index a4ab163..0896254 100644
--- a/monitor.c
+++ b/monitor.c
@@ -2027,14 +2027,16 @@ static void tlb_info(Monitor *mon)
}
}
-static void mem_print(Monitor *mon, uint32_t *pstart, int *plast_prot,
- uint32_t end, int prot)
+static void mem_print(Monitor *mon, target_phys_addr_t *pstart,
+ int *plast_prot,
+ target_phys_addr_t end, int prot)
{
int prot1;
prot1 = *plast_prot;
if (prot != prot1) {
if (*pstart != -1) {
- monitor_printf(mon, "%08x-%08x %08x %c%c%c\n",
+ monitor_printf(mon, TARGET_FMT_plx "-" TARGET_FMT_plx " "
+ TARGET_FMT_plx " %c%c%c\n",
*pstart, end, end - *pstart,
prot1 & PG_USER_MASK ? 'u' : '-',
'r',
@@ -2048,18 +2050,12 @@ static void mem_print(Monitor *mon, uint32_t *pstart, int *plast_prot,
}
}
-static void mem_info(Monitor *mon)
+static void mem_info_32(Monitor *mon, CPUState *env)
{
- CPUState *env;
int l1, l2, prot, last_prot;
- uint32_t pgd, pde, pte, start, end;
-
- env = mon_get_cpu();
+ uint32_t pgd, pde, pte;
+ target_phys_addr_t start, end;
- if (!(env->cr[0] & CR0_PG_MASK)) {
- monitor_printf(mon, "PG disabled\n");
- return;
- }
pgd = env->cr[3] & ~0xfff;
last_prot = 0;
start = -1;
@@ -2091,6 +2087,162 @@ static void mem_info(Monitor *mon)
}
}
}
+
+static void mem_info_pae32(Monitor *mon, CPUState *env)
+{
+ int l1, l2, l3, prot, last_prot;
+ uint64_t pdpe, pde, pte;
+ uint64_t pdp_addr, pd_addr, pt_addr;
+ target_phys_addr_t start, end;
+
+ pdp_addr = env->cr[3] & ~0x1f;
+ last_prot = 0;
+ start = -1;
+ for (l1 = 0; l1 < 4; l1++) {
+ cpu_physical_memory_read(pdp_addr + l1 * 8, (uint8_t *)&pdpe, 8);
+ pdpe = le64_to_cpu(pdpe);
+ end = l1 << 30;
+ if (pdpe & PG_PRESENT_MASK) {
+ pd_addr = pdpe & 0x3fffffffff000ULL;
+ for (l2 = 0; l2 < 512; l2++) {
+ cpu_physical_memory_read(pd_addr + l2 * 8,
+ (uint8_t *)&pde, 8);
+ pde = le64_to_cpu(pde);
+ end = (l1 << 30) + (l2 << 21);
+ if (pde & PG_PRESENT_MASK) {
+ if (pde & PG_PSE_MASK) {
+ prot = pde & (PG_USER_MASK | PG_RW_MASK |
+ PG_PRESENT_MASK);
+ mem_print(mon, &start, &last_prot, end, prot);
+ } else {
+ pt_addr = pde & 0x3fffffffff000ULL;
+ for (l3 = 0; l3 < 512; l3++) {
+ cpu_physical_memory_read(pt_addr + l3 * 8,
+ (uint8_t *)&pte, 8);
+ pte = le64_to_cpu(pte);
+ end = (l1 << 30) + (l2 << 21) + (l3 << 12);
+ if (pte & PG_PRESENT_MASK) {
+ prot = pte & (PG_USER_MASK | PG_RW_MASK |
+ PG_PRESENT_MASK);
+ } else {
+ prot = 0;
+ }
+ mem_print(mon, &start, &last_prot, end, prot);
+ }
+ }
+ } else {
+ prot = 0;
+ mem_print(mon, &start, &last_prot, end, prot);
+ }
+ }
+ } else {
+ prot = 0;
+ mem_print(mon, &start, &last_prot, end, prot);
+ }
+ }
+}
+
+
+#ifdef TARGET_X86_64
+static void mem_info_64(Monitor *mon, CPUState *env)
+{
+ int prot, last_prot;
+ uint64_t l1, l2, l3, l4;
+ uint64_t pml4e, pdpe, pde, pte;
+ uint64_t pml4_addr, pdp_addr, pd_addr, pt_addr, start, end;
+
+ pml4_addr = env->cr[3] & 0x3fffffffff000ULL;
+ last_prot = 0;
+ start = -1;
+ for (l1 = 0; l1 < 512; l1++) {
+ cpu_physical_memory_read(pml4_addr + l1 * 8, (uint8_t *)&pml4e, 8);
+ pml4e = le64_to_cpu(pml4e);
+ end = l1 << 39;
+ if (pml4e & PG_PRESENT_MASK) {
+ pdp_addr = pml4e & 0x3fffffffff000ULL;
+ for (l2 = 0; l2 < 512; l2++) {
+ cpu_physical_memory_read(pdp_addr + l2 * 8, (uint8_t *)&pdpe,
+ 8);
+ pdpe = le64_to_cpu(pdpe);
+ end = (l1 << 39) + (l2 << 30);
+ if (pdpe & PG_PRESENT_MASK) {
+ if (pdpe & PG_PSE_MASK) {
+ prot = pde & (PG_USER_MASK | PG_RW_MASK |
+ PG_PRESENT_MASK);
+ mem_print(mon, &start, &last_prot, end, prot);
+ } else {
+ pd_addr = pdpe & 0x3fffffffff000ULL;
+ for (l3 = 0; l3 < 512; l3++) {
+ cpu_physical_memory_read(pd_addr + l3 * 8,
+ (uint8_t *)&pde, 8);
+ pde = le64_to_cpu(pde);
+ end = (l1 << 39) + (l2 << 30) + (l3 << 21);
+ if (pde & PG_PRESENT_MASK) {
+ if (pde & PG_PSE_MASK) {
+ prot = pde & (PG_USER_MASK | PG_RW_MASK |
+ PG_PRESENT_MASK);
+ mem_print(mon, &start, &last_prot, end, prot);
+ } else {
+ pt_addr = pde & 0x3fffffffff000ULL;
+ for (l4 = 0; l4 < 512; l4++) {
+ cpu_physical_memory_read(pt_addr
+ + l4 * 8,
+ (uint8_t *)&pte,
+ 8);
+ pte = le64_to_cpu(pte);
+ end = (l1 << 39) + (l2 << 30) +
+ (l3 << 21) + (l4 << 12);
+ if (pte & PG_PRESENT_MASK) {
+ prot = pte & (PG_USER_MASK | PG_RW_MASK |
+ PG_PRESENT_MASK);
+ } else {
+ prot = 0;
+ }
+ mem_print(mon, &start, &last_prot, end, prot);
+ }
+ }
+ } else {
+ prot = 0;
+ mem_print(mon, &start, &last_prot, end, prot);
+ }
+ }
+ }
+ } else {
+ prot = 0;
+ mem_print(mon, &start, &last_prot, end, prot);
+ }
+ }
+ } else {
+ prot = 0;
+ mem_print(mon, &start, &last_prot, end, prot);
+ }
+ }
+}
+#endif
+
+static void mem_info(Monitor *mon)
+{
+ CPUState *env;
+
+ env = mon_get_cpu();
+
+ if (!(env->cr[0] & CR0_PG_MASK)) {
+ monitor_printf(mon, "PG disabled\n");
+ return;
+ }
+ if (env->cr[4] & CR4_PAE_MASK) {
+#ifdef TARGET_X86_64
+ if (env->hflags & HF_LMA_MASK) {
+ mem_info_64(mon, env);
+ } else
+#endif
+ {
+ mem_info_pae32(mon, env);
+ }
+ } else {
+ mem_info_32(mon, env);
+ }
+}
#endif
#if defined(TARGET_SH4)