1
0
mirror of https://github.com/taigrr/gopher-os synced 2025-01-18 04:43:13 -08:00

Merge pull request #65 from achilleasa/fix-kernel-elf-section-mapping-bug

Fix kernel elf section mapping bug
This commit is contained in:
Achilleas Anagnostopoulos 2018-03-22 19:17:34 +00:00 committed by GitHub
commit c0b9f62f78
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 22 additions and 15 deletions

View File

@ -63,7 +63,7 @@ func (pdt *PageDirectoryTable) Init(pdtFrame pmm.Frame) *kernel.Error {
lastPdtEntry.SetFrame(pdtFrame) lastPdtEntry.SetFrame(pdtFrame)
// Remove temporary mapping // Remove temporary mapping
unmapFn(pdtPage) _ = unmapFn(pdtPage)
return nil return nil
} }

View File

@ -69,7 +69,7 @@ func pageFaultHandler(errorCode uint64, frame *irq.Frame, regs *irq.Regs) {
} else { } else {
// Copy page contents, mark as RW and remove CoW flag // Copy page contents, mark as RW and remove CoW flag
mem.Memcopy(faultPage.Address(), tmpPage.Address(), mem.PageSize) mem.Memcopy(faultPage.Address(), tmpPage.Address(), mem.PageSize)
unmapFn(tmpPage) _ = unmapFn(tmpPage)
// Update mapping to point to the new frame, flag it as RW and // Update mapping to point to the new frame, flag it as RW and
// remove the CoW flag // remove the CoW flag
@ -139,7 +139,7 @@ func reserveZeroedFrame() *kernel.Error {
return err return err
} }
mem.Memset(tempPage.Address(), 0, mem.PageSize) mem.Memset(tempPage.Address(), 0, mem.PageSize)
unmapFn(tempPage) _ = unmapFn(tempPage)
// From this point on, ReservedZeroedFrame cannot be mapped with a RW flag // From this point on, ReservedZeroedFrame cannot be mapped with a RW flag
protectReservedZeroedPage = true protectReservedZeroedPage = true
@ -181,7 +181,6 @@ func setupPDTForKernel(kernelPageOffset uintptr) *kernel.Error {
// Query the ELF sections of the kernel image and establish mappings // Query the ELF sections of the kernel image and establish mappings
// for each one using the appropriate flags // for each one using the appropriate flags
pageSizeMinus1 := uint64(mem.PageSize - 1)
var visitor = func(_ string, secFlags multiboot.ElfSectionFlag, secAddress uintptr, secSize uint64) { var visitor = func(_ string, secFlags multiboot.ElfSectionFlag, secAddress uintptr, secSize uint64) {
// Bail out if we have encountered an error; also ignore sections // Bail out if we have encountered an error; also ignore sections
// not using the kernel's VMA // not using the kernel's VMA
@ -199,11 +198,15 @@ func setupPDTForKernel(kernelPageOffset uintptr) *kernel.Error {
flags |= FlagRW flags |= FlagRW
} }
// We assume that all sections are page-aligned by the linker script // Map the start and end VMA addresses for the section contents
// into a start and end (inclusive) page number. To figure out
// the physical start frame we just need to subtract the
// kernel's VMA offset from the virtual address and round that
// down to the nearest frame number.
curPage := PageFromAddress(secAddress) curPage := PageFromAddress(secAddress)
lastPage := PageFromAddress(secAddress + uintptr(secSize-1))
curFrame := pmm.Frame((secAddress - kernelPageOffset) >> mem.PageShift) curFrame := pmm.Frame((secAddress - kernelPageOffset) >> mem.PageShift)
endFrame := curFrame + pmm.Frame(((secSize+pageSizeMinus1) & ^pageSizeMinus1)>>mem.PageShift) for ; curPage <= lastPage; curFrame, curPage = curFrame+1, curPage+1 {
for ; curFrame < endFrame; curFrame, curPage = curFrame+1, curPage+1 {
if err = pdt.Map(curPage, curFrame, flags); err != nil { if err = pdt.Map(curPage, curFrame, flags); err != nil {
return return
} }

View File

@ -330,10 +330,14 @@ func TestSetupPDTForKernel(t *testing.T) {
translateFn = func(_ uintptr) (uintptr, *kernel.Error) { return 0xbadf00d000, nil } translateFn = func(_ uintptr) (uintptr, *kernel.Error) { return 0xbadf00d000, nil }
mapTemporaryFn = func(f pmm.Frame) (Page, *kernel.Error) { return Page(f), nil } mapTemporaryFn = func(f pmm.Frame) (Page, *kernel.Error) { return Page(f), nil }
visitElfSectionsFn = func(v multiboot.ElfSectionVisitor) { visitElfSectionsFn = func(v multiboot.ElfSectionVisitor) {
v(".debug", 0, 0, uint64(mem.PageSize>>1)) // address < VMA; should be ignored // address < VMA; should be ignored
v(".text", multiboot.ElfSectionExecutable, 0xbadc0ffee, uint64(mem.PageSize>>1)) v(".debug", 0, 0, uint64(mem.PageSize>>1))
v(".data", multiboot.ElfSectionWritable, 0xbadc0ffee, uint64(mem.PageSize)) // section uses 32-byte alignment instead of page alignment and has a size
v(".rodata", 0, 0xbadc0ffee, uint64(mem.PageSize<<1)) // equal to 1 page. Due to rounding, we need to actually map 2 pages.
v(".text", multiboot.ElfSectionExecutable, 0x10032, uint64(mem.PageSize))
v(".data", multiboot.ElfSectionWritable, 0x2000, uint64(mem.PageSize))
// section is page-aligned and occupies exactly 2 pages
v(".rodata", 0, 0x3000, uint64(mem.PageSize<<1))
} }
mapCount := 0 mapCount := 0
mapFn = func(page Page, frame pmm.Frame, flags PageTableEntryFlag) *kernel.Error { mapFn = func(page Page, frame pmm.Frame, flags PageTableEntryFlag) *kernel.Error {
@ -342,11 +346,11 @@ func TestSetupPDTForKernel(t *testing.T) {
var expFlags PageTableEntryFlag var expFlags PageTableEntryFlag
switch mapCount { switch mapCount {
case 0: case 0, 1:
expFlags = FlagPresent expFlags = FlagPresent
case 1: case 2:
expFlags = FlagPresent | FlagNoExecute | FlagRW expFlags = FlagPresent | FlagNoExecute | FlagRW
case 2, 3: case 3, 4:
expFlags = FlagPresent | FlagNoExecute expFlags = FlagPresent | FlagNoExecute
} }
@ -361,7 +365,7 @@ func TestSetupPDTForKernel(t *testing.T) {
t.Fatal(err) t.Fatal(err)
} }
if exp := 4; mapCount != exp { if exp := 5; mapCount != exp {
t.Errorf("expected Map to be called %d times; got %d", exp, mapCount) t.Errorf("expected Map to be called %d times; got %d", exp, mapCount)
} }
}) })