blob: 93f8b818df56a83da1a999b743d24794c6d6233c [file] [log] [blame]
/*
* Copyright (C) 2023 The Android Open Source Project
*
* SPDX-License-Identifier: BSD-2-Clause
*/
#include <android_bootloader_transport.h>
#include <serial.h>
struct header {
uint32_t cmd : 31;
uint32_t is_response : 1;
uint32_t payload_size;
} __attribute__((packed));
static bool verify_device_is_console(struct udevice* console)
{
if (console->driver->id != UCLASS_SERIAL) {
log_err("Passed device: %s isn't a serial. Uclass: %d\n",
console->name, console->driver->id);
return false;
}
struct dm_serial_ops *ops = serial_get_ops(console);
if (ops->putc == NULL) {
log_err("Passed device doesn't support putc\n");
return false;
}
if (ops->getc == NULL) {
log_err("Passed device doesn't support getc\n");
return false;
}
return true;
}
static ssize_t console_write(struct udevice* console, const void* data, size_t size)
{
const unsigned char* data_chars = data;
struct dm_serial_ops *ops = serial_get_ops(console);
ssize_t i;
for (i = 0; i < size; i++) {
int ret;
if ((ret = ops->putc(console, data_chars[i])) != 0) {
log_err("error writing to console: %d\n", ret);
return ret;
}
}
return i;
}
static ssize_t console_read(struct udevice* console, void* data, size_t size)
{
unsigned char* data_chars = data;
struct dm_serial_ops *ops = serial_get_ops(console);
ssize_t i;
for (i = 0; i < size; i++) {
int c;
while ((c = ops->getc(console)) == -EAGAIN) {}
if (c < 0) {
log_err("error reading from console: %d\n", c);
return c;
}
data_chars[i] = c;
}
return i;
}
int android_bootloader_request_response(struct udevice *console, uint32_t command,
const void *request, size_t request_size,
void *response, size_t response_size)
{
if (!verify_device_is_console(console)) {
return -EINVAL;
}
struct header req_header = {
.cmd = command,
.is_response = 0,
.payload_size = request_size,
};
int ret;
printf("Writing %d bytes to %s console\n", sizeof(req_header), console->name);
ret = console_write(console, &req_header, sizeof(req_header));
if (ret != sizeof(req_header)) {
log_err("Failed to write android bootloader request header: %d\n", ret);
return ret;
}
ret = console_write(console, request, request_size);
if (ret != request_size) {
log_err("Failed to write android bootloader request body: %d\n", ret);
return ret;
}
struct header expected_response_header = {
.cmd = command,
.is_response = 1,
.payload_size = response_size,
};
struct header resp_header;
printf("Reading %d bytes from %s console\n", sizeof(resp_header), console->name);
ret = console_read(console, &resp_header, sizeof(resp_header));
if (ret != sizeof(resp_header)) {
log_err("Failed to read android bootloader response header: %d\n", ret);
return ret;
}
int resp_comparison = memcmp(&resp_header, &expected_response_header,
sizeof(resp_header));
if (resp_comparison != 0) {
log_err("Received unexpected android bootloader response header.\n");
log_err("Expected cmd = %d, received cmd = %d\n",
expected_response_header.cmd, resp_header.cmd);
log_err("Expected is_response = %d, received is_response = %d\n",
expected_response_header.is_response,
resp_header.is_response);
log_err("Expected payload_size = %d, received payload_size = %d\n",
expected_response_header.payload_size,
resp_header.payload_size);
return -EINVAL;
}
ret = console_read(console, response, response_size);
if (ret != response_size) {
log_err("Failed to read android bootloader response body: %d\n", ret);
return ret;
}
return 0;
}