1// Copyright 2018 The Fuchsia Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "zbi.h"
6
7#include <libzbi/zbi-zx.h>
8#include <stdio.h>
9#include <zircon/status.h>
10
11zx_status_t netboot_prepare_zbi(zx_handle_t nbkernel_vmo,
12                                zx_handle_t nbbootdata_vmo,
13                                const uint8_t* cmdline, uint32_t cmdline_size,
14                                dmctl_mexec_args_t* args) {
15    zbi::ZbiVMO kernel, data;
16
17    if (nbkernel_vmo == ZX_HANDLE_INVALID) {
18        printf("netbootloader: no kernel!\n");
19        return ZX_ERR_INVALID_ARGS;
20    }
21
22    if (nbbootdata_vmo == ZX_HANDLE_INVALID) {
23        // Split the complete ZBI into its kernel and data parts.
24        zbi::ZbiVMO zbi;
25        auto status = zbi.Init(zx::vmo{nbkernel_vmo});
26        if (status != ZX_OK) {
27            printf("netbootloader: can't map complete ZBI: %d (%s)\n",
28                   status, zx_status_get_string(status));
29            return status;
30        }
31        auto result = zbi.SplitComplete(&kernel, &data);
32        if (result != ZBI_RESULT_OK) {
33            printf("netbootloader: invalid complete ZBI: %d\n", result);
34            return ZX_ERR_INTERNAL;
35        }
36    } else {
37        // Old-style boot with separate kernel and data ZBIs.
38        printf("netbootloader: old-style boot is deprecated;"
39               " switch to complete ZBI!\n");
40        auto status = kernel.Init(zx::vmo{nbkernel_vmo});
41        if (status != ZX_OK) {
42            printf("netbootloader: can't map kernel ZBI: %d (%s)\n",
43                   status, zx_status_get_string(status));
44            return status;
45        }
46        status = data.Init(zx::vmo{nbbootdata_vmo});
47        if (status != ZX_OK) {
48            printf("netbootloader: can't map kernel ZBI: %d (%s)\n",
49                   status, zx_status_get_string(status));
50            return status;
51        }
52    }
53
54    if (cmdline_size > 0) {
55        auto result = data.AppendSection(cmdline_size, ZBI_TYPE_CMDLINE, 0, 0,
56                                         cmdline);
57        if (result != ZBI_RESULT_OK) {
58            printf("netbootloader: failed to append command line: %d\n",
59                   result);
60            return ZX_ERR_INTERNAL;
61        }
62    }
63
64    printf("netbootloader: kernel ZBI %#x bytes data ZBI %#x bytes\n",
65           kernel.Length(), data.Length());
66
67    args->kernel = kernel.Release().release();
68    args->bootdata = data.Release().release();
69    return ZX_OK;
70}
71