summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--GNUmakefile4
-rw-r--r--RedirectionConstants.h24
-rw-r--r--ider.c68
-rw-r--r--redir.c57
-rw-r--r--redir.h63
5 files changed, 202 insertions, 14 deletions
diff --git a/GNUmakefile b/GNUmakefile
index b348505..a021a17 100644
--- a/GNUmakefile
+++ b/GNUmakefile
@@ -73,8 +73,8 @@ distclean: clean
#################################################################
-amtterm: amtterm.o redir.o tcp.o auth.o ssl.o
-amtider: amtider.o redir.o tcp.o auth.o ssl.o
+amtterm: amtterm.o redir.o tcp.o auth.o ssl.o ider.o
+amtider: amtider.o redir.o tcp.o auth.o ssl.o ider.o
gamt: gamt.o redir.o tcp.o parseconfig.o auth.o ssl.o
#################################################################
diff --git a/RedirectionConstants.h b/RedirectionConstants.h
index e5db8aa..fcced21 100644
--- a/RedirectionConstants.h
+++ b/RedirectionConstants.h
@@ -73,6 +73,30 @@
#define IDER_FEATURE_SET_REGISTER_STATE 0x03
#define IDER_FEATURE_ENABLE 0x01
+/* IDER output register mask values */
+#define IDER_INTERRUPT_MASK 0x01
+#define IDER_ERROR_MASK 0x02
+#define IDER_SECTOR_COUNT_MASK 0x04
+#define IDER_SECTOR_NUM_MASK 0x08
+#define IDER_BYTE_CNT_LSG_MASK 0x10
+#define IDER_BYTE_CNT_MSB_MASK 0x20
+#define IDER_DRIVE_SELECT_MASK 0x40
+#define IDER_STATUS_MASK 0x80
+
+/* IDER status register mask values */
+#define IDER_STATUS_BSY 0x80
+#define IDER_STATUS_DRDY 0x40
+#define IDER_STATUS_DF 0x20
+#define IDER_STATUS_DSC 0x10
+#define IDER_STATUS_DRQ 0x80
+#define IDER_STATUS_CORR 0x40
+#define IDER_STATUS_IDX 0x02
+#define IDER_STATUS_ERR 0x01
+
+/* IDER interrupt reason mask values */
+#define IDER_INTERRUPT_IO 0x02
+#define IDER_INTERRUPT_CD 0x01
+
#define START_IDER_REDIRECTION_LENGTH 18
#define START_IDER_REDIRECTION_REPLY_LENGTH 30 //TODO: There is a OEM Defined data field that we are assuming to be 0 bytes..
#define END_IDER_REDIRECTION_LENGTH 8
diff --git a/ider.c b/ider.c
new file mode 100644
index 0000000..e1405c4
--- /dev/null
+++ b/ider.c
@@ -0,0 +1,68 @@
+/*
+ * Intel AMT IDE redirection protocol helper functions.
+ *
+ * Copyright (C) 2022 Hannes Reinecke <hare@suse.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 2 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, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include <sys/types.h>
+#include <string.h>
+#include <scsi/scsi.h>
+#include "redir.h"
+
+static int ider_packet_sense(struct redir *r, unsigned int seqno,
+ unsigned char device, unsigned char sense,
+ unsigned char asc, unsigned char asq)
+{
+ unsigned char mask = IDER_INTERRUPT_MASK | IDER_SECTOR_COUNT_MASK |
+ IDER_DRIVE_SELECT_MASK | IDER_STATUS_MASK;
+ struct ider_command_response_message msg = {
+ .type = IDER_COMMAND_END_RESPONSE,
+ .output.mask = mask,
+ .output.sector_count = IDER_INTERRUPT_IO | IDER_INTERRUPT_CD,
+ .output.drive_select = device,
+ .output.status = IDER_STATUS_DRDY | IDER_STATUS_DSC,
+ };
+ memcpy(&msg.sequence_number, &seqno, 4);
+ if (sense) {
+ msg.output.error = (sense << 4);
+ msg.output.mask |= IDER_ERROR_MASK;
+ msg.output.status |= IDER_STATUS_ERR;
+ msg.sense = sense;
+ msg.asc = asc;
+ msg.asq = asq;
+ }
+ return redir_write(r, (const char *)&msg, sizeof(msg));
+}
+
+int ider_handle_command(struct redir *r, unsigned int seqno,
+ unsigned char *cdb)
+{
+ unsigned char device = 0xb0;
+
+ if (!r->filename)
+ /* NOT READY, MEDIUM NOT PRESENT */
+ return ider_packet_sense(r, seqno, device, 0x02, 0x3a, 0x0);
+
+ switch (cdb[0]) {
+ case TEST_UNIT_READY:
+ return ider_packet_sense(r, seqno, device, 0, 0, 0);
+ default:
+ break;
+ }
+ /* ILLEGAL REQUEST, CDB NOT SUPPORTED */
+ return ider_packet_sense(r, seqno, device, 0x05, 0x20, 0x00);
+}
diff --git a/redir.c b/redir.c
index ac41212..6e1e0f8 100644
--- a/redir.c
+++ b/redir.c
@@ -99,7 +99,7 @@ static void hexdump(const char *prefix, const unsigned char *data, size_t size)
}
}
-static ssize_t redir_write(struct redir *r, const char *buf, size_t count)
+ssize_t redir_write(struct redir *r, const char *buf, size_t count)
{
int rc;
@@ -416,17 +416,17 @@ int redir_ider_config(struct redir *r)
IDER_FEATURE_SET_REGISTER_STATE,
IDER_FEATURE_ENABLE | r->enable_options, 0, 0, 0
};
- r->seqno++;
redir_state(r, REDIR_CFG_IDER);
+ r->seqno++;
return redir_write(r, request, sizeof(request));
}
-int redir_ider_reset(struct redir *r)
+int redir_ider_reset(struct redir *r, unsigned int seqno)
{
unsigned char request[IDER_RESET_OCCURED_RESPONSE_LENGTH] = {
IDER_RESET_OCCURED_RESPONSE, 0, 0, 0,
- r->seqno & 0xff, (r->seqno >> 8) & 0xff,
- (r->seqno >> 16) & 0xff, (r->seqno >> 24) & 0xff,
+ seqno & 0xff, (seqno >> 8) & 0xff,
+ (seqno >> 16) & 0xff, (seqno >> 24) & 0xff,
};
return redir_write(r, request, sizeof(request));
@@ -443,6 +443,25 @@ int redir_ider_stop(struct redir *r)
return redir_write(r, request, sizeof(request));
}
+static int redir_ider_command(struct redir *r, unsigned int seqno)
+{
+ struct ider_command_written_message *msg =
+ (struct ider_command_written_message *)r->buf;
+ int i;
+
+ if (msg->command != 0xa0) {
+ snprintf(r->err, sizeof(r->err), "Unhandled IDE command %02x",
+ msg->command);
+ return -1;
+ }
+ fprintf(stderr, "command %02x: ", msg->command);
+ for (i = 0; i < sizeof(msg->packet_data); i++)
+ fprintf(stderr, "%02x ", msg->packet_data[i]);
+ fprintf(stderr, "\n");
+
+ return ider_handle_command(r, seqno, msg->packet_data);
+}
+
int redir_ider_recv(struct redir *r)
{
unsigned char msg[64];
@@ -490,12 +509,21 @@ int redir_ider_recv(struct redir *r)
return bshift;
}
+static inline unsigned int redir_hdr_seqno(struct redir *r)
+{
+ return (unsigned int)r->buf[4] |
+ (unsigned int)r->buf[5] << 8 |
+ (unsigned int)r->buf[6] << 16 |
+ (unsigned int)r->buf[7] << 24;
+}
+
static int in_loopback_mode = 0;
static int powered_off = 0;
int redir_data(struct redir *r)
{
int rc, bshift;
+ unsigned int seqno;
repeat:
if (r->trace) {
@@ -655,16 +683,23 @@ repeat:
bshift = r->blen;
if (r->blen < IDER_DISABLE_ENABLE_FEATURES_REPLY_LENGTH)
goto again;
+ if (r->seqno != redir_hdr_seqno(r))
+ goto err;
redir_state(r, REDIR_RUN_IDER);
break;
case IDER_RESET_OCCURED:
bshift = r->blen;
- r->seqno = (unsigned int)r->buf[4] |
- (unsigned int)r->buf[5] << 8 |
- (unsigned int)r->buf[6] << 16 |
- (unsigned int)r->buf[7] << 24;
- fprintf(stderr, "reset, mask %u\n", r->buf[8]);
- if (-1 == redir_ider_reset(r))
+ seqno = redir_hdr_seqno(r);
+ fprintf(stderr, "seqno %u: reset, mask %u\n", seqno, r->buf[8]);
+ if (-1 == redir_ider_reset(r, seqno))
+ goto err;
+ break;
+ case IDER_COMMAND_WRITTEN:
+ bshift = r->blen;
+ if (r->blen < sizeof(struct ider_command_written_message))
+ goto again;
+ seqno = redir_hdr_seqno(r);
+ if (-1 == redir_ider_command(r, seqno))
goto err;
break;
case IDER_DATA_FROM_HOST:
diff --git a/redir.h b/redir.h
index d170562..b610f20 100644
--- a/redir.h
+++ b/redir.h
@@ -36,6 +36,8 @@ struct redir {
unsigned int tx_bufsize;
unsigned int rx_bufsize;
unsigned int enable_options;
+ unsigned int tx_length;
+ unsigned int tx_offset;
int sock;
unsigned char buf[64];
@@ -59,6 +61,61 @@ struct __attribute__ ((__packed__)) controls_from_host_message {
unsigned char status;
};
+struct __attribute__ ((__packed__)) ider_command_written_message {
+ unsigned char type;
+ unsigned char reserved[3];
+ uint32_t sequence_number;
+ unsigned char cable_sel; /* 8 */
+ unsigned char feature; /* 9 */
+ unsigned char sector_count; /* 10 */
+ unsigned char sector_number; /* 11 */
+ uint16_t byte_count; /* 12 */
+ unsigned char drive_select; /* 14 */
+ unsigned char command; /* 15 */
+ unsigned char packet_data[12]; /* 16 */
+};
+
+struct __attribute__ ((__packed__)) ider_data_regs {
+ unsigned char mask;
+ unsigned char error;
+ unsigned char sector_count;
+ unsigned char sector_num;
+ unsigned char byte_count_lsb;
+ unsigned char byte_count_msb;
+ unsigned char drive_select;
+ unsigned char status;
+};
+
+struct __attribute__ ((__packed__)) ider_command_response_message {
+ unsigned char type;
+ unsigned char reserved[2];
+ unsigned char attributes;
+ uint32_t sequence_number;
+ unsigned char cable_sel; /* unused */
+ uint16_t transfer_bytes;
+ unsigned char packet_num; /* unused */
+ unsigned char input_regs[8]; /* unused */
+ struct ider_data_regs output;
+ unsigned char sense;
+ unsigned char asc;
+ unsigned char asq;
+};
+
+struct __attribute__ ((__packed__)) ider_data_to_host_message {
+ unsigned char type;
+ unsigned char reserved[2];
+ unsigned char attributes;
+ uint32_t sequence_number;
+ unsigned char cable_sel; /* unused */
+ uint16_t transfer_bytes;
+ unsigned char packet_num; /* unused */
+ struct ider_data_regs input;
+ struct ider_data_regs output;
+ unsigned char sense;
+ unsigned char asc;
+ unsigned char asq;
+};
+
const char *redir_state_name(enum redir_state state);
const char *redir_state_desc(enum redir_state state);
@@ -72,8 +129,12 @@ int redir_sol_send(struct redir *r, unsigned char *buf, int blen);
int redir_sol_recv(struct redir *r);
int redir_ider_start(struct redir *r);
int redir_ider_config(struct redir *r);
-int redir_ider_reset(struct redir *r);
+int redir_ider_reset(struct redir *r, unsigned int seqno);
int redir_ider_stop(struct redir *r);
int redir_ider_send(struct redir *r, unsigned char *buf, int blen);
int redir_ider_recv(struct redir *r);
int redir_data(struct redir *r);
+ssize_t redir_write(struct redir *r, const char *buf, size_t count);
+
+int ider_handle_command(struct redir *r, unsigned int seqno,
+ unsigned char *cdb);