-
Notifications
You must be signed in to change notification settings - Fork 216
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Guard the lower 1MB of memory #317
Conversation
0e8dd0d
to
0be989a
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks a lot for this PR!
I'm not sure if I understand the approach though. Why are the changes to LegacyMemoryRegion::kind
necessary and how do they help in guarding the first MB?
I think the main issue is that the UEFI allocation used for loading the kernel might already use the first MB if we are unlucky. So to be safe, we would need to allocate that first megabyte before creating the allocation. We can use the "allocate at address" API mentioned by @tsoutsman in #311 (comment) for that.
6acd260
to
2b84ae0
Compare
@phil-opp this is ready for review. I also added tests. |
This also adds a new fuction to ignore the attempts to guard the lower 1MB if it's really required.
2b84ae0
to
3b383d3
Compare
@@ -28,8 +28,11 @@ pub struct LegacyFrameAllocator<I, D> { | |||
memory_map: I, | |||
current_descriptor: Option<D>, | |||
next_frame: PhysFrame, | |||
start_frame: PhysFrame, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We already use the name start_frame
in multiple places, so we should name this field differently to avoid confusion. I think min_frame
would be a fitting name:
start_frame: PhysFrame, | |
min_frame: PhysFrame, |
if frame.start_address().as_u64() < LOWER_MEMORY_END_PAGE { | ||
// Skip the first 1MB of frames, regardless of what was requested. | ||
// there are use cases that require lower conventional memory access. (Such as SMP SIPI) | ||
return Self::new(memory_map); | ||
} | ||
|
||
return unsafe { Self::unsafe_new_starting_at(frame, memory_map) }; | ||
} | ||
|
||
/// Creates a new frame allocator based on the given legacy memory regions. Skips any frames | ||
/// before the given `frame`, without attempting to protect the lower 1MB of memory. | ||
pub unsafe fn unsafe_new_starting_at(frame: PhysFrame, memory_map: I) -> Self { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This seems a bit complicated. How about we just use a max
call in new_starting_at
and keep calling it from the new
function?
if frame.start_address().as_u64() < LOWER_MEMORY_END_PAGE { | |
// Skip the first 1MB of frames, regardless of what was requested. | |
// there are use cases that require lower conventional memory access. (Such as SMP SIPI) | |
return Self::new(memory_map); | |
} | |
return unsafe { Self::unsafe_new_starting_at(frame, memory_map) }; | |
} | |
/// Creates a new frame allocator based on the given legacy memory regions. Skips any frames | |
/// before the given `frame`, without attempting to protect the lower 1MB of memory. | |
pub unsafe fn unsafe_new_starting_at(frame: PhysFrame, memory_map: I) -> Self { | |
// Skip the first 1MB of frames, regardless of what was requested. | |
// there are use cases that require lower conventional memory access. (Such as SMP SIPI) | |
let lower_mem_end = PhysFrame::containing_address(PhysAddr::new(LOWER_MEMORY_END_PAGE)); | |
let frame = core::cmp::max(frame, lower_mem_end); |
// also skip the first 1MB of frames, there are use cases that require lower conventional memory access. (Such as SMP SIPI) | ||
let start_frame = PhysFrame::containing_address(PhysAddr::new(LOWER_MEMORY_END_PAGE)); | ||
unsafe { Self::unsafe_new_starting_at(start_frame, memory_map) } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
With the suggested changes below, we could keep the previous implementation:
// also skip the first 1MB of frames, there are use cases that require lower conventional memory access. (Such as SMP SIPI) | |
let start_frame = PhysFrame::containing_address(PhysAddr::new(LOWER_MEMORY_END_PAGE)); | |
unsafe { Self::unsafe_new_starting_at(start_frame, memory_map) } | |
let start_frame = PhysFrame::containing_address(PhysAddr::new(0x1000)); | |
Self::new_starting_at(start_frame, memory_map) |
} else if descriptor.start() >= next_free | ||
|| end <= self.start_frame.start_address() | ||
{ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would prefer to split this condition so that we can add a comment:
} else if descriptor.start() >= next_free | |
|| end <= self.start_frame.start_address() | |
{ | |
} else if descriptor.start() >= next_free { | |
MemoryRegionKind::Usable | |
} else if end <= self.start_frame.start_address() { | |
// treat regions that end before the minimum frame as usable too |
} else if descriptor.start() >= next_free { | ||
} else if descriptor.start() >= next_free | ||
|| end <= self.start_frame.start_address() | ||
{ | ||
MemoryRegionKind::Usable | ||
} else { | ||
// part of the region is used -> add it separately |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think we need to update this else
branch too, in case the descriptor goes beyond 0x100000
.
api/src/info.rs
Outdated
/// Unused conventional memory, can be used by the kernel. | ||
Usable, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Reordering the variants changes their integer value, which is technically a breaking change. So we should undo this change if possible.
if region.end <= LOWER_MEMORY_END_PAGE && region.kind == MemoryRegionKind::Usable { | ||
let pages = (region.end - region.start) / 4096; | ||
count += pages; | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We should also account for regions that don't end at LOWER_MEMORY_END_PAGE
. For example:
if region.end <= LOWER_MEMORY_END_PAGE && region.kind == MemoryRegionKind::Usable { | |
let pages = (region.end - region.start) / 4096; | |
count += pages; | |
} | |
if region.kind == MemoryRegionKind::Usable && region.start < LOWER_MEMORY_END_PAGE { | |
let end = core::cmp::min(region.end, LOWER_MEMORY_END_PAGE); | |
let pages = (end - region.start) / 4096; | |
count += pages; | |
} |
Thanks for the updates! I left some suggestions, otherwise these changes look good to me. However, I still think that we need to ensure that we don't use the first megabyte for the kernel allocation in the UEFI loader, as I noted above:
|
Co-authored-by: Philipp Oppermann <dev@phil-opp.com>
This change was not intentional.
@jasoncouture Friendly ping :). What's the status of this? |
I'll take another look weekend after next. Got some personal things to attend for the next week or so. |
This commit fixes the review changes in rust-osdev#317. Most of the credit should go to Jason Couture <jasonc@alertr.info>
This commit fixes the review changes in rust-osdev#317. Most of the credit should go to Jason Couture <jasonc@alertr.info>
This commit fixes the review changes in rust-osdev#317. Most of the credit should go to Jason Couture <jasonc@alertr.info> Co-authored-by: Jason Couture <jasonc@alertr.info>
This commit fixes the review changes in rust-osdev#317. Most of the credit should go to Jason Couture <jasonc@alertr.info> Co-authored-by: Jason Couture <jasonc@alertr.info>
This commit fixes the review changes in rust-osdev#317. Most of the credit should go to Jason Couture <jasonc@alertr.info> Co-authored-by: Jason Couture <jasonc@alertr.info>
Superseded by #446 |
This also adds a new fuction to ignore the attempts to guard the lower 1MB if it's really required.
Closes #311