summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Android.mk4
-rw-r--r--boot.c244
-rw-r--r--i9305.h6
-rw-r--r--sahara.c397
-rw-r--r--sahara.h43
5 files changed, 487 insertions, 207 deletions
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 <sahara.h>
#include <i9305.h>
-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 <wolfgit@wiedmeyer.de>
+ *
+ * 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 <http://www.gnu.org/licenses/>.
+ */
+
+#include <stdio.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <string.h>
+
+#include <sahara.h>
+#include <i9305.h>
+
+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