Subversion Repositories HelenOS-historic

Compare Revisions

Ignore whitespace Rev 748 → Rev 749

/kernel/trunk/arch/ia64/include/mm/page.h
32,6 → 32,7
 
#include <arch/mm/frame.h>
#include <genarch/mm/page_ht.h>
#include <arch/mm/asid.h>
#include <arch/types.h>
#include <typedefs.h>
#include <debug.h>
46,20 → 47,21
#define SET_PTL0_ADDRESS_ARCH(ptl0)
 
/** Implementation of page hash table interface. */
#define HT_ENTRIES_ARCH (VHPT_SIZE/sizeof(pte_t))
#define HT_HASH_ARCH(page, asid) vhpt_hash((page), (asid))
#define HT_COMPARE_ARCH(page, asid, t) 0
#define HT_SLOT_EMPTY_ARCH(t) 1
#define HT_INVALIDATE_SLOT_ARCH(t)
#define HT_GET_NEXT_ARCH(t) 0
#define HT_SET_NEXT_ARCH(t, s)
#define HT_SET_RECORD_ARCH(t, page, asid, frame, flags)
#define HT_ENTRIES_ARCH (VHPT_SIZE/sizeof(pte_t))
#define HT_HASH_ARCH(page, asid) vhpt_hash((page), (asid))
#define HT_COMPARE_ARCH(page, asid, t) vhpt_compare((page), (asid), (t))
#define HT_SLOT_EMPTY_ARCH(t) ((t)->present.tag.tag_info.ti)
#define HT_INVALIDATE_SLOT_ARCH(t) (t)->present.tag.tag_info.ti = true
#define HT_GET_NEXT_ARCH(t) (t)->present.next
#define HT_SET_NEXT_ARCH(t, s) (t)->present.next = (s)
#define HT_SET_RECORD_ARCH(t, page, asid, frame, flags) vhpt_set_record(t, page, asid, frame, flags)
 
#define PPN_SHIFT 12
 
#define VRN_SHIFT 61
#define VRN_MASK (7LL << VRN_SHIFT)
 
#define VRN_KERNEL 0
#define VRN_WORK 1LL
#define REGION_REGISTERS 8
 
#define VHPT_WIDTH 20 /* 1M */
67,6 → 69,19
 
#define VHPT_BASE page_ht /* Must be aligned to VHPT_SIZE */
 
/** Memory Attributes. */
#define MA_WRITEBACK 0x0
#define MA_UNCACHEABLE 0x4
 
/** Privilege Levels. Only the most and the least privileged ones are ever used. */
#define PL_KERNEL 0x0
#define PL_USER 0x3
 
/* Access Rigths. Only certain combinations are used by the kernel. */
#define AR_READ 0x0
#define AR_EXECUTE 0x1
#define AR_WRITE 0x2
 
struct vhpt_tag_info {
unsigned long long tag : 63;
unsigned ti : 1;
101,7 → 116,7
union vhpt_tag tag;
/* Word 3 */
unsigned long long next : 64; /**< Collision chain next pointer. */
pte_t *next; /**< Collision chain next pointer. */
} __attribute__ ((packed));
 
struct vhpt_entry_not_present {
119,7 → 134,7
union vhpt_tag tag;
/* Word 3 */
unsigned long long next : 64; /**< Collision chain next pointer. */
pte_t *next; /**< Collision chain next pointer. */
} __attribute__ ((packed));
 
126,6 → 141,7
typedef union vhpt_entry {
struct vhpt_entry_present present;
struct vhpt_entry_not_present not_present;
__u64 word[4];
} vhpt_entry;
 
struct region_register_map {
243,5 → 259,7
 
extern void page_arch_init(void);
extern pte_t *vhpt_hash(__address page, asid_t asid);
extern bool vhpt_compare(__address page, asid_t asid, pte_t *t);
extern void vhpt_set_record(pte_t *t, __address page, asid_t asid, __address frame, int flags);
 
#endif
/kernel/trunk/arch/ia64/include/mm/asid.h
42,6 → 42,11
#define RIDS_PER_ASID 7
#define RID_OVERFLOW 16777216 /* 2^24 */
 
#define ASID2RID(asid, vrn) (((asid)*RIDS_PER_ASID)+(vrn))
#define RID2ASID(rid) ((rid)/RIDS_PER_ASID)
 
typedef __u32 rid_t;
 
/**
* This macro is needed only to compile the kernel.
* On ia64, its value is ignored.
/kernel/trunk/arch/ia64/src/mm/asid.c
49,6 → 49,7
#include <arch/mm/asid.h>
#include <mm/asid.h>
#include <mm/as.h>
#include <genarch/mm/page_ht.h>
#include <mm/tlb.h>
#include <list.h>
#include <typedefs.h>
104,6 → 105,17
as->asid = next_asid++;
spinlock_unlock(&as->lock);
}
/*
* The page hash table uses VHPT long format PTE's.
* Unfortunatelly, this format has no space to
* store as_t pointer, so it is necessary to
* invalidate the whole structure after all ASIDs
* have been reassigned. The information swept out
* from the page hash table can be later reconstructed
* from as_t structures on demand.
*/
ht_invalidate_all();
 
/*
* Finish TLB shootdown.
/kernel/trunk/arch/ia64/src/mm/page.c
30,7 → 30,9
#include <arch/mm/page.h>
#include <genarch/mm/page_ht.h>
#include <mm/asid.h>
#include <arch/mm/asid.h>
#include <arch/types.h>
#include <typedefs.h>
#include <print.h>
#include <mm/page.h>
#include <mm/frame.h>
40,8 → 42,18
#include <arch/barrier.h>
#include <memstr.h>
 
static void set_vhpt_environment(void);
 
/** Initialize ia64 virtual address translation subsystem. */
void page_arch_init(void)
{
page_operations = &page_ht_operations;
pk_disable();
set_vhpt_environment();
}
 
/** Initialize VHPT and region registers. */
static void set_vhpt_environment(void)
void set_vhpt_environment(void)
{
region_register rr;
pta_register pta;
94,22 → 106,9
srlz_d();
}
 
/** Initialize ia64 virtual address translation subsystem. */
void page_arch_init(void)
{
page_operations = &page_ht_operations;
pk_disable();
set_vhpt_environment();
}
 
/** Calculate address of collision chain from VPN and ASID.
*
* This is rather non-trivial function.
* First, it has to translate ASID to RID.
* This is achieved by taking VRN bits of
* page into account.
* Second, it must preserve the region register
* it writes the RID to.
* Interrupts must be disabled.
*
* @param page Address of virtual page including VRN bits.
* @param asid Address space identifier.
119,20 → 118,135
pte_t *vhpt_hash(__address page, asid_t asid)
{
region_register rr_save, rr;
index_t vrn;
rid_t rid;
pte_t *t;
 
rr_save.word = rr_read(VRN_WORK);
vrn = page >> VRN_SHIFT;
rid = ASID2RID(asid, vrn);
rr_save.word = rr_read(vrn);
if (rr_save.map.rid == rid) {
/*
* The RID is already in place, compute thash and return.
*/
t = (pte_t *) thash(page);
return t;
}
/*
* The RID must be written to some region register.
* To speed things up, register indexed by vrn is used.
*/
rr.word = rr_save.word;
if ((page >> VRN_SHIFT) != VRN_KERNEL)
rr.map.rid = (asid * RIDS_PER_ASID) + (page >> VRN_SHIFT);
else
rr.map.rid = ASID_KERNEL;
rr_write(VRN_WORK, rr.word);
rr.map.rid = rid;
rr_write(vrn, rr.word);
srlz_i();
t = (pte_t *) thash((VRN_WORK << VRN_SHIFT) | (~(VRN_MASK) & page));
rr_write(VRN_WORK, rr_save.word);
t = (pte_t *) thash(page);
rr_write(vrn, rr_save.word);
srlz_i();
srlz_d();
 
return t;
}
 
/** Compare ASID and VPN against PTE.
*
* Interrupts must be disabled.
*
* @param page Address of virtual page including VRN bits.
* @param asid Address space identifier.
*
* @return True if page and asid match the page and asid of t, false otherwise.
*/
bool vhpt_compare(__address page, asid_t asid, pte_t *t)
{
region_register rr_save, rr;
index_t vrn;
rid_t rid;
bool match;
 
ASSERT(t);
 
vrn = page >> VRN_SHIFT;
rid = ASID2RID(asid, vrn);
rr_save.word = rr_read(vrn);
if (rr_save.map.rid == rid) {
/*
* The RID is already in place, compare ttag with t and return.
*/
return ttag(page) == t->present.tag.tag_word;
}
/*
* The RID must be written to some region register.
* To speed things up, register indexed by vrn is used.
*/
rr.word = rr_save.word;
rr.map.rid = rid;
rr_write(vrn, rr.word);
srlz_i();
match = (ttag(page) == t->present.tag.tag_word);
rr_write(vrn, rr_save.word);
srlz_i();
srlz_d();
 
return match;
}
 
/** Set up one VHPT entry.
*
* @param t VHPT entry to be set up.
* @param page Virtual address of the page mapped by the entry.
* @param asid Address space identifier of the address space to which page belongs.
* @param frame Physical address of the frame to wich page is mapped.
* @param flags Different flags for the mapping.
*/
void vhpt_set_record(pte_t *t, __address page, asid_t asid, __address frame, int flags)
{
region_register rr_save, rr;
index_t vrn;
rid_t rid;
__u64 tag;
 
ASSERT(t);
 
vrn = page >> VRN_SHIFT;
rid = ASID2RID(asid, vrn);
/*
* Compute ttag.
*/
rr_save.word = rr_read(vrn);
rr.word = rr_save.word;
rr.map.rid = rid;
rr_write(vrn, rr.word);
srlz_i();
tag = ttag(page);
rr_write(vrn, rr_save.word);
srlz_i();
srlz_d();
/*
* Clear the entry.
*/
t->word[0] = 0;
t->word[1] = 0;
t->word[2] = 0;
t->word[3] = 0;
t->present.p = true;
t->present.ma = (flags & PAGE_CACHEABLE) ? MA_WRITEBACK : MA_UNCACHEABLE;
t->present.a = false; /* not accessed */
t->present.d = false; /* not dirty */
t->present.pl = (flags & PAGE_USER) ? PL_USER : PL_KERNEL;
t->present.ar = (flags & PAGE_WRITE) ? AR_WRITE : AR_READ;
t->present.ar |= (flags & PAGE_EXEC) ? AR_EXECUTE : 0;
t->present.ppn = frame >> PPN_SHIFT;
t->present.ed = false; /* exception not deffered */
t->present.ps = PAGE_WIDTH;
t->present.key = 0;
t->present.tag.tag_word = tag;
t->present.next = NULL;
}