1// Copyright 2017 The Fuchsia Authors
2//
3// Use of this source code is governed by a MIT-style
4// license that can be found in the LICENSE file or at
5// https://opensource.org/licenses/MIT
6
7#include <assert.h>
8#include <stdio.h>
9#include <pdev/driver.h>
10#include <pdev/pdev.h>
11#include <lk/init.h>
12
13static const zbi_header_t* driver_zbi = NULL;
14
15extern const struct lk_pdev_init_struct __start_lk_pdev_init[];
16extern const struct lk_pdev_init_struct __stop_lk_pdev_init[];
17
18static void pdev_init_driver(uint32_t type, const void* driver_data, uint32_t length, uint level) {
19    const struct lk_pdev_init_struct *ptr;
20    for (ptr = __start_lk_pdev_init; ptr != __stop_lk_pdev_init; ptr++) {
21        if (ptr->type == type && ptr->level == level) {
22            ptr->hook(driver_data, length);
23            return;
24        }
25    }
26}
27
28static void pdev_run_hooks(uint level) {
29    if (!driver_zbi) return;
30
31    const zbi_header_t* item = driver_zbi;
32    DEBUG_ASSERT(item->type == ZBI_TYPE_CONTAINER);
33    DEBUG_ASSERT(item->extra == ZBI_CONTAINER_MAGIC);
34
35    const uint8_t* start = (uint8_t*)item + sizeof(zbi_header_t);
36    const uint8_t* end = start + item->length;
37
38    while ((uint32_t)(end - start) > sizeof(zbi_header_t)) {
39        item = (const zbi_header_t*)start;
40        if (item->type == ZBI_TYPE_KERNEL_DRIVER) {
41            // kernel driver type is in boot item extra
42            // driver data follows boot item
43            pdev_init_driver(item->extra, &item[1], item->length, level);
44        }
45        start += ZBI_ALIGN(sizeof(zbi_header_t) + item->length);
46    }
47}
48
49void pdev_init(const zbi_header_t* zbi) {
50    ASSERT(zbi);
51    driver_zbi = zbi;
52
53    pdev_run_hooks(LK_INIT_LEVEL_PLATFORM_EARLY);
54}
55
56static void platform_dev_init(uint level) {
57    pdev_run_hooks(level);
58}
59
60LK_INIT_HOOK(platform_dev_init, platform_dev_init, LK_INIT_LEVEL_PLATFORM);
61