/* $NetBSD: $ */

/*-
  * Copyright (c) 2009 UPMC/LIP6
  * All rights reserved.
  * This software is distributed under the following condiions
  * compliant with the NetBSD foundation policy.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
  * are met:
  * 1. Redistributions of source code must retain the above copyright
  *    notice, this list of conditions and the following disclaimer.
  * 2. Redistributions in binary form must reproduce the above copyright
  *    notice, this list of conditions and the following disclaimer in the
  *    documentation and/or other materials provided with the distribution.
  *
  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  * POSSIBILITY OF SUCH DAMAGE.
  */

#ifndef  __TSARMIPS_PTE_H__
#define  __TSARMIPS_PTE_H__

/*
 * structures describing the MMU of the TSAR architecture
 * https://www-soc.lip6.fr/trac/tsar/wiki/VirtualMemory
 * Entries of first and second level are different.
 * The first level is a 8k page directory of 2048 32bits entries
 *  each entry describe either a 2M mapping, or point to a 4k page table.
 * The second level is a 4k page table of 512 64bits entries.
 */

/* level 1 page directory/page table defines */

/* level 1 page directory */
#define PDE1_V	(1 << 31)	/* entry valid */
#define PDE1_T	(1 << 30)	/* 1 == entry is a PTD (points to PTE2s) */

#define PDE1_SHIFT 21
#define PDE1_NBPTD  (1ULL << PDE1_SHIFT) /* bytes mapped by L1 ent (2MB) */
#define PDE1_MASK 0xffe00000
#define PDE1_FRAME (PDE1_MASK)
#define VADDR_TO_PDE1I(va) (((va) & PDE1_MASK) >> PDE1_SHIFT)
#define PD1_SIZE (PAGE_SIZE * 2) /* size of a PT1 page table */

/* level 1 page table */
#define PTE1_V	(1 << 31)	/* entry valid */
#define PTE1_T	(1 << 30)	/* 0 == entry is a PTE1 (maps a 2M page) */
#define PTE1_L	(1 << 29)	/* accessed by local CPU */
#define PTE1_R	(1 << 28)	/* accessed by remote CPU */
#define PTE1_C	(1 << 27)	/* cachable */
#define PTE1_W	(1 << 26)	/* writable */
#define PTE1_X	(1 << 25)	/* executable */
#define PTE1_U	(1 << 24)	/* user-accessible */
#define PTE1_G	(1 << 23)	/* global */
#define PTE1_D	(1 << 22)	/* dirty */
#define PTE1_w	(1 << 21)	/* software-only: wired (i.e. non-pageable) */

#undef PTE1_G
#define PTE1_G 0 /* tsarleti bug */

#define PTE1_SHIFT 21
#define PTE1_NBPTE  (1ULL << PTE1_SHIFT) /* bytes mapped by L1 ent (2MB) */
#define PTE1_MASK PTD1_MASK
#define PTE1_FRAME PDE1_FRAME
#define VADDR_TO_PTE1I(va) VADDR_TO_PDE1I(va)
#define PT1_SIZE (PAGE_SIZE * 2) /* size of a PD page table */

/* level 2 page table */
/*
 * One entry is on 2 32bit words: the first one contains flags, the second
 * the page number.
 */

#define PTE2_V	(1 << 31)	/* entry valid */
				/* 30: reserved, must be 0 */
#define PTE2_L	(1 << 29)	/* accessed by local CPU */
#define PTE2_R	(1 << 28)	/* accessed by remote CPU */
#define PTE2_C	(1 << 27)	/* cachable */
#define PTE2_W	(1 << 26)	/* writable */
#define PTE2_X	(1 << 25)	/* executable */
#define PTE2_U	(1 << 24)	/* user-accessible */
#define PTE2_G	(1 << 23)	/* global */
#define PTE2_D	(1 << 22)	/* dirty */
#define PTE2_pv	(1 <<  1)	/* software-only: managed (i.e. on a pv list) */
#define PTE2_w	(1 <<  0)	/* software-only: wired (i.e. non-pageable) */

#undef PTE2_G
#define PTE2_G 0 /* tsarleti bug */

#define PTE2_RL (PTE2_L|PTE2_R)

#define PTE2_SHIFT 12
#define PTE2_NBPTE  (1ULL << PTE2_SHIFT) /* bytes mapped by L2 ent (4KB) */
#define PTE2_MASK 0x0001ff000
#define PTE2_FRAME (PTE2_MASK | PDE1_FRAME)
#define VADDR_TO_PTE2I(va) (((va) & PTE2_MASK) >> PTE2_SHIFT)
#define PT2_SIZE PAGE_SIZE /* size of a PT2 page table */

#ifndef _LOCORE
typedef uint32_t pde1_t;
#define PTD1_ADDRMASK 0x0fffffffUL
#define PTD1_TO_PTE2PADDR(pde1) \
    ((paddr_t)((pde1_t)(pde1) & PTD1_ADDRMASK) << PTE2_SHIFT)

typedef uint32_t pte1_t;
#define PTE1_ADDRMASK 0x0007ffffUL
#define PTE1_TO_PADDR(pte1) \
    ((paddr_t)((pte1_t)(pte1) & PTE1_ADDRMASK) << PTE1_SHIFT)

typedef union {
	struct {
		
		uint32_t pte2_flags; /* PTE entry flags */
		uint32_t pte2_ppn; /* 28bit page number */
	} s;
	uint64_t pte2_val;
} pte2_t;
#define pte2_flags	s.pte2_flags
#define pte2_ppn	s.pte2_ppn

#define PTE2_ADDRMASK 0x0fffffffUL
#define PTE2_TO_PADDR(pte2) \
    ((paddr_t)((pte2).pte2_ppn & PTE2_ADDRMASK) << PTE2_SHIFT)

#define PD1_NENT (PD1_SIZE / sizeof(pde1_t))
#define PT1_NENT (PT1_SIZE / sizeof(pte1_t))
#define PT2_NENT (PT2_SIZE / sizeof(pte2_t))

static inline bool
pde1_valid_entry(pde1_t *p)
{
	return (*p & PDE1_V) ? true : false;
}

static inline bool
pte1_valid_entry(pte1_t *p)
{
	return (*p & PTE1_V) ? true : false;
}

static inline bool
pte2_valid_entry(pte2_t *p)
{
	return (p->pte2_flags & PTE2_V) ? true : false;
}
#endif /* ! _LOCORE */

#endif /* __TSARMIPS_PTE_H__ */
