suppressed page_unprotect_range() - fixed access_ok()
authorbellard <bellard@c046a42c-6fe2-441c-8c8c-71466251a162>
Wed, 14 Nov 2007 10:51:00 +0000 (10:51 +0000)
committerbellard <bellard@c046a42c-6fe2-441c-8c8c-71466251a162>
Wed, 14 Nov 2007 10:51:00 +0000 (10:51 +0000)
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3641 c046a42c-6fe2-441c-8c8c-71466251a162

cpu-all.h
exec.c
linux-user/qemu.h
linux-user/syscall.c

index 76daec9..f4db592 100644 (file)
--- a/cpu-all.h
+++ b/cpu-all.h
@@ -690,7 +690,6 @@ extern unsigned long qemu_host_page_mask;
 void page_dump(FILE *f);
 int page_get_flags(target_ulong address);
 void page_set_flags(target_ulong start, target_ulong end, int flags);
-void page_unprotect_range(target_ulong data, target_ulong data_size);
 int page_check_range(target_ulong start, target_ulong len, int flags);
 
 CPUState *cpu_copy(CPUState *env);
diff --git a/exec.c b/exec.c
index e817a4e..6384df2 100644 (file)
--- a/exec.c
+++ b/exec.c
@@ -1894,10 +1894,19 @@ int page_check_range(target_ulong start, target_ulong len, int flags)
         if( !(p->flags & PAGE_VALID) )
             return -1;
 
-        if (!(p->flags & PAGE_READ) && (flags & PAGE_READ) )
-            return -1;
-        if (!(p->flags & PAGE_WRITE) && (flags & PAGE_WRITE) )
+        if ((flags & PAGE_READ) && !(p->flags & PAGE_READ))
             return -1;
+        if (flags & PAGE_WRITE) {
+            if (!(p->flags & PAGE_WRITE_ORG))
+                return -1;
+            /* unprotect the page if it was put read-only because it
+               contains translated code */
+            if (!(p->flags & PAGE_WRITE)) {
+                if (!page_unprotect(addr, 0, NULL))
+                    return -1;
+            }
+            return 0;
+        }
     }
     return 0;
 }
@@ -1942,21 +1951,6 @@ int page_unprotect(target_ulong address, unsigned long pc, void *puc)
     return 0;
 }
 
-/* call this function when system calls directly modify a memory area */
-/* ??? This should be redundant now we have lock_user.  */
-void page_unprotect_range(target_ulong data, target_ulong data_size)
-{
-    target_ulong start, end, addr;
-
-    start = data;
-    end = start + data_size;
-    start &= TARGET_PAGE_MASK;
-    end = TARGET_PAGE_ALIGN(end);
-    for(addr = start; addr < end; addr += TARGET_PAGE_SIZE) {
-        page_unprotect(addr, 0, NULL);
-    }
-}
-
 static inline void tlb_set_dirty(CPUState *env,
                                  unsigned long addr, target_ulong vaddr)
 {
index 581ee27..5917cb5 100644 (file)
@@ -207,8 +207,11 @@ int target_msync(abi_ulong start, abi_ulong len, int flags);
 #define VERIFY_READ 0
 #define VERIFY_WRITE 1 /* implies read access */
 
-#define access_ok(type,addr,size) \
-    (page_check_range((target_ulong)addr,size,(type==VERIFY_READ)?PAGE_READ:PAGE_WRITE)==0)
+static inline int access_ok(int type, abi_ulong addr, abi_ulong size)
+{
+    return page_check_range((target_ulong)addr, size,
+                            (type == VERIFY_READ) ? PAGE_READ : (PAGE_READ | PAGE_WRITE)) == 0;
+}
 
 /* NOTE __get_user and __put_user use host pointers and don't check access. */
 /* These are usually used to access struct data members once the
index 6c8f689..1e4ad96 100644 (file)
@@ -2773,7 +2773,6 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
         ret = 0; /* avoid warning */
         break;
     case TARGET_NR_read:
-        page_unprotect_range(arg2, arg3);
         if (!(p = lock_user(VERIFY_WRITE, arg2, arg3, 0)))
             goto efault;
         ret = get_errno(read(arg1, p, arg3));
@@ -4537,7 +4536,6 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
         break;
 #ifdef TARGET_NR_pread
     case TARGET_NR_pread:
-        page_unprotect_range(arg2, arg3);
         if (!(p = lock_user(VERIFY_WRITE, arg2, arg3, 0)))
             goto efault;
         ret = get_errno(pread(arg1, p, arg3, arg4));