/*
    Copyright 2001 (c) by Claudio Jeker,
    Swiss Federal Institute of Technology,
    Computer Engineering and Networks Laboratory.
 
    TOPSY -- A Teachable Operating System.
             Implementation of a tiny and simple
             micro kernel for teaching purposes.
 
    For further information, please visit http://www.tik.ee.ethz.ch/~topsy
 
    This software is provided under the terms of the GNU General Public 
    Licence. A full copy of the GNU GPL is provided in the file COPYING 
    found in the development root of Topsy.
*/
/*
	
    File:                  $Source: /home/ruf/cvs_Topsy/cvs/Topsy/VMemory/Attic/vm_page.h,v $
    Affiliation:           ETH Zuerich, TIK
    Version:               $Revision: 2922 $
    Last Date of Change:   $Date: 2007-03-19 17:48:52 +0100 (Mon, 19 Mär 2007) $  by: $Author: baderma $
 
*/

/*
	 vm_page: machine independent part of the page handling stuff
 
	 Here we define the vm_page API to access and modify pages in the VM System.
	 It is important that this API is used so the code can be more modular and
	 object oriented. In other words, don't touch the vm_page structure directly!
 
	 The vm_page structures are allocated and initialized on boot up. For all 
	 physical pages in the system there exists one such vm_page struct. 
	 Only drivers with support for virtualy memory mapped IO need to allocate 
	 extra wired vm_pages. 
	 There exist multiple page queues where a page can be located:
	 - free list: list of pages that are not used but not zeroed out
	 - zero list: list of pages that are free and zeroed out
	 - used list: list of pages that are in use
	 - wired list: list of pages that are specially wired (e.g. for drivers)
	 - unused list:list of pages that are left because of rounding errors.
	 
	 To support Copy-on-Write, page loan out and snapshots an additional
	 abstarction level is needed. The vm_pref structure adds this abstraction
	 layer. 
	 How does it work? Why do we need it?
	 If we only want to support Copy-on-Write we wouldn't need this 
	 abstraction because all pages have only one object where they belong to.
	 The problem starts with page loan out and Snapshots. Suddenly we have 
	 multiple objects that point to this page. Without the reference it would be
	 hard to store the pages in all the different locations without having the 
	 problem of large search times. The vm_pref belongs only to one vm_page and 
	 one or more (COW) vm_object, so we can use this structure for fast (hash 
	 tree based) lookups.
	 vm_prefs are object dependent so it is possible to have special lookup 
	 functions for each object. It's up to the object manager to store and 
	 link his vm_pref structure.
 
	 Meaning of the refcount:
	 The refcount steers the Copy-on-Write behaviour. If the refcount is zero 
	 the page is unused (free). If the refcount is greater then one then we 
	 have one of the copy on write cases so we have do make a copy of the page.
	 This has to be done until the refcount drops to one.
	 
	 Some notes about locking:
	 there exist two locks for pages the one lock is for the object and the other
	 lock is for the global page queues (free, zero, ...). Some modifications can
	 be done with only on lock others need locks on object(O) and queue(P).
	 vm_pages normaly need a P (page queue) lock whereas the vm_prefs use 
	 the O (object) lock.
	 The only exception is the refcount where both locks are needed. XXX ???
	 
 */
#ifndef __VM_PAGE_H__
#define __VM_PAGE_H__

#include "tailq.h"
#include "types.h"

#include "vm_bootup.h"

#define PQ_FREE 0x01
#define PQ_ZERO 0x02
#define PQ_USED 0x03
#define PQ_WIRED 0x04


struct vm_page
{
  TAILQ_ENTRY(vm_page) pageq; /* page queue (P) */
  unsigned int pqflags; /* page queue flags (P) */

  unsigned long pagenr; /* physical page nr (do not modify!) */

  unsigned int refcount; /* reference count
  													* to read: (O or P)
  													* to write: (O and P) ??? what if multiple O XXX
  													*/
  /* XXX LockDesc reflock; The simplest sollution */
};

TAILQ_HEAD(vm_pageq_header, vm_page);


/* this is only the object independent structure, this structure has to
 * be added at the head of object dependent prefs */
struct vm_pref
{
  offset_t offset; /* offset in the object
  										* XXX	address needs to be paged aligned */

  address_t object; /* back pointer to the object useing this reference */

  struct vm_page* page; /* pointer to vm_page structure */

  /* the internal linking of prevs into objects is object dependent
  	 so the vm_pref has to be added at the beginning of a object
  	 dependent vm_pref descriptor
   */
};

#define VM_PREF(x) ((struct vm_pref*)(x))

void vm_page_init(struct vm_segmap* segmap);
/* called only once at startup, allocates one vm_page struct per physical
	 page. If this function fails we get a nice PANIC else we have allmost
	 all pages on the free list. Some pages are hardwired to the kernel with
	 vm_page_resv().
 */

struct vm_page* vm_page_map(unsigned int pagenr);
/* early reserved pages for kernel are linked to an object via this function.
	 Do a search for the pagenr and return this page.
 */

struct vm_page* vm_page_wire(address_t phys);
/* allocate a vm_page and wire that page to a physical address.
	 This function can be used by drivers to allocate direct mapped memory
 */

/* Object API:
 *	the following functions should be used by the vm object to access
 *	vm_pages. The only value of a page that can be savely accessed from
 *	a vm_pref is the page number via the VM_PAGE_GETNR macro.
 */
#define VM_PAGE_GETNR(vmpage) ((vmpage)->pagenr)
unsigned long vm_page_getnr(struct vm_page* p);
/* get the physical page nr for this page */
address_t vm_page_getaddr(struct vm_page* p);

int vm_page_ref(struct vm_page* p);
/* add reference to page or better increase refcount */

int vm_page_unref(struct vm_page* p);
/* remove reference to page or just decrease the refcount */

int vm_page_getref(struct vm_page* p);
/* return current refcount */

struct vm_page* vm_page_get(unsigned int flags);
/* returns a free page if possible */

int vm_page_unget(struct vm_page* p);
/* if refcount drops to zero this function should be called */

unsigned int vm_page_getflags(struct vm_page* p);
/* get the page queue flags of the page */

struct vm_page* vm_page_copy(struct vm_page* p);
/* copy the specified page */

void vm_page_print(struct vm_page* p);
void vm_page_print_all(int flags);

#endif
