Commit dde79789 authored by Rusty Russell's avatar Rusty Russell Committed by Linus Torvalds

lguest: documentation IV: Launcher

Documentation: The Launcher
Signed-off-by: default avatarRusty Russell <rusty@rustcorp.com.au>
Signed-off-by: default avatarAndrew Morton <akpm@linux-foundation.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@linux-foundation.org>
parent e2c97843
This diff is collapsed.
...@@ -208,24 +208,39 @@ static int emulate_insn(struct lguest *lg) ...@@ -208,24 +208,39 @@ static int emulate_insn(struct lguest *lg)
return 1; return 1;
} }
/*L:305
* Dealing With Guest Memory.
*
* When the Guest gives us (what it thinks is) a physical address, we can use
* the normal copy_from_user() & copy_to_user() on that address: remember,
* Guest physical == Launcher virtual.
*
* But we can't trust the Guest: it might be trying to access the Launcher
* code. We have to check that the range is below the pfn_limit the Launcher
* gave us. We have to make sure that addr + len doesn't give us a false
* positive by overflowing, too. */
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)
{ {
return (addr+len) / PAGE_SIZE < lg->pfn_limit && (addr+len >= addr); return (addr+len) / PAGE_SIZE < lg->pfn_limit && (addr+len >= addr);
} }
/* Just like get_user, but don't let guest access lguest binary. */ /* This is a convenient routine to get a 32-bit value from the Guest (a very
* common operation). Here we can see how useful the kill_lguest() routine we
* met in the Launcher can be: we return a random value (0) instead of needing
* to return an error. */
u32 lgread_u32(struct lguest *lg, unsigned long addr) u32 lgread_u32(struct lguest *lg, unsigned long addr)
{ {
u32 val = 0; u32 val = 0;
/* Don't let them access lguest binary */ /* Don't let them access lguest binary. */
if (!lguest_address_ok(lg, addr, sizeof(val)) if (!lguest_address_ok(lg, addr, sizeof(val))
|| get_user(val, (u32 __user *)addr) != 0) || get_user(val, (u32 __user *)addr) != 0)
kill_guest(lg, "bad read address %#lx", addr); kill_guest(lg, "bad read address %#lx", addr);
return val; return val;
} }
/* Same thing for writing a value. */
void lgwrite_u32(struct lguest *lg, unsigned long addr, u32 val) void lgwrite_u32(struct lguest *lg, unsigned long addr, u32 val)
{ {
if (!lguest_address_ok(lg, addr, sizeof(val)) if (!lguest_address_ok(lg, addr, sizeof(val))
...@@ -233,6 +248,9 @@ void lgwrite_u32(struct lguest *lg, unsigned long addr, u32 val) ...@@ -233,6 +248,9 @@ void lgwrite_u32(struct lguest *lg, unsigned long addr, u32 val)
kill_guest(lg, "bad write address %#lx", addr); 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) 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)
...@@ -243,6 +261,7 @@ void lgread(struct lguest *lg, void *b, unsigned long addr, unsigned bytes) ...@@ -243,6 +261,7 @@ void lgread(struct lguest *lg, void *b, unsigned long addr, unsigned bytes)
} }
} }
/* Similarly, our generic routine to copy into a range of Guest bytes. */
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)
{ {
...@@ -250,6 +269,7 @@ void lgwrite(struct lguest *lg, unsigned long addr, const void *b, ...@@ -250,6 +269,7 @@ void lgwrite(struct lguest *lg, unsigned long addr, const void *b,
|| copy_to_user((void __user *)addr, b, bytes) != 0) || copy_to_user((void __user *)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) :*/
static void set_ts(void) static void set_ts(void)
{ {
......
This diff is collapsed.
...@@ -244,6 +244,30 @@ unsigned long get_dma_buffer(struct lguest *lg, unsigned long key, ...@@ -244,6 +244,30 @@ unsigned long get_dma_buffer(struct lguest *lg, unsigned long key,
/* hypercalls.c: */ /* hypercalls.c: */
void do_hypercalls(struct lguest *lg); void do_hypercalls(struct lguest *lg);
/*L:035
* Let's step aside for the moment, to study one important routine that's used
* widely in the Host code.
*
* There are many cases where the Guest does something invalid, like pass crap
* to a hypercall. Since only the Guest kernel can make hypercalls, it's quite
* acceptable to simply terminate the Guest and give the Launcher a nicely
* formatted reason. It's also simpler for the Guest itself, which doesn't
* need to check most hypercalls for "success"; if you're still running, it
* succeeded.
*
* Once this is called, the Guest will never run again, so most Host code can
* call this then continue as if nothing had happened. This means many
* functions don't have to explicitly return an error code, which keeps the
* code simple.
*
* It also means that this can be called more than once: only the first one is
* remembered. The only trick is that we still need to kill the Guest even if
* we can't allocate memory to store the reason. Linux has a neat way of
* packing error codes into invalid pointers, so we use that here.
*
* Like any macro which uses an "if", it is safely wrapped in a run-once "do {
* } while(0)".
*/
#define kill_guest(lg, fmt...) \ #define kill_guest(lg, fmt...) \
do { \ do { \
if (!(lg)->dead) { \ if (!(lg)->dead) { \
...@@ -252,6 +276,7 @@ do { \ ...@@ -252,6 +276,7 @@ do { \
(lg)->dead = ERR_PTR(-ENOMEM); \ (lg)->dead = ERR_PTR(-ENOMEM); \
} \ } \
} while(0) } while(0)
/* (End of aside) :*/
static inline unsigned long guest_pa(struct lguest *lg, unsigned long vaddr) static inline unsigned long guest_pa(struct lguest *lg, unsigned long vaddr)
{ {
......
This diff is collapsed.
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment