1 /*
2  * Copyright (c) 2020 Raspberry Pi (Trading) Ltd.
3  *
4  * SPDX-License-Identifier: BSD-3-Clause
5  */
6 
7 #include "pico/bootrom.h"
8 #include "boot/picoboot.h"
9 #include "boot/picobin.h"
10 
11 /// \tag::table_lookup[]
12 
rom_func_lookup(uint32_t code)13 void *rom_func_lookup(uint32_t code) {
14     return rom_func_lookup_inline(code);
15 }
16 
17 #pragma GCC diagnostic push
18 // diagnostic: GCC thinks near-zero value is a null pointer member access, but it's not
19 #pragma GCC diagnostic ignored "-Warray-bounds"
rom_data_lookup(uint32_t code)20 void *rom_data_lookup(uint32_t code) {
21 #if PICO_RP2040
22     rom_table_lookup_fn rom_table_lookup = (rom_table_lookup_fn) rom_hword_as_ptr(BOOTROM_TABLE_LOOKUP_OFFSET);
23     uint16_t *data_table = (uint16_t *) rom_hword_as_ptr(BOOTROM_DATA_TABLE_OFFSET);
24     return rom_table_lookup(data_table, code);
25 #else
26 #ifdef __riscv
27     uint32_t rom_offset_adjust = rom_size_is_64k() ? 32 * 1024 : 0;
28     rom_table_lookup_fn rom_table_lookup = (rom_table_lookup_fn) (uintptr_t)*(uint16_t*)(BOOTROM_TABLE_LOOKUP_OFFSET + rom_offset_adjust);
29 #else
30     rom_table_lookup_fn rom_table_lookup = (rom_table_lookup_fn) (uintptr_t)*(uint16_t*)(BOOTROM_TABLE_LOOKUP_OFFSET);
31 #endif
32     return rom_table_lookup(code, RT_FLAG_DATA);
33 #endif
34 }
35 #pragma GCC diagnostic pop
36 /// \end::table_lookup[]
37 
rom_funcs_lookup(uint32_t * table,unsigned int count)38 bool rom_funcs_lookup(uint32_t *table, unsigned int count) {
39     bool ok = true;
40     for (unsigned int i = 0; i < count; i++) {
41         table[i] = (uintptr_t) rom_func_lookup(table[i]);
42         if (!table[i]) ok = false;
43     }
44     return ok;
45 }
46 
47 
rom_reset_usb_boot(uint32_t usb_activity_gpio_pin_mask,uint32_t disable_interface_mask)48 void __attribute__((noreturn)) rom_reset_usb_boot(uint32_t usb_activity_gpio_pin_mask, uint32_t disable_interface_mask) {
49 #ifdef ROM_FUNC_RESET_USB_BOOT
50     rom_reset_usb_boot_fn func = (rom_reset_usb_boot_fn) rom_func_lookup(ROM_FUNC_RESET_USB_BOOT);
51     func(usb_activity_gpio_pin_mask, disable_interface_mask);
52 #elif defined(ROM_FUNC_REBOOT)
53     uint32_t flags = disable_interface_mask;
54     if (usb_activity_gpio_pin_mask) {
55         flags |= BOOTSEL_FLAG_GPIO_PIN_SPECIFIED;
56         // the parameter is actually the gpio number, but we only care if BOOTSEL_FLAG_GPIO_PIN_SPECIFIED
57         usb_activity_gpio_pin_mask = (uint32_t)__builtin_ctz(usb_activity_gpio_pin_mask);
58     }
59     rom_reboot(REBOOT2_FLAG_REBOOT_TYPE_BOOTSEL | REBOOT2_FLAG_NO_RETURN_ON_SUCCESS, 10, flags, usb_activity_gpio_pin_mask);
60     __builtin_unreachable();
61 #else
62     panic_unsupported();
63 #endif
64 }
65 
rom_reset_usb_boot_extra(int usb_activity_gpio_pin,uint32_t disable_interface_mask,bool usb_activity_gpio_pin_active_low)66 void __attribute__((noreturn)) rom_reset_usb_boot_extra(int usb_activity_gpio_pin, uint32_t disable_interface_mask, bool usb_activity_gpio_pin_active_low) {
67 #ifdef ROM_FUNC_RESET_USB_BOOT
68     (void)usb_activity_gpio_pin_active_low;
69     rom_reset_usb_boot_fn func = (rom_reset_usb_boot_fn) rom_func_lookup(ROM_FUNC_RESET_USB_BOOT);
70     func(usb_activity_gpio_pin < 0 ? 0 : (1u << usb_activity_gpio_pin), disable_interface_mask);
71 #elif defined(ROM_FUNC_REBOOT)
72     uint32_t flags = disable_interface_mask;
73     if (usb_activity_gpio_pin >= 0) {
74         flags |= BOOTSEL_FLAG_GPIO_PIN_SPECIFIED;
75         if (usb_activity_gpio_pin_active_low) {
76             flags |= BOOTSEL_FLAG_GPIO_PIN_ACTIVE_LOW;
77         }
78     }
79     rom_reboot(REBOOT2_FLAG_REBOOT_TYPE_BOOTSEL | REBOOT2_FLAG_NO_RETURN_ON_SUCCESS, 10, flags, (uint)usb_activity_gpio_pin);
80     __builtin_unreachable();
81 #else
82     panic_unsupported();
83 #endif
84 }
85 
86 #if !PICO_RP2040
rom_get_boot_random(uint32_t out[4])87 bool rom_get_boot_random(uint32_t out[4]) {
88     uint32_t result[5];
89     rom_get_sys_info_fn func = (rom_get_sys_info_fn) rom_func_lookup_inline(ROM_FUNC_GET_SYS_INFO);
90     if (5 == func(result, count_of(result), SYS_INFO_BOOT_RANDOM)) {
91         for(uint i=0;i<4;i++) {
92             out[i] = result[i+1];
93         }
94         return true;
95     }
96     return false;
97 }
98 
rom_add_flash_runtime_partition(uint32_t start_offset,uint32_t size,uint32_t permissions)99 int rom_add_flash_runtime_partition(uint32_t start_offset, uint32_t size, uint32_t permissions) {
100     if ((start_offset) & 4095 || (size & 4095)) return PICO_ERROR_BAD_ALIGNMENT;
101     if (!size || start_offset + size > 32 * 1024 * 1024) return PICO_ERROR_INVALID_ARG;
102     if (permissions & ~PICOBIN_PARTITION_PERMISSIONS_BITS) return PICO_ERROR_INVALID_ARG;
103 
104     void **ptr = (void **)rom_data_lookup(ROM_DATA_PARTITION_TABLE_PTR);
105     assert(ptr);
106     assert(*ptr);
107     struct pt {
108         struct {
109             uint8_t partition_count;
110             uint8_t permission_partition_count; // >= partition_count and includes any regions added at runtime
111             bool loaded;
112         };
113         uint32_t unpartitioned_space_permissions_and_flags;
114         resident_partition_t partitions[PARTITION_TABLE_MAX_PARTITIONS];
115     } *pt = (struct pt *)*ptr;
116     assert(pt->loaded); // even if empty it should have been populated by the bootrom
117     if (pt->permission_partition_count < pt->partition_count) pt->permission_partition_count = pt->partition_count;
118     if (pt->permission_partition_count < PARTITION_TABLE_MAX_PARTITIONS) {
119         pt->partitions[pt->permission_partition_count].permissions_and_location = permissions |
120                 ((start_offset / 4096) << PICOBIN_PARTITION_LOCATION_FIRST_SECTOR_LSB) |
121                 ((start_offset + size - 4096) / 4096) << PICOBIN_PARTITION_LOCATION_LAST_SECTOR_LSB;
122         pt->partitions[pt->permission_partition_count].permissions_and_flags = permissions;
123         return pt->permission_partition_count++;
124     }
125     return PICO_ERROR_INSUFFICIENT_RESOURCES;
126 }
127 #endif