diff --git a/src/gopheros/kernel/mem/vmm/vmm.go b/src/gopheros/kernel/mem/vmm/vmm.go index 1e8fa98..16bc74a 100644 --- a/src/gopheros/kernel/mem/vmm/vmm.go +++ b/src/gopheros/kernel/mem/vmm/vmm.go @@ -181,7 +181,6 @@ func setupPDTForKernel(kernelPageOffset uintptr) *kernel.Error { // Query the ELF sections of the kernel image and establish mappings // for each one using the appropriate flags - pageSizeMinus1 := uint64(mem.PageSize - 1) var visitor = func(_ string, secFlags multiboot.ElfSectionFlag, secAddress uintptr, secSize uint64) { // Bail out if we have encountered an error; also ignore sections // not using the kernel's VMA @@ -199,11 +198,15 @@ func setupPDTForKernel(kernelPageOffset uintptr) *kernel.Error { 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) + lastPage := PageFromAddress(secAddress + uintptr(secSize-1)) curFrame := pmm.Frame((secAddress - kernelPageOffset) >> mem.PageShift) - endFrame := curFrame + pmm.Frame(((secSize+pageSizeMinus1) & ^pageSizeMinus1)>>mem.PageShift) - for ; curFrame < endFrame; curFrame, curPage = curFrame+1, curPage+1 { + for ; curPage <= lastPage; curFrame, curPage = curFrame+1, curPage+1 { if err = pdt.Map(curPage, curFrame, flags); err != nil { return } diff --git a/src/gopheros/kernel/mem/vmm/vmm_test.go b/src/gopheros/kernel/mem/vmm/vmm_test.go index c9b8fa3..fd768fd 100644 --- a/src/gopheros/kernel/mem/vmm/vmm_test.go +++ b/src/gopheros/kernel/mem/vmm/vmm_test.go @@ -330,10 +330,14 @@ func TestSetupPDTForKernel(t *testing.T) { translateFn = func(_ uintptr) (uintptr, *kernel.Error) { return 0xbadf00d000, nil } mapTemporaryFn = func(f pmm.Frame) (Page, *kernel.Error) { return Page(f), nil } visitElfSectionsFn = func(v multiboot.ElfSectionVisitor) { - v(".debug", 0, 0, uint64(mem.PageSize>>1)) // address < VMA; should be ignored - v(".text", multiboot.ElfSectionExecutable, 0xbadc0ffee, uint64(mem.PageSize>>1)) - v(".data", multiboot.ElfSectionWritable, 0xbadc0ffee, uint64(mem.PageSize)) - v(".rodata", 0, 0xbadc0ffee, uint64(mem.PageSize<<1)) + // address < VMA; should be ignored + v(".debug", 0, 0, uint64(mem.PageSize>>1)) + // section uses 32-byte alignment instead of page alignment and has a size + // 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 mapFn = func(page Page, frame pmm.Frame, flags PageTableEntryFlag) *kernel.Error { @@ -342,11 +346,11 @@ func TestSetupPDTForKernel(t *testing.T) { var expFlags PageTableEntryFlag switch mapCount { - case 0: + case 0, 1: expFlags = FlagPresent - case 1: + case 2: expFlags = FlagPresent | FlagNoExecute | FlagRW - case 2, 3: + case 3, 4: expFlags = FlagPresent | FlagNoExecute } @@ -361,7 +365,7 @@ func TestSetupPDTForKernel(t *testing.T) { 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) } })