summaryrefslogtreecommitdiffstats
path: root/sys/powerpc/powerpc
diff options
context:
space:
mode:
authorian <ian@FreeBSD.org>2014-05-14 14:17:51 +0000
committerian <ian@FreeBSD.org>2014-05-14 14:17:51 +0000
commit1baea4807a7a800ea024080ecb08d8018d423b35 (patch)
tree8bba76de8ef5301e1c8c1469cba379463335efa1 /sys/powerpc/powerpc
parent796f2c87ad85df08fa64cd699bc66b9054363166 (diff)
downloadFreeBSD-src-1baea4807a7a800ea024080ecb08d8018d423b35.zip
FreeBSD-src-1baea4807a7a800ea024080ecb08d8018d423b35.tar.gz
MFC r258800, r258802, r258805, r258806, r258807, r258851, r258857,
r259199, r259484, r259513, r259514, r259516 The kernel stack guard pages are only below the stack pointer, not above. Remove unnecessary double-setting of the thread's onfault state in copyinstr(). Open Firmware mandates that certain cross-references, in particular those in /chosen, be ihandles. The ePAPR spec makes those cross-reference phandles, since FDT has no concept of ihandles. Have the OF FDT CI module interpret queries about ihandles as cross-reference phandles. Real OF systems have an ihandle under /chosen/stdout, not a phandle. Use the right type. Rearchitect platform memory map parsing to make it less Open Firmware-centric. Remove fdtbus_bs_tag definition, which is now obsolete. The remainder of this file is also slated for future demolition. Return the correct IEEE 1275 code for "nextprop". Use the common Open Firmware PCI interrupt routing code instead of the duplicate version in dev/fdt. Configure interrupt sense based on device tree information. Simplify the ofw_bus_lookup_imap() API slightly: make it allocate maskbuf internally instead of requiring the caller to allocate it.
Diffstat (limited to 'sys/powerpc/powerpc')
-rw-r--r--sys/powerpc/powerpc/copyinout.c12
-rw-r--r--sys/powerpc/powerpc/platform.c94
-rw-r--r--sys/powerpc/powerpc/platform_if.m4
3 files changed, 88 insertions, 22 deletions
diff --git a/sys/powerpc/powerpc/copyinout.c b/sys/powerpc/powerpc/copyinout.c
index a1c0456..a8108d6 100644
--- a/sys/powerpc/powerpc/copyinout.c
+++ b/sys/powerpc/powerpc/copyinout.c
@@ -250,22 +250,11 @@ copyin(const void *udaddr, void *kaddr, size_t len)
int
copyinstr(const void *udaddr, void *kaddr, size_t len, size_t *done)
{
- struct thread *td;
- pmap_t pm;
- faultbuf env;
const char *up;
char *kp;
size_t l;
int rv, c;
- td = curthread;
- pm = &td->td_proc->p_vmspace->vm_pmap;
-
- if (setfault(env)) {
- td->td_pcb->pcb_onfault = NULL;
- return (EFAULT);
- }
-
kp = kaddr;
up = udaddr;
@@ -288,7 +277,6 @@ copyinstr(const void *udaddr, void *kaddr, size_t len, size_t *done)
*done = l;
}
- td->td_pcb->pcb_onfault = NULL;
return (rv);
}
diff --git a/sys/powerpc/powerpc/platform.c b/sys/powerpc/powerpc/platform.c
index 6fae2e8..c7ab51f 100644
--- a/sys/powerpc/powerpc/platform.c
+++ b/sys/powerpc/powerpc/platform.c
@@ -64,17 +64,93 @@ static char plat_name[64] = "";
SYSCTL_STRING(_hw, OID_AUTO, platform, CTLFLAG_RD | CTLFLAG_TUN,
plat_name, 0, "Platform currently in use");
-static struct mem_region *pregions = NULL;
-static struct mem_region *aregions = NULL;
+static struct mem_region pregions[PHYS_AVAIL_SZ];
+static struct mem_region aregions[PHYS_AVAIL_SZ];
static int npregions, naregions;
+/*
+ * Memory region utilities: determine if two regions overlap,
+ * and merge two overlapping regions into one
+ */
+static int
+memr_overlap(struct mem_region *r1, struct mem_region *r2)
+{
+ if ((r1->mr_start + r1->mr_size) < r2->mr_start ||
+ (r2->mr_start + r2->mr_size) < r1->mr_start)
+ return (FALSE);
+
+ return (TRUE);
+}
+
+static void
+memr_merge(struct mem_region *from, struct mem_region *to)
+{
+ vm_offset_t end;
+ end = ulmax(to->mr_start + to->mr_size, from->mr_start + from->mr_size);
+ to->mr_start = ulmin(from->mr_start, to->mr_start);
+ to->mr_size = end - to->mr_start;
+}
+
+/*
+ * Quick sort callout for comparing memory regions.
+ */
+static int
+mr_cmp(const void *a, const void *b)
+{
+ const struct mem_region *regiona, *regionb;
+
+ regiona = a;
+ regionb = b;
+ if (regiona->mr_start < regionb->mr_start)
+ return (-1);
+ else if (regiona->mr_start > regionb->mr_start)
+ return (1);
+ else
+ return (0);
+}
+
void
mem_regions(struct mem_region **phys, int *physsz, struct mem_region **avail,
int *availsz)
{
- if (pregions == NULL)
- PLATFORM_MEM_REGIONS(plat_obj, &pregions, &npregions,
- &aregions, &naregions);
+ int i, j, still_merging;
+
+ if (npregions == 0) {
+ PLATFORM_MEM_REGIONS(plat_obj, &pregions[0], &npregions,
+ aregions, &naregions);
+ qsort(pregions, npregions, sizeof(*pregions), mr_cmp);
+ qsort(aregions, naregions, sizeof(*aregions), mr_cmp);
+
+ /* Remove overlapping available regions */
+ do {
+ still_merging = FALSE;
+ for (i = 0; i < naregions; i++) {
+ if (aregions[i].mr_size == 0)
+ continue;
+ for (j = i+1; j < naregions; j++) {
+ if (aregions[j].mr_size == 0)
+ continue;
+ if (!memr_overlap(&aregions[j],
+ &aregions[i]))
+ continue;
+
+ memr_merge(&aregions[j], &aregions[i]);
+ /* mark inactive */
+ aregions[j].mr_size = 0;
+ still_merging = TRUE;
+ }
+ }
+ } while (still_merging == TRUE);
+
+ /* Collapse zero-length available regions */
+ for (i = 0; i < naregions; i++) {
+ if (aregions[i].mr_size == 0) {
+ memcpy(&aregions[i], &aregions[i+1],
+ (naregions - i - 1)*sizeof(*aregions));
+ naregions--;
+ }
+ }
+ }
*phys = pregions;
*avail = aregions;
@@ -87,9 +163,11 @@ mem_valid(vm_offset_t addr, int len)
{
int i;
- if (pregions == NULL)
- PLATFORM_MEM_REGIONS(plat_obj, &pregions, &npregions,
- &aregions, &naregions);
+ if (npregions == 0) {
+ struct mem_region *p, *a;
+ int na, np;
+ mem_regions(&p, &np, &a, &na);
+ }
for (i = 0; i < npregions; i++)
if ((addr >= pregions[i].mr_start)
diff --git a/sys/powerpc/powerpc/platform_if.m b/sys/powerpc/powerpc/platform_if.m
index 55f9ae6..dfa2be1 100644
--- a/sys/powerpc/powerpc/platform_if.m
+++ b/sys/powerpc/powerpc/platform_if.m
@@ -120,9 +120,9 @@ METHOD int attach {
METHOD void mem_regions {
platform_t _plat;
- struct mem_region **_memp;
+ struct mem_region *_memp;
int *_memsz;
- struct mem_region **_availp;
+ struct mem_region *_availp;
int *_availsz;
};
OpenPOWER on IntegriCloud