Index: arm/arm/machdep.c =================================================================== --- arm/arm/machdep.c (revision 257547) +++ arm/arm/machdep.c (working copy) @@ -65,6 +65,7 @@ __FBSDID("$FreeBSD$"); #include #include #include +#include #include #include #include @@ -103,6 +104,7 @@ __FBSDID("$FreeBSD$"); #ifdef FDT #include +#include #include #endif @@ -1188,8 +1190,8 @@ physmap_init(struct mem_region *availmem_regions, void * initarm(struct arm_boot_params *abp) { + struct mem_region *availmem_regions; struct mem_region memory_regions[FDT_MEM_REGIONS]; - struct mem_region availmem_regions[FDT_MEM_REGIONS]; struct mem_region reserved_regions[FDT_MEM_REGIONS]; struct pv_addr kernel_l1pt; struct pv_addr dpcpu; @@ -1202,9 +1204,6 @@ initarm(struct arm_boot_params *abp) int memory_regions_sz; int availmem_regions_sz; int reserved_regions_sz; - vm_offset_t start, end; - vm_offset_t rstart, rend; - int curr; lastaddr = parse_boot_param(abp); memsize = 0; @@ -1242,66 +1241,24 @@ initarm(struct arm_boot_params *abp) /* Grab physical memory regions information from device tree. */ if (fdt_get_reserved_regions(reserved_regions, &reserved_regions_sz) != 0) reserved_regions_sz = 0; - + /* - * Now exclude all the reserved regions + * Extend the reserved regions, to PAGE_SIZE. */ - curr = 0; - for (i = 0; i < memory_regions_sz; i++) { - start = memory_regions[i].mr_start; - end = start + memory_regions[i].mr_size; - for (j = 0; j < reserved_regions_sz; j++) { - rstart = reserved_regions[j].mr_start; - rend = rstart + reserved_regions[j].mr_size; - /* - * Restricted region is before available - * Skip restricted region - */ - if (rend <= start) - continue; - /* - * Restricted region is behind available - * No further processing required - */ - if (rstart >= end) - break; - /* - * Restricted region includes memory region - * skip available region - */ - if ((start >= rstart) && (rend >= end)) { - start = rend; - end = rend; - break; - } - /* - * Memory region includes restricted region - */ - if ((rstart > start) && (end > rend)) { - availmem_regions[curr].mr_start = start; - availmem_regions[curr++].mr_size = rstart - start; - start = rend; - break; - } - /* - * Memory region partially overlaps with restricted - */ - if ((rstart >= start) && (rstart <= end)) { - end = rstart; - } - else if ((rend >= start) && (rend <= end)) { - start = rend; - } - } + ranges_align(reserved_regions, reserved_regions_sz, PAGE_SIZE); + /* + * Now exclude all the reserved regions. + */ + ranges_diff(memory_regions, &memory_regions_sz, reserved_regions, + reserved_regions_sz); + /* + * Join neighbor regions. + */ + ranges_join(memory_regions, &memory_regions_sz); - if (end > start) { - availmem_regions[curr].mr_start = start; - availmem_regions[curr++].mr_size = end - start; - } - } + availmem_regions = memory_regions; + availmem_regions_sz = memory_regions_sz; - availmem_regions_sz = curr; - /* Platform-specific initialisation */ vm_max_kernel_address = initarm_lastaddr(); Index: dev/fdt/fdt_regions.h =================================================================== --- dev/fdt/fdt_regions.h (revision 0) +++ dev/fdt/fdt_regions.h (working copy) @@ -0,0 +1,172 @@ +/*- + * Copyright (c) 2013 Aleksandr Rybalko + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD$ + */ + +#ifndef _DEV_FDT_FDT_REGIONS_H_ +#define _DEV_FDT_FDT_REGIONS_H_ + +#define REGION_ALIGN(r, sz) \ +do { \ + vm_offset_t tmp, mask; \ + mask = ((vm_offset_t)sz - 1); \ + tmp = (r).mr_start & mask; \ + (r).mr_start &= ~mask; \ + (r).mr_size += (tmp + mask); \ + (r).mr_size &= ~mask; \ +} while (0) + +#define REGION_BEGIN(r) ((r).mr_start) +#define REGION_END(r) ((r).mr_start + (r).mr_size) +#define POINT_IN_REGION(r, p) ((REGION_BEGIN(r) <= (p)) && \ + ((p) <= REGION_END(r))) +#define REGIONS_BISECTS(r1, r2) (POINT_IN_REGION(r1, REGION_BEGIN(r2)) || \ + POINT_IN_REGION(r1, REGION_END(r2))) +#define REGION_COPY(dst, src) do {(dst).mr_start = (src).mr_start; \ + (dst).mr_size = (src).mr_size;} while (0) + +#define REGION_SWAP(dst, src) \ +do { \ + struct mem_region tmp; \ + REGION_COPY(tmp, dst); \ + REGION_COPY(dst, src); \ + REGION_COPY(src, tmp); \ +} while (0) + +static inline void +bubble_sort(vm_offset_t *ar, int cnt) +{ + int i, swapped; + vm_offset_t tmp; + + for (;;) { + for (i = 0, swapped = 0; i < (cnt - 1); i ++) { + if (ar[i + 1] < ar[i]) { + tmp = ar[i + 1]; + ar[i + 1] = ar[i]; + ar[i] = tmp; + swapped++; + } + } + if (!swapped) + break; + } +} + +static inline void +regions_sort(struct mem_region *r, int cnt) +{ + int i, swapped; + + if (cnt < 2) /* Nothing to sort. */ + return; + + for (;;) { + for (i = 0, swapped = 0; i < (cnt - 1); i ++) { + if (r[i + 1].mr_start < r[i].mr_start) { + REGION_SWAP(r[i], r[i + 1]); + swapped++; + } + } + if (!swapped) + break; + } +} + +static inline void +range_diff(struct mem_region *r1, struct mem_region *r2, struct mem_region *ret) +{ + vm_offset_t ar[4]; + int i = 0; + + bzero(ret, sizeof(struct mem_region) * 2); + ar[0] = REGION_BEGIN(*r1); + ar[1] = REGION_END(*r1); + ar[2] = REGION_BEGIN(*r2); + ar[3] = REGION_END(*r2); + + bubble_sort(ar, 4); + + if (ar[0] == REGION_BEGIN(*r1)) { + ret[i].mr_start = ar[0]; + ret[i].mr_size = ar[1] - ar[0]; + i++; + } + if (ar[3] == REGION_END(*r1)) { + ret[i].mr_start = ar[2]; + ret[i].mr_size = ar[3] - ar[2]; + } +} + +static inline void +ranges_diff(struct mem_region *main, int *ms, struct mem_region *sub, int ss) +{ + struct mem_region ret[2]; + int m, r; + + for (r = 0; r < ss; r++) { + for (m = 0; m < *ms; m++) { + range_diff(&main[m], &sub[r], ret); + REGION_COPY(main[m], ret[0]); + if (ret[1].mr_size != 0) { + REGION_COPY(main[*ms], ret[1]); + (*ms)++; + regions_sort(main, *ms); + } + } + } +} + +static inline void +ranges_join(struct mem_region *main, int *ms) +{ + int m, result_sz; + + if (*ms < 2) /* Nothing to join. */ + return; + result_sz = *ms; + for (m = 0; m < (*ms - 1); m++) { + if (REGION_END(main[m]) == REGION_BEGIN(main[m + 1])) { + main[m].mr_size += main[m + 1].mr_size; + main[m + 1].mr_start = UINT_MAX; + main[m + 1].mr_size = 0; + result_sz--; + } + } + regions_sort(main, *ms); + *ms = result_sz; +} + +static inline void +ranges_align(struct mem_region *main, int cnt, vm_offset_t sz) +{ + int m; + + for (m = 0; m < cnt; m++) + REGION_ALIGN(main[m], sz); +} + +#endif /* _DEV_FDT_FDT_REGIONS_H_ */ Property changes on: dev/fdt/fdt_regions.h ___________________________________________________________________ Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property