diff options
author | Neal H. Walfield <neal@gnu.org> | 2008-11-14 16:10:32 +0100 |
---|---|---|
committer | Neal H. Walfield <neal@gnu.org> | 2008-11-14 16:10:32 +0100 |
commit | 4cb0b81ebd2cf2353bfcee32fcbd5bf40cf7aa8a (patch) | |
tree | f6ab4f7c8e500114e73239bf6c5a635092760fb0 | |
parent | 0aa96b12bc6086c9ac922316ba877cce9b8b8898 (diff) |
Map pages preemptively.
hurd/
2008-11-14 Neal H. Walfield <neal@gnu.org>
* rpc.h: Include <l4/space.h>.
(RPC_): When receiving a message, accept any mapping.
viengoos/
2008-11-14 Neal H. Walfield <neal@gnu.org>
* server.c (struct fault_info): New structure.
(page_fault): New function.
(server_loop): Implement page fault handling in terms of the new
function. When copying a capability that makes a page available
in the caller's hardware address space, map it preemptively. When
clearing a discarded bit for a page that appears in the caller's
hardware address space, allocate the object and map it
preemptively.
-rw-r--r-- | hurd/ChangeLog | 5 | ||||
-rw-r--r-- | hurd/rpc.h | 3 | ||||
-rw-r--r-- | viengoos/ChangeLog | 11 | ||||
-rw-r--r-- | viengoos/server.c | 269 |
4 files changed, 205 insertions, 83 deletions
diff --git a/hurd/ChangeLog b/hurd/ChangeLog index d75c512..72ac590 100644 --- a/hurd/ChangeLog +++ b/hurd/ChangeLog @@ -1,3 +1,8 @@ +2008-11-14 Neal H. Walfield <neal@gnu.org> + + * rpc.h: Include <l4/space.h>. + (RPC_): When receiving a message, accept any mapping. + 2008-11-12 Neal H. Walfield <neal@gnu.org> * trace.h (trace_buffer_dump): Take additional arguments func and @@ -103,6 +103,7 @@ #include <hurd/stddef.h> #include <l4/ipc.h> +#include <l4/space.h> #include <errno.h> /* First we define some cpp help macros. */ @@ -644,7 +645,7 @@ (&msg)); \ \ l4_msg_load (msg); \ - l4_accept (L4_UNTYPED_WORDS_ACCEPTOR); \ + l4_accept (l4_map_grant_items (L4_COMPLETE_ADDRESS_SPACE)); \ \ bool call = true; \ for (;;) \ diff --git a/viengoos/ChangeLog b/viengoos/ChangeLog index 77819ff..55e0935 100644 --- a/viengoos/ChangeLog +++ b/viengoos/ChangeLog @@ -1,3 +1,14 @@ +2008-11-14 Neal H. Walfield <neal@gnu.org> + + * server.c (struct fault_info): New structure. + (page_fault): New function. + (server_loop): Implement page fault handling in terms of the new + function. When copying a capability that makes a page available + in the caller's hardware address space, map it preemptively. When + clearing a discarded bit for a page that appears in the caller's + hardware address space, allocate the object and map it + preemptively. + 2008-11-12 Neal H. Walfield <neal@gnu.org> * list.h (list_queue): Rename from this... diff --git a/viengoos/server.c b/viengoos/server.c index 623b743..e26eeb8 100644 --- a/viengoos/server.c +++ b/viengoos/server.c @@ -52,7 +52,7 @@ struct trace_buffer rpc_trace = TRACE_BUFFER_INIT ("rpcs", 0, /* Like debug but also prints the method id and saves to the trace buffer if level is less than or equal to 4. */ -#define DEBUG(level, format, args...) \ +# define DEBUG(level, format, args...) \ do \ { \ if (level <= 4) \ @@ -69,11 +69,92 @@ struct trace_buffer rpc_trace = TRACE_BUFFER_INIT ("rpcs", 0, while (0) #else -#define DEBUG(level, format, args...) do {} while (0) +# define DEBUG(level, format, args...) do {} while (0) #endif #define PAGEFAULT_METHOD 2 +struct fault_info +{ + struct object *page; + bool discarded; + bool writable; +}; + +/* Fault the page at PAGE_ADDR in thread THREAD's address space in. + Does not map it (but marks it as mapped). If there is no page or + some other error occurs, returns PAGE == 0. If the page is + discarded, sets DISCARDED to true. */ +static struct fault_info +page_fault (struct activity *activity, + struct thread *thread, + l4_word_t page_addr, + bool require_writable) +{ + struct fault_info info; + memset (&info, 0, sizeof (info)); + + struct cap cap; + cap = as_object_lookup_rel (activity, &thread->aspace, + addr_chop (PTR_TO_ADDR (page_addr), + PAGESIZE_LOG2), + cap_rpage, &info.writable); + assert (cap.type == cap_void + || cap.type == cap_page + || cap.type == cap_rpage); + + if (require_writable && ! info.writable) + { + debug (5, "Access fault at %x", page_addr); + return info; + } + + if (! info.writable && cap.discardable) + { + debug (5, "Clearing discardable predicate for cap designating " + OID_FMT " (%s)", + OID_PRINTF (cap.oid), cap_type_string (cap.type)); + cap.discardable = false; + } + + struct object *page = cap_to_object_soft (activity, &cap); + if (! page && cap.type != cap_void) + /* It's not in-memory. See if it was discarded. If not, + load it using cap_to_object. */ + { + int object = (cap.oid % (FOLIO_OBJECTS + 1)) - 1; + oid_t foid = cap.oid - object - 1; + struct folio *folio + = (struct folio *) object_find (activity, foid, + OBJECT_POLICY_DEFAULT); + assert (folio); + assert (object_type ((struct object *) folio) == cap_folio); + + if (folio_object_discarded (folio, object)) + { + debug (5, OID_FMT " (%s) was discarded", + OID_PRINTF (cap.oid), + cap_type_string (folio_object_type (folio, + object))); + + assert (! folio_object_content (folio, object)); + + info.discarded = true; + + debug (5, "Raising discarded fault at %x", page_addr); + } + else + page = cap_to_object (activity, &cap); + } + + if (page) + object_to_object_desc (page)->mapped = true; + + info.page = page; + + return info; +} + void server_loop (void) { @@ -233,84 +314,20 @@ server_loop (void) l4_word_t ip; l4_word_t fault = l4_pagefault (msg_tag, &access, &ip); bool w = !! (access & L4_FPAGE_WRITABLE); - enum cap_type type = w ? cap_page : cap_rpage; DEBUG (4, "%s fault at %x (ip = %x)", w ? "Write" : "Read", fault, ip); - l4_word_t page_addr = fault & ~(PAGESIZE - 1); - - bool writable; - struct cap cap; - struct object *page = NULL; - - bool raise_fault = false; - bool discarded = false; - - cap = as_object_lookup_rel (activity, &thread->aspace, - addr_chop (PTR_TO_ADDR (page_addr), - PAGESIZE_LOG2), - type, &writable); - assert (cap.type == cap_void - || cap.type == cap_page - || cap.type == cap_rpage); - - if (! writable && cap.discardable) - { - debug (5, "Clearing discardable predicate for cap designating " - OID_FMT " (%s)", - OID_PRINTF (cap.oid), cap_type_string (cap.type)); - cap.discardable = false; - } - - page = cap_to_object_soft (activity, &cap); - if (! page && cap.type != cap_void) - /* It's not in-memory. See if it was discarded. If not, - load it using cap_to_object. */ - { - int object = (cap.oid % (FOLIO_OBJECTS + 1)) - 1; - oid_t foid = cap.oid - object - 1; - struct folio *folio - = (struct folio *) object_find (activity, foid, - OBJECT_POLICY_DEFAULT); - assert (folio); - assert (object_type ((struct object *) folio) == cap_folio); - - if (folio_object_discarded (folio, object)) - { - debug (5, OID_FMT " (%s) was discarded", - OID_PRINTF (cap.oid), - cap_type_string (folio_object_type (folio, - object))); - - assert (! folio_object_content (folio, object)); - raise_fault = true; - discarded = true; - - DEBUG (5, "Raising discarded fault at %x", page_addr); - } - else - page = cap_to_object (activity, &cap); - } + l4_word_t page_addr = fault & ~(PAGESIZE - 1); - if (! page) - { - raise_fault = true; - DEBUG (5, "fault (ip: %x; fault: %x.%c)!", - ip, fault, w ? 'w' : 'r'); - } - else if (w && ! writable) - /* Only allow permitted writes through. */ - { - raise_fault = true; - DEBUG (5, "access fault (ip: %x; fault: %x.%c)!", - ip, fault, w ? 'w' : 'r'); - } + struct fault_info fault_info + = page_fault (activity, thread, page_addr, w); - if (raise_fault) + if (fault_info.discarded || ! fault_info.page) { DEBUG (4, "Reflecting fault (ip: %x; fault: %x.%c%s)!", - ip, fault, w ? 'w' : 'r', discarded ? " discarded" : ""); + ip, fault, w ? 'w' : 'r', + fault_info.discarded ? " discarded" : ""); l4_word_t c = _L4_XCHG_REGS_DELIVER; l4_thread_id_t targ = thread->tid; @@ -321,8 +338,9 @@ server_loop (void) struct exception_info info; info.access = access; - info.type = type; - info.discarded = discarded; + info.type = w ? cap_page : cap_rpage; + + info.discarded = fault_info.discarded; l4_msg_t msg; exception_fault_send_marshal (&msg, PTR_TO_ADDR (fault), @@ -333,15 +351,19 @@ server_loop (void) continue; } - DEBUG (4, "%s fault at %x (ip=%x), replying with %p (" OID_FMT ")", - w ? "Write" : "Read", fault, ip, page, OID_PRINTF (cap.oid)); - l4_map_item_t map_item - = l4_map_item (l4_fpage_add_rights (l4_fpage ((uintptr_t) page, - PAGESIZE), - access), - page_addr); + access = L4_FPAGE_READABLE; + if (fault_info.writable) + access |= L4_FPAGE_WRITABLE; - object_to_object_desc (page)->mapped = true; + DEBUG (4, "%s fault at %x (ip=%x), replying with %p(r%s)", + w ? "Write" : "Read", fault, ip, fault_info.page, + fault_info.writable ? "w" : ""); + l4_map_item_t map_item + = l4_map_item + (l4_fpage_add_rights (l4_fpage ((uintptr_t) fault_info.page, + PAGESIZE), + access), + page_addr); /* Formulate the reply message. */ l4_pagefault_reply_formulate_in (msg, &map_item); @@ -975,6 +997,47 @@ server_loop (void) break; case RM_cap_copy: rm_cap_copy_reply_marshal (&msg); + + if (ADDR_IS_VOID (target_as_addr) + && cap_types_compatible (target->type, cap_page) + && (addr_depth (target_addr) + CAP_GUARD_BITS (target) + == ADDR_BITS - PAGESIZE_LOG2)) + /* The target address space is the caller's. The target + object appears to be a page. It seems to be + installed at a point where it would appear in the + hardware address space. If this is really the case, + then we can map it now and save a fault later. */ + { + profile_region ("cap_copy(prefault)"); + + l4_word_t page_addr + = addr_prefix (addr_extend (target_addr, + CAP_GUARD_BITS (target), + CAP_GUARD (target))); + struct fault_info fault_info + = page_fault (principal, thread, page_addr, false); + if (fault_info.page) + { + assert (! fault_info.discarded); + + l4_fpage_t fpage + = l4_fpage ((uintptr_t) fault_info.page, PAGESIZE); + + if (fault_info.writable) + fpage = l4_fpage_add_rights (fpage, + L4_FPAGE_READABLE + | L4_FPAGE_WRITABLE); + else + fpage = l4_fpage_add_rights (fpage, + L4_FPAGE_READABLE); + + l4_map_item_t map_item = l4_map_item (fpage, page_addr); + l4_msg_append_map_item (msg, map_item); + } + + profile_region_end (); + } + break; } break; @@ -1112,9 +1175,51 @@ server_loop (void) if (folio_object_version (folio, idx) != cap.version) REPLY (ENOENT); + bool was_discarded = folio_object_discarded (folio, idx); folio_object_discarded_set (folio, idx, false); rm_object_discarded_clear_reply_marshal (&msg); + + if (was_discarded + && cap_types_compatible (cap.type, cap_page) + && (addr_depth (object_addr) + CAP_GUARD_BITS (&cap) + == ADDR_BITS - PAGESIZE_LOG2)) + /* The target object was discarded, appears to be a page + and seems to be installed at a point where it would + appear in the hardware address space. If this is + really the case, then we can map it now and save a + fault later. */ + { + profile_region ("object_discard(prefault)"); + + l4_word_t page_addr + = addr_prefix (addr_extend (object_addr, + CAP_GUARD_BITS (&cap), + CAP_GUARD (&cap))); + struct fault_info fault_info + = page_fault (principal, thread, page_addr, false); + if (fault_info.page) + { + assert (! fault_info.discarded); + + l4_fpage_t fpage + = l4_fpage ((uintptr_t) fault_info.page, PAGESIZE); + + if (fault_info.writable) + fpage = l4_fpage_add_rights (fpage, + L4_FPAGE_READABLE + | L4_FPAGE_WRITABLE); + else + fpage = l4_fpage_add_rights (fpage, + L4_FPAGE_READABLE); + + l4_map_item_t map_item = l4_map_item (fpage, page_addr); + l4_msg_append_map_item (msg, map_item); + } + + profile_region_end (); + } + break; } |