root/headers/private/kernel/vm/VMArea.h
/*
 * Copyright 2009-2010, Ingo Weinhold, ingo_weinhold@gmx.de.
 * Copyright 2002-2009, Axel Dörfler, axeld@pinc-software.de.
 * Distributed under the terms of the MIT License.
 *
 * Copyright 2001-2002, Travis Geiselbrecht. All rights reserved.
 * Distributed under the terms of the NewOS License.
 */
#ifndef _KERNEL_VM_VM_AREA_H
#define _KERNEL_VM_VM_AREA_H


#include <vm_defs.h>

#include <lock.h>
#include <util/DoublyLinkedList.h>
#include <util/SinglyLinkedList.h>
#include <util/AVLTree.h>
#include <vm/vm_types.h>


struct VMAddressSpace;
struct VMCache;
struct VMKernelAddressSpace;
struct VMUserAddressSpace;


struct VMAreaUnwiredWaiter
        : public DoublyLinkedListLinkImpl<VMAreaUnwiredWaiter> {
        VMArea*                                 area;
        addr_t                                  base;
        size_t                                  size;
        ConditionVariable               condition;
        ConditionVariableEntry  waitEntry;
};

typedef DoublyLinkedList<VMAreaUnwiredWaiter> VMAreaUnwiredWaiterList;


struct VMAreaWiredRange : SinglyLinkedListLinkImpl<VMAreaWiredRange> {
        VMArea*                                 area;
        addr_t                                  base;
        size_t                                  size;
        bool                                    writable;
        bool                                    implicit;       // range created automatically
        VMAreaUnwiredWaiterList waiters;

        VMAreaWiredRange()
        {
        }

        VMAreaWiredRange(addr_t base, size_t size, bool writable, bool implicit)
                :
                area(NULL),
                base(base),
                size(size),
                writable(writable),
                implicit(implicit)
        {
        }

        void SetTo(addr_t base, size_t size, bool writable, bool implicit)
        {
                this->area = NULL;
                this->base = base;
                this->size = size;
                this->writable = writable;
                this->implicit = implicit;
        }

        bool IntersectsWith(addr_t base, size_t size) const
        {
                return this->base + this->size - 1 >= base
                        && base + size - 1 >= this->base;
        }
};

typedef SinglyLinkedList<VMAreaWiredRange> VMAreaWiredRangeList;


struct VMPageWiringInfo {
        VMAreaWiredRange        range;
        phys_addr_t                     physicalAddress;
                                                        // the actual physical address corresponding to
                                                        // the virtual address passed to vm_wire_page()
                                                        // (i.e. with in-page offset)
        vm_page*                        page;
};


struct VMAreasTreeNode {
        AVLTreeNode tree_node;
};


struct VMArea : private VMAreasTreeNode {
public:
        enum {
                // AddWaiterIfWired() flags
                IGNORE_WRITE_WIRED_RANGES       = 0x01, // ignore existing ranges that
                                                                                        // wire for writing
        };

public:
        area_id                                 id;
        char                                    name[B_OS_NAME_LENGTH];
        uint32                                  protection;
        uint32                                  protection_max;
        uint16                                  wiring;

private:
        uint16                                  memory_type;    // >> shifted by MEMORY_TYPE_SHIFT

public:
        VMCache*                                cache;                  // protected by sAreaCacheLock
        off_t                                   cache_offset;
        uint32                                  cache_type;
        VMAreaMappings                  mappings;               // protected by the TranslationMap lock
        uint8*                                  page_protections; // protected by cache lock

        struct VMAddressSpace*  address_space;

private:
        DoublyLinkedListLink<VMArea> fCacheLink;

public:
        typedef DoublyLinkedList<VMArea,
                DoublyLinkedListMemberGetLink<VMArea, &VMArea::fCacheLink> > CacheList;

                        addr_t                          Base() const    { return fBase; }
                        size_t                          Size() const    { return fSize; }

        inline  uint32                          MemoryType() const;
        inline  void                            SetMemoryType(uint32 memoryType);

                        bool                            ContainsAddress(addr_t address) const
                                                                        { return address >= fBase
                                                                                && address <= fBase + (fSize - 1); }

                        bool                            IsWired() const
                                                                        { return !fWiredRanges.IsEmpty(); }
                        bool                            IsWired(addr_t base, size_t size) const;

                        void                            Wire(VMAreaWiredRange* range);
                        void                            Unwire(VMAreaWiredRange* range);
                        VMAreaWiredRange*       Unwire(addr_t base, size_t size, bool writable);

                        bool                            AddWaiterIfWired(VMAreaUnwiredWaiter* waiter);
                        bool                            AddWaiterIfWired(VMAreaUnwiredWaiter* waiter,
                                                                        addr_t base, size_t size, uint32 flags = 0);

protected:
                                                                VMArea(VMAddressSpace* addressSpace,
                                                                        uint32 wiring, uint32 protection);
                                                                ~VMArea();

                        status_t                        Init(const char* name, uint32 allocationFlags);

protected:
                        friend struct VMAreasTreeDefinition;
                        friend struct VMKernelAddressSpace;
                        friend struct VMUserAddressSpace;

protected:
                        void                            SetBase(addr_t base)    { fBase = base; }
                        void                            SetSize(size_t size)    { fSize = size; }

protected:
                        addr_t                          fBase;
                        size_t                          fSize;
                        VMAreaWiredRangeList fWiredRanges;
};


struct VMAreasTreeDefinition {
        typedef area_id         Key;
        typedef VMArea          Value;

        AVLTreeNode* GetAVLTreeNode(VMArea* value) const
        {
                return &value->tree_node;
        }

        VMArea* GetValue(AVLTreeNode* node) const
        {
                const addr_t vmTreeNodeAddr = (addr_t)node
                        - offsetof(VMAreasTreeNode, tree_node);
                VMAreasTreeNode* vmTreeNode =
                        reinterpret_cast<VMAreasTreeNode*>(vmTreeNodeAddr);
                return static_cast<VMArea*>(vmTreeNode);
        }

        int Compare(area_id key, const VMArea* value) const
        {
                const area_id valueId = value->id;
                if (valueId == key)
                        return 0;
                return key < valueId ? -1 : 1;
        }

        int Compare(const VMArea* a, const VMArea* b) const
        {
                return Compare(a->id, b);
        }
};

typedef AVLTree<VMAreasTreeDefinition> VMAreasTree;


struct VMAreas {
        static  status_t                        Init();

        static  status_t                        ReadLock()
                                                                        { return rw_lock_read_lock(&sLock); }
        static  void                            ReadUnlock()
                                                                        { rw_lock_read_unlock(&sLock); }
        static  status_t                        WriteLock()
                                                                        { return rw_lock_write_lock(&sLock); }
        static  void                            WriteUnlock()
                                                                        { rw_lock_write_unlock(&sLock); }

        static  VMArea*                         LookupLocked(area_id id)
                                                                        { return sTree.Find(id); }
        static  VMArea*                         Lookup(area_id id);
        static  area_id                         Find(const char* name);
        static  status_t                        Insert(VMArea* area);
        static  void                            Remove(VMArea* area);

        static  VMAreasTree::Iterator GetIterator()
                                                                        { return sTree.GetIterator(); }

private:
        static  rw_lock                         sLock;
        static  VMAreasTree                     sTree;
};


uint32
VMArea::MemoryType() const
{
        return (uint32)memory_type << MEMORY_TYPE_SHIFT;
}


void
VMArea::SetMemoryType(uint32 memoryType)
{
        memory_type = memoryType >> MEMORY_TYPE_SHIFT;
}


#endif  // _KERNEL_VM_VM_AREA_H