alarm: Force unset_alarm to grab the CV lock
[akaros.git] / kern / include / mm.h
index 4aec314..88c7dec 100644 (file)
  * Memory management for processes: syscall related functions, virtual memory
  * regions, etc. */
 
-#ifndef ROS_KERN_MM_H
-#define ROS_KERN_MM_H
+#pragma once
 
 #include <ros/common.h>
+#include <ros/mman.h>
 #include <atomic.h>
 #include <sys/queue.h>
 #include <slab.h>
+#include <kref.h>
+#include <rcu.h>
 
-/* Memory region for a process, consisting of linear(virtual) addresses.  This
- * is what the kernel allocates a process, and the physical mapping can be done
- * lazily (or not).  This way, if a page is swapped out, and the PTE says it
- * isn't present, we still have a way to account for how the whole region ought
- * to be dealt with.
- * Some things are per-region:
- * - probably something with shared memory
- * - mmaping files: we can have a logical connection to something other than
- *   anonymous memory
- * - on a fault, was this memory supposed to be there? (swap, lazy, etc), or is
- *   the region free?
- * Others are per-page:
- * - was this page supposed to be protected somehow(guard)? could be per-region
- * - where is this page in the swap?
- * If we try to store this info in the PTE, we only have 31 bits, and it's more
- * arch dependent.  Handling jumbos is a pain.  And it's replicated across all
- * pages for a coarse granularity things.  And we can't add things easily.
- *
- * so a process has a (sorted) list of these for it's VA space, hanging off it's
- * struct proc.  or off it's mm?
- * - we don't share an mm between processes anymore (tasks/threads)
- *   - though we share most everything with vpm.
- *   - want to be able to do all the same things with vpm as with regular mem
- *     (file back mmap, etc)
- *   - contexts or whatever share lots of mem things, like accounting, limits,
- *   overall process stuff, the rest of the page tables.
- *     - so there should be some overall mm, and probably directly in the
- *     struct proc (or just one other struct directly embedded, not a pointer
- *     to one where a bunch of processes use it)
- *             - if we embed, mm.h doesn't need to know about process.h
- *   so an mm can have a bunch of "address spaces" - or at least different
- *   contexts
- *
- * how does this change or where does this belong with virtual private memory?
- * will also affect get_free_va_range
- *     - also, do we want a separate brk per?  or just support mmap on private mem?
- */
-struct file;
+struct chan;
+struct fd_table;
 struct proc;                                                           /* preprocessor games */
 
-/* This might turn into a per-process mem management structure.  For now, we're
- * using the proc struct.  This would have things like the vmr list/tree, cr3,
- * mem usage stats, something with private memory, etc.  Not sure if we'll ever
- * need this. */
-struct mm {
-       spinlock_t mm_lock;
+#define F_OR_C_CHAN 2
+
+struct file_or_chan {
+       int type;
+       struct chan *chan;
+       struct fs_file *fsf;    /* weak ref, set during mmap. */
+       struct kref kref;
+       struct rcu_head rcu;
 };
 
-/* Basic structure defining a region of a process's virtual memory */
+char *foc_to_name(struct file_or_chan *foc);
+char *foc_abs_path(struct file_or_chan *foc, char *path, size_t max_size);
+ssize_t foc_read(struct file_or_chan *foc, void *buf, size_t amt, off64_t off);
+struct file_or_chan *foc_open(char *path, int omode, int perm);
+struct file_or_chan *fd_to_foc(struct fd_table *fdt, int fd);
+void foc_incref(struct file_or_chan *foc);
+void foc_decref(struct file_or_chan *foc);
+void *foc_pointer(struct file_or_chan *foc);
+size_t foc_get_len(struct file_or_chan *foc);
+
+/* Basic structure defining a region of a process's virtual memory.  Note we
+ * don't refcnt these.  Either they are in the TAILQ/tree, or they should be
+ * freed.  There should be no other references floating around.  We still need
+ * to sort out how we share memory and how we'll do private memory with these
+ * VMRs. */
 struct vm_region {
        TAILQ_ENTRY(vm_region)          vm_link;
+       TAILQ_ENTRY(vm_region)          vm_pm_link;
        struct proc                                     *vm_proc;       /* owning process, for now */
-       //struct mm                                     *vm_mm;         /* owning address space */
        uintptr_t                                       vm_base;
        uintptr_t                                       vm_end;
-       int                                                     vm_perm;        
-       int                                                     vm_flags;       
-       struct file                                     *vm_file;
+       int                                                     vm_prot;
+       int                                                     vm_flags;
+       struct file_or_chan                     *__vm_foc;
        size_t                                          vm_foff;
+       bool                                            vm_ready;       /* racy, for the PM checks */
+       bool                                            vm_shootdown_needed;
 };
 TAILQ_HEAD(vmr_tailq, vm_region);                      /* Declares 'struct vmr_tailq' */
 
-#include <process.h>                                           /* preprocessor games */
+static inline bool vmr_has_file(struct vm_region *vmr)
+{
+       return vmr->__vm_foc ? true : false;
+}
+
+static inline char *vmr_to_filename(struct vm_region *vmr)
+{
+       assert(vmr_has_file(vmr));
+       return foc_to_name(vmr->__vm_foc);
+}
 
-/* VM Region Management Functions.  For now, these just maintain themselves -
- * anything related to mapping needs to be done by the caller. */
 void vmr_init(void);
-struct vm_region *create_vmr(struct proc *p, uintptr_t va, size_t len);
-struct vm_region *split_vmr(struct vm_region *vmr, uintptr_t va);
-int merge_vmr(struct vm_region *first, struct vm_region *second);
-int grow_vmr(struct vm_region *vmr, uintptr_t va);
-int shrink_vmr(struct vm_region *vmr, uintptr_t va);
-void destroy_vmr(struct vm_region *vmr);
-struct vm_region *find_vmr(struct proc *p, uintptr_t va);
-struct vm_region *find_first_vmr(struct proc *p, uintptr_t va);
-void isolate_vmrs(struct proc *p, uintptr_t va, size_t len);
-void duplicate_vmrs(struct proc *p, struct proc *new_p);
+void unmap_and_destroy_vmrs(struct proc *p);
+int duplicate_vmrs(struct proc *p, struct proc *new_p);
 void print_vmrs(struct proc *p);
+void enumerate_vmrs(struct proc *p,
+                                       void (*func)(struct vm_region *vmr, void *opaque),
+                                       void *opaque);
 
 /* mmap() related functions.  These manipulate VMRs and change the hardware page
- * tables. */
+ * tables.  Any requests below the LOWEST_VA will silently be upped.  This may
+ * be a dynamic proc-specific variable later. */
+#define MMAP_LOWEST_VA PAGE_SIZE
+#define MMAP_LD_FIXED_VA 0x100000
 void *mmap(struct proc *p, uintptr_t addr, size_t len, int prot, int flags,
            int fd, size_t offset);
 void *do_mmap(struct proc *p, uintptr_t addr, size_t len, int prot, int flags,
-             struct file *f, size_t offset);
+              struct file_or_chan *foc, size_t offset);
 int mprotect(struct proc *p, uintptr_t addr, size_t len, int prot);
 int munmap(struct proc *p, uintptr_t addr, size_t len);
 int handle_page_fault(struct proc *p, uintptr_t va, int prot);
+int handle_page_fault_nofile(struct proc *p, uintptr_t va, int prot);
+unsigned long populate_va(struct proc *p, uintptr_t va, unsigned long nr_pgs);
 
-/* These assume the memory/proc_lock is held already */
-void *__do_mmap(struct proc *p, uintptr_t addr, size_t len, int prot, int flags,
-               struct file *f, size_t offset);
+/* These assume the mm_lock is held already */
 int __do_mprotect(struct proc *p, uintptr_t addr, size_t len, int prot);
 int __do_munmap(struct proc *p, uintptr_t addr, size_t len);
-int __handle_page_fault(struct proc* p, uintptr_t va, int prot);
 
-#endif /* !ROS_KERN_MM_H */
+/* Kernel Dynamic Memory Mappings */
+struct arena *vmap_arena;
+void vmap_init(void);
+/* Gets PML1 page-aligned virtual addresses for the kernel's dynamic vmap.
+ * You'll need to map it to something.  When you're done, 'put-' will also unmap
+ * the vaddr for you. */
+uintptr_t get_vmap_segment(size_t nr_bytes);
+void put_vmap_segment(uintptr_t vaddr, size_t nr_bytes);
+int map_vmap_segment(uintptr_t vaddr, uintptr_t paddr, unsigned long num_pages,
+                     int perm);
+/* Helper wrappers for getting and mapping a specific paddr. */
+uintptr_t vmap_pmem(uintptr_t paddr, size_t nr_bytes);
+uintptr_t vmap_pmem_nocache(uintptr_t paddr, size_t nr_bytes);
+uintptr_t vmap_pmem_writecomb(uintptr_t paddr, size_t nr_bytes);
+int vunmap_vmem(uintptr_t vaddr, size_t nr_bytes);