Index: kernel/generic/src/mm/frame.c
===================================================================
--- kernel/generic/src/mm/frame.c	(revision 818fffee39e7af9d4be402c0bbf35d4a06b82d6c)
+++ kernel/generic/src/mm/frame.c	(revision 40c8c17482d672e755c855c6fd5664b0e933e483)
@@ -240,6 +240,6 @@
 NO_TRACE static bool zone_can_alloc(zone_t *zone, uint8_t order)
 {
-	return (zone_flags_available(zone->flags)
-	    && buddy_system_can_alloc(zone->buddy_system, order));
+	return ((zone->flags & ZONE_AVAILABLE) &&
+	    buddy_system_can_alloc(zone->buddy_system, order));
 }
 
@@ -265,5 +265,5 @@
 		 * Check whether the zone meets the search criteria.
 		 */
-		if ((zones.info[i].flags & flags) == flags) {
+		if (ZONE_FLAGS_MATCH(zones.info[i].flags, flags)) {
 			/*
 			 * Check if the zone has 2^order frames area available.
@@ -460,5 +460,5 @@
 NO_TRACE static pfn_t zone_frame_alloc(zone_t *zone, uint8_t order)
 {
-	ASSERT(zone_flags_available(zone->flags));
+	ASSERT(zone->flags & ZONE_AVAILABLE);
 	
 	/* Allocate frames from zone buddy system */
@@ -490,5 +490,5 @@
 NO_TRACE static size_t zone_frame_free(zone_t *zone, size_t frame_idx)
 {
-	ASSERT(zone_flags_available(zone->flags));
+	ASSERT(zone->flags & ZONE_AVAILABLE);
 	
 	frame_t *frame = &zone->frames[frame_idx];
@@ -518,5 +518,5 @@
 NO_TRACE static void zone_mark_unavailable(zone_t *zone, size_t frame_idx)
 {
-	ASSERT(zone_flags_available(zone->flags));
+	ASSERT(zone->flags & ZONE_AVAILABLE);
 	
 	frame_t *frame = zone_get_frame(zone, frame_idx);
@@ -549,6 +549,6 @@
     buddy_system_t *buddy)
 {
-	ASSERT(zone_flags_available(zones.info[z1].flags));
-	ASSERT(zone_flags_available(zones.info[z2].flags));
+	ASSERT(zones.info[z1].flags & ZONE_AVAILABLE);
+	ASSERT(zones.info[z2].flags & ZONE_AVAILABLE);
 	ASSERT(zones.info[z1].flags == zones.info[z2].flags);
 	ASSERT(zones.info[z1].base < zones.info[z2].base);
@@ -645,5 +645,5 @@
 NO_TRACE static void return_config_frames(size_t znum, pfn_t pfn, size_t count)
 {
-	ASSERT(zone_flags_available(zones.info[znum].flags));
+	ASSERT(zones.info[znum].flags & ZONE_AVAILABLE);
 	
 	size_t cframes = SIZE2FRAMES(zone_conf_size(count));
@@ -681,5 +681,5 @@
     size_t count)
 {
-	ASSERT(zone_flags_available(zones.info[znum].flags));
+	ASSERT(zones.info[znum].flags & ZONE_AVAILABLE);
 	ASSERT(frame_idx + count < zones.info[znum].count);
 	
@@ -723,9 +723,6 @@
 	 * set of flags
 	 */
-	if ((z1 >= zones.count) || (z2 >= zones.count)
-	    || (z2 - z1 != 1)
-	    || (!zone_flags_available(zones.info[z1].flags))
-	    || (!zone_flags_available(zones.info[z2].flags))
-	    || (zones.info[z1].flags != zones.info[z2].flags)) {
+	if ((z1 >= zones.count) || (z2 >= zones.count) || (z2 - z1 != 1) ||
+	    (zones.info[z1].flags != zones.info[z2].flags)) {
 		ret = false;
 		goto errout;
@@ -828,5 +825,5 @@
 	zone->buddy_system = buddy;
 	
-	if (zone_flags_available(flags)) {
+	if (flags & ZONE_AVAILABLE) {
 		/*
 		 * Compute order for buddy system and initialize
@@ -865,4 +862,13 @@
 {
 	return (count * sizeof(frame_t) + buddy_conf_size(fnzb(count)));
+}
+
+/** Allocate external configuration frames from low memory. */
+pfn_t zone_external_conf_alloc(size_t count)
+{
+	size_t size = zone_conf_size(count);
+	size_t order = ispwr2(size) ? fnzb(size) : (fnzb(size) + 1);
+
+	return ADDR2PFN((uintptr_t) frame_alloc(order - FRAME_WIDTH, FRAME_LOWMEM));
 }
 
@@ -888,5 +894,5 @@
 	irq_spinlock_lock(&zones.lock, true);
 	
-	if (zone_flags_available(flags)) {  /* Create available zone */
+	if (flags & ZONE_AVAILABLE) {  /* Create available zone */
 		/* Theoretically we could have NULL here, practically make sure
 		 * nobody tries to do that. If some platform requires, remove
@@ -894,4 +900,7 @@
 		 */
 		ASSERT(confframe != ADDR2PFN((uintptr_t ) NULL));
+
+		/* Update the known end of physical memory. */
+		config.physmem_end = max(config.physmem_end, PFN2ADDR(start + count));
 		
 		/* If confframe is supposed to be inside our zone, then make sure
@@ -1232,5 +1241,5 @@
 	
 	/* Tell the architecture to create some memory */
-	frame_arch_init();
+	frame_low_arch_init();
 	if (config.cpu_active == 1) {
 		frame_mark_unavailable(ADDR2PFN(KA2PA(config.base)),
@@ -1255,4 +1264,37 @@
 		frame_mark_unavailable(0, 1);
 	}
+	frame_high_arch_init();
+}
+
+/** Adjust bounds of physical memory region according to low/high memory split.
+ *
+ * @param low[in]	If true, the adujstment is performed to make the region
+ *			fit in the low memory. Otherwise the adjustment is
+ *			performed to make the region fit in the high memory.
+ * @param basep[inout]	Pointer to a variable which contains the region's base
+ *			address and which may receive the adjusted base address.
+ * @param sizep[inout]	Pointer to a variable which contains the region's size
+ *			and which may receive the adjusted size.
+ * @retun		True if the region still exists even after the
+ *			adjustment, false otherwise.
+ */
+bool frame_adjust_zone_bounds(bool low, uintptr_t *basep, size_t *sizep)
+{
+	uintptr_t limit = config.identity_size;
+
+	if (low) {
+		if (*basep > limit)
+			return false;
+		if (*basep + *sizep > limit)
+			*sizep = limit - *basep;
+	} else {
+		if (*basep + *sizep <= limit)
+			return false;
+		if (*basep <= limit) {
+			*sizep -= limit - *basep;
+			*basep = limit;
+		}
+	}
+	return true;
 }
 
@@ -1293,5 +1335,5 @@
 		*total += (uint64_t) FRAMES2SIZE(zones.info[i].count);
 		
-		if (zone_flags_available(zones.info[i].flags)) {
+		if (zones.info[i].flags & ZONE_AVAILABLE) {
 			*busy += (uint64_t) FRAMES2SIZE(zones.info[i].busy_count);
 			*free += (uint64_t) FRAMES2SIZE(zones.info[i].free_count);
@@ -1344,5 +1386,5 @@
 		irq_spinlock_unlock(&zones.lock, true);
 		
-		bool available = zone_flags_available(flags);
+		bool available = ((flags & ZONE_AVAILABLE) != 0);
 		
 		printf("%-4zu", i);
@@ -1356,8 +1398,10 @@
 #endif
 		
-		printf(" %12zu %c%c%c      ", count,
-		    available ? 'A' : ' ',
-		    (flags & ZONE_RESERVED) ? 'R' : ' ',
-		    (flags & ZONE_FIRMWARE) ? 'F' : ' ');
+		printf(" %12zu %c%c%c%c%c    ", count,
+		    available ? 'A' : '-',
+		    (flags & ZONE_RESERVED) ? 'R' : '-',
+		    (flags & ZONE_FIRMWARE) ? 'F' : '-',
+		    (flags & ZONE_LOWMEM) ? 'L' : '-',
+		    (flags & ZONE_HIGHMEM) ? 'H' : '-');
 		
 		if (available)
@@ -1401,5 +1445,5 @@
 	irq_spinlock_unlock(&zones.lock, true);
 	
-	bool available = zone_flags_available(flags);
+	bool available = ((flags & ZONE_AVAILABLE) != 0);
 	
 	uint64_t size;
@@ -1411,8 +1455,10 @@
 	printf("Zone size:         %zu frames (%" PRIu64 " %s)\n", count,
 	    size, size_suffix);
-	printf("Zone flags:        %c%c%c\n",
-	    available ? 'A' : ' ',
-	    (flags & ZONE_RESERVED) ? 'R' : ' ',
-	    (flags & ZONE_FIRMWARE) ? 'F' : ' ');
+	printf("Zone flags:        %c%c%c%c%c\n",
+	    available ? 'A' : '-',
+	    (flags & ZONE_RESERVED) ? 'R' : '-',
+	    (flags & ZONE_FIRMWARE) ? 'F' : '-',
+	    (flags & ZONE_LOWMEM) ? 'L' : '-',
+	    (flags & ZONE_HIGHMEM) ? 'H' : '-');
 	
 	if (available) {
