diff options
-rw-r--r-- | GNUmakefile | 4 | ||||
-rw-r--r-- | RedirectionConstants.h | 24 | ||||
-rw-r--r-- | ider.c | 68 | ||||
-rw-r--r-- | redir.c | 57 | ||||
-rw-r--r-- | redir.h | 63 |
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 @@ -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); +} @@ -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: @@ -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); |