diff options
author | Rusty Russell <rusty@rustcorp.com.au> | 2007-10-21 21:24:24 -0400 |
---|---|---|
committer | Rusty Russell <rusty@rustcorp.com.au> | 2007-10-23 01:49:56 -0400 |
commit | 2d37f94a28170ca656438758fca577acb49a7932 (patch) | |
tree | 21049219a98d314a2c442293e512b74d879e6270 /drivers | |
parent | 56ae43dfe233323683248a5c553bad7160db2fa5 (diff) |
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: Rusty Russell <rusty@rustcorp.com.au>
Acked-by: Jes Sorensen <jes@sgi.com>
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/lguest/core.c | 39 | ||||
-rw-r--r-- | drivers/lguest/hypercalls.c | 2 | ||||
-rw-r--r-- | drivers/lguest/interrupts_and_traps.c | 2 | ||||
-rw-r--r-- | drivers/lguest/lg.h | 23 | ||||
-rw-r--r-- | drivers/lguest/page_tables.c | 10 | ||||
-rw-r--r-- | drivers/lguest/segments.c | 4 | ||||
-rw-r--r-- | drivers/lguest/x86/core.c | 4 |
7 files changed, 38 insertions, 46 deletions
diff --git a/drivers/lguest/core.c b/drivers/lguest/core.c index 3aec29ec7715..35d19ae58de7 100644 --- a/drivers/lguest/core.c +++ b/drivers/lguest/core.c | |||
@@ -145,33 +145,10 @@ int lguest_address_ok(const struct lguest *lg, | |||
145 | return (addr+len) / PAGE_SIZE < lg->pfn_limit && (addr+len >= addr); | 145 | return (addr+len) / PAGE_SIZE < lg->pfn_limit && (addr+len >= addr); |
146 | } | 146 | } |
147 | 147 | ||
148 | /* This is a convenient routine to get a 32-bit value from the Guest (a very | 148 | /* This routine copies memory from the Guest. Here we can see how useful the |
149 | * common operation). Here we can see how useful the kill_lguest() routine we | 149 | * kill_lguest() routine we met in the Launcher can be: we return a random |
150 | * met in the Launcher can be: we return a random value (0) instead of needing | 150 | * value (all zeroes) instead of needing to return an error. */ |
151 | * to return an error. */ | 151 | void __lgread(struct lguest *lg, void *b, unsigned long addr, unsigned bytes) |
152 | u32 lgread_u32(struct lguest *lg, unsigned long addr) | ||
153 | { | ||
154 | u32 val = 0; | ||
155 | |||
156 | /* Don't let them access lguest binary. */ | ||
157 | if (!lguest_address_ok(lg, addr, sizeof(val)) | ||
158 | || get_user(val, (u32 *)(lg->mem_base + addr)) != 0) | ||
159 | kill_guest(lg, "bad read address %#lx: pfn_limit=%u membase=%p", addr, lg->pfn_limit, lg->mem_base); | ||
160 | return val; | ||
161 | } | ||
162 | |||
163 | /* Same thing for writing a value. */ | ||
164 | void lgwrite_u32(struct lguest *lg, unsigned long addr, u32 val) | ||
165 | { | ||
166 | if (!lguest_address_ok(lg, addr, sizeof(val)) | ||
167 | || put_user(val, (u32 *)(lg->mem_base + addr)) != 0) | ||
168 | kill_guest(lg, "bad write address %#lx", addr); | ||
169 | } | ||
170 | |||
171 | /* This routine is more generic, and copies a range of Guest bytes into a | ||
172 | * buffer. If the copy_from_user() fails, we fill the buffer with zeroes, so | ||
173 | * the caller doesn't end up using uninitialized kernel memory. */ | ||
174 | void lgread(struct lguest *lg, void *b, unsigned long addr, unsigned bytes) | ||
175 | { | 152 | { |
176 | if (!lguest_address_ok(lg, addr, bytes) | 153 | if (!lguest_address_ok(lg, addr, bytes) |
177 | || copy_from_user(b, lg->mem_base + addr, bytes) != 0) { | 154 | || 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 | } | 158 | } |
182 | } | 159 | } |
183 | 160 | ||
184 | /* Similarly, our generic routine to copy into a range of Guest bytes. */ | 161 | /* This is the write (copy into guest) version. */ |
185 | void lgwrite(struct lguest *lg, unsigned long addr, const void *b, | 162 | void __lgwrite(struct lguest *lg, unsigned long addr, const void *b, |
186 | unsigned bytes) | 163 | unsigned bytes) |
187 | { | 164 | { |
188 | if (!lguest_address_ok(lg, addr, bytes) | 165 | if (!lguest_address_ok(lg, addr, bytes) |
189 | || copy_to_user(lg->mem_base + addr, b, bytes) != 0) | 166 | || copy_to_user(lg->mem_base + addr, b, bytes) != 0) |
190 | kill_guest(lg, "bad write address %#lx len %u", addr, bytes); | 167 | kill_guest(lg, "bad write address %#lx len %u", addr, bytes); |
191 | } | 168 | } |
192 | /* (end of memory access helper routines) :*/ | 169 | /*:*/ |
193 | 170 | ||
194 | /*H:030 Let's jump straight to the the main loop which runs the Guest. | 171 | /*H:030 Let's jump straight to the the main loop which runs the Guest. |
195 | * Remember, this is called by the Launcher reading /dev/lguest, and we keep | 172 | * Remember, this is called by the Launcher reading /dev/lguest, and we keep |
diff --git a/drivers/lguest/hypercalls.c b/drivers/lguest/hypercalls.c index 3a53788ba450..9d5184c7c14a 100644 --- a/drivers/lguest/hypercalls.c +++ b/drivers/lguest/hypercalls.c | |||
@@ -47,7 +47,7 @@ static void do_hcall(struct lguest *lg, struct hcall_args *args) | |||
47 | char msg[128]; | 47 | char msg[128]; |
48 | /* If the lgread fails, it will call kill_guest() itself; the | 48 | /* If the lgread fails, it will call kill_guest() itself; the |
49 | * kill_guest() with the message will be ignored. */ | 49 | * kill_guest() with the message will be ignored. */ |
50 | lgread(lg, msg, args->arg1, sizeof(msg)); | 50 | __lgread(lg, msg, args->arg1, sizeof(msg)); |
51 | msg[sizeof(msg)-1] = '\0'; | 51 | msg[sizeof(msg)-1] = '\0'; |
52 | kill_guest(lg, "CRASH: %s", msg); | 52 | kill_guest(lg, "CRASH: %s", msg); |
53 | break; | 53 | break; |
diff --git a/drivers/lguest/interrupts_and_traps.c b/drivers/lguest/interrupts_and_traps.c index 3271c0031a1b..82966982cb38 100644 --- a/drivers/lguest/interrupts_and_traps.c +++ b/drivers/lguest/interrupts_and_traps.c | |||
@@ -45,7 +45,7 @@ static void push_guest_stack(struct lguest *lg, unsigned long *gstack, u32 val) | |||
45 | { | 45 | { |
46 | /* Stack grows upwards: move stack then write value. */ | 46 | /* Stack grows upwards: move stack then write value. */ |
47 | *gstack -= 4; | 47 | *gstack -= 4; |
48 | lgwrite_u32(lg, *gstack, val); | 48 | lgwrite(lg, *gstack, u32, val); |
49 | } | 49 | } |
50 | 50 | ||
51 | /*H:210 The set_guest_interrupt() routine actually delivers the interrupt or | 51 | /*H:210 The set_guest_interrupt() routine actually delivers the interrupt or |
diff --git a/drivers/lguest/lg.h b/drivers/lguest/lg.h index 4d45b7036e82..d9144beca82c 100644 --- a/drivers/lguest/lg.h +++ b/drivers/lguest/lg.h | |||
@@ -98,12 +98,27 @@ struct lguest | |||
98 | extern struct mutex lguest_lock; | 98 | extern struct mutex lguest_lock; |
99 | 99 | ||
100 | /* core.c: */ | 100 | /* core.c: */ |
101 | u32 lgread_u32(struct lguest *lg, unsigned long addr); | ||
102 | void lgwrite_u32(struct lguest *lg, unsigned long addr, u32 val); | ||
103 | void lgread(struct lguest *lg, void *buf, unsigned long addr, unsigned len); | ||
104 | void lgwrite(struct lguest *lg, unsigned long, const void *buf, unsigned len); | ||
105 | int lguest_address_ok(const struct lguest *lg, | 101 | int lguest_address_ok(const struct lguest *lg, |
106 | unsigned long addr, unsigned long len); | 102 | unsigned long addr, unsigned long len); |
103 | void __lgread(struct lguest *, void *, unsigned long, unsigned); | ||
104 | void __lgwrite(struct lguest *, unsigned long, const void *, unsigned); | ||
105 | |||
106 | /*L:306 Using memory-copy operations like that is usually inconvient, so we | ||
107 | * have the following helper macros which read and write a specific type (often | ||
108 | * an unsigned long). | ||
109 | * | ||
110 | * This reads into a variable of the given type then returns that. */ | ||
111 | #define lgread(lg, addr, type) \ | ||
112 | ({ type _v; __lgread((lg), &_v, (addr), sizeof(_v)); _v; }) | ||
113 | |||
114 | /* This checks that the variable is of the given type, then writes it out. */ | ||
115 | #define lgwrite(lg, addr, type, val) \ | ||
116 | do { \ | ||
117 | typecheck(type, val); \ | ||
118 | __lgwrite((lg), (addr), &(val), sizeof(val)); \ | ||
119 | } while(0) | ||
120 | /* (end of memory access helper routines) :*/ | ||
121 | |||
107 | int run_guest(struct lguest *lg, unsigned long __user *user); | 122 | int run_guest(struct lguest *lg, unsigned long __user *user); |
108 | 123 | ||
109 | /* Helper macros to obtain the first 12 or the last 20 bits, this is only the | 124 | /* Helper macros to obtain the first 12 or the last 20 bits, this is only the |
diff --git a/drivers/lguest/page_tables.c b/drivers/lguest/page_tables.c index fe3c7575647b..2a45f0691c9b 100644 --- a/drivers/lguest/page_tables.c +++ b/drivers/lguest/page_tables.c | |||
@@ -209,7 +209,7 @@ int demand_page(struct lguest *lg, unsigned long vaddr, int errcode) | |||
209 | pte_t *spte; | 209 | pte_t *spte; |
210 | 210 | ||
211 | /* First step: get the top-level Guest page table entry. */ | 211 | /* First step: get the top-level Guest page table entry. */ |
212 | gpgd = __pgd(lgread_u32(lg, gpgd_addr(lg, vaddr))); | 212 | gpgd = lgread(lg, gpgd_addr(lg, vaddr), pgd_t); |
213 | /* Toplevel not present? We can't map it in. */ | 213 | /* Toplevel not present? We can't map it in. */ |
214 | if (!(pgd_flags(gpgd) & _PAGE_PRESENT)) | 214 | if (!(pgd_flags(gpgd) & _PAGE_PRESENT)) |
215 | return 0; | 215 | return 0; |
@@ -235,7 +235,7 @@ int demand_page(struct lguest *lg, unsigned long vaddr, int errcode) | |||
235 | /* OK, now we look at the lower level in the Guest page table: keep its | 235 | /* OK, now we look at the lower level in the Guest page table: keep its |
236 | * address, because we might update it later. */ | 236 | * address, because we might update it later. */ |
237 | gpte_ptr = gpte_addr(lg, gpgd, vaddr); | 237 | gpte_ptr = gpte_addr(lg, gpgd, vaddr); |
238 | gpte = __pte(lgread_u32(lg, gpte_ptr)); | 238 | gpte = lgread(lg, gpte_ptr, pte_t); |
239 | 239 | ||
240 | /* If this page isn't in the Guest page tables, we can't page it in. */ | 240 | /* If this page isn't in the Guest page tables, we can't page it in. */ |
241 | if (!(pte_flags(gpte) & _PAGE_PRESENT)) | 241 | if (!(pte_flags(gpte) & _PAGE_PRESENT)) |
@@ -278,7 +278,7 @@ int demand_page(struct lguest *lg, unsigned long vaddr, int errcode) | |||
278 | 278 | ||
279 | /* Finally, we write the Guest PTE entry back: we've set the | 279 | /* Finally, we write the Guest PTE entry back: we've set the |
280 | * _PAGE_ACCESSED and maybe the _PAGE_DIRTY flags. */ | 280 | * _PAGE_ACCESSED and maybe the _PAGE_DIRTY flags. */ |
281 | lgwrite_u32(lg, gpte_ptr, pte_val(gpte)); | 281 | lgwrite(lg, gpte_ptr, pte_t, gpte); |
282 | 282 | ||
283 | /* We succeeded in mapping the page! */ | 283 | /* We succeeded in mapping the page! */ |
284 | return 1; | 284 | return 1; |
@@ -366,12 +366,12 @@ unsigned long guest_pa(struct lguest *lg, unsigned long vaddr) | |||
366 | pte_t gpte; | 366 | pte_t gpte; |
367 | 367 | ||
368 | /* First step: get the top-level Guest page table entry. */ | 368 | /* First step: get the top-level Guest page table entry. */ |
369 | gpgd = __pgd(lgread_u32(lg, gpgd_addr(lg, vaddr))); | 369 | gpgd = lgread(lg, gpgd_addr(lg, vaddr), pgd_t); |
370 | /* Toplevel not present? We can't map it in. */ | 370 | /* Toplevel not present? We can't map it in. */ |
371 | if (!(pgd_flags(gpgd) & _PAGE_PRESENT)) | 371 | if (!(pgd_flags(gpgd) & _PAGE_PRESENT)) |
372 | kill_guest(lg, "Bad address %#lx", vaddr); | 372 | kill_guest(lg, "Bad address %#lx", vaddr); |
373 | 373 | ||
374 | gpte = __pte(lgread_u32(lg, gpte_addr(lg, gpgd, vaddr))); | 374 | gpte = lgread(lg, gpte_addr(lg, gpgd, vaddr), pte_t); |
375 | if (!(pte_flags(gpte) & _PAGE_PRESENT)) | 375 | if (!(pte_flags(gpte) & _PAGE_PRESENT)) |
376 | kill_guest(lg, "Bad address %#lx", vaddr); | 376 | kill_guest(lg, "Bad address %#lx", vaddr); |
377 | 377 | ||
diff --git a/drivers/lguest/segments.c b/drivers/lguest/segments.c index 95eb9cf297bf..c2434ec99f7b 100644 --- a/drivers/lguest/segments.c +++ b/drivers/lguest/segments.c | |||
@@ -150,7 +150,7 @@ void load_guest_gdt(struct lguest *lg, unsigned long table, u32 num) | |||
150 | kill_guest(lg, "too many gdt entries %i", num); | 150 | kill_guest(lg, "too many gdt entries %i", num); |
151 | 151 | ||
152 | /* We read the whole thing in, then fix it up. */ | 152 | /* We read the whole thing in, then fix it up. */ |
153 | lgread(lg, lg->arch.gdt, table, num * sizeof(lg->arch.gdt[0])); | 153 | __lgread(lg, lg->arch.gdt, table, num * sizeof(lg->arch.gdt[0])); |
154 | fixup_gdt_table(lg, 0, ARRAY_SIZE(lg->arch.gdt)); | 154 | fixup_gdt_table(lg, 0, ARRAY_SIZE(lg->arch.gdt)); |
155 | /* Mark that the GDT changed so the core knows it has to copy it again, | 155 | /* Mark that the GDT changed so the core knows it has to copy it again, |
156 | * even if the Guest is run on the same CPU. */ | 156 | * 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 | { | 161 | { |
162 | struct desc_struct *tls = &lg->arch.gdt[GDT_ENTRY_TLS_MIN]; | 162 | struct desc_struct *tls = &lg->arch.gdt[GDT_ENTRY_TLS_MIN]; |
163 | 163 | ||
164 | lgread(lg, tls, gtls, sizeof(*tls)*GDT_ENTRY_TLS_ENTRIES); | 164 | __lgread(lg, tls, gtls, sizeof(*tls)*GDT_ENTRY_TLS_ENTRIES); |
165 | fixup_gdt_table(lg, GDT_ENTRY_TLS_MIN, GDT_ENTRY_TLS_MAX+1); | 165 | fixup_gdt_table(lg, GDT_ENTRY_TLS_MIN, GDT_ENTRY_TLS_MAX+1); |
166 | lg->changed |= CHANGED_GDT_TLS; | 166 | lg->changed |= CHANGED_GDT_TLS; |
167 | } | 167 | } |
diff --git a/drivers/lguest/x86/core.c b/drivers/lguest/x86/core.c index ef976ccb4192..9eed12d5a395 100644 --- a/drivers/lguest/x86/core.c +++ b/drivers/lguest/x86/core.c | |||
@@ -222,7 +222,7 @@ static int emulate_insn(struct lguest *lg) | |||
222 | return 0; | 222 | return 0; |
223 | 223 | ||
224 | /* Decoding x86 instructions is icky. */ | 224 | /* Decoding x86 instructions is icky. */ |
225 | lgread(lg, &insn, physaddr, 1); | 225 | insn = lgread(lg, physaddr, u8); |
226 | 226 | ||
227 | /* 0x66 is an "operand prefix". It means it's using the upper 16 bits | 227 | /* 0x66 is an "operand prefix". It means it's using the upper 16 bits |
228 | of the eax register. */ | 228 | of the eax register. */ |
@@ -230,7 +230,7 @@ static int emulate_insn(struct lguest *lg) | |||
230 | shift = 16; | 230 | shift = 16; |
231 | /* The instruction is 1 byte so far, read the next byte. */ | 231 | /* The instruction is 1 byte so far, read the next byte. */ |
232 | insnlen = 1; | 232 | insnlen = 1; |
233 | lgread(lg, &insn, physaddr + insnlen, 1); | 233 | insn = lgread(lg, physaddr + insnlen, u8); |
234 | } | 234 | } |
235 | 235 | ||
236 | /* We can ignore the lower bit for the moment and decode the 4 opcodes | 236 | /* We can ignore the lower bit for the moment and decode the 4 opcodes |