* [Qemu-devel] [PATCH 1/4] linux-user: Safety belt for h2g
2008-07-14 22:09 [Qemu-devel] [PATCH 0/4] linux-user: Detect and fix 32-bit guest on 64-bit host issues Jan Kiszka
@ 2008-07-14 21:54 ` Jan Kiszka
2008-07-14 22:09 ` [Qemu-devel] [PATCH 3/4] linux-user: Allocate guest-reachable descriptor tables Jan Kiszka
` (2 subsequent siblings)
3 siblings, 0 replies; 5+ messages in thread
From: Jan Kiszka @ 2008-07-14 21:54 UTC (permalink / raw)
To: qemu-devel
h2g can only work on 64-bit hosts if the provided address is mappable to
the guest range. Neglecting this was already the source for several
bugs. Instrument the macro so that it will trigger earlier in the
future (at least as long as we have this kind of mapping mechanism).
Signed-off-by: Jan Kiszka <jan.kiszka@web.de>
---
cpu-all.h | 8 +++++++-
1 file changed, 7 insertions(+), 1 deletion(-)
Index: b/cpu-all.h
===================================================================
--- a/cpu-all.h
+++ b/cpu-all.h
@@ -659,6 +659,8 @@ static inline void stfq_be_p(void *ptr,
/* MMU memory access macros */
#if defined(CONFIG_USER_ONLY)
+#include <assert.h>
+
/* On some host systems the guest address space is reserved on the host.
* This allows the guest address space to be offset to a convenient location.
*/
@@ -667,7 +669,11 @@ static inline void stfq_be_p(void *ptr,
/* All direct uses of g2h and h2g need to go away for usermode softmmu. */
#define g2h(x) ((void *)((unsigned long)(x) + GUEST_BASE))
-#define h2g(x) ((target_ulong)((unsigned long)(x) - GUEST_BASE))
+#define h2g(x) ({ \
+ unsigned long __ret = (unsigned long)(x) - GUEST_BASE; \
+ assert(__ret == (target_ulong)__ret); \
+ __ret; \
+})
#define saddr(x) g2h(x)
#define laddr(x) g2h(x)
^ permalink raw reply [flat|nested] 5+ messages in thread* [Qemu-devel] [PATCH 3/4] linux-user: Allocate guest-reachable descriptor tables
2008-07-14 22:09 [Qemu-devel] [PATCH 0/4] linux-user: Detect and fix 32-bit guest on 64-bit host issues Jan Kiszka
2008-07-14 21:54 ` [Qemu-devel] [PATCH 1/4] linux-user: Safety belt for h2g Jan Kiszka
@ 2008-07-14 22:09 ` Jan Kiszka
2008-07-14 22:09 ` [Qemu-devel] [PATCH 4/4] linux-user: Fix page_find_alloc for 32-bit use on 64-bit hosts Jan Kiszka
2008-07-14 22:09 ` [Qemu-devel] [PATCH 2/4] linux-user: Introduce qemu_vmalloc_guest_safe Jan Kiszka
3 siblings, 0 replies; 5+ messages in thread
From: Jan Kiszka @ 2008-07-14 22:09 UTC (permalink / raw)
To: qemu-devel
IDT, GDT and LDTs have to allocated from memory regions also reachable
by the guests. Obtain them via the new qemu_vmalloc_guest_safe service.
Signed-off-by: Jan Kiszka <jan.kiszka@web.de>
---
linux-user/i386/syscall.h | 2 ++
linux-user/main.c | 13 +++++++------
linux-user/syscall.c | 3 ++-
linux-user/x86_64/syscall.h | 2 ++
4 files changed, 13 insertions(+), 7 deletions(-)
Index: b/linux-user/main.c
===================================================================
--- a/linux-user/main.c
+++ b/linux-user/main.c
@@ -280,9 +280,9 @@ static void write_dt(void *ptr, unsigned
p[1] = tswapl(e2);
}
-#if TARGET_X86_64
-uint64_t idt_table[512];
+uint64_t *idt_table;
+#if TARGET_X86_64
static void set_gate64(void *ptr, unsigned int type, unsigned int dpl,
uint64_t addr, unsigned int sel)
{
@@ -301,8 +301,6 @@ static void set_idt(int n, unsigned int
set_gate64(idt_table + n * 2, 0, dpl, 0, 0);
}
#else
-uint64_t idt_table[256];
-
static void set_gate(void *ptr, unsigned int type, unsigned int dpl,
uint32_t addr, unsigned int sel)
{
@@ -2444,8 +2442,10 @@ int main(int argc, char **argv)
#endif
/* linux interrupt setup */
+ idt_table = qemu_vmalloc_guest_safe(sizeof(uint64_t) * TARGET_IDT_ENTRIES);
+ memset(idt_table, 0, sizeof(uint64_t) * TARGET_IDT_ENTRIES);
env->idt.base = h2g(idt_table);
- env->idt.limit = sizeof(idt_table) - 1;
+ env->idt.limit = sizeof(uint64_t) * TARGET_IDT_ENTRIES - 1;
set_idt(0, 0);
set_idt(1, 0);
set_idt(2, 0);
@@ -2471,7 +2471,8 @@ int main(int argc, char **argv)
/* linux segment setup */
{
uint64_t *gdt_table;
- gdt_table = qemu_mallocz(sizeof(uint64_t) * TARGET_GDT_ENTRIES);
+ gdt_table = qemu_vmalloc_guest_safe(sizeof(uint64_t) * TARGET_GDT_ENTRIES);
+ memset(gdt_table, 0, sizeof(uint64_t) * TARGET_GDT_ENTRIES);
env->gdt.base = h2g((unsigned long)gdt_table);
env->gdt.limit = sizeof(uint64_t) * TARGET_GDT_ENTRIES - 1;
#ifdef TARGET_ABI32
Index: b/linux-user/i386/syscall.h
===================================================================
--- a/linux-user/i386/syscall.h
+++ b/linux-user/i386/syscall.h
@@ -22,6 +22,8 @@ struct target_pt_regs {
/* ioctls */
+#define TARGET_IDT_ENTRIES 256
+
#define TARGET_LDT_ENTRIES 8192
#define TARGET_LDT_ENTRY_SIZE 8
Index: b/linux-user/x86_64/syscall.h
===================================================================
--- a/linux-user/x86_64/syscall.h
+++ b/linux-user/x86_64/syscall.h
@@ -29,6 +29,8 @@ struct target_pt_regs {
/* top of stack page */
};
+#define TARGET_IDT_ENTRIES 512
+
/* Maximum number of LDT entries supported. */
#define TARGET_LDT_ENTRIES 8192
/* The size of each LDT entry. */
Index: b/linux-user/syscall.c
===================================================================
--- a/linux-user/syscall.c
+++ b/linux-user/syscall.c
@@ -2473,7 +2473,8 @@ static abi_long write_ldt(CPUX86State *e
}
/* allocate the LDT */
if (!ldt_table) {
- ldt_table = malloc(TARGET_LDT_ENTRIES * TARGET_LDT_ENTRY_SIZE);
+ ldt_table = qemu_vmalloc_guest_safe(TARGET_LDT_ENTRIES
+ * TARGET_LDT_ENTRY_SIZE);
if (!ldt_table)
return -TARGET_ENOMEM;
memset(ldt_table, 0, TARGET_LDT_ENTRIES * TARGET_LDT_ENTRY_SIZE);
^ permalink raw reply [flat|nested] 5+ messages in thread* [Qemu-devel] [PATCH 4/4] linux-user: Fix page_find_alloc for 32-bit use on 64-bit hosts
2008-07-14 22:09 [Qemu-devel] [PATCH 0/4] linux-user: Detect and fix 32-bit guest on 64-bit host issues Jan Kiszka
2008-07-14 21:54 ` [Qemu-devel] [PATCH 1/4] linux-user: Safety belt for h2g Jan Kiszka
2008-07-14 22:09 ` [Qemu-devel] [PATCH 3/4] linux-user: Allocate guest-reachable descriptor tables Jan Kiszka
@ 2008-07-14 22:09 ` Jan Kiszka
2008-07-14 22:09 ` [Qemu-devel] [PATCH 2/4] linux-user: Introduce qemu_vmalloc_guest_safe Jan Kiszka
3 siblings, 0 replies; 5+ messages in thread
From: Jan Kiszka @ 2008-07-14 22:09 UTC (permalink / raw)
To: qemu-devel
page_find_alloc, used e.g. for TB allocation, is not safe on 64-bit
hosts for 32-bit guests. Patch below fixes this by requesting new pages
only from the guest-reachable address range.
Signed-off-by: Jan Kiszka <jan.kiszka@web.de>
---
exec.c | 24 +++++++++++++++++-------
linux-user/mmap.c | 2 +-
linux-user/qemu.h | 1 +
3 files changed, 19 insertions(+), 8 deletions(-)
Index: b/linux-user/qemu.h
===================================================================
--- a/linux-user/qemu.h
+++ b/linux-user/qemu.h
@@ -232,6 +232,7 @@ void sparc64_get_context(CPUSPARCState *
#endif
/* mmap.c */
+abi_ulong mmap_find_vma(abi_ulong start, abi_ulong size);
int target_mprotect(abi_ulong start, abi_ulong len, int prot);
abi_long target_mmap(abi_ulong start, abi_ulong len, int prot,
int flags, int fd, abi_ulong offset);
Index: b/linux-user/mmap.c
===================================================================
--- a/linux-user/mmap.c
+++ b/linux-user/mmap.c
@@ -297,7 +297,7 @@ unsigned long last_brk;
*/
/* page_init() marks pages used by the host as reserved to be sure not
to use them. */
-static abi_ulong mmap_find_vma(abi_ulong start, abi_ulong size)
+abi_ulong mmap_find_vma(abi_ulong start, abi_ulong size)
{
abi_ulong addr, addr1, addr_start;
int prot;
Index: b/exec.c
===================================================================
--- a/exec.c
+++ b/exec.c
@@ -294,18 +294,28 @@ static inline PageDesc *page_find_alloc(
if (!p) {
/* allocate if not found */
#if defined(CONFIG_USER_ONLY)
+ void *start = NULL;
unsigned long addr;
size_t len = sizeof(PageDesc) * L2_SIZE;
- /* Don't use qemu_malloc because it may recurse. */
- p = mmap(0, len, PROT_READ | PROT_WRITE,
+
+#if TARGET_LONG_BITS < HOST_LONG_BITS
+ {
+ /* Ensure we allocate from the guest-reachable rage */
+ abi_ulong guest_start;
+
+ len = HOST_PAGE_ALIGN(len);
+ guest_start = mmap_find_vma(0, len);
+ assert(guest_start != (abi_ulong)-1);
+ start = g2h(guest_start);
+ }
+#endif
+ p = mmap(start, len, PROT_READ | PROT_WRITE,
MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
+ assert(p != MAP_FAILED);
*lp = p;
addr = h2g(p);
- if (addr == (target_ulong)addr) {
- page_set_flags(addr & TARGET_PAGE_MASK,
- TARGET_PAGE_ALIGN(addr + len),
- PAGE_RESERVED);
- }
+ page_set_flags(addr & TARGET_PAGE_MASK, TARGET_PAGE_ALIGN(addr + len),
+ PAGE_RESERVED);
#else
p = qemu_mallocz(sizeof(PageDesc) * L2_SIZE);
*lp = p;
^ permalink raw reply [flat|nested] 5+ messages in thread* [Qemu-devel] [PATCH 2/4] linux-user: Introduce qemu_vmalloc_guest_safe
2008-07-14 22:09 [Qemu-devel] [PATCH 0/4] linux-user: Detect and fix 32-bit guest on 64-bit host issues Jan Kiszka
` (2 preceding siblings ...)
2008-07-14 22:09 ` [Qemu-devel] [PATCH 4/4] linux-user: Fix page_find_alloc for 32-bit use on 64-bit hosts Jan Kiszka
@ 2008-07-14 22:09 ` Jan Kiszka
3 siblings, 0 replies; 5+ messages in thread
From: Jan Kiszka @ 2008-07-14 22:09 UTC (permalink / raw)
To: qemu-devel
Add qemu_vmalloc_guest_safe to allocate memory from a region that are
reachable by user-space guests. Addresses returned by this function can
safely be provided to h2g.
Signed-off-by: Jan Kiszka <jan.kiszka@web.de>
---
linux-user/mmap.c | 37 +++++++++++++++++++++++++++++++++++++
linux-user/qemu.h | 1 +
2 files changed, 38 insertions(+)
Index: b/linux-user/mmap.c
===================================================================
--- a/linux-user/mmap.c
+++ b/linux-user/mmap.c
@@ -94,6 +94,43 @@ void *qemu_vmalloc(size_t size)
return p;
}
+void *qemu_vmalloc_guest_safe(size_t size)
+{
+#if TARGET_LONG_BIT < HOST_LONG_BITS
+ void *p;
+ unsigned long addr;
+ abi_ulong guest_start;
+
+ mmap_lock();
+
+ /* Ensure we allocate from the guest-reachable rage */
+ size = HOST_PAGE_ALIGN(size);
+ guest_start = mmap_find_vma(0, size);
+ if (guest_start == (abi_ulong)-1) {
+ p = NULL;
+ goto unlock_exit;
+ }
+
+ /* Use map and mark the pages as used. */
+ p = mmap(g2h(guest_start), size, PROT_READ | PROT_WRITE,
+ MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
+ if (p == MAP_FAILED) {
+ p = NULL;
+ goto unlock_exit;
+ }
+
+ addr = (unsigned long)p;
+ page_set_flags(addr & TARGET_PAGE_MASK, TARGET_PAGE_ALIGN(addr + size),
+ PAGE_RESERVED);
+
+unlock_exit:
+ mmap_unlock();
+ return p;
+#else
+ return qemu_vmalloc(size);
+#endif
+}
+
void *qemu_malloc(size_t size)
{
char * p;
Index: b/linux-user/qemu.h
===================================================================
--- a/linux-user/qemu.h
+++ b/linux-user/qemu.h
@@ -247,6 +247,7 @@ void mmap_unlock(void);
void mmap_fork_start(void);
void mmap_fork_end(int child);
#endif
+void *qemu_vmalloc_guest_safe(size_t size);
/* user access */
^ permalink raw reply [flat|nested] 5+ messages in thread