Subversion Repositories HelenOS

Compare Revisions

Ignore whitespace Rev 2089 → Rev 2130

/tags/0.2.0.4/kernel/arch/ia64/src/mm/tlb.c
0,0 → 1,688
/*
* Copyright (c) 2006 Jakub Jermar
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* - Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* - 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.
* - The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.
*/
 
/** @addtogroup ia64mm
* @{
*/
/** @file
*/
 
/*
* TLB management.
*/
 
#include <mm/tlb.h>
#include <mm/asid.h>
#include <mm/page.h>
#include <mm/as.h>
#include <arch/mm/tlb.h>
#include <arch/mm/page.h>
#include <arch/mm/vhpt.h>
#include <arch/barrier.h>
#include <arch/interrupt.h>
#include <arch/pal/pal.h>
#include <arch/asm.h>
#include <panic.h>
#include <print.h>
#include <arch.h>
#include <interrupt.h>
 
/** Invalidate all TLB entries. */
void tlb_invalidate_all(void)
{
ipl_t ipl;
uintptr_t adr;
uint32_t count1, count2, stride1, stride2;
int i, j;
adr = PAL_PTCE_INFO_BASE();
count1 = PAL_PTCE_INFO_COUNT1();
count2 = PAL_PTCE_INFO_COUNT2();
stride1 = PAL_PTCE_INFO_STRIDE1();
stride2 = PAL_PTCE_INFO_STRIDE2();
ipl = interrupts_disable();
 
for(i = 0; i < count1; i++) {
for(j = 0; j < count2; j++) {
asm volatile (
"ptc.e %0 ;;"
:
: "r" (adr)
);
adr += stride2;
}
adr += stride1;
}
 
interrupts_restore(ipl);
 
srlz_d();
srlz_i();
#ifdef CONFIG_VHPT
vhpt_invalidate_all();
#endif
}
 
/** Invalidate entries belonging to an address space.
*
* @param asid Address space identifier.
*/
void tlb_invalidate_asid(asid_t asid)
{
tlb_invalidate_all();
}
 
 
void tlb_invalidate_pages(asid_t asid, uintptr_t page, count_t cnt)
{
region_register rr;
bool restore_rr = false;
int b = 0;
int c = cnt;
 
uintptr_t va;
va = page;
 
rr.word = rr_read(VA2VRN(va));
if ((restore_rr = (rr.map.rid != ASID2RID(asid, VA2VRN(va))))) {
/*
* The selected region register does not contain required RID.
* Save the old content of the register and replace the RID.
*/
region_register rr0;
 
rr0 = rr;
rr0.map.rid = ASID2RID(asid, VA2VRN(va));
rr_write(VA2VRN(va), rr0.word);
srlz_d();
srlz_i();
}
while(c >>= 1)
b++;
b >>= 1;
uint64_t ps;
switch (b) {
case 0: /*cnt 1-3*/
ps = PAGE_WIDTH;
break;
case 1: /*cnt 4-15*/
/*cnt=((cnt-1)/4)+1;*/
ps = PAGE_WIDTH+2;
va &= ~((1<<ps)-1);
break;
case 2: /*cnt 16-63*/
/*cnt=((cnt-1)/16)+1;*/
ps = PAGE_WIDTH+4;
va &= ~((1<<ps)-1);
break;
case 3: /*cnt 64-255*/
/*cnt=((cnt-1)/64)+1;*/
ps = PAGE_WIDTH+6;
va &= ~((1<<ps)-1);
break;
case 4: /*cnt 256-1023*/
/*cnt=((cnt-1)/256)+1;*/
ps = PAGE_WIDTH+8;
va &= ~((1<<ps)-1);
break;
case 5: /*cnt 1024-4095*/
/*cnt=((cnt-1)/1024)+1;*/
ps = PAGE_WIDTH+10;
va &= ~((1<<ps)-1);
break;
case 6: /*cnt 4096-16383*/
/*cnt=((cnt-1)/4096)+1;*/
ps = PAGE_WIDTH+12;
va &= ~((1<<ps)-1);
break;
case 7: /*cnt 16384-65535*/
case 8: /*cnt 65536-(256K-1)*/
/*cnt=((cnt-1)/16384)+1;*/
ps = PAGE_WIDTH+14;
va &= ~((1<<ps)-1);
break;
default:
/*cnt=((cnt-1)/(16384*16))+1;*/
ps=PAGE_WIDTH+18;
va&=~((1<<ps)-1);
break;
}
/*cnt+=(page!=va);*/
for(; va<(page+cnt*(PAGE_SIZE)); va += (1<<ps)) {
asm volatile (
"ptc.l %0,%1;;"
:
: "r" (va), "r" (ps<<2)
);
}
srlz_d();
srlz_i();
if (restore_rr) {
rr_write(VA2VRN(va), rr.word);
srlz_d();
srlz_i();
}
}
 
/** Insert data into data translation cache.
*
* @param va Virtual page address.
* @param asid Address space identifier.
* @param entry The rest of TLB entry as required by TLB insertion format.
*/
void dtc_mapping_insert(uintptr_t va, asid_t asid, tlb_entry_t entry)
{
tc_mapping_insert(va, asid, entry, true);
}
 
/** Insert data into instruction translation cache.
*
* @param va Virtual page address.
* @param asid Address space identifier.
* @param entry The rest of TLB entry as required by TLB insertion format.
*/
void itc_mapping_insert(uintptr_t va, asid_t asid, tlb_entry_t entry)
{
tc_mapping_insert(va, asid, entry, false);
}
 
/** Insert data into instruction or data translation cache.
*
* @param va Virtual page address.
* @param asid Address space identifier.
* @param entry The rest of TLB entry as required by TLB insertion format.
* @param dtc If true, insert into data translation cache, use instruction translation cache otherwise.
*/
void tc_mapping_insert(uintptr_t va, asid_t asid, tlb_entry_t entry, bool dtc)
{
region_register rr;
bool restore_rr = false;
 
rr.word = rr_read(VA2VRN(va));
if ((restore_rr = (rr.map.rid != ASID2RID(asid, VA2VRN(va))))) {
/*
* The selected region register does not contain required RID.
* Save the old content of the register and replace the RID.
*/
region_register rr0;
 
rr0 = rr;
rr0.map.rid = ASID2RID(asid, VA2VRN(va));
rr_write(VA2VRN(va), rr0.word);
srlz_d();
srlz_i();
}
asm volatile (
"mov r8=psr;;\n"
"rsm %0;;\n" /* PSR_IC_MASK */
"srlz.d;;\n"
"srlz.i;;\n"
"mov cr.ifa=%1\n" /* va */
"mov cr.itir=%2;;\n" /* entry.word[1] */
"cmp.eq p6,p7 = %4,r0;;\n" /* decide between itc and dtc */
"(p6) itc.i %3;;\n"
"(p7) itc.d %3;;\n"
"mov psr.l=r8;;\n"
"srlz.d;;\n"
:
: "i" (PSR_IC_MASK), "r" (va), "r" (entry.word[1]), "r" (entry.word[0]), "r" (dtc)
: "p6", "p7", "r8"
);
if (restore_rr) {
rr_write(VA2VRN(va), rr.word);
srlz_d();
srlz_i();
}
}
 
/** Insert data into instruction translation register.
*
* @param va Virtual page address.
* @param asid Address space identifier.
* @param entry The rest of TLB entry as required by TLB insertion format.
* @param tr Translation register.
*/
void itr_mapping_insert(uintptr_t va, asid_t asid, tlb_entry_t entry, index_t tr)
{
tr_mapping_insert(va, asid, entry, false, tr);
}
 
/** Insert data into data translation register.
*
* @param va Virtual page address.
* @param asid Address space identifier.
* @param entry The rest of TLB entry as required by TLB insertion format.
* @param tr Translation register.
*/
void dtr_mapping_insert(uintptr_t va, asid_t asid, tlb_entry_t entry, index_t tr)
{
tr_mapping_insert(va, asid, entry, true, tr);
}
 
/** Insert data into instruction or data translation register.
*
* @param va Virtual page address.
* @param asid Address space identifier.
* @param entry The rest of TLB entry as required by TLB insertion format.
* @param dtr If true, insert into data translation register, use instruction translation register otherwise.
* @param tr Translation register.
*/
void tr_mapping_insert(uintptr_t va, asid_t asid, tlb_entry_t entry, bool dtr, index_t tr)
{
region_register rr;
bool restore_rr = false;
 
rr.word = rr_read(VA2VRN(va));
if ((restore_rr = (rr.map.rid != ASID2RID(asid, VA2VRN(va))))) {
/*
* The selected region register does not contain required RID.
* Save the old content of the register and replace the RID.
*/
region_register rr0;
 
rr0 = rr;
rr0.map.rid = ASID2RID(asid, VA2VRN(va));
rr_write(VA2VRN(va), rr0.word);
srlz_d();
srlz_i();
}
 
asm volatile (
"mov r8=psr;;\n"
"rsm %0;;\n" /* PSR_IC_MASK */
"srlz.d;;\n"
"srlz.i;;\n"
"mov cr.ifa=%1\n" /* va */
"mov cr.itir=%2;;\n" /* entry.word[1] */
"cmp.eq p6,p7=%5,r0;;\n" /* decide between itr and dtr */
"(p6) itr.i itr[%4]=%3;;\n"
"(p7) itr.d dtr[%4]=%3;;\n"
"mov psr.l=r8;;\n"
"srlz.d;;\n"
:
: "i" (PSR_IC_MASK), "r" (va), "r" (entry.word[1]), "r" (entry.word[0]), "r" (tr), "r" (dtr)
: "p6", "p7", "r8"
);
if (restore_rr) {
rr_write(VA2VRN(va), rr.word);
srlz_d();
srlz_i();
}
}
 
/** Insert data into DTLB.
*
* @param page Virtual page address including VRN bits.
* @param frame Physical frame address.
* @param dtr If true, insert into data translation register, use data translation cache otherwise.
* @param tr Translation register if dtr is true, ignored otherwise.
*/
void dtlb_kernel_mapping_insert(uintptr_t page, uintptr_t frame, bool dtr, index_t tr)
{
tlb_entry_t entry;
entry.word[0] = 0;
entry.word[1] = 0;
entry.p = true; /* present */
entry.ma = MA_WRITEBACK;
entry.a = true; /* already accessed */
entry.d = true; /* already dirty */
entry.pl = PL_KERNEL;
entry.ar = AR_READ | AR_WRITE;
entry.ppn = frame >> PPN_SHIFT;
entry.ps = PAGE_WIDTH;
if (dtr)
dtr_mapping_insert(page, ASID_KERNEL, entry, tr);
else
dtc_mapping_insert(page, ASID_KERNEL, entry);
}
 
/** Purge kernel entries from DTR.
*
* Purge DTR entries used by the kernel.
*
* @param page Virtual page address including VRN bits.
* @param width Width of the purge in bits.
*/
void dtr_purge(uintptr_t page, count_t width)
{
asm volatile ("ptr.d %0, %1\n" : : "r" (page), "r" (width<<2));
}
 
 
/** Copy content of PTE into data translation cache.
*
* @param t PTE.
*/
void dtc_pte_copy(pte_t *t)
{
tlb_entry_t entry;
 
entry.word[0] = 0;
entry.word[1] = 0;
entry.p = t->p;
entry.ma = t->c ? MA_WRITEBACK : MA_UNCACHEABLE;
entry.a = t->a;
entry.d = t->d;
entry.pl = t->k ? PL_KERNEL : PL_USER;
entry.ar = t->w ? AR_WRITE : AR_READ;
entry.ppn = t->frame >> PPN_SHIFT;
entry.ps = PAGE_WIDTH;
dtc_mapping_insert(t->page, t->as->asid, entry);
#ifdef CONFIG_VHPT
vhpt_mapping_insert(t->page, t->as->asid, entry);
#endif
}
 
/** Copy content of PTE into instruction translation cache.
*
* @param t PTE.
*/
void itc_pte_copy(pte_t *t)
{
tlb_entry_t entry;
 
entry.word[0] = 0;
entry.word[1] = 0;
ASSERT(t->x);
entry.p = t->p;
entry.ma = t->c ? MA_WRITEBACK : MA_UNCACHEABLE;
entry.a = t->a;
entry.pl = t->k ? PL_KERNEL : PL_USER;
entry.ar = t->x ? (AR_EXECUTE | AR_READ) : AR_READ;
entry.ppn = t->frame >> PPN_SHIFT;
entry.ps = PAGE_WIDTH;
itc_mapping_insert(t->page, t->as->asid, entry);
#ifdef CONFIG_VHPT
vhpt_mapping_insert(t->page, t->as->asid, entry);
#endif
}
 
/** Instruction TLB fault handler for faults with VHPT turned off.
*
* @param vector Interruption vector.
* @param istate Structure with saved interruption state.
*/
void alternate_instruction_tlb_fault(uint64_t vector, istate_t *istate)
{
region_register rr;
rid_t rid;
uintptr_t va;
pte_t *t;
va = istate->cr_ifa; /* faulting address */
rr.word = rr_read(VA2VRN(va));
rid = rr.map.rid;
 
page_table_lock(AS, true);
t = page_mapping_find(AS, va);
if (t) {
/*
* The mapping was found in software page hash table.
* Insert it into data translation cache.
*/
itc_pte_copy(t);
page_table_unlock(AS, true);
} else {
/*
* Forward the page fault to address space page fault handler.
*/
page_table_unlock(AS, true);
if (as_page_fault(va, PF_ACCESS_EXEC, istate) == AS_PF_FAULT) {
fault_if_from_uspace(istate,"Page fault at %p",va);
panic("%s: va=%p, rid=%d, iip=%p\n", __FUNCTION__, va, rid, istate->cr_iip);
}
}
}
 
/** Data TLB fault handler for faults with VHPT turned off.
*
* @param vector Interruption vector.
* @param istate Structure with saved interruption state.
*/
void alternate_data_tlb_fault(uint64_t vector, istate_t *istate)
{
region_register rr;
rid_t rid;
uintptr_t va;
pte_t *t;
va = istate->cr_ifa; /* faulting address */
rr.word = rr_read(VA2VRN(va));
rid = rr.map.rid;
if (RID2ASID(rid) == ASID_KERNEL) {
if (VA2VRN(va) == VRN_KERNEL) {
/*
* Provide KA2PA(identity) mapping for faulting piece of
* kernel address space.
*/
dtlb_kernel_mapping_insert(va, KA2PA(va), false, 0);
return;
}
}
 
page_table_lock(AS, true);
t = page_mapping_find(AS, va);
if (t) {
/*
* The mapping was found in the software page hash table.
* Insert it into data translation cache.
*/
dtc_pte_copy(t);
page_table_unlock(AS, true);
} else {
/*
* Forward the page fault to the address space page fault handler.
*/
page_table_unlock(AS, true);
if (as_page_fault(va, PF_ACCESS_READ, istate) == AS_PF_FAULT) {
fault_if_from_uspace(istate,"Page fault at %p",va);
panic("%s: va=%p, rid=%d, iip=%p\n", __FUNCTION__, va, rid, istate->cr_iip);
}
}
}
 
/** Data nested TLB fault handler.
*
* This fault should not occur.
*
* @param vector Interruption vector.
* @param istate Structure with saved interruption state.
*/
void data_nested_tlb_fault(uint64_t vector, istate_t *istate)
{
panic("%s\n", __FUNCTION__);
}
 
/** Data Dirty bit fault handler.
*
* @param vector Interruption vector.
* @param istate Structure with saved interruption state.
*/
void data_dirty_bit_fault(uint64_t vector, istate_t *istate)
{
region_register rr;
rid_t rid;
uintptr_t va;
pte_t *t;
va = istate->cr_ifa; /* faulting address */
rr.word = rr_read(VA2VRN(va));
rid = rr.map.rid;
 
page_table_lock(AS, true);
t = page_mapping_find(AS, va);
ASSERT(t && t->p);
if (t && t->p && t->w) {
/*
* Update the Dirty bit in page tables and reinsert
* the mapping into DTC.
*/
t->d = true;
dtc_pte_copy(t);
} else {
if (as_page_fault(va, PF_ACCESS_WRITE, istate) == AS_PF_FAULT) {
fault_if_from_uspace(istate,"Page fault at %p",va);
panic("%s: va=%p, rid=%d, iip=%p\n", __FUNCTION__, va, rid, istate->cr_iip);
t->d = true;
dtc_pte_copy(t);
}
}
page_table_unlock(AS, true);
}
 
/** Instruction access bit fault handler.
*
* @param vector Interruption vector.
* @param istate Structure with saved interruption state.
*/
void instruction_access_bit_fault(uint64_t vector, istate_t *istate)
{
region_register rr;
rid_t rid;
uintptr_t va;
pte_t *t;
 
va = istate->cr_ifa; /* faulting address */
rr.word = rr_read(VA2VRN(va));
rid = rr.map.rid;
 
page_table_lock(AS, true);
t = page_mapping_find(AS, va);
ASSERT(t && t->p);
if (t && t->p && t->x) {
/*
* Update the Accessed bit in page tables and reinsert
* the mapping into ITC.
*/
t->a = true;
itc_pte_copy(t);
} else {
if (as_page_fault(va, PF_ACCESS_EXEC, istate) == AS_PF_FAULT) {
fault_if_from_uspace(istate,"Page fault at %p",va);
panic("%s: va=%p, rid=%d, iip=%p\n", __FUNCTION__, va, rid, istate->cr_iip);
t->a = true;
itc_pte_copy(t);
}
}
page_table_unlock(AS, true);
}
 
/** Data access bit fault handler.
*
* @param vector Interruption vector.
* @param istate Structure with saved interruption state.
*/
void data_access_bit_fault(uint64_t vector, istate_t *istate)
{
region_register rr;
rid_t rid;
uintptr_t va;
pte_t *t;
 
va = istate->cr_ifa; /* faulting address */
rr.word = rr_read(VA2VRN(va));
rid = rr.map.rid;
 
page_table_lock(AS, true);
t = page_mapping_find(AS, va);
ASSERT(t && t->p);
if (t && t->p) {
/*
* Update the Accessed bit in page tables and reinsert
* the mapping into DTC.
*/
t->a = true;
dtc_pte_copy(t);
} else {
if (as_page_fault(va, PF_ACCESS_READ, istate) == AS_PF_FAULT) {
fault_if_from_uspace(istate,"Page fault at %p",va);
panic("%s: va=%p, rid=%d, iip=%p\n", __FUNCTION__, va, rid, istate->cr_iip);
t->a = true;
itc_pte_copy(t);
}
}
page_table_unlock(AS, true);
}
 
/** Page not present fault handler.
*
* @param vector Interruption vector.
* @param istate Structure with saved interruption state.
*/
void page_not_present(uint64_t vector, istate_t *istate)
{
region_register rr;
rid_t rid;
uintptr_t va;
pte_t *t;
va = istate->cr_ifa; /* faulting address */
rr.word = rr_read(VA2VRN(va));
rid = rr.map.rid;
 
page_table_lock(AS, true);
t = page_mapping_find(AS, va);
ASSERT(t);
if (t->p) {
/*
* If the Present bit is set in page hash table, just copy it
* and update ITC/DTC.
*/
if (t->x)
itc_pte_copy(t);
else
dtc_pte_copy(t);
page_table_unlock(AS, true);
} else {
page_table_unlock(AS, true);
if (as_page_fault(va, PF_ACCESS_READ, istate) == AS_PF_FAULT) {
fault_if_from_uspace(istate,"Page fault at %p",va);
panic("%s: va=%p, rid=%d\n", __FUNCTION__, va, rid);
}
}
}
 
/** @}
*/
/tags/0.2.0.4/kernel/arch/ia64/src/mm/vhpt.c
0,0 → 1,93
/*
* Copyright (c) 2006 Jakub Vana
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* - Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* - 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.
* - The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.
*/
 
/** @addtogroup ia64mm
* @{
*/
/** @file
*/
 
#include <memstr.h>
#include <arch/mm/vhpt.h>
#include <mm/frame.h>
#include <print.h>
 
static vhpt_entry_t* vhpt_base;
 
uintptr_t vhpt_set_up(void)
{
vhpt_base = frame_alloc(VHPT_WIDTH - FRAME_WIDTH, FRAME_KA | FRAME_ATOMIC);
if (!vhpt_base)
panic("Kernel configured with VHPT but no memory for table.");
vhpt_invalidate_all();
return (uintptr_t) vhpt_base;
}
 
 
void vhpt_mapping_insert(uintptr_t va, asid_t asid, tlb_entry_t entry)
{
region_register rr_save, rr;
index_t vrn;
rid_t rid;
uint64_t tag;
 
vhpt_entry_t *ventry;
 
 
vrn = va >> VRN_SHIFT;
rid = ASID2RID(asid, vrn);
rr_save.word = rr_read(vrn);
rr.word = rr_save.word;
rr.map.rid = rid;
rr_write(vrn, rr.word);
srlz_i();
ventry = (vhpt_entry_t *) thash(va);
tag = ttag(va);
rr_write(vrn, rr_save.word);
srlz_i();
srlz_d();
 
ventry->word[0] = entry.word[0];
ventry->word[1] = entry.word[1];
ventry->present.tag.tag_word = tag;
}
 
void vhpt_invalidate_all()
{
memsetb((uintptr_t) vhpt_base, 1 << VHPT_WIDTH, 0);
}
 
void vhpt_invalidate_asid(asid_t asid)
{
vhpt_invalidate_all();
}
 
/** @}
*/
/tags/0.2.0.4/kernel/arch/ia64/src/mm/page.c
0,0 → 1,266
/*
* Copyright (c) 2006 Jakub Jermar
* Copyright (c) 2006 Jakub Vana
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* - Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* - 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.
* - The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.
*/
 
/** @addtogroup ia64mm
* @{
*/
/** @file
*/
 
#include <arch/mm/page.h>
#include <genarch/mm/page_ht.h>
#include <mm/asid.h>
#include <arch/mm/asid.h>
#include <arch/mm/vhpt.h>
#include <arch/types.h>
#include <print.h>
#include <mm/page.h>
#include <mm/frame.h>
#include <config.h>
#include <panic.h>
#include <arch/asm.h>
#include <arch/barrier.h>
#include <memstr.h>
 
static void set_environment(void);
 
/** Initialize ia64 virtual address translation subsystem. */
void page_arch_init(void)
{
page_mapping_operations = &ht_mapping_operations;
pk_disable();
set_environment();
}
 
/** Initialize VHPT and region registers. */
void set_environment(void)
{
region_register rr;
pta_register pta;
int i;
#ifdef CONFIG_VHPT
uintptr_t vhpt_base;
#endif
 
/*
* First set up kernel region register.
* This is redundant (see start.S) but we keep it here just for sure.
*/
rr.word = rr_read(VRN_KERNEL);
rr.map.ve = 0; /* disable VHPT walker */
rr.map.ps = PAGE_WIDTH;
rr.map.rid = ASID2RID(ASID_KERNEL, VRN_KERNEL);
rr_write(VRN_KERNEL, rr.word);
srlz_i();
srlz_d();
 
/*
* And setup the rest of region register.
*/
for(i = 0; i < REGION_REGISTERS; i++) {
/* skip kernel rr */
if (i == VRN_KERNEL)
continue;
rr.word = rr_read(i);
rr.map.ve = 0; /* disable VHPT walker */
rr.map.rid = RID_KERNEL;
rr.map.ps = PAGE_WIDTH;
rr_write(i, rr.word);
srlz_i();
srlz_d();
}
 
#ifdef CONFIG_VHPT
vhpt_base = vhpt_set_up();
#endif
/*
* Set up PTA register.
*/
pta.word = pta_read();
#ifndef CONFIG_VHPT
pta.map.ve = 0; /* disable VHPT walker */
pta.map.base = 0 >> PTA_BASE_SHIFT;
#else
pta.map.ve = 1; /* enable VHPT walker */
pta.map.base = vhpt_base >> PTA_BASE_SHIFT;
#endif
pta.map.vf = 1; /* large entry format */
pta.map.size = VHPT_WIDTH;
pta_write(pta.word);
srlz_i();
srlz_d();
}
 
/** Calculate address of collision chain from VPN and ASID.
*
* Interrupts must be disabled.
*
* @param page Address of virtual page including VRN bits.
* @param asid Address space identifier.
*
* @return VHPT entry address.
*/
vhpt_entry_t *vhpt_hash(uintptr_t page, asid_t asid)
{
region_register rr_save, rr;
index_t vrn;
rid_t rid;
vhpt_entry_t *v;
 
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.
*/
v = (vhpt_entry_t *) thash(page);
return v;
}
/*
* 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();
v = (vhpt_entry_t *) thash(page);
rr_write(vrn, rr_save.word);
srlz_i();
srlz_d();
 
return v;
}
 
/** 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(uintptr_t page, asid_t asid, vhpt_entry_t *v)
{
region_register rr_save, rr;
index_t vrn;
rid_t rid;
bool match;
 
ASSERT(v);
 
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) == v->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) == v->present.tag.tag_word);
rr_write(vrn, rr_save.word);
srlz_i();
srlz_d();
 
return match;
}
 
/** Set up one VHPT entry.
*
* @param v 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(vhpt_entry_t *v, uintptr_t page, asid_t asid, uintptr_t frame, int flags)
{
region_register rr_save, rr;
index_t vrn;
rid_t rid;
uint64_t tag;
 
ASSERT(v);
 
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.
*/
v->word[0] = 0;
v->word[1] = 0;
v->word[2] = 0;
v->word[3] = 0;
v->present.p = true;
v->present.ma = (flags & PAGE_CACHEABLE) ? MA_WRITEBACK : MA_UNCACHEABLE;
v->present.a = false; /* not accessed */
v->present.d = false; /* not dirty */
v->present.pl = (flags & PAGE_USER) ? PL_USER : PL_KERNEL;
v->present.ar = (flags & PAGE_WRITE) ? AR_WRITE : AR_READ;
v->present.ar |= (flags & PAGE_EXEC) ? AR_EXECUTE : 0;
v->present.ppn = frame >> PPN_SHIFT;
v->present.ed = false; /* exception not deffered */
v->present.ps = PAGE_WIDTH;
v->present.key = 0;
v->present.tag.tag_word = tag;
}
 
/** @}
*/
/tags/0.2.0.4/kernel/arch/ia64/src/mm/as.c
0,0 → 1,89
/*
* Copyright (c) 2006 Jakub Jermar
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* - Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* - 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.
* - The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.
*/
 
/** @addtogroup ia64mm
* @{
*/
/** @file
*/
 
#include <arch/mm/as.h>
#include <arch/mm/asid.h>
#include <arch/mm/page.h>
#include <genarch/mm/as_ht.h>
#include <genarch/mm/asid_fifo.h>
#include <mm/asid.h>
#include <arch.h>
#include <arch/barrier.h>
#include <synch/spinlock.h>
 
/** Architecture dependent address space init. */
void as_arch_init(void)
{
as_operations = &as_ht_operations;
asid_fifo_init();
}
 
/** Prepare registers for switching to another address space.
*
* @param as Address space.
*/
void as_install_arch(as_t *as)
{
ipl_t ipl;
region_register rr;
int i;
ipl = interrupts_disable();
spinlock_lock(&as->lock);
ASSERT(as->asid != ASID_INVALID);
/*
* Load respective ASID (7 consecutive RIDs) to
* region registers.
*/
for (i = 0; i < REGION_REGISTERS; i++) {
if (i == VRN_KERNEL)
continue;
rr.word = rr_read(i);
rr.map.ve = false; /* disable VHPT walker */
rr.map.rid = ASID2RID(as->asid, i);
rr.map.ps = PAGE_WIDTH;
rr_write(i, rr.word);
}
srlz_d();
srlz_i();
spinlock_unlock(&as->lock);
interrupts_restore(ipl);
}
 
/** @}
*/
/tags/0.2.0.4/kernel/arch/ia64/src/mm/frame.c
0,0 → 1,58
/*
* Copyright (c) 2005 Jakub Jermar
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* - Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* - 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.
* - The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.
*/
 
/** @addtogroup ia64mm
* @{
*/
/** @file
*/
 
#include <arch/mm/frame.h>
#include <mm/frame.h>
#include <config.h>
#include <panic.h>
 
/*
* This is Ski-specific and certainly not sufficient
* for real ia64 systems that provide memory map.
*/
#define ROM_BASE 0xa0000
#define ROM_SIZE (384*1024)
 
void frame_arch_init(void)
{
zone_create(0, config.memory_size >> FRAME_WIDTH, 1, 0);
/*
* Blacklist ROM regions.
*/
frame_mark_unavailable(ADDR2PFN(ROM_BASE), ROM_SIZE >> FRAME_WIDTH);
}
 
/** @}
*/