提交 2d37f94a 编写于 作者: R Rusty Russell

generalize lgread_u32/lgwrite_u32.

Jes complains that page table code still uses lgread_u32 even though
it now uses general kernel pte types.  The best thing to do is to
generalize lgread_u32 and lgwrite_u32.

This means we lose the efficiency of getuser().  We could potentially
regain it if we used __copy_from_user instead of copy_from_user, but
I'm not certain that our range check is equivalent to access_ok() on
all platforms.
Signed-off-by: NRusty Russell <rusty@rustcorp.com.au>
Acked-by: NJes Sorensen <jes@sgi.com>
上级 56ae43df
...@@ -145,33 +145,10 @@ int lguest_address_ok(const struct lguest *lg, ...@@ -145,33 +145,10 @@ int lguest_address_ok(const struct lguest *lg,
return (addr+len) / PAGE_SIZE < lg->pfn_limit && (addr+len >= addr); return (addr+len) / PAGE_SIZE < lg->pfn_limit && (addr+len >= addr);
} }
/* This is a convenient routine to get a 32-bit value from the Guest (a very /* This routine copies memory from the Guest. Here we can see how useful the
* common operation). Here we can see how useful the kill_lguest() routine we * kill_lguest() routine we met in the Launcher can be: we return a random
* met in the Launcher can be: we return a random value (0) instead of needing * value (all zeroes) instead of needing to return an error. */
* to return an error. */ void __lgread(struct lguest *lg, void *b, unsigned long addr, unsigned bytes)
u32 lgread_u32(struct lguest *lg, unsigned long addr)
{
u32 val = 0;
/* Don't let them access lguest binary. */
if (!lguest_address_ok(lg, addr, sizeof(val))
|| get_user(val, (u32 *)(lg->mem_base + addr)) != 0)
kill_guest(lg, "bad read address %#lx: pfn_limit=%u membase=%p", addr, lg->pfn_limit, lg->mem_base);
return val;
}
/* Same thing for writing a value. */
void lgwrite_u32(struct lguest *lg, unsigned long addr, u32 val)
{
if (!lguest_address_ok(lg, addr, sizeof(val))
|| put_user(val, (u32 *)(lg->mem_base + addr)) != 0)
kill_guest(lg, "bad write address %#lx", addr);
}
/* This routine is more generic, and copies a range of Guest bytes into a
* buffer. If the copy_from_user() fails, we fill the buffer with zeroes, so
* the caller doesn't end up using uninitialized kernel memory. */
void lgread(struct lguest *lg, void *b, unsigned long addr, unsigned bytes)
{ {
if (!lguest_address_ok(lg, addr, bytes) if (!lguest_address_ok(lg, addr, bytes)
|| copy_from_user(b, lg->mem_base + addr, bytes) != 0) { || copy_from_user(b, lg->mem_base + addr, bytes) != 0) {
...@@ -181,15 +158,15 @@ void lgread(struct lguest *lg, void *b, unsigned long addr, unsigned bytes) ...@@ -181,15 +158,15 @@ void lgread(struct lguest *lg, void *b, unsigned long addr, unsigned bytes)
} }
} }
/* Similarly, our generic routine to copy into a range of Guest bytes. */ /* This is the write (copy into guest) version. */
void lgwrite(struct lguest *lg, unsigned long addr, const void *b, void __lgwrite(struct lguest *lg, unsigned long addr, const void *b,
unsigned bytes) unsigned bytes)
{ {
if (!lguest_address_ok(lg, addr, bytes) if (!lguest_address_ok(lg, addr, bytes)
|| copy_to_user(lg->mem_base + addr, b, bytes) != 0) || copy_to_user(lg->mem_base + addr, b, bytes) != 0)
kill_guest(lg, "bad write address %#lx len %u", addr, bytes); kill_guest(lg, "bad write address %#lx len %u", addr, bytes);
} }
/* (end of memory access helper routines) :*/ /*:*/
/*H:030 Let's jump straight to the the main loop which runs the Guest. /*H:030 Let's jump straight to the the main loop which runs the Guest.
* Remember, this is called by the Launcher reading /dev/lguest, and we keep * Remember, this is called by the Launcher reading /dev/lguest, and we keep
......
...@@ -47,7 +47,7 @@ static void do_hcall(struct lguest *lg, struct hcall_args *args) ...@@ -47,7 +47,7 @@ static void do_hcall(struct lguest *lg, struct hcall_args *args)
char msg[128]; char msg[128];
/* If the lgread fails, it will call kill_guest() itself; the /* If the lgread fails, it will call kill_guest() itself; the
* kill_guest() with the message will be ignored. */ * kill_guest() with the message will be ignored. */
lgread(lg, msg, args->arg1, sizeof(msg)); __lgread(lg, msg, args->arg1, sizeof(msg));
msg[sizeof(msg)-1] = '\0'; msg[sizeof(msg)-1] = '\0';
kill_guest(lg, "CRASH: %s", msg); kill_guest(lg, "CRASH: %s", msg);
break; break;
......
...@@ -45,7 +45,7 @@ static void push_guest_stack(struct lguest *lg, unsigned long *gstack, u32 val) ...@@ -45,7 +45,7 @@ static void push_guest_stack(struct lguest *lg, unsigned long *gstack, u32 val)
{ {
/* Stack grows upwards: move stack then write value. */ /* Stack grows upwards: move stack then write value. */
*gstack -= 4; *gstack -= 4;
lgwrite_u32(lg, *gstack, val); lgwrite(lg, *gstack, u32, val);
} }
/*H:210 The set_guest_interrupt() routine actually delivers the interrupt or /*H:210 The set_guest_interrupt() routine actually delivers the interrupt or
......
...@@ -98,12 +98,27 @@ struct lguest ...@@ -98,12 +98,27 @@ struct lguest
extern struct mutex lguest_lock; extern struct mutex lguest_lock;
/* core.c: */ /* core.c: */
u32 lgread_u32(struct lguest *lg, unsigned long addr);
void lgwrite_u32(struct lguest *lg, unsigned long addr, u32 val);
void lgread(struct lguest *lg, void *buf, unsigned long addr, unsigned len);
void lgwrite(struct lguest *lg, unsigned long, const void *buf, unsigned len);
int lguest_address_ok(const struct lguest *lg, int lguest_address_ok(const struct lguest *lg,
unsigned long addr, unsigned long len); unsigned long addr, unsigned long len);
void __lgread(struct lguest *, void *, unsigned long, unsigned);
void __lgwrite(struct lguest *, unsigned long, const void *, unsigned);
/*L:306 Using memory-copy operations like that is usually inconvient, so we
* have the following helper macros which read and write a specific type (often
* an unsigned long).
*
* This reads into a variable of the given type then returns that. */
#define lgread(lg, addr, type) \
({ type _v; __lgread((lg), &_v, (addr), sizeof(_v)); _v; })
/* This checks that the variable is of the given type, then writes it out. */
#define lgwrite(lg, addr, type, val) \
do { \
typecheck(type, val); \
__lgwrite((lg), (addr), &(val), sizeof(val)); \
} while(0)
/* (end of memory access helper routines) :*/
int run_guest(struct lguest *lg, unsigned long __user *user); int run_guest(struct lguest *lg, unsigned long __user *user);
/* Helper macros to obtain the first 12 or the last 20 bits, this is only the /* Helper macros to obtain the first 12 or the last 20 bits, this is only the
......
...@@ -209,7 +209,7 @@ int demand_page(struct lguest *lg, unsigned long vaddr, int errcode) ...@@ -209,7 +209,7 @@ int demand_page(struct lguest *lg, unsigned long vaddr, int errcode)
pte_t *spte; pte_t *spte;
/* First step: get the top-level Guest page table entry. */ /* First step: get the top-level Guest page table entry. */
gpgd = __pgd(lgread_u32(lg, gpgd_addr(lg, vaddr))); gpgd = lgread(lg, gpgd_addr(lg, vaddr), pgd_t);
/* Toplevel not present? We can't map it in. */ /* Toplevel not present? We can't map it in. */
if (!(pgd_flags(gpgd) & _PAGE_PRESENT)) if (!(pgd_flags(gpgd) & _PAGE_PRESENT))
return 0; return 0;
...@@ -235,7 +235,7 @@ int demand_page(struct lguest *lg, unsigned long vaddr, int errcode) ...@@ -235,7 +235,7 @@ int demand_page(struct lguest *lg, unsigned long vaddr, int errcode)
/* OK, now we look at the lower level in the Guest page table: keep its /* OK, now we look at the lower level in the Guest page table: keep its
* address, because we might update it later. */ * address, because we might update it later. */
gpte_ptr = gpte_addr(lg, gpgd, vaddr); gpte_ptr = gpte_addr(lg, gpgd, vaddr);
gpte = __pte(lgread_u32(lg, gpte_ptr)); gpte = lgread(lg, gpte_ptr, pte_t);
/* If this page isn't in the Guest page tables, we can't page it in. */ /* If this page isn't in the Guest page tables, we can't page it in. */
if (!(pte_flags(gpte) & _PAGE_PRESENT)) if (!(pte_flags(gpte) & _PAGE_PRESENT))
...@@ -278,7 +278,7 @@ int demand_page(struct lguest *lg, unsigned long vaddr, int errcode) ...@@ -278,7 +278,7 @@ int demand_page(struct lguest *lg, unsigned long vaddr, int errcode)
/* Finally, we write the Guest PTE entry back: we've set the /* Finally, we write the Guest PTE entry back: we've set the
* _PAGE_ACCESSED and maybe the _PAGE_DIRTY flags. */ * _PAGE_ACCESSED and maybe the _PAGE_DIRTY flags. */
lgwrite_u32(lg, gpte_ptr, pte_val(gpte)); lgwrite(lg, gpte_ptr, pte_t, gpte);
/* We succeeded in mapping the page! */ /* We succeeded in mapping the page! */
return 1; return 1;
...@@ -366,12 +366,12 @@ unsigned long guest_pa(struct lguest *lg, unsigned long vaddr) ...@@ -366,12 +366,12 @@ unsigned long guest_pa(struct lguest *lg, unsigned long vaddr)
pte_t gpte; pte_t gpte;
/* First step: get the top-level Guest page table entry. */ /* First step: get the top-level Guest page table entry. */
gpgd = __pgd(lgread_u32(lg, gpgd_addr(lg, vaddr))); gpgd = lgread(lg, gpgd_addr(lg, vaddr), pgd_t);
/* Toplevel not present? We can't map it in. */ /* Toplevel not present? We can't map it in. */
if (!(pgd_flags(gpgd) & _PAGE_PRESENT)) if (!(pgd_flags(gpgd) & _PAGE_PRESENT))
kill_guest(lg, "Bad address %#lx", vaddr); kill_guest(lg, "Bad address %#lx", vaddr);
gpte = __pte(lgread_u32(lg, gpte_addr(lg, gpgd, vaddr))); gpte = lgread(lg, gpte_addr(lg, gpgd, vaddr), pte_t);
if (!(pte_flags(gpte) & _PAGE_PRESENT)) if (!(pte_flags(gpte) & _PAGE_PRESENT))
kill_guest(lg, "Bad address %#lx", vaddr); kill_guest(lg, "Bad address %#lx", vaddr);
......
...@@ -150,7 +150,7 @@ void load_guest_gdt(struct lguest *lg, unsigned long table, u32 num) ...@@ -150,7 +150,7 @@ void load_guest_gdt(struct lguest *lg, unsigned long table, u32 num)
kill_guest(lg, "too many gdt entries %i", num); kill_guest(lg, "too many gdt entries %i", num);
/* We read the whole thing in, then fix it up. */ /* We read the whole thing in, then fix it up. */
lgread(lg, lg->arch.gdt, table, num * sizeof(lg->arch.gdt[0])); __lgread(lg, lg->arch.gdt, table, num * sizeof(lg->arch.gdt[0]));
fixup_gdt_table(lg, 0, ARRAY_SIZE(lg->arch.gdt)); fixup_gdt_table(lg, 0, ARRAY_SIZE(lg->arch.gdt));
/* Mark that the GDT changed so the core knows it has to copy it again, /* Mark that the GDT changed so the core knows it has to copy it again,
* even if the Guest is run on the same CPU. */ * even if the Guest is run on the same CPU. */
...@@ -161,7 +161,7 @@ void guest_load_tls(struct lguest *lg, unsigned long gtls) ...@@ -161,7 +161,7 @@ void guest_load_tls(struct lguest *lg, unsigned long gtls)
{ {
struct desc_struct *tls = &lg->arch.gdt[GDT_ENTRY_TLS_MIN]; struct desc_struct *tls = &lg->arch.gdt[GDT_ENTRY_TLS_MIN];
lgread(lg, tls, gtls, sizeof(*tls)*GDT_ENTRY_TLS_ENTRIES); __lgread(lg, tls, gtls, sizeof(*tls)*GDT_ENTRY_TLS_ENTRIES);
fixup_gdt_table(lg, GDT_ENTRY_TLS_MIN, GDT_ENTRY_TLS_MAX+1); fixup_gdt_table(lg, GDT_ENTRY_TLS_MIN, GDT_ENTRY_TLS_MAX+1);
lg->changed |= CHANGED_GDT_TLS; lg->changed |= CHANGED_GDT_TLS;
} }
......
...@@ -222,7 +222,7 @@ static int emulate_insn(struct lguest *lg) ...@@ -222,7 +222,7 @@ static int emulate_insn(struct lguest *lg)
return 0; return 0;
/* Decoding x86 instructions is icky. */ /* Decoding x86 instructions is icky. */
lgread(lg, &insn, physaddr, 1); insn = lgread(lg, physaddr, u8);
/* 0x66 is an "operand prefix". It means it's using the upper 16 bits /* 0x66 is an "operand prefix". It means it's using the upper 16 bits
of the eax register. */ of the eax register. */
...@@ -230,7 +230,7 @@ static int emulate_insn(struct lguest *lg) ...@@ -230,7 +230,7 @@ static int emulate_insn(struct lguest *lg)
shift = 16; shift = 16;
/* The instruction is 1 byte so far, read the next byte. */ /* The instruction is 1 byte so far, read the next byte. */
insnlen = 1; insnlen = 1;
lgread(lg, &insn, physaddr + insnlen, 1); insn = lgread(lg, physaddr + insnlen, u8);
} }
/* We can ignore the lower bit for the moment and decode the 4 opcodes /* We can ignore the lower bit for the moment and decode the 4 opcodes
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册