hw: avoid address overflow in Tlb::remove_region()

ref #589
This commit is contained in:
Martin Stein 2013-09-16 15:35:00 +02:00 committed by Norman Feske
parent 909c2dbc95
commit de87fa1b5c

View File

@ -398,47 +398,43 @@ namespace Arm
} }
/** /**
* Remove translations, wich overlap with a given virtual region * Remove translations that overlap with a given virtual region
* *
* \param vo offset of the virtual region within the region * \param vo region offset within the tables virtual region
* represented by this table
* \param size region size * \param size region size
*/ */
void remove_region(addr_t const vo, size_t const size) void remove_region(addr_t vo, size_t const size)
{ {
/* traverse all possibly affected entries */ addr_t const ve = vo + size;
addr_t residual_vo = vo;
unsigned i; unsigned i;
while (1) while (1)
{ {
/* check if anything is left over to remove */ if (vo >= ve) { return; }
if (residual_vo >= vo + size) return; if (_index_by_vo(i, vo)) { return; }
addr_t next_vo;
/* check if residual region overlaps with table */
if (_index_by_vo(i, residual_vo)) return;
/* update current entry and recalculate residual region */
switch (Descriptor::type(_entries[i])) { switch (Descriptor::type(_entries[i])) {
case Descriptor::FAULT: { case Descriptor::FAULT: {
residual_vo = (residual_vo & Fault::VIRT_BASE_MASK) vo &= Fault::VIRT_BASE_MASK;
+ Fault::VIRT_SIZE; next_vo = vo + Fault::VIRT_SIZE;
break; } break; }
case Descriptor::SMALL_PAGE: { case Descriptor::SMALL_PAGE: {
residual_vo = (residual_vo & Small_page::VIRT_BASE_MASK) vo &= Small_page::VIRT_BASE_MASK;
+ Small_page::VIRT_SIZE;
Descriptor::invalidate(_entries[i]); Descriptor::invalidate(_entries[i]);
next_vo = vo + Small_page::VIRT_SIZE;
break; } break; }
case Descriptor::LARGE_PAGE: { case Descriptor::LARGE_PAGE: {
PDBG("Removal of large pages not implemented"); PDBG("large pages not supported by now");
while (1) ; while (1) ;
break; } break; }
} }
if (next_vo < vo) { return; }
vo = next_vo;
} }
} }
@ -800,63 +796,55 @@ namespace Arm
} }
/** /**
* Remove translations, wich overlap with a given virtual region * Remove translations that overlap with a given virtual region
* *
* \param vo offset of the virtual region within the region * \param vo region offset within the tables virtual region
* represented by this table
* \param size region size * \param size region size
*/ */
void remove_region(addr_t const vo, size_t const size) void remove_region(addr_t vo, size_t const size)
{ {
/* traverse all possibly affected entries */ addr_t const ve = vo + size;
addr_t residual_vo = vo;
unsigned i; unsigned i;
while (1) while (1)
{ {
/* check if anything is left over to remove */ if (vo >= ve) { return; }
if (residual_vo >= vo + size) return; if (_index_by_vo(i, vo)) { return; }
addr_t next_vo;
switch (Descriptor::type(_entries[i])) {
/* check if the residual region overlaps with this table */ case Descriptor::FAULT: {
if (_index_by_vo(i, residual_vo)) return;
/* update current entry and recalculate residual region */ vo &= Fault::VIRT_BASE_MASK;
switch (Descriptor::type(_entries[i])) next_vo = vo + Fault::VIRT_SIZE;
{ break; }
case Descriptor::FAULT:
{
residual_vo = (residual_vo & Fault::VIRT_BASE_MASK)
+ Fault::VIRT_SIZE;
break;
}
case Descriptor::PAGE_TABLE:
{
/* instruct page table to remove residual region */
Page_table * const pt = (Page_table *)
(addr_t)Page_table_descriptor::Pa_31_10::masked(_entries[i]);
size_t const residual_size = vo + size - residual_vo;
addr_t const pt_vo = residual_vo
- Section::Pa_31_20::masked(residual_vo);
pt->remove_region(pt_vo, residual_size);
/* recalculate residual region */ case Descriptor::PAGE_TABLE: {
residual_vo = (residual_vo & Page_table::VIRT_BASE_MASK)
+ Page_table::VIRT_SIZE; typedef Page_table_descriptor Ptd;
break; typedef Page_table Pt;
}
case Descriptor::SECTION: vo &= Pt::VIRT_BASE_MASK;
{ Pt * const pt = (Pt *)Ptd::Pa_31_10::masked(_entries[i]);
addr_t const pt_vo = vo - Section::Pa_31_20::masked(vo);
pt->remove_region(pt_vo, ve - vo);
next_vo = vo + Pt::VIRT_SIZE;
break; }
case Descriptor::SECTION: {
vo &= Section::VIRT_BASE_MASK;
Descriptor::invalidate(_entries[i]); Descriptor::invalidate(_entries[i]);
residual_vo = (residual_vo & Section::VIRT_BASE_MASK) next_vo = vo + Section::VIRT_SIZE;
+ Section::VIRT_SIZE; break; }
break;
} case Descriptor::SUPERSECTION: {
case Descriptor::SUPERSECTION:
{ PDBG("supersections not supported by now");
PDBG("Removal of supersections not implemented"); while (1) { }
while (1); break; }
break;
}
} }
if (next_vo < vo) { return; }
vo = next_vo;
} }
} }