Handle corner case in nested RM handling

When using an ELF image as returned from the iso9660 server, such an
image is represented as a managed dataspace composed of various portions
of one RAM dataspace, each portion attached with a different offset.
Now, when mapping the text segment of the ELF image (usually starting at
0x1000 within the image), the code mapped at 0x1000 may correspond to
any offset within the RAM dataspace used by the iso9660 server. In
particular, the src-fault address (the one within the RAM dataspace) may
be higher than dst-fault address (somewhere just above 0x1000 where a
page-fault occurred). Thereby, 'curr_rm_base' may become negative
during the reverse lookup of 'Rm_client::pager'. This corner case used
to let the 'Fault_area::constrain' function return an invalid fault
area, and thereby let the reverse lookup fail. The improved version
explicitly checks for the address overflow condition and tries to
constrain the dst fault address to the largest possible log2 page within
the positive address range.
This commit is contained in:
Norman Feske 2012-01-23 21:04:57 +01:00
parent 31cda45e26
commit 91f59690c4

View File

@ -596,8 +596,26 @@ bool Rm_session_component::reverse_lookup(addr_t dst_base,
if (!*src_dataspace)
return false;
/* constrain destination fault area to region */
dst_fault_area->constrain(dst_base + region->base(), region->size());
/*
* Constrain destination fault area to region
*
* Handle corner case when the 'dst_base' is negative. In this case, we
* determine the largest flexpage within the positive portion of the
* region.
*/
addr_t region_base = region->base() + dst_base;
size_t region_size = region->size();
/* check for overflow condition */
while ((long)region_base < 0 && (long)(region_base + region_size) > 0) {
/* increment base address by half of the region size */
region_base += region_size >> 1;
/* lower the region size by one log2 step */
region_size >>= 1;
}
dst_fault_area->constrain(region_base, region_size);
/* calculate source fault address relative to 'src_dataspace' */
addr_t src_fault_offset = fault_addr - region->base() + region->offset();