Program Listing for File vm.hpp

Return to documentation for file (vm/vm.hpp)

/* SPDX-License-Identifier: BSD-2-Clause */
#pragma once
#include "frg/spinlock.hpp"
#include "lib/list.hpp"
#include <hal/hal.hpp>
#include <hal/mmu.hpp>
#include <lib/base.hpp>
#include <vm/vmem.h>

#define VM_ENABLE_COW 1

namespace Gaia::Vm {
void init();

extern Hal::Vm::Pagemap kernel_pagemap;

struct Object;

class Space {
public:
  Result<uintptr_t, Error> map(Object *obj, frg::optional<uintptr_t> address,
                               size_t size, Hal::Vm::Prot prot);

  Result<Void, Error> unmap(uintptr_t address, size_t size);

  // Matches i386 mmu
  enum FaultFlags {
    PRESENT = (1 << 0),
    WRITE = (1 << 1),
    USER = (1 << 2),
    EXEC = (1 << 4),
  };

  // Fault on address, returns true if fault was resolved
  bool fault(uintptr_t address, FaultFlags flags);

  Result<uintptr_t, Error> new_anon(frg::optional<uintptr_t> address,
                                    size_t size, Hal::Vm::Prot prot);

  Result<Void, Error> copy(Space *dest);

  void activate() { pagemap->activate(); }

  Space(Hal::Vm::Pagemap *pagemap, Vmem vmem) : pagemap(pagemap), vmem(vmem) {}

  Space(const char *name, bool user) {
    pagemap = new Hal::Vm::Pagemap();
    pagemap->init(!user);

    vmem_init(&vmem, name, (void *)0x80000000000, 0x100000000, 0x1000, 0, 0, 0,
              0, 0);
  }

  void release();

  Hal::Vm::Pagemap *pagemap;

private:
  struct Entry {
    ListNode<Entry> link;
    uintptr_t start;
    size_t size;
    Object *obj;
    Hal::Vm::Prot prot;

    Entry(uintptr_t start, size_t size, Object *obj, Hal::Vm::Prot prot)
        : start(start), size(size), obj(obj), prot(prot) {}
  };

  List<Entry, &Entry::link> entries;

  Vmem vmem;
};

class AnonMap;

struct Anon;

struct Object {
  int refcnt;
  size_t size;

  union {
    struct {
      AnonMap *amap;
      Object *parent; // if copied-on-write, original parent
    } anon;
  };

  // Create a (CoW-optimized) copy of the object
  Object *copy();

  // Retain a reference to an object
  void retain();

  // Release the object
  // NOTE: if the refcnt reaches 0, object WILL commit suicide (`delete this`)
  void release();

  Object(size_t size);
  Object(size_t size, AnonMap *amap);

  // Try and resolve a fault on the object
  bool fault(Space *map, uintptr_t vaddr, size_t offset,
             Space::FaultFlags flags, Hal::Vm::Prot obj_prot);
};

struct Anon {
  int refcnt;
  void *physpage;
  size_t offset; // offset within the amap
  frg::simple_spinlock lock;

  void release();
  Anon *copy();
  Anon(void *physpage, size_t offset)
      : refcnt(1), physpage(physpage), offset(offset){};
};

class AnonMap {
public:
  struct Entry {
    Anon *anon;
    ListNode<Entry> link;
  };

  frg::optional<Entry *> anon_at(uintptr_t page);

  void insert_anon(Anon *anon);

  AnonMap *copy();

  void release();

private:
  List<Entry, &Entry::link> entries;
};
} // namespace Gaia::Vm