Cache-buster syscall, sync and async varieties
authorBarret Rhoden <brho@cs.berkeley.edu>
Mon, 11 May 2009 01:10:45 +0000 (18:10 -0700)
committerBarret Rhoden <brho@cs.berkeley.edu>
Mon, 11 May 2009 01:10:45 +0000 (18:10 -0700)
Just grabs a lock and writes a value to a certain number of entries to
an array in kernel space.  Right now, the array is sitting at
0xd0000000, which is far from being allocated for anything.

Also added a wrapper function to get both an async and a sys desc, which
seems to be the common case for a lot of syscalls.

inc/lib.h
inc/null.h
inc/syscall.h
kern/init.c
kern/syscall.c
lib/asynccall.c
lib/null.c
lib/syscall.c
user/null.c

index 6854879..b6abbbe 100644 (file)
--- a/inc/lib.h
+++ b/inc/lib.h
@@ -38,6 +38,9 @@ char* readline(const char *buf);
 // syscall.c
 void sys_null();
 error_t sys_null_async(syscall_desc_t* desc);
+void sys_cache_buster(uint32_t num_writes, uint32_t val);
+error_t sys_cache_buster_async(syscall_desc_t* desc, uint32_t num_writes,
+                               uint32_t val);
 void sys_cputs(const char *string, size_t len);
 error_t sys_cputs_async(const char *s, size_t len, syscall_desc_t* desc,
                      void (*cleanup_handler)(void*), void* cleanup_data);
@@ -55,9 +58,13 @@ typedef struct async_desc {
        void (*cleanup)(void* data);
        void* data;
 } async_desc_t;
+
+// Response to an async call.  Should be some sort of aggregation of the
+// syscall responses.
 typedef struct async_rsp_t {
        int32_t retval;
 } async_rsp_t;
+
 // This is per-thread, and used when entering a async library call to properly
 // group syscall_desc_t used during the processing of that async call
 extern async_desc_t* current_async_desc;
@@ -65,20 +72,18 @@ extern async_desc_t* current_async_desc;
 #include <inc/stdio.h>
 #include <inc/assert.h>
 
-
 // This pooltype contains syscall_desc_t, which is how you wait on one syscall.
 POOL_TYPE_DEFINE(syscall_desc_t, syscall_desc_pool, MAX_SYSCALLS);
 POOL_TYPE_DEFINE(async_desc_t, async_desc_pool, MAX_ASYNCCALLS);
+
 // These are declared in libmain.c
 extern syscall_desc_pool_t syscall_desc_pool;
 extern async_desc_pool_t async_desc_pool;
-// Finds a free async_desc_t, on which you can wait for a series of syscalls
-async_desc_t* get_async_desc(void);
-// Wait on all syscalls within this async call.  TODO - timeout or something?
+
 error_t waiton_async_call(async_desc_t* desc, async_rsp_t* rsp);
-// Finds a free sys_desc_t, on which you can wait for a specific syscall, and
-// binds it to the group desc.
+async_desc_t* get_async_desc(void);
 syscall_desc_t* get_sys_desc(async_desc_t* desc);
+error_t get_all_desc(async_desc_t** a_desc, syscall_desc_t** s_desc);
 
 
 /* File open modes */
index b7987ed..0665096 100644 (file)
@@ -3,5 +3,8 @@
 
 void null();
 error_t null_async(async_desc_t** desc);
+void cache_buster(uint32_t num_writes, uint32_t val);
+error_t cache_buster_async(async_desc_t** desc, uint32_t num_writes,
+                           uint32_t val);
 
 #endif // ROS_INC_NULL_H
index 2756ab3..fb8deb6 100644 (file)
@@ -9,6 +9,7 @@
 enum
 {
        SYS_null = 1,
+       SYS_cache_buster,
        SYS_cputs,
        SYS_cgetc,
        SYS_getenvid,
index 669d922..7efa471 100644 (file)
@@ -84,22 +84,22 @@ void kernel_init(multiboot_info_t *mboot_info)
        //ENV_CREATE(user_hello);
        //ENV_CREATE(user_hello);
        //ENV_CREATE(user_hello);
-       ENV_CREATE(user_null);
-       ENV_CREATE(user_null);
+       //ENV_CREATE(user_null);
+       //ENV_CREATE(user_null);
        ENV_CREATE(user_null);
 
        //env_run(&envs[0]);
        smp_call_function_single(2, run_env_handler, &envs[0], 0);
-       smp_call_function_single(4, run_env_handler, &envs[1], 0);
-       smp_call_function_single(6, run_env_handler, &envs[2], 0);
+       //smp_call_function_single(4, run_env_handler, &envs[1], 0);
+       //smp_call_function_single(6, run_env_handler, &envs[2], 0);
 
        // wait 5 sec, then print what's in shared mem
        udelay(5000000);
        printk("Servicing syscalls from Core 0:\n\n");
        while (1) {
                process_generic_syscalls(&envs[0], 1);
-               process_generic_syscalls(&envs[1], 1);
-               process_generic_syscalls(&envs[2], 1);
+               //process_generic_syscalls(&envs[1], 1);
+               //process_generic_syscalls(&envs[2], 1);
                cpu_relax();
        }
        panic("Don't Panic");
index 655d5f0..496d906 100644 (file)
@@ -20,6 +20,23 @@ static void sys_null(env_t* e)
        return;
 }
 
+// Writes 'val' to 'num_writes' entries of the well-known array in the kernel
+// address space.  It's just #defined to be some random 4MB chunk (which ought
+// to be boot_alloced or something).  Meant to grab exclusive access to cache
+// lines, to simulate doing something useful.
+static void sys_cache_buster(env_t* e, uint32_t num_writes, uint32_t val)
+{
+       #define BUSTER_ADDR 0xd0000000
+       #define MAX_WRITES 1048576
+       uint32_t* buster = (uint32_t*)BUSTER_ADDR;
+       static uint32_t buster_lock = 0;
+       
+       spin_lock(&buster_lock);
+       for (int i = 0; i < MIN(num_writes, MAX_WRITES); i++)
+               buster[i] = val;
+       spin_unlock(&buster_lock);
+}
+
 // Print a string to the system console.
 // The string is exactly 'len' characters long.
 // Destroys the environment on memory errors.
@@ -96,6 +113,9 @@ int32_t syscall(env_t* e, uint32_t syscallno, uint32_t a1, uint32_t a2,
                case SYS_null:
                        sys_null(e);
                        return 0;
+               case SYS_cache_buster:
+                       sys_cache_buster(e, a1, a2);
+                       return 0;
                case SYS_cputs:
                        sys_cputs(e, (char *DANGEROUS)a1, (size_t)a2);
                        return 0;  // would rather have this return the number of chars put.
index dcbdb74..dbf9eff 100644 (file)
@@ -2,15 +2,7 @@
 #include <inc/syscall.h>
 #include <inc/queue.h>
 
-async_desc_t* get_async_desc(void)
-{
-       async_desc_t* desc = POOL_GET(&async_desc_pool);
-       if (desc)
-               // Clear out any data that was in the old desc
-               memset(desc, 0, sizeof(*desc));
-       return desc;
-}
-
+// Wait on all syscalls within this async call.  TODO - timeout or something?
 error_t waiton_async_call(async_desc_t* desc, async_rsp_t* rsp)
 {
        syscall_rsp_t syscall_rsp;
@@ -40,6 +32,18 @@ error_t waiton_async_call(async_desc_t* desc, async_rsp_t* rsp)
        return err;
 }
 
+// Finds a free async_desc_t, on which you can wait for a series of syscalls
+async_desc_t* get_async_desc(void)
+{
+       async_desc_t* desc = POOL_GET(&async_desc_pool);
+       if (desc)
+               // Clear out any data that was in the old desc
+               memset(desc, 0, sizeof(*desc));
+       return desc;
+}
+
+// Finds a free sys_desc_t, on which you can wait for a specific syscall, and
+// binds it to the group desc.
 syscall_desc_t* get_sys_desc(async_desc_t* desc)
 {
        syscall_desc_t* d = POOL_GET(&syscall_desc_pool);
@@ -50,3 +54,20 @@ syscall_desc_t* get_sys_desc(async_desc_t* desc)
        }
        return d;
 }
+
+// Gets an async and a sys desc, with the sys bound to async.  Also sets
+// current_async_desc.  This is meant as an easy wrapper when there is only one
+// syscall for an async call.
+error_t get_all_desc(async_desc_t** a_desc, syscall_desc_t** s_desc)
+{
+       assert(a_desc && s_desc);
+       if ((current_async_desc = get_async_desc()) == NULL)
+               return E_BUSY;
+       *a_desc = current_async_desc;
+       if (*s_desc = get_sys_desc(current_async_desc))
+               return 0;
+       // in case we could get an async, but not a syscall desc, then clean up.
+       POOL_PUT(&async_desc_pool, current_async_desc);
+       current_async_desc = NULL;
+       return E_BUSY;
+}
index b6df173..35b4ad9 100644 (file)
@@ -13,8 +13,23 @@ void null()
 
 error_t null_async(async_desc_t** desc)
 {
-       if ((current_async_desc = get_async_desc()) == NULL)
-               return E_BUSY;
-       *desc = current_async_desc;
-       return sys_null_async(get_sys_desc(current_async_desc));
+       error_t e;
+       syscall_desc_t* sysdesc;
+       if (e = get_all_desc(desc, &sysdesc))
+               return e;
+       return sys_null_async(sysdesc);
+}
+
+void cache_buster(uint32_t num_writes, uint32_t val)
+{
+       sys_cache_buster(num_writes, val);
+}
+
+error_t cache_buster_async(async_desc_t** desc, uint32_t num_writes, uint32_t val)
+{
+       error_t e;
+       syscall_desc_t* sysdesc;
+       if (e = get_all_desc(desc, &sysdesc))
+               return e;
+       return sys_cache_buster_async(sysdesc, num_writes, val);
 }
index 2de1a5c..cb79749 100644 (file)
@@ -85,6 +85,23 @@ error_t sys_null_async(syscall_desc_t* desc)
        return async_syscall(&syscall, desc);
 }
 
+void sys_cache_buster(uint32_t num_writes, uint32_t val)
+{
+       syscall(SYS_cache_buster, num_writes, val, 0, 0, 0);
+}
+
+error_t sys_cache_buster_async(syscall_desc_t* desc, uint32_t num_writes,
+                               uint32_t val)
+{
+       syscall_req_t syscall = {SYS_cache_buster, 0,
+                                {num_writes, val, [2 ... (NUM_SYS_ARGS-1)] 0}};
+       // just to be safe, 0 these out.  they should have been 0'd right after
+       // the desc was POOL_GET'd
+       desc->cleanup = NULL;
+       desc->data = NULL;
+       return async_syscall(&syscall, desc);
+}
+
 error_t sys_cputs_async(const char *s, size_t len, syscall_desc_t* desc,
                      void (*cleanup_handler)(void*), void* cleanup_data)
 {
index 435f0ce..6eddeae 100644 (file)
@@ -25,7 +25,13 @@ uint64_t total(uint64_t (COUNT(length) array)[], int length)
 
 void umain(void)
 {
-       measure_function(sys_null(), NUM_ITERATIONS, "sys_null");
+       async_desc_t *desc1, *desc2;
+       async_rsp_t rsp1, rsp2;
+       cache_buster_async(&desc1, 20, 0xdeadbeef);
+       cache_buster_async(&desc2, 10, 0xcafebabe);
+       waiton_async_call(desc1, &rsp1);
+       waiton_async_call(desc2, &rsp2);
+       //measure_function(sys_null(), NUM_ITERATIONS, "sys_null");
        //measure_function(asm volatile("nop;"), NUM_ITERATIONS, "nop");
        //measure_function(cprintf("Reg Sync call  \n"), 10, "printf");
        //measure_function_async(cprintf_async(&desc, "Cross-Core call\n"), desc, 10,\