]> rtime.felk.cvut.cz Git - l4.git/blobdiff - kernel/fiasco/src/kern/ux/mem_space-ux.cpp
Update
[l4.git] / kernel / fiasco / src / kern / ux / mem_space-ux.cpp
index 7a9ad8299ea326c020356a783267c8b1ca0d90e6..7d92780628fe8cc9d76f663a43fed26f6856d30e 100644 (file)
@@ -4,15 +4,24 @@
  */
 
 INTERFACE[ux]:
+
+#include "entry_frame.h"
 #include <sys/types.h>         // for pid_t
 #include "kmem.h"
 #include "mem_layout.h"
 #include "paging.h"
 
+extern "C" FIASCO_FASTCALL
+int
+thread_page_fault(Address, Mword, Address, Mword, Return_frame *);
+
+
 EXTENSION class Mem_space
 {
 protected:
-  pid_t     _pid;
+  int sync_kernel() const { return 0; }
+
+  pid_t _pid;
 };
 
 IMPLEMENTATION[ux]:
@@ -24,44 +33,44 @@ IMPLEMENTATION[ux]:
 #include "cpu_lock.h"
 #include "lock_guard.h"
 #include "mem_layout.h"
+#include "processor.h"
+#include "regdefs.h"
 #include "trampoline.h"
 #include <cstring>
 #include "config.h"
 #include "emulation.h"
 #include "logdefs.h"
 
-PRIVATE static inline NEEDS ["kmem.h", "emulation.h"]
+PROTECTED static inline NEEDS ["kmem.h", "emulation.h"]
 Pdir *
 Mem_space::current_pdir()
 {
-  return reinterpret_cast<Pdir *>(Kmem::phys_to_virt (Emulation::pdir_addr()));
+  return reinterpret_cast<Pdir*>(Kmem::phys_to_virt(Emulation::pdir_addr()));
 }
 
 IMPLEMENT inline NEEDS ["kmem.h", "emulation.h"]
 void
 Mem_space::make_current()
 {
-  Emulation::set_pdir_addr (Kmem::virt_to_phys (_dir));
+  Emulation::set_pdir_addr(Kmem::virt_to_phys(_dir));
   _current.cpu(current_cpu()) = this;
 }
 
+// returns host pid number
 PUBLIC inline
 pid_t
-Mem_space::pid() const                 // returns host pid number
-{
-  return _pid;
-}
+Mem_space::pid() const
+{ return _pid; }
 
+// sets host pid number
 PUBLIC inline
 void
-Mem_space::set_pid(pid_t pid)          // sets host pid number
-{
-  _pid = pid;
-}
+Mem_space::set_pid(pid_t pid)
+{ _pid = pid; }
 
-IMPLEMENT inline NEEDS["logdefs.h",Mem_space::current_pdir]
+IMPLEMENT inline NEEDS["logdefs.h"]
 void
-Mem_space::switchin_context(Mem_space *from)
+Mem_space::switchin_context(Mem_space *from, unsigned)
 {
   if (this == from)
     return;
@@ -74,15 +83,15 @@ IMPLEMENT inline NEEDS [<asm/unistd.h>, <sys/mman.h>, "boot_info.h",
                         "cpu_lock.h", "lock_guard.h", "mem_layout.h",
                         "trampoline.h"]
 void
-Mem_space::page_map (Address phys, Address virt, Address size, unsigned attr)
+Mem_space::page_map(Address phys, Address virt, Address size, Attr attr)
 {
-  Lock_guard <Cpu_lock> guard (&cpu_lock);
+  auto guard = lock_guard(cpu_lock);
 
-  Mword *trampoline = (Mword *) Mem_layout::kernel_trampoline_page;
+  Mword *trampoline = (Mword *)Mem_layout::kernel_trampoline_page;
 
   *(trampoline + 1) = virt;
   *(trampoline + 2) = size;
-  *(trampoline + 3) = PROT_READ | (attr & Page_writable ? PROT_WRITE : 0);
+  *(trampoline + 3) = PROT_READ | (attr.rights & Page::Rights::W() ? PROT_WRITE : 0);
   *(trampoline + 4) = MAP_SHARED | MAP_FIXED;
   *(trampoline + 5) = Boot_info::fd();
 
@@ -94,36 +103,163 @@ Mem_space::page_map (Address phys, Address virt, Address size, unsigned attr)
   else
     *(trampoline + 6) = phys;
 
-  Trampoline::syscall (pid(), __NR_mmap, Mem_layout::Trampoline_page + 4);
+  Trampoline::syscall(pid(), __NR_mmap, Mem_layout::Trampoline_page + 4);
 }
 
 IMPLEMENT inline NEEDS [<asm/unistd.h>, "cpu_lock.h", "lock_guard.h",
                         "trampoline.h"]
 void
-Mem_space::page_unmap (Address virt, Address size)
+Mem_space::page_unmap(Address virt, Address size)
 {
-  Lock_guard <Cpu_lock> guard (&cpu_lock);
+  auto guard = lock_guard(cpu_lock);
 
-  Trampoline::syscall (pid(), __NR_munmap, virt, size);
+  Trampoline::syscall(pid(), __NR_munmap, virt, size);
 }
 
 IMPLEMENT inline NEEDS [<asm/unistd.h>, "cpu_lock.h", "lock_guard.h",
                         "trampoline.h"]
 void
-Mem_space::page_protect (Address virt, Address size, unsigned attr)
+Mem_space::page_protect(Address virt, Address size, unsigned attr)
 {
-  Lock_guard <Cpu_lock> guard (&cpu_lock);
+  auto guard = lock_guard(cpu_lock);
 
-  Trampoline::syscall (pid(), __NR_mprotect, virt, size,
-                       PROT_READ | (attr & Page_writable ? PROT_WRITE : 0));
+  Trampoline::syscall(pid(), __NR_mprotect, virt, size,
+                      PROT_READ | (attr & Page_writable ? PROT_WRITE : 0));
 }
 
-IMPLEMENT inline
+
+/**
+ * Translate virtual memory address in user space to virtual memory
+ * address in kernel space (requires all physical memory be mapped).
+ * @param addr Virtual address in user address space.
+ * @param write Type of memory access (read or write) for page-faults.
+ * @return Virtual address in kernel address space.
+ */
+PRIVATE inline NEEDS[Mem_space::current_pdir]
+template< typename T >
+T *
+Mem_space::user_to_kernel(T const *addr, bool write)
+{
+  Phys_addr phys;
+  Virt_addr virt = Virt_addr((Address) addr);
+  Attr attr;
+  unsigned error = 0;
+  Page_order size;
+
+  for (;;)
+    {
+      // See if there is a mapping for this address
+      if (v_lookup(virt, &phys, &size, &attr))
+        {
+          // Add offset to frame
+          phys = phys | cxx::get_lsb(virt, size);
+
+          // See if we want to write and are not allowed to
+          // Generic check because INTEL_PTE_WRITE == INTEL_PDE_WRITE
+          if (!write || (attr.rights & Page::Rights::W()))
+            return (T*)Mem_layout::phys_to_pmem(Phys_addr::val(phys));
+
+          error |= PF_ERR_PRESENT;
+        }
+
+      if (write)
+        error |= PF_ERR_WRITE;
+
+      // If we tried to access user memory of a space other than current_mem_space()
+      // our Long-IPC partner must do a page-in. This is analogue to IA32
+      // page-faulting in the IPC window. Set PF_ERR_REMTADDR hint.
+      // Otherwise we faulted on our own user memory. Set PF_ERR_USERADDR hint.
+      error |= (dir() == current_pdir() ? PF_ERR_USERADDR : PF_ERR_REMTADDR);
+
+      // No mapping or insufficient access rights, raise pagefault.
+      // Pretend open interrupts, we restore the current state afterwards.
+      Cpu_lock::Status was_locked = cpu_lock.test();
+
+      thread_page_fault(Virt_addr::val(virt), error, 0, Proc::processor_state() | EFLAGS_IF, 0);
+
+      cpu_lock.set (was_locked);
+    }
+}
+
+IMPLEMENT inline NEEDS ["config.h", "cpu_lock.h", "lock_guard.h"]
+template< typename T >
+T
+Mem_space::peek_user(T const *addr)
+{
+  T value;
+
+  // Check if we cross page boundaries
+  if (((Address)addr                   & Config::PAGE_MASK) ==
+     (((Address)addr + sizeof (T) - 1) & Config::PAGE_MASK))
+    {
+      auto guard = lock_guard(cpu_lock);
+      value = *user_to_kernel(addr, false);
+    }
+  else
+    copy_from_user<T>(&value, addr, 1);
+
+  return value;
+}
+
+IMPLEMENT inline NEEDS ["config.h", "cpu_lock.h", "lock_guard.h"]
+template< typename T >
 void
-Mem_space::kmem_update (void *)
-{}
+Mem_space::poke_user(T *addr, T value)
+{
+  // Check if we cross page boundaries
+  if (((Address)addr                   & Config::PAGE_MASK) ==
+     (((Address)addr + sizeof (T) - 1) & Config::PAGE_MASK))
+    {
+      auto guard = lock_guard(cpu_lock);
+      *user_to_kernel(addr, true) = value;
+    }
+  else
+    copy_to_user<T>(addr, &value, 1);
+}
+
+PRIVATE
+template< typename T >
+void
+Mem_space::copy_from_user(T *kdst, T const *usrc, size_t n)
+{
+  auto guard = lock_guard(cpu_lock);
+
+  char *ptr = (char *)usrc;
+  char *dst = (char *)kdst;
+  char *src = 0;
 
-PRIVATE inline
+  n *= sizeof (T);
+
+  while (n--)
+    {
+      if (!src || ((Address)ptr & ~Config::PAGE_MASK) == 0)
+        src = user_to_kernel(ptr, false);
+
+      *dst++ = *src++;
+      ptr++;
+    }
+}
+
+PRIVATE inline NEEDS ["config.h", "cpu_lock.h", "lock_guard.h"]
+template< typename T >
 void
-Mem_space::initial_sync()
-{}
+Mem_space::copy_to_user(T *udst, T const *ksrc, size_t n)
+{
+  auto guard = lock_guard(cpu_lock);
+
+  char *ptr = (char *)udst;
+  char *src = (char *)ksrc;
+  char *dst = 0;
+
+  n *= sizeof (T);
+
+  while (n--)
+    {
+      if (!dst || ((Address)ptr & ~Config::PAGE_MASK) == 0)
+        dst = user_to_kernel(ptr, true);
+
+      *dst++ = *src++;
+      ptr++;
+    }
+}
+