1/*
2 * Copyright 2020, Data61, CSIRO (ABN 41 687 119 230)
3 *
4 * SPDX-License-Identifier: GPL-2.0-only
5 */
6
7#include <binaries/efi/efi.h>
8#include <elfloader_common.h>
9
10void *__application_handle = NULL;             // current efi application handler
11efi_system_table_t *__efi_system_table = NULL; // current efi system table
12
13extern void _start(void);
14unsigned int efi_main(uintptr_t application_handle, uintptr_t efi_system_table)
15{
16    clear_bss();
17    __application_handle = (void *)application_handle;
18    __efi_system_table = (efi_system_table_t *)efi_system_table;
19    _start();
20    return 0;
21}
22
23void *efi_get_fdt(void)
24{
25    efi_guid_t fdt_guid = make_efi_guid(0xb1b621d5, 0xf19c, 0x41a5,  0x83, 0x0b, 0xd9, 0x15, 0x2c, 0x69, 0xaa, 0xe0);
26    efi_config_table_t *tables = (efi_config_table_t *)__efi_system_table->tables;
27
28    for (uint32_t i = 0; i < __efi_system_table->nr_tables; i++) {
29        if (!efi_guideq(fdt_guid, tables[i].guid))
30            continue;
31
32        return (void *)tables[i].table;
33    }
34
35    return NULL;
36}
37
38/* Before starting the kernel we should notify the UEFI firmware about it
39 * otherwise the internal watchdog may reboot us after 5 min.
40 *
41 * This means boot time services are not available anymore. We should store
42 * system information e.g. current memory map and pass them to kernel.
43 */
44unsigned long efi_exit_boot_services(void)
45{
46    unsigned long status;
47    efi_memory_desc_t *memory_map;
48    unsigned long map_size;
49    unsigned long desc_size, key;
50    uint32_t desc_version;
51
52    efi_boot_services_t *bts = get_efi_boot_services();
53
54    /*
55     * As the number of existing memeory segments are unknown,
56     * we need to resort to a trial and error to guess that.
57     * We start from 32 and increase it by one until get a valid value.
58     */
59    map_size = sizeof(*memory_map) * 32;
60
61again:
62    status = bts->allocate_pool(EFI_LOADER_DATA, map_size, (void **)&memory_map);
63
64    if (status != EFI_SUCCESS)
65        return status;
66
67    status = bts->get_memory_map(&map_size, memory_map, &key, &desc_size, &desc_version);
68    if (status == EFI_BUFFER_TOO_SMALL) {
69        bts->free_pool(memory_map);
70
71        map_size += sizeof(*memory_map);
72        goto again;
73    }
74
75    if (status != EFI_SUCCESS){
76        bts->free_pool(memory_map);
77        return status;
78    }
79
80    status = bts->exit_boot_services(__application_handle, key);
81    return status;
82}
83