/*!
    \file  Segments.h
    \brief Segment memory management

    Copyright (c) 2003 HigePon
    WITHOUT ANY WARRANTY

    \author  HigePon
    \version $Revision: 1.2 $
    \date   create:2003/10/19 update:$Date: 2004/04/28 09:31:30 $
*/
#ifndef _MONA_SEGMENTS_
#define _MONA_SEGMENTS_

#include "PageManager.h"
#include "operator.h"
#include "kernel.h"
#include "string.h"
#include "Process.h"

class SharedMemoryObject {

  public:
    SharedMemoryObject();
    SharedMemoryObject(dword id, dword size);
    SharedMemoryObject(dword id, dword size, dword pid, dword linearAddress);
    void initilize(dword id, dword size);
    virtual ~SharedMemoryObject();

    inline virtual int getAttachedCount() const {
        return attachedCount_;
    }

    inline virtual void setAttachedCount(int count) {
        attachedCount_ = count;
    }

    inline virtual dword getId() const {
        return id_;
    }

    inline virtual dword getSize() const {
        return size_;
    }

    inline virtual int isMapped(int physicalIndex) const {

        if (physicalIndex >= physicalPageCount_) return UN_MAPPED;
        return physicalPages_[physicalIndex];
    }

    inline virtual void map(int physicalIndex, PhysicalAddress address) {

        if (physicalIndex >= physicalPageCount_) return;

        physicalPages_[physicalIndex] = address;
    }

  public:
    static void setup();
    static bool open(dword id, dword size);
    static bool open(dword id, dword size, dword pid, dword linearAddress);
    static bool attach(dword id, struct Process* process, LinearAddress address);
    static bool detach(dword id, struct Process* process);
    static SharedMemoryObject* find(dword id);
    static const int UN_MAPPED = -1;

  private:
    dword id_;
    dword size_;
    int attachedCount_;
    int physicalPageCount_;
    int* physicalPages_;
};

class Segment {

  public:
    virtual bool faultHandler(LinearAddress address, dword error) = 0;

    inline virtual int getErrorNumber() {
        return errorNumber_;
    }

    inline virtual LinearAddress getStart() {
        return start_;
    }

    inline virtual dword getSize() {
        return size_;
    }

    inline virtual bool inRange(LinearAddress address) {

        return (address >= start_ && address < start_ + size_);
    }

  protected:
    LinearAddress start_;
    dword         size_;
    byte errorNumber_;

  public:
    static const byte FAULT_STACK_OVERFLOW = 0x01;
    static const byte FAULT_OUT_OF_RANGE   = 0x02;
    static const byte FAULT_UNKNOWN        = 0x03;
};

class StackSegment : public Segment {

  public:
    StackSegment(LinearAddress start, dword size);
    StackSegment(Process* process, LinearAddress start, dword initileSize, dword maxSize);
    virtual ~StackSegment();

  public:
    virtual bool faultHandler(LinearAddress address, dword error);
    virtual bool inRange(LinearAddress address) {
        return (address >= start_ - PageManager::ARCH_PAGE_SIZE && address <= start_);
    }

  private:
    bool tryExtend(Process* process, LinearAddress address);
    bool allocatePage(Process* process, LinearAddress address);

  protected:
    bool isAutoExtend_;
    dword maxSize_;
};

class HeapSegment : public Segment {

  public:
    HeapSegment(LinearAddress start, dword size);
    virtual ~HeapSegment();

  public:
    virtual bool faultHandler(LinearAddress address, dword error);
};

class SharedMemorySegment : public Segment {

  public:
    SharedMemorySegment();
    SharedMemorySegment(LinearAddress start, dword size, SharedMemoryObject* sharedMemoryObject);
    virtual ~SharedMemorySegment();

  public:
    virtual bool faultHandler(LinearAddress address, dword error);
    inline virtual dword getId() const {
        return sharedMemoryObject_->getId();
    }

  public:
    static SharedMemorySegment* find(Process* process, dword id);

  protected:
    SharedMemoryObject* sharedMemoryObject_;
};

#endif
