From 9af74e1e2707bee3dcbf1008682566d330418d8a Mon Sep 17 00:00:00 2001 From: Wolfgang Wiedmeyer Date: Tue, 18 Jul 2017 17:07:43 +0200 Subject: refactoring and first shot at EFS sync Receiving the actual EFS data doesn't work yet. And sometimes, the modem ends up in states where it crashes after exchanging hellos. Signed-off-by: Wolfgang Wiedmeyer --- Android.mk | 4 +- boot.c | 244 +++++++------------------------------ i9305.h | 6 + sahara.c | 397 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ sahara.h | 43 +++++-- 5 files changed, 487 insertions(+), 207 deletions(-) create mode 100644 sahara.c diff --git a/Android.mk b/Android.mk index 66cec18..65c1703 100644 --- a/Android.mk +++ b/Android.mk @@ -19,7 +19,9 @@ LOCAL_PATH := $(call my-dir) include $(CLEAR_VARS) -LOCAL_SRC_FILES := boot.c +LOCAL_SRC_FILES := \ + boot.c \ + sahara.c LOCAL_C_INCLUDES := \ $(LOCAL_PATH) diff --git a/boot.c b/boot.c index 86a189e..d22de18 100644 --- a/boot.c +++ b/boot.c @@ -26,187 +26,40 @@ #include #include -int hello_handshake(int tty_fd) +int configure_tty(int *tty_fd, time_t timeout_sec, long int timeout_usec) { - struct sah_hello_req hello_req; - struct sah_hello_resp hello_resp; - int rc; - - rc = read(tty_fd, &hello_req, sizeof(hello_req)); - if (rc < (int) sizeof(hello_req) - || hello_req.header.command != SAH_COMMAND_HELLO_REQ) { - printf("error receiving hello\n"); - return -1; - } - - if (hello_req.mode != SAH_MODE_TRANSFER_PENDING - && hello_req.mode != SAH_MODE_TRANSFER_COMPLETE) { - printf("requested SAHARA mode %d is not supported\n", hello_req.mode); - return -1; - } - - hello_resp.header.command = SAH_COMMAND_HELLO_RESP; - hello_resp.header.packet_size = sizeof(hello_resp); - hello_resp.version = hello_req.version; - hello_resp.min_version = hello_req.min_version; - hello_resp.status = 0; - hello_resp.mode = hello_req.mode; - - rc = write(tty_fd, &hello_resp, sizeof(hello_resp)); - if (rc < (int) sizeof(hello_resp)) { - printf("failed to write hello response\n"); - return -1; - } - - return 0; -} - -int file_for_id(unsigned int id, char **file) -{ - switch (id) { - case 6: - *file = FILE_APPS; - break; - case 8: - *file = FILE_DSP1; - break; - case 12: - *file = FILE_DSP2; - break; - case 16: - *file = FILE_EFS1; - break; - case 17: - *file = FILE_EFS2; - break; - case 20: - *file = FILE_EFS3; - break; - case 21: - *file = FILE_SBL1; - break; - case 22: - *file = FILE_SBL2; - break; - case 23: - *file = FILE_RPM; - break; - case 28: - *file = FILE_DSP3; - break; - case 29: - *file = FILE_ACDB; - break; - default: - return -1; - } - - return 0; -} - -int send_data(int tty_fd, struct sah_header *header) -{ - struct sah_data_req data_req; - char *file = NULL; - int file_fd; - char file_data[MAX_DATA_SEND_SIZE]; - int rc; - - rc = read(tty_fd, header, sizeof(*header)); - if (rc < (int) sizeof(header)) { - printf("failed to receive header for data request\n"); - return -1; - } - - if (header->command == SAH_COMMAND_DATA_END_REQ) - return 1; - - rc = read(tty_fd, &data_req, sizeof(data_req)); - if (rc < (int) sizeof(data_req)) { - printf("error receiving data req\n"); - return -1; - } - - if(data_req.size > MAX_DATA_SEND_SIZE) { - printf("requested data size is too big\n"); - return -1; - } - - rc = file_for_id(data_req.id, &file); - if (rc < 0) { - printf("failed to identify requested file\n"); - return -1; - } - - file_fd = open(file, O_RDONLY); - if (file_fd < 0) { - printf("failed to open requested file\n"); - return -1; - } - - lseek(file_fd, data_req.offset, SEEK_SET); - - rc = read(file_fd, &file_data, data_req.size); - if (rc < (int) data_req.size) { - printf("failed to read data from file\n"); - return -1; - } - - write(tty_fd, &file_data, data_req.size); - if (rc < (int) data_req.size) { - printf("failed to send data\n"); - } - - return 0; -} - -int send_file(int tty_fd, struct sah_data_end_ack *data_end_ack) -{ - struct sah_header header; - struct sah_data_end_req data_end_req; + int tty_dev; + struct termios termios; + struct timeval timeout; + fd_set fds; int rc; - rc = hello_handshake(tty_fd); - if (rc < 0) { - printf("failed to do hello handshake\n"); - return -1; - } - - do { - rc = send_data(tty_fd, &header); - if (rc < 0) { - printf("error while sending data\n"); - return -1; - } - } while (header.command == SAH_COMMAND_DATA_REQ); - - rc = read(tty_fd, &data_end_req, sizeof(data_end_req)); - if (rc < (int) sizeof(data_end_req)) { - printf("error receiving data end request\n"); + tty_dev = open(TTY_DEVICE, O_RDWR | O_SYNC); + if (tty_dev < 0) { + printf("failed to open modem tty device\n"); return -1; + } else { + printf("opened modem tty device\n"); } - if (data_end_req.status != 0) { - printf("file transfer end status is nonzero\n"); - return -1; - } + tcgetattr(tty_dev, &termios); + cfmakeraw(&termios); + cfsetispeed(&termios, B9600); + cfsetospeed(&termios, B9600); + tcsetattr(tty_dev, TCSANOW, &termios); - printf("id %d: file transfer complete\n", data_end_req.id); + FD_ZERO(&fds); + FD_SET(tty_dev, &fds); + timeout.tv_sec = timeout_sec; + timeout.tv_usec = timeout_usec; - header.command = SAH_COMMAND_DATA_END_RESP; - header.packet_size = 8; - rc = write(tty_fd, &header, sizeof(header)); - if (rc < (int) sizeof(header)) { - printf("failed to write data end response\n"); + rc = select(tty_dev+1, NULL, &fds, NULL, &timeout); + if (rc <= 0) { + printf("failed to set timeout\n"); return -1; } - rc = read(tty_fd, data_end_ack, sizeof(*data_end_ack)); - if (rc < (int) sizeof(*data_end_ack) - || data_end_ack->header.command != SAH_COMMAND_DATA_END_ACK) { - printf("error receiving data end ack\n"); - return -1; - } + *tty_fd = tty_dev; return 0; } @@ -214,12 +67,8 @@ int send_file(int tty_fd, struct sah_data_end_ack *data_end_ack) int main() { int mdm_dev, tty_dev; - struct termios termios; - struct timeval timeout; - fd_set fds; - + int mode; struct sah_data_end_ack data_end_ack; - int rc; mdm_dev = open(MDM_DEVICE, O_RDONLY | O_NONBLOCK); @@ -240,29 +89,9 @@ int main() // wait until modem is awake sleep(2); - tty_dev = open(TTY_DEVICE, O_RDWR | O_SYNC); - if (tty_dev < 0) { - printf("failed to open modem tty device\n"); - return -1; - } - else { - printf("opened modem tty device\n"); - } - - tcgetattr(tty_dev, &termios); - cfmakeraw(&termios); - cfsetispeed(&termios, B9600); - cfsetospeed(&termios, B9600); - tcsetattr(tty_dev, TCSANOW, &termios); - - FD_ZERO(&fds); - FD_SET(tty_dev, &fds); - timeout.tv_sec = 2; - timeout.tv_usec = 0; - - rc = select(tty_dev + 1, NULL, &fds, NULL, &timeout); - if (rc <= 0) { - printf("failed to set timeout\n"); + rc = configure_tty(&tty_dev, 2, 0); + if (rc < 0) { + printf("failed to configure serial interface\n"); return -1; } @@ -276,6 +105,9 @@ int main() if(data_end_ack.status == 1) { printf("all files transferred\n"); + } else { + printf("unknown status for data end ack\n"); + return -1; } close(tty_dev); @@ -285,7 +117,6 @@ int main() printf("failed to wait for normal boot\n"); return -1; } - printf("waited for normal boot\n"); rc = ioctl(mdm_dev, WAIT_FOR_ERROR); @@ -302,5 +133,20 @@ int main() else printf("error: cdc-wdm device does not exist\n"); + printf("\nconfiguring EFS sync\n"); + + rc = configure_tty(&tty_dev, 0, 500000); + if (rc < 0) { + printf("failed to configure serial interface\n"); + } + + while (1) { + rc = handle_memory_debug(tty_dev); + if (rc < 0) { + printf("error during modem operation\n"); + return -1; + } + } + return 0; } diff --git a/i9305.h b/i9305.h index e9e6385..e374ef8 100644 --- a/i9305.h +++ b/i9305.h @@ -25,6 +25,7 @@ #define WAKE_CHARM _IO(CHARM_CODE, 1) #define NORMAL_BOOT_DONE _IOW(CHARM_CODE, 5, int) #define WAIT_FOR_ERROR _IOW(CHARM_CODE, 12, int) +#define WAIT_FOR_RESTART _IOR(CHARM_CODE, 7, int) #define MAX_DATA_SEND_SIZE 1*1024*1024 @@ -41,4 +42,9 @@ #define FILE_SBL2 "/firmware/image/sbl2.mbn" #define FILE_RPM "/firmware/image/rpm.mbn" +// EFS sync +#define SYNC_PATH "/dev/block/modem/dump_path/" +#define SYNC_EFS1 "m9kefs1" +#define SYNC_EFS2 "m9kefs2" + #endif diff --git a/sahara.c b/sahara.c new file mode 100644 index 0000000..2533759 --- /dev/null +++ b/sahara.c @@ -0,0 +1,397 @@ +/* + * Copyright (C) 2017 Wolfgang Wiedmeyer + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include +#include +#include +#include +#include + +#include +#include + +int check_mode(int mode_recv, int mode_expected) +{ + if ((mode_expected == SAH_MODE_TRANSFER_PENDING + || mode_expected == SAH_MODE_TRANSFER_COMPLETE) + && (mode_recv == SAH_MODE_TRANSFER_PENDING + || mode_recv == SAH_MODE_TRANSFER_COMPLETE)) + return 0; + else if (mode_recv == mode_expected) + return 0; + else + return -1; +} + +int hello_response(int tty_fd, int mode) +{ + struct sah_hello_req hello_req; + struct sah_hello_resp hello_resp; + int rc; + + rc = read(tty_fd, &hello_req, sizeof(hello_req)); + if (rc < (int) sizeof(hello_req)) { + printf("error receiving hello, wrong packet size\n"); + return -1; + } + + rc = check_mode(hello_req.mode, mode); + if (rc < 0) { + printf("mode %d is not the expected mode %d\n", + hello_req.mode, mode); + return -1; + } + + hello_resp.header.command = SAH_COMMAND_HELLO_RESP; + hello_resp.header.packet_size = sizeof(hello_resp); + hello_resp.version = hello_req.version; + hello_resp.min_version = hello_req.min_version; + hello_resp.status = 0; + hello_resp.mode = hello_req.mode; + + rc = write(tty_fd, &hello_resp, sizeof(hello_resp)); + if (rc < (int) sizeof(hello_resp)) { + printf("failed to write hello response\n"); + return -1; + } + + return 0; +} + +int hello_handshake(int tty_fd, int mode) +{ + struct sah_header header; + int rc; + + rc = read(tty_fd, &header, sizeof(header)); + if (rc < (int) sizeof(header)) { + printf("failed to receive header for hello request\n"); + return -1; + } else if (header.command != SAH_COMMAND_HELLO_REQ) { + printf("error receiving hello, received command %d\n", + header.command); + return -1; + } + + rc = hello_response(tty_fd, mode); + if (rc < 0) { + printf("failed to send hello response\n"); + return -1; + } + + return 0; +} + +int file_for_id(unsigned int id, char **file) +{ + switch (id) { + case 6: + *file = FILE_APPS; + break; + case 8: + *file = FILE_DSP1; + break; + case 12: + *file = FILE_DSP2; + break; + case 16: + *file = FILE_EFS1; + break; + case 17: + *file = FILE_EFS2; + break; + case 20: + *file = FILE_EFS3; + break; + case 21: + *file = FILE_SBL1; + break; + case 22: + *file = FILE_SBL2; + break; + case 23: + *file = FILE_RPM; + break; + case 28: + *file = FILE_DSP3; + break; + case 29: + *file = FILE_ACDB; + break; + default: + return -1; + } + + return 0; +} + +int send_data(int tty_fd, struct sah_header *header) +{ + struct sah_data_req data_req; + char *file = NULL; + int file_fd; + char file_data[MAX_DATA_SEND_SIZE]; + int rc; + + rc = read(tty_fd, header, sizeof(*header)); + if (rc < (int) sizeof(header)) { + printf("failed to receive header for data request\n"); + return -1; + } + + if (header->command == SAH_COMMAND_DATA_END_REQ) + return 1; + + rc = read(tty_fd, &data_req, sizeof(data_req)); + if (rc < (int) sizeof(data_req)) { + printf("error receiving data req\n"); + return -1; + } + + if(data_req.size > MAX_DATA_SEND_SIZE) { + printf("requested data size is too big\n"); + return -1; + } + + rc = file_for_id(data_req.id, &file); + if (rc < 0) { + printf("failed to identify requested file\n"); + return -1; + } + + file_fd = open(file, O_RDONLY); + if (file_fd < 0) { + printf("failed to open requested file\n"); + return -1; + } + + lseek(file_fd, data_req.offset, SEEK_SET); + + rc = read(file_fd, &file_data, data_req.size); + if (rc < (int) data_req.size) { + printf("failed to read data from file\n"); + return -1; + } + + write(tty_fd, &file_data, data_req.size); + if (rc < (int) data_req.size) { + printf("failed to send data\n"); + } + + return 0; +} + +int send_file(int tty_fd, struct sah_data_end_ack *data_end_ack) +{ + struct sah_header header; + struct sah_data_end_req data_end_req; + int rc; + + rc = hello_handshake(tty_fd, SAH_MODE_TRANSFER_PENDING); + if (rc < 0) { + printf("failed to do hello handshake\n"); + return -1; + } + + do { + rc = send_data(tty_fd, &header); + if (rc < 0) { + printf("error while sending data\n"); + return -1; + } + } while (header.command == SAH_COMMAND_DATA_REQ); + + rc = read(tty_fd, &data_end_req, sizeof(data_end_req)); + if (rc < (int) sizeof(data_end_req)) { + printf("error receiving data end request\n"); + return -1; + } + + if (data_end_req.status != 0) { + printf("file transfer end status is nonzero\n"); + return -1; + } + + printf("id %d: file transfer complete\n", data_end_req.id); + + header.command = SAH_COMMAND_DATA_END_RESP; + header.packet_size = 8; + rc = write(tty_fd, &header, sizeof(header)); + if (rc < (int) sizeof(header)) { + printf("failed to write data end response\n"); + return -1; + } + + rc = read(tty_fd, data_end_ack, sizeof(*data_end_ack)); + if (rc < (int) sizeof(*data_end_ack) + || data_end_ack->header.command != SAH_COMMAND_DATA_END_ACK) { + printf("error receiving data end ack\n"); + return -1; + } + + return 0; +} + +int check_efs_file_request(unsigned char name[20]) +{ + unsigned char efs1[20] = SYNC_EFS1; + unsigned char efs2[20] = SYNC_EFS2; + + if(memcmp(name, efs1, 20) == 0 || memcmp(name, efs2, 20) == 0) + return 0; + else + return -1; +} + +int request_efs_data(int tty_fd, + struct sah_memory_read_req memory_read_req) +{ + char file_data[MAX_DATA_SEND_SIZE]; + int rc; + + rc = write(tty_fd, &memory_read_req, sizeof(memory_read_req)); + if (rc < (int) sizeof(memory_read_req)) { + printf("failed to send memory read request for table\n"); + return -1; + } + + rc = read(tty_fd, &file_data, memory_read_req.size); + if (rc < (int) memory_read_req.size) { + printf("failed to read memory table data\n"); + return -1; + } + + printf("successfully received EFS data\n"); + printf("TODO: implement writing data to EFS partition\n"); + + return 0; +} + +int efs_sync(int tty_fd) +{ + struct sah_memory_debug_req memory_debug_req; + struct sah_memory_read_req memory_read_req; + struct sah_memory_table memory_table; + struct sah_header header; + int i = 0; + int rc; + + rc = read(tty_fd, &memory_debug_req, sizeof(memory_debug_req)); + if (rc < (int) sizeof(memory_debug_req)) { + printf("failed to receive memory debug data\n"); + return -1; + } + + memory_read_req.header.command = SAH_COMMAND_MEMORY_READ_REQ; + memory_read_req.header.packet_size = 16; + memory_read_req.address = memory_debug_req.address; + memory_read_req.size = memory_debug_req.size; + rc = write(tty_fd, &memory_read_req, sizeof(memory_read_req)); + if (rc < (int) sizeof(memory_read_req)) { + printf("failed to send initial memory read request\n"); + return -1; + } + + rc = read(tty_fd, &memory_table, sizeof(memory_table)); + if (rc < (int) sizeof(memory_table)) { + printf("failed to receive memory table\n"); + return -1; + } + + printf("requested file %s with address %d and size %d\n", + memory_table.file, memory_table.address, + memory_table.size); + + rc = check_efs_file_request(memory_table.file); + if (rc < 0) { + printf("access to requested file is not allowed\n"); + return -1; + } + + if( memory_table.size > MAX_DATA_SEND_SIZE) { + printf("requested memory table size is too big\n"); + return -1; + } + + memory_read_req.address = memory_table.address; + memory_read_req.size = memory_table.size; + do { + rc = request_efs_data(tty_fd, memory_read_req); + // abort after 3 retries + if (i++ > 2) + break; + } while (rc < 0); + + header.command = SAH_COMMAND_RESET_REQ; + header.packet_size = 8; + rc = write(tty_fd, &header, sizeof(header)); + if (rc < (int) sizeof(header)) { + printf("failed to send reset request\n"); + return -1; + } + + rc = read(tty_fd, &header, sizeof(header)); + if (rc < (int) sizeof(header)) { + printf("error receiving reset response\n"); + return -1; + } else if (header.command != SAH_COMMAND_RESET_RESP) { + printf("received command %d instead of reset response\n", + header.command); + return -1; + } + + return 0; +} + +int handle_memory_debug(int tty_fd) +{ + struct sah_header header; + int rc; + + rc = read(tty_fd, &header, sizeof(header)); + if (rc < (int) sizeof(header)) { + printf("failed to receive header for command\n"); + return -1; + } + + switch (header.command) { + case SAH_COMMAND_HELLO_REQ: + printf("received hello\n"); + rc = hello_response(tty_fd, SAH_MODE_MEMORY_DEBUG); + if (rc < 0) { + printf("failed to send hello response\n"); + return -1; + } + printf("sent hello response\n"); + break; + case SAH_COMMAND_MEMORY_DEBUG_REQ: + printf("received memory debug command\n"); + rc = efs_sync(tty_fd); + if (rc < 0) { + printf("failed to receive EFS data\n"); + return -1; + } + printf("successful EFS sync\n"); + break; + default: + printf("received unknown command %d with size %d\n", + header.command, header.packet_size); + return -1; + } + + return 0; +} diff --git a/sahara.h b/sahara.h index c3cf7af..b4b0e7b 100644 --- a/sahara.h +++ b/sahara.h @@ -26,14 +26,19 @@ //modes #define SAH_MODE_TRANSFER_PENDING 0x00 #define SAH_MODE_TRANSFER_COMPLETE 0x01 +#define SAH_MODE_MEMORY_DEBUG 0x02 // commands -#define SAH_COMMAND_HELLO_REQ 0x01 -#define SAH_COMMAND_HELLO_RESP 0x02 -#define SAH_COMMAND_DATA_REQ 0x03 -#define SAH_COMMAND_DATA_END_REQ 0x04 -#define SAH_COMMAND_DATA_END_RESP 0x05 -#define SAH_COMMAND_DATA_END_ACK 0x06 +#define SAH_COMMAND_HELLO_REQ 0x01 +#define SAH_COMMAND_HELLO_RESP 0x02 +#define SAH_COMMAND_DATA_REQ 0x03 +#define SAH_COMMAND_DATA_END_REQ 0x04 +#define SAH_COMMAND_DATA_END_RESP 0x05 +#define SAH_COMMAND_DATA_END_ACK 0x06 +#define SAH_COMMAND_RESET_REQ 0x07 +#define SAH_COMMAND_RESET_RESP 0x08 +#define SAH_COMMAND_MEMORY_DEBUG_REQ 0x09 +#define SAH_COMMAND_MEMORY_READ_REQ 0x0A struct sah_header { unsigned int command; @@ -41,7 +46,6 @@ struct sah_header { } __attribute__((__packed__)); struct sah_hello_req { - struct sah_header header; unsigned int version; unsigned int min_version; unsigned int not_needed; @@ -74,4 +78,29 @@ struct sah_data_end_ack { unsigned int status; // 0 more file requests to come, 1 complete } __attribute__((__packed__)); +struct sah_memory_debug_req { + unsigned int address; + unsigned int size; +} __attribute__((__packed__)); + +struct sah_memory_read_req { + struct sah_header header; + unsigned int address; + unsigned int size; +} __attribute__((__packed__)); + +// response after a memory read request +struct sah_memory_table { + unsigned int unknown; + unsigned int address; + unsigned int size; + unsigned char empty[20]; + unsigned char file[20]; +} __attribute__((__packed__)); + +int hello_response(int tty_fd, int mode); +int hello_handshake(int tty_fd, int mode); +int send_file(int tty_fd, struct sah_data_end_ack *data_end_ack); +int handle_memory_debug(int tty_fd); + #endif -- cgit v1.2.3