diff --git a/base-nova/include/base/ipc_pager.h b/base-nova/include/base/ipc_pager.h index db34af652..5738df050 100644 --- a/base-nova/include/base/ipc_pager.h +++ b/base-nova/include/base/ipc_pager.h @@ -66,6 +66,8 @@ namespace Genode { Nova::Rights(true, _rw, true)); } + bool write_combined() { return _write_combined; }; + addr_t dst_addr() { return _dst_addr; } }; diff --git a/base-nova/include/nova/syscall-generic.h b/base-nova/include/nova/syscall-generic.h index b6e89bd92..079d397ee 100644 --- a/base-nova/include/nova/syscall-generic.h +++ b/base-nova/include/nova/syscall-generic.h @@ -463,6 +463,11 @@ namespace Nova { */ unsigned msg_words() { return items & 0xffffU; } + /** + * Return current number of message items on UTCB + */ + unsigned msg_items() { return items >> 16; } + /** * Append message-transfer item to message buffer * @@ -478,7 +483,7 @@ namespace Nova { /* transfer items start at the end of the UTCB */ items += 1 << 16; Item *item = reinterpret_cast(this); - item += (PAGE_SIZE_BYTE / sizeof(struct Item)) - (items >> 16); + item += (PAGE_SIZE_BYTE / sizeof(struct Item)) - msg_items(); /* check that there is enough space left on UTCB */ if (msg + msg_words() >= reinterpret_cast(item)) { diff --git a/base-nova/src/base/ipc/pager.cc b/base-nova/src/base/ipc/pager.cc index 936189dc2..3826b1ff4 100644 --- a/base-nova/src/base/ipc/pager.cc +++ b/base-nova/src/base/ipc/pager.cc @@ -57,7 +57,8 @@ void Ipc_pager::set_reply_mapping(Mapping m) { Nova::Utcb *utcb = (Nova::Utcb *)Thread_base::myself()->utcb(); utcb->set_msg_word(0); - bool res = utcb->append_item(m.mem_crd(), m.dst_addr()); + bool res = utcb->append_item(m.mem_crd(), m.dst_addr(), false, false, + false, m.write_combined()); /* one item ever fits on the UTCB */ (void)res; } diff --git a/base-nova/src/core/echo.cc b/base-nova/src/core/echo.cc index 6dc881e14..0256b6621 100644 --- a/base-nova/src/core/echo.cc +++ b/base-nova/src/core/echo.cc @@ -45,11 +45,13 @@ static void echo_reply() Nova::Crd snd_rcv(echo()->utcb()->msg[0]); Nova::mword_t offset = echo()->utcb()->msg[1]; bool kern_pd = echo()->utcb()->msg[2]; + bool dma_mem = echo()->utcb()->msg[3]; /* reset message transfer descriptor */ echo()->utcb()->set_msg_word(0); /* append capability-range as message-transfer item */ - bool res = echo()->utcb()->append_item(snd_rcv, offset, kern_pd); + bool res = echo()->utcb()->append_item(snd_rcv, offset, kern_pd, false, + false, dma_mem); /* set return code, 0 means failure */ echo()->utcb()->msg[0] = res; diff --git a/base-nova/src/core/include/nova_util.h b/base-nova/src/core/include/nova_util.h index b3b080c18..024b2a04c 100644 --- a/base-nova/src/core/include/nova_util.h +++ b/base-nova/src/core/include/nova_util.h @@ -29,21 +29,23 @@ enum { verbose_local_map = false }; /** - * Establish a one-to-one mapping + * Establish a mapping * * \param utcb UTCB of the calling EC * \param src_crd capability range descriptor of source * resource to map locally * \param dst_crd capability range descriptor of mapping * target + * \param kern_pd Whether to map the items from the kernel or from core + * \param dma_mem Whether the memory is usable for DMA or not * - * This functions sends a mapping from the calling EC to the echo EC. - * In order to successfully transfer the mapping, we have to open a - * corresponding receive window at the echo EC. We do this by poking - * a receive-capability-range descriptor directly onto the echo UTCB. + * This functions sends a message from the calling EC to the echo EC. + * The calling EC opens a receive window and the echo EC creates a transfer + * item of the message and replies. The kernel will map during the reply + * from the echo EC to the calling EC. */ static int map_local(Nova::Utcb *utcb, Nova::Crd src_crd, Nova::Crd dst_crd, - bool kern_pd = false) + bool kern_pd = false, bool dma_mem = false) { /* open receive window at current EC */ utcb->crd_rcv = dst_crd; @@ -52,16 +54,18 @@ static int map_local(Nova::Utcb *utcb, Nova::Crd src_crd, Nova::Crd dst_crd, utcb->msg[0] = src_crd.value(); utcb->msg[1] = 0; utcb->msg[2] = kern_pd; - utcb->set_msg_word(3); + utcb->msg[3] = dma_mem; + utcb->set_msg_word(4); /* establish the mapping via a portal traversal during reply phase */ Nova::uint8_t res = Nova::call(echo()->pt_sel()); - if (res != Nova::NOVA_OK || utcb->msg_words() != 1 || !utcb->msg[0]) { + if (res != Nova::NOVA_OK || utcb->msg_words() != 1 || !utcb->msg[0] || + utcb->msg_items() != 1) { PERR("Failure - map_local 0x%lx:%lu:%u->0x%lx:%lu:%u - call result=%x" - " utcb=%x:%lx !!! %p %u", + " utcb=%x:%x:%lx !!! utcb=%p kern=%u", src_crd.addr(), src_crd.order(), src_crd.type(), - dst_crd.addr(), dst_crd.order(), dst_crd.type(), - res, utcb->msg_words(), utcb->msg[0], utcb, kern_pd); + dst_crd.addr(), dst_crd.order(), dst_crd.type(), res, + utcb->msg_items(), utcb->msg_words(), utcb->msg[0], utcb, kern_pd); return res > 0 ? res : -1; } /* clear receive window */ @@ -74,12 +78,11 @@ static int map_local(Nova::Utcb *utcb, Nova::Crd src_crd, Nova::Crd dst_crd, static inline int unmap_local(Nova::Crd crd, bool self = true) { return Nova::revoke(crd, self); } -inline int -map_local_phys_to_virt(Nova::Utcb *utcb, Nova::Crd src, Nova::Crd dst) { +inline int map_local_phys_to_virt(Nova::Utcb *utcb, Nova::Crd src, + Nova::Crd dst) { return map_local(utcb, src, dst, true); } -inline int -map_local_one_to_one(Nova::Utcb *utcb, Nova::Crd crd) { +inline int map_local_one_to_one(Nova::Utcb *utcb, Nova::Crd crd) { return map_local(utcb, crd, crd, true); } @@ -95,7 +98,7 @@ inline int map_local(Nova::Utcb *utcb, Genode::addr_t from_start, Genode::addr_t to_start, Genode::size_t num_pages, Nova::Rights const &permission, - bool kern_pd = false) + bool kern_pd = false, bool dma_mem = false) { if (verbose_local_map) Genode::printf("::map_local: from %lx to %lx, %zd pages from kernel %u\n", @@ -146,7 +149,7 @@ inline int map_local(Nova::Utcb *utcb, int const res = map_local(utcb, Mem_crd((from_curr >> 12), order - get_page_size_log2(), permission), Mem_crd((to_curr >> 12), order - get_page_size_log2(), permission), - kern_pd); + kern_pd, dma_mem); if (res) return res; /* advance offset by current flexpage size */ diff --git a/base-nova/src/core/io_mem_session_support.cc b/base-nova/src/core/io_mem_session_support.cc index 06f63f06b..02aa8401d 100644 --- a/base-nova/src/core/io_mem_session_support.cc +++ b/base-nova/src/core/io_mem_session_support.cc @@ -51,10 +51,10 @@ addr_t Io_mem_session_component::_map_local(addr_t base, size_t size) } /* map the dataspace's physical pages to local addresses */ - const Nova::Rights rights(true, true, true); - map_local((Nova::Utcb *)Thread_base::myself()->utcb(), - base, (addr_t)virt_addr, - page_rounded_size >> get_page_size_log2(), rights, true); + const Nova::Rights rights(true, true, false); + int res = map_local((Nova::Utcb *)Thread_base::myself()->utcb(), + base, (addr_t)virt_addr, + page_rounded_size >> get_page_size_log2(), rights, true); - return (addr_t)virt_addr; + return res ? 0 : (addr_t)virt_addr; } diff --git a/base-nova/src/core/ram_session_support.cc b/base-nova/src/core/ram_session_support.cc index 2e1578b94..b1ebc7298 100644 --- a/base-nova/src/core/ram_session_support.cc +++ b/base-nova/src/core/ram_session_support.cc @@ -86,10 +86,17 @@ void Ram_session_component::_clear_ds(Dataspace_component *ds) page_rounded_size, ds->phys_addr(), virt_addr, Thread_base::myself()->utcb()); /* map the dataspace's physical pages to local addresses */ - const Nova::Rights rights(true, true, true); - map_local((Nova::Utcb *)Thread_base::myself()->utcb(), - ds->phys_addr(), (addr_t)virt_addr, - page_rounded_size >> get_page_size_log2(), rights, true); + const Nova::Rights rights(true, ds->writable(), true); + int res = map_local((Nova::Utcb *)Thread_base::myself()->utcb(), + ds->phys_addr(), (addr_t)virt_addr, + page_rounded_size >> get_page_size_log2(), rights, + true); + + if (res) { + PERR("map failed - ram ds size=0x%8zx phys 0x%8lx, core-local 0x%8p\n", + page_rounded_size, ds->phys_addr(), virt_addr); + return; + } memset(virt_addr, 0, page_rounded_size);