[bootsvc] Decommit pages from the BOOTDATA VMO

Pages that contain unused boot items within the BOOTDATA VMO should be
decommitted.

Change-Id: I05ecc05cca71990ba274c0a9fd1f7d3032a03d3d
diff --git a/zircon/system/core/bootsvc/main.cpp b/zircon/system/core/bootsvc/main.cpp
index 8c7b2bba..327549b 100644
--- a/zircon/system/core/bootsvc/main.cpp
+++ b/zircon/system/core/bootsvc/main.cpp
@@ -205,7 +205,7 @@
     status = bootfs_svc->AddBootfs(std::move(bootfs_vmo));
     ZX_ASSERT_MSG(status == ZX_OK, "bootfs add failed: %s\n", zx_status_get_string(status));
 
-    // Process the ZBI containers to get additional bootfs parts
+    // Process the ZBI boot image
     printf("bootsvc: Retrieving boot image...\n");
     zx::vmo image_vmo;
     bootsvc::ItemMap item_map;
diff --git a/zircon/system/core/bootsvc/util.cpp b/zircon/system/core/bootsvc/util.cpp
index 3d6ed86..0c450aa 100644
--- a/zircon/system/core/bootsvc/util.cpp
+++ b/zircon/system/core/bootsvc/util.cpp
@@ -6,9 +6,11 @@
 
 #include <ctype.h>
 
+#include <fbl/algorithm.h>
 #include <fs/connection.h>
 #include <safemath/checked_math.h>
 #include <zircon/boot/image.h>
+#include <zircon/assert.h>
 #include <zircon/process.h>
 #include <zircon/processargs.h>
 #include <zircon/status.h>
@@ -21,7 +23,6 @@
     case ZBI_TYPE_CRASHLOG:
     case ZBI_TYPE_KERNEL_DRIVER:
     case ZBI_TYPE_PLATFORM_ID:
-    case ZBI_TYPE_STORAGE_BOOTFS:
     case ZBI_TYPE_STORAGE_RAMDISK:
         return true;
     default:
@@ -29,11 +30,21 @@
     }
 }
 
+// Discards the boot item from the boot image VMO.
+void DiscardItem(zx::vmo* vmo, uint32_t begin_in, uint32_t end_in) {
+    uint64_t begin = fbl::round_up(begin_in, static_cast<uint32_t>(PAGE_SIZE));
+    uint64_t end = fbl::round_down(end_in, static_cast<uint32_t>(PAGE_SIZE));
+    if (begin < end) {
+        zx_status_t status = vmo->op_range(ZX_VMO_OP_DECOMMIT, begin, end - begin, nullptr, 0);
+        ZX_ASSERT_MSG(status == ZX_OK, "Discarding boot item failed: %s\n",
+                    zx_status_get_string(status));
+    }
+}
+
 bootsvc::ItemKey CreateItemKey(uint32_t type, uint32_t extra) {
     switch (type) {
-    case ZBI_TYPE_STORAGE_BOOTFS:
     case ZBI_TYPE_STORAGE_RAMDISK:
-        // If this is for storage, set the extra value to zero.
+        // If this is for a ramdisk, set the extra value to zero.
         return bootsvc::ItemKey{.type = type, .extra = 0};
     default:
         // Otherwise, store the extra value.
@@ -43,9 +54,8 @@
 
 bootsvc::ItemValue CreateItemValue(uint32_t type, uint32_t off, uint32_t len) {
     switch (type) {
-    case ZBI_TYPE_STORAGE_BOOTFS:
     case ZBI_TYPE_STORAGE_RAMDISK:
-        // If this is for storage, capture the ZBI header.
+        // If this is for a ramdisk, capture the ZBI header.
         len = safemath::CheckAdd(len, sizeof(zbi_header_t)).ValueOrDie<uint32_t>();
         break;
     default:
@@ -62,20 +72,24 @@
 const char* const kLastPanicFilePath = "log/last-panic.txt";
 
 zx_status_t RetrieveBootImage(zx::vmo* out_vmo, ItemMap* out_map) {
-    // Validate boot container provided by startup handle.
+    // Validate boot image VMO provided by startup handle.
     zx::vmo vmo(zx_take_startup_handle(PA_HND(PA_VMO_BOOTDATA, 0)));
     zbi_header_t header;
     zx_status_t status = vmo.read(&header, 0, sizeof(header));
     if (status != ZX_OK) {
-        printf("bootsvc: Failed to read ZBI container header: %s\n", zx_status_get_string(status));
+        printf("bootsvc: Failed to read ZBI image header: %s\n", zx_status_get_string(status));
         return status;
     } else if (header.type != ZBI_TYPE_CONTAINER || header.extra != ZBI_CONTAINER_MAGIC ||
                header.magic != ZBI_ITEM_MAGIC || !(header.flags & ZBI_FLAG_VERSION)) {
-        printf("bootsvc: Invalid ZBI container header\n");
+        printf("bootsvc: Invalid ZBI image header\n");
         return ZX_ERR_IO_DATA_INTEGRITY;
     }
 
-    // Read boot items from boot container.
+    // Used to discard pages from the boot image VMO.
+    uint32_t discard_begin = 0;
+    uint32_t discard_end = 0;
+
+    // Read boot items from the boot image VMO.
     ItemMap map;
     uint32_t off = sizeof(header);
     uint32_t len = header.length;
@@ -89,17 +103,23 @@
             return ZX_ERR_IO_DATA_INTEGRITY;
         }
         uint32_t item_len = ZBI_ALIGN(header.length + static_cast<uint32_t>(sizeof(zbi_header_t)));
+        uint32_t next_off = safemath::CheckAdd(off, item_len).ValueOrDie();
         if (item_len > len) {
             printf("bootsvc: ZBI item too large (%u > %u)\n", item_len, len);
             return ZX_ERR_IO_DATA_INTEGRITY;
         } else if (StoreItem(header.type)) {
             map.emplace(CreateItemKey(header.type, header.extra),
                         CreateItemValue(header.type, off, header.length));
+            DiscardItem(&vmo, discard_begin, discard_end);
+            discard_begin = next_off;
+        } else {
+            discard_end = next_off;
         }
-        off = safemath::CheckAdd(off, item_len).ValueOrDie();
+        off = next_off;
         len = safemath::CheckSub(len, item_len).ValueOrDie();
     }
 
+    DiscardItem(&vmo, discard_begin, discard_end);
     *out_vmo = std::move(vmo);
     *out_map = std::move(map);
     return ZX_OK;