git: fc5ab0227bba - stable/13 - Handle non-page aligned/sized memory in physmem
- Go to: [ bottom of page ] [ top of archives ] [ this month ]
Date: Tue, 03 May 2022 14:04:41 UTC
The branch stable/13 has been updated by andrew: URL: https://cgit.FreeBSD.org/src/commit/?id=fc5ab0227bbaa265aa8e4e0247cf816040ac4b44 commit fc5ab0227bbaa265aa8e4e0247cf816040ac4b44 Author: Andrew Turner <andrew@FreeBSD.org> AuthorDate: 2022-03-28 11:37:09 +0000 Commit: Andrew Turner <andrew@FreeBSD.org> CommitDate: 2022-05-03 14:04:04 +0000 Handle non-page aligned/sized memory in physmem In some configurations the firmware may pass memory regions that are not page sized or aligned, e.g. when using 16k pages on arm64. If this is the case we will calculate many small regions because the alignment is applied before being inserted. As we round the start up and end down this will leave a 1 page hole between what should have been a single region. Fix by keeping the original alignment until we are just about to insert the region into the avail array. Sponsored by: The FreeBSD Foundation Differential Revision: https://reviews.freebsd.org/D34694 (cherry picked from commit d8bff5b67c9b6a85f409a7408e45e7e87d39c5a2) --- sys/kern/subr_physmem.c | 17 ++++------------- tests/sys/kern/subr_physmem_test.c | 22 ++++++++++++++++++++-- 2 files changed, 24 insertions(+), 15 deletions(-) diff --git a/sys/kern/subr_physmem.c b/sys/kern/subr_physmem.c index 106200dd814e..99b4c2141612 100644 --- a/sys/kern/subr_physmem.c +++ b/sys/kern/subr_physmem.c @@ -180,7 +180,7 @@ regions_to_avail(vm_paddr_t *avail, uint32_t exflags, size_t maxavail, uint64_t maxphyssz, long *pavail, long *prealmem) { size_t acnt, exi, hwi; - uint64_t end, start, xend, xstart; + uint64_t adj, end, start, xend, xstart; long availmem, totalmem; const struct region *exp, *hwp; uint64_t availsz; @@ -190,8 +190,9 @@ regions_to_avail(vm_paddr_t *avail, uint32_t exflags, size_t maxavail, availsz = 0; acnt = 0; for (hwi = 0, hwp = hwregions; hwi < hwcnt; ++hwi, ++hwp) { - start = hwp->addr; - end = hwp->size + start; + adj = round_page(hwp->addr) - hwp->addr; + start = round_page(hwp->addr); + end = trunc_page(hwp->size + adj) + start; totalmem += atop((vm_offset_t)(end - start)); for (exi = 0, exp = exregions; exi < excnt; ++exi, ++exp) { /* @@ -337,8 +338,6 @@ insert_region(struct region *regions, size_t rcnt, vm_paddr_t addr, void physmem_hardware_region(uint64_t pa, uint64_t sz) { - vm_offset_t adj; - /* * Filter out the page at PA 0x00000000. The VM can't handle it, as * pmap_extract() == 0 means failure. @@ -371,14 +370,6 @@ physmem_hardware_region(uint64_t pa, uint64_t sz) sz -= 1024 * 1024; } - /* - * Round the starting address up to a page boundary, and truncate the - * ending page down to a page boundary. - */ - adj = round_page(pa) - pa; - pa = round_page(pa); - sz = trunc_page(sz - adj); - if (sz > 0 && hwcnt < nitems(hwregions)) hwcnt = insert_region(hwregions, hwcnt, pa, sz, 0); } diff --git a/tests/sys/kern/subr_physmem_test.c b/tests/sys/kern/subr_physmem_test.c index a562bacec65c..10824f7fe4ff 100644 --- a/tests/sys/kern/subr_physmem_test.c +++ b/tests/sys/kern/subr_physmem_test.c @@ -76,14 +76,12 @@ ATF_TC_BODY(hwregion, tc) ATF_CHECK_EQ(avail[0], 2 * PAGE_SIZE); ATF_CHECK_EQ(avail[1], 6 * PAGE_SIZE); -#ifdef notyet /* This doesn't currently work */ /* Add the remaining part of the page */ physmem_hardware_region(6 * PAGE_SIZE + PAGE_SIZE / 2, PAGE_SIZE / 2); len = physmem_avail(avail, 4); ATF_CHECK_EQ(len, 2); ATF_CHECK_EQ(avail[0], 2 * PAGE_SIZE); ATF_CHECK_EQ(avail[1], 7 * PAGE_SIZE); -#endif } ATF_TC_WITHOUT_HEAD(hwregion_exclude); @@ -113,10 +111,30 @@ ATF_TC_BODY(hwregion_exclude, tc) ATF_CHECK_EQ(avail[3], 7 * PAGE_SIZE); } +ATF_TC_WITHOUT_HEAD(hwregion_unordered); +ATF_TC_BODY(hwregion_unordered, tc) +{ + vm_paddr_t avail[4]; + size_t len; + + /* Add a partial page */ + physmem_hardware_region(PAGE_SIZE, PAGE_SIZE / 2); + /* Add a full page not touching the previous */ + physmem_hardware_region( 2 * PAGE_SIZE, PAGE_SIZE); + /* Add the remainder of the first page */ + physmem_hardware_region(PAGE_SIZE + PAGE_SIZE / 2, PAGE_SIZE / 2); + + len = physmem_avail(avail, 4); + ATF_CHECK_EQ(len, 2); + ATF_CHECK_EQ(avail[0], PAGE_SIZE); + ATF_CHECK_EQ(avail[1], 3 * PAGE_SIZE); +} + ATF_TP_ADD_TCS(tp) { ATF_TP_ADD_TC(tp, hwregion); ATF_TP_ADD_TC(tp, hwregion_exclude); + ATF_TP_ADD_TC(tp, hwregion_unordered); return (atf_no_error()); }