[ndebug] Move NDebug from main LK tree to Coral tree.

This commit is contained in:
Gurjant Kalsi
2016-06-03 16:28:00 -07:00
parent c01adc6e0d
commit 5324238022
15 changed files with 2 additions and 1256 deletions

View File

View File

@@ -1,53 +0,0 @@
/*
* Copyright 2016 Google Inc. All Rights Reserved.
* Author: gkalsi@google.com (Gurjant Kalsi)
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files
* (the "Software"), to deal in the Software without restriction,
* including without limitation the rights to use, copy, modify, merge,
* publish, distribute, sublicense, and/or sell copies of the Software,
* and to permit persons to whom the Software is furnished to do so,
* subject to the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#pragma once
#include <compiler.h>
#include <stdint.h>
#include <sys/types.h>
#define NDEBUG_MAX_PACKET_SIZE (64)
__BEGIN_CDECLS
typedef enum {
NDEBUG_CHANNEL_SYS,
NDEBUG_CHANNEL_USR,
NDEBUG_CHANNEL_COUNT, // Count: always last.
} channel_t;
void ndebug_init(void);
ssize_t ndebug_usb_read(const channel_t ch, const size_t n,
const lk_time_t timeout, uint8_t *buf);
ssize_t ndebug_usb_write(const channel_t ch, const size_t n,
const lk_time_t timeout, uint8_t *buf);
status_t ndebug_await_connection(const channel_t ch, const lk_time_t timeout);
status_t msg_host(const channel_t ch, const uint32_t message,
const lk_time_t timeout, uint8_t *buf);
__END_CDECLS

View File

@@ -1,44 +0,0 @@
/*
* Copyright 2016 Google Inc. All Rights Reserved.
* Author: gkalsi@google.com (Gurjant Kalsi)
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files
* (the "Software"), to deal in the Software without restriction,
* including without limitation the rights to use, copy, modify, merge,
* publish, distribute, sublicense, and/or sell copies of the Software,
* and to permit persons to whom the Software is furnished to do so,
* subject to the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#pragma once
#include <stdint.h>
typedef struct __attribute__((packed)) {
uint32_t magic;
uint32_t type;
} ndebug_ctrl_packet_t;
#define NDEBUG_CTRL_PACKET_MAGIC (0x4354524C)
#define NDEBUG_CTRL_CMD_RESET (0x01)
#define NDEBUG_CTRL_CMD_DATA (0x02)
#define NDEBUG_CTRL_CMD_ESTABLISHED (0x03)
#define NDEBUG_USB_CLASS_USER_DEFINED (0xFF)
#define NDEBUG_SUBCLASS (0x02)
#define NDEBUG_PROTOCOL_LK_SYSTEM (0x01)
#define NDEBUG_PROTOCOL_SERIAL_PIPE (0x02)

View File

@@ -1,43 +0,0 @@
/*
* Copyright 2016 Google Inc. All Rights Reserved.
* Author: gkalsi@google.com (Gurjant Kalsi)
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files
* (the "Software"), to deal in the Software without restriction,
* including without limitation the rights to use, copy, modify, merge,
* publish, distribute, sublicense, and/or sell copies of the Software,
* and to permit persons to whom the Software is furnished to do so,
* subject to the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#pragma once
#include <compiler.h>
#include <lib/ndebug/ndebug.h>
#include <lib/ndebug/shared_structs.h>
__BEGIN_CDECLS
#define NDEBUG_USR_MAX_PACKET_SIZE (NDEBUG_MAX_PACKET_SIZE - sizeof(ndebug_ctrl_packet_t))
// Read and write to the NDebug user channel.
ssize_t ndebug_read_usr(uint8_t *buf, const lk_time_t timeout);
ssize_t ndebug_write_usr(uint8_t *buf, const size_t n, const lk_time_t timeout);
// Wait for the host to establish a connection on the usr channel.
status_t ndebug_await_connection_usr(lk_time_t timeout);
__END_CDECLS

View File

@@ -1,292 +0,0 @@
/*
* Copyright 2016 Google Inc. All Rights Reserved.
* Author: gkalsi@google.com (Gurjant Kalsi)
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files
* (the "Software"), to deal in the Software without restriction,
* including without limitation the rights to use, copy, modify, merge,
* publish, distribute, sublicense, and/or sell copies of the Software,
* and to permit persons to whom the Software is furnished to do so,
* subject to the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#include <lib/ndebug/ndebug.h>
#include <assert.h>
#include <dev/udc.h>
#include <dev/usb.h>
#include <dev/usbc.h>
#include <err.h>
#include <kernel/event.h>
#include <lib/ndebug/shared_structs.h>
#include <string.h>
#include <trace.h>
#define LOCAL_TRACE 0
#define W(w) (w & 0xff), (w >> 8)
#define W3(w) (w & 0xff), ((w >> 8) & 0xff), ((w >> 16) & 0xff)
#define IFACE_SUBCLASS_IDX (0x06)
#define IFACE_PROTOCOL_IDX (0x07)
#define IFACE_IN_ADDR_IDX (0x0B)
#define IFACE_OUT_ADDR_IDX (0x12)
#define CH_TO_ADDR(CH) ((CH) + 1)
#define CHECK_CHANNEL(CH) \
do { DEBUG_ASSERT((CH) < NDEBUG_CHANNEL_COUNT); } while (false);
#define SYS_EP_ADDR (CH_TO_ADDR(NDEBUG_CHANNEL_SYS))
#define USR_EP_ADDR (CH_TO_ADDR(NDEBUG_CHANNEL_USR))
#define NDEBUG_SUBCLASS (0x02)
#define NDEBUG_PROTOCOL_LK_SYSTEM (0x01)
#define NDEBUG_PROTOCOL_SERIAL_PIPE (0x02)
static usbc_transfer_t rx_transfer[NDEBUG_CHANNEL_COUNT];
static usbc_transfer_t tx_transfer[NDEBUG_CHANNEL_COUNT];
static event_t rx_event[NDEBUG_CHANNEL_COUNT];
static event_t tx_event[NDEBUG_CHANNEL_COUNT];
static event_t usb_online_event;
static const uint8_t bulk_pair_descriptor_template[] = {
0x09, /* length */
INTERFACE, /* type */
0x00, /* interface num - Unused, patched in by dev/usb */
0x00, /* alternates */
0x02, /* endpoint count */
0xff, /* interface class - User Deficned */
0x00, /* interface subclass - Patched by client */
0x00, /* interface protocol - Patched by client */
0x00, /* string index */
/* endpoint 1 IN */
0x07, /* length */
ENDPOINT, /* type */
0x80, /* address - Patched by Client */
0x02, /* type: bulk */
W(64), /* max packet size: 64 */
00, /* interval - unused for bulk */
/* endpoint 1 OUT */
0x07, /* length */
ENDPOINT, /* type */
0x00, /* address - Patched by client */
0x02, /* type: bulk */
W(64), /* max packet size: 64 */
00, /* interval - unused for bulk */
};
static void init_channel(uint8_t subclass, uint8_t protocol, uint8_t ep_addr)
{
uint8_t desc[sizeof(bulk_pair_descriptor_template)];
// Make a copy of the template descriptor and fill in the missing fields.
memcpy(desc, bulk_pair_descriptor_template,
sizeof(bulk_pair_descriptor_template));
desc[IFACE_SUBCLASS_IDX] = subclass;
desc[IFACE_PROTOCOL_IDX] = protocol;
desc[IFACE_IN_ADDR_IDX] = ep_addr | 0x80;
desc[IFACE_OUT_ADDR_IDX] = ep_addr;
// Append the interfaces.
usb_append_interface_lowspeed(desc, sizeof(desc));
usb_append_interface_highspeed(desc, sizeof(desc));
}
static void setup_usb_endpoint(uint8_t ep_num)
{
usbc_setup_endpoint(ep_num, USB_IN, 0x40, USB_BULK);
usbc_setup_endpoint(ep_num, USB_OUT, 0x40, USB_BULK);
}
static status_t ndebug_register_cb(
void *cookie,
usb_callback_op_t op,
const union usb_callback_args *args
)
{
if (op == USB_CB_ONLINE) {
for (channel_t ch = 0; ch < NDEBUG_CHANNEL_COUNT; ++ch) {
setup_usb_endpoint(CH_TO_ADDR(ch));
}
event_signal(&usb_online_event, false);
} else if (op == USB_CB_RESET || op == USB_CB_DISCONNECT ||
op == USB_CB_OFFLINE) {
event_unsignal(&usb_online_event);
}
return NO_ERROR;
}
void ndebug_init(void)
{
for (channel_t ch = 0; ch < NDEBUG_CHANNEL_COUNT; ++ch) {
event_init(&rx_event[ch], 0, EVENT_FLAG_AUTOUNSIGNAL);
event_init(&tx_event[ch], 0, EVENT_FLAG_AUTOUNSIGNAL);
}
init_channel(NDEBUG_SUBCLASS, NDEBUG_PROTOCOL_LK_SYSTEM, SYS_EP_ADDR);
init_channel(NDEBUG_SUBCLASS, NDEBUG_PROTOCOL_SERIAL_PIPE, USR_EP_ADDR);
event_init(&usb_online_event, 0, 0);
usb_register_callback(&ndebug_register_cb, NULL);
}
static status_t usb_xmit_cplt_cb(ep_t endpoint, usbc_transfer_t *t)
{
uint32_t channel = (uint32_t)t->extra;
CHECK_CHANNEL(channel);
event_signal(&tx_event[channel], false);
return 0;
}
static status_t usb_recv_cplt_cb(ep_t endpoint, usbc_transfer_t *t)
{
uint32_t channel = (uint32_t)t->extra;
CHECK_CHANNEL(channel);
event_signal(&rx_event[channel], false);
return 0;
}
ssize_t ndebug_usb_read(const channel_t ch, const size_t n,
const lk_time_t timeout, uint8_t *buf)
{
CHECK_CHANNEL(ch);
usbc_transfer_t *transfer = &rx_transfer[ch];
transfer->callback = &usb_recv_cplt_cb;
transfer->result = 0;
transfer->buf = buf;
transfer->buflen = n;
transfer->bufpos = 0;
transfer->extra = (void *)ch;
usbc_queue_rx(CH_TO_ADDR(ch), transfer);
status_t res = event_wait_timeout(&rx_event[ch], timeout);
if (res != NO_ERROR) {
return res;
}
if (transfer->result != NO_ERROR) {
return transfer->result;
}
return transfer->bufpos;
}
ssize_t ndebug_usb_write(const channel_t ch, const size_t n,
const lk_time_t timeout, uint8_t *buf)
{
CHECK_CHANNEL(ch);
usbc_transfer_t *transfer = &tx_transfer[ch];
transfer->callback = &usb_xmit_cplt_cb;
transfer->result = 0;
transfer->buf = buf;
transfer->buflen = n;
transfer->bufpos = 0;
transfer->extra = (void *)ch;
usbc_queue_tx(CH_TO_ADDR(ch), transfer);
status_t res = event_wait_timeout(&tx_event[ch], timeout);
if (res != NO_ERROR) {
return res;
}
if (transfer->result != NO_ERROR) {
return transfer->result;
}
return n;
}
static bool is_valid_connection_request(ssize_t n, const uint8_t *buf)
{
LTRACEF("length: %ld, buf: 0x%p\n", n, buf);
if (n < (ssize_t)sizeof(ndebug_ctrl_packet_t)) {
dprintf(INFO, "Malformed Packet. Expected at least %u bytes, got %ld\n",
sizeof(ndebug_ctrl_packet_t), n);
return false;
}
ndebug_ctrl_packet_t *pkt = (ndebug_ctrl_packet_t *)buf;
return pkt->magic == NDEBUG_CTRL_PACKET_MAGIC &&
pkt->type == NDEBUG_CTRL_CMD_RESET;
}
status_t msg_host(
const channel_t ch, const uint32_t message,
const lk_time_t timeout, uint8_t *buf
)
{
LTRACEF("message: %d\n", message);
ndebug_ctrl_packet_t *pkt = (ndebug_ctrl_packet_t *)buf;
pkt->magic = NDEBUG_CTRL_PACKET_MAGIC;
pkt->type = message;
ssize_t res =
ndebug_usb_write(ch, sizeof(ndebug_ctrl_packet_t), timeout, buf);
if (res == ERR_TIMED_OUT) {
dprintf(INFO, "send message %d timed out\n", message);
} else if (res < 0) {
dprintf(INFO, "send message %d failed with error %ld\n", message, res);
}
return res;
}
status_t ndebug_await_connection(const channel_t ch, const lk_time_t timeout)
{
LTRACEF("channel: %u, timeout: %u\n", ch, timeout);
uint8_t buf[NDEBUG_MAX_PACKET_SIZE];
status_t result = event_wait_timeout(&usb_online_event, timeout);
if (result != NO_ERROR) {
return result;
}
while (true) {
ssize_t bytes =
ndebug_usb_read(ch, NDEBUG_MAX_PACKET_SIZE, timeout, buf);
if (bytes < 0) return bytes;
if (bytes < (ssize_t)sizeof(ndebug_ctrl_packet_t)) continue;
if (!is_valid_connection_request(bytes, buf)) {
msg_host(ch, NDEBUG_CTRL_CMD_RESET, timeout, buf);
continue;
}
if (msg_host(ch, NDEBUG_CTRL_CMD_ESTABLISHED, timeout, buf) < 0) {
continue;
}
return NO_ERROR;
}
}

View File

@@ -1,12 +0,0 @@
LOCAL_DIR := $(GET_LOCAL_DIR)
MODULE := $(LOCAL_DIR)
# MODULE_DEPS := \
MODULE_SRCS += \
$(LOCAL_DIR)/ndebug.c \
$(LOCAL_DIR)/user.c \
include make/module.mk

View File

@@ -1,157 +0,0 @@
/*
* Copyright 2016 Google Inc. All Rights Reserved.
* Author: gkalsi@google.com (Gurjant Kalsi)
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files
* (the "Software"), to deal in the Software without restriction,
* including without limitation the rights to use, copy, modify, merge,
* publish, distribute, sublicense, and/or sell copies of the Software,
* and to permit persons to whom the Software is furnished to do so,
* subject to the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#include <lib/ndebug/ndebug.h>
#include <lib/ndebug/shared_structs.h>
#include <lib/ndebug/user.h>
#include <assert.h>
#include <err.h>
#include <kernel/mutex.h>
#include <stdlib.h>
#include <string.h>
#include <trace.h>
#define LOCAL_TRACE 0
#define HOST_MSG_TIMEOUT (1000) // 1 Second
static volatile bool connected = false;
static mutex_t usr_mutex = MUTEX_INITIAL_VALUE(usr_mutex);
static uint8_t scratch_buffer[NDEBUG_MAX_PACKET_SIZE];
status_t ndebug_await_connection_usr(lk_time_t timeout)
{
LTRACEF("timeout: %u\n", timeout);
status_t result = ndebug_await_connection(NDEBUG_CHANNEL_USR, timeout);
if (result == NO_ERROR) {
connected = true;
} else {
connected = false;
}
return result;
}
ssize_t ndebug_read_usr(uint8_t *buf, const lk_time_t timeout)
{
LTRACEF("buf: 0x%p, timeout: %u\n", buf, timeout);
if (!connected) {
// User must call ndebugusr_await_host and establish a connection
// before continuing.
return ERR_CHANNEL_CLOSED;
}
mutex_acquire(&usr_mutex);
// Retry Loop
while (true) {
ssize_t result = ndebug_usb_read(NDEBUG_CHANNEL_USR,
NDEBUG_MAX_PACKET_SIZE,
timeout, scratch_buffer);
if (result < (ssize_t)sizeof(ndebug_ctrl_packet_t)) {
dprintf(INFO, "Short Packet. Len = %ld\n", result);
continue;
}
ndebug_ctrl_packet_t *ctrl = (ndebug_ctrl_packet_t *)scratch_buffer;
if (ctrl->magic != NDEBUG_CTRL_PACKET_MAGIC) {
dprintf(INFO, "Bad Packet Magic = %u\n", ctrl->magic);
continue;
}
if (ctrl->type == NDEBUG_CTRL_CMD_RESET) {
msg_host(NDEBUG_CHANNEL_USR, NDEBUG_CTRL_CMD_RESET, timeout,
scratch_buffer);
connected = false;
mutex_release(&usr_mutex);
return ERR_CHANNEL_CLOSED;
} else if (ctrl->type == NDEBUG_CTRL_CMD_DATA) {
const ssize_t n_data_bytes = result - sizeof(ndebug_ctrl_packet_t);
memcpy(buf, scratch_buffer + sizeof(ndebug_ctrl_packet_t),
n_data_bytes);
mutex_release(&usr_mutex);
return n_data_bytes;
} else {
dprintf(INFO, "Unexpected packet type = %u\n", ctrl->type);
}
}
}
ssize_t ndebug_write_usr(uint8_t *buf, const size_t n, const lk_time_t timeout)
{
LTRACEF("buf = 0x%p, n = %u, timeout = %u\n", buf, n, timeout);
if (!connected) {
// User must call ndebugusr_await_host and establish a connection
// before continuing.
return ERR_CHANNEL_CLOSED;
}
mutex_acquire(&usr_mutex);
uint8_t *cursor = scratch_buffer;
ndebug_ctrl_packet_t *pkt = (ndebug_ctrl_packet_t *)cursor;
pkt->magic = NDEBUG_CTRL_PACKET_MAGIC;
pkt->type = NDEBUG_CTRL_CMD_DATA;
cursor += sizeof(ndebug_ctrl_packet_t);
ssize_t res;
size_t bytes_remaining = n;
do {
size_t bytes_to_copy = MIN(NDEBUG_USR_MAX_PACKET_SIZE, bytes_remaining);
memcpy(cursor, buf, bytes_to_copy);
buf += bytes_to_copy;
bytes_remaining -= bytes_to_copy;
res = ndebug_usb_write(
NDEBUG_CHANNEL_USR,
bytes_to_copy + sizeof(ndebug_ctrl_packet_t),
timeout,
scratch_buffer
);
if (res < 0) {
break;
}
} while (bytes_remaining > 0);
mutex_release(&usr_mutex);
if (res < 0) {
return res;
} else {
return (ssize_t)n;
}
}

1
tools/.gitignore vendored
View File

@@ -1,3 +1,2 @@
lkboot
mkimage
ndbg

View File

@@ -1,5 +1,5 @@
all: lkboot mkimage ndbg
all: lkboot mkimage
LKBOOT_SRCS := lkboot.c liblkboot.c network.c
LKBOOT_DEPS := network.h liblkboot.h ../app/lkboot/lkboot_protocol.h
@@ -13,11 +13,5 @@ MKIMAGE_INCS := -I../external/lib/mincrypt/include -I../lib/bootimage/include
mkimage: $(MKIMAGE_SRCS) $(MKIMAGE_DEPS)
gcc -Wall -g -o $@ $(MKIMAGE_INCS) $(MKIMAGE_SRCS)
NDEBUG_DEPS :=
NDEBUG_SRCS := ndebug/ndebug.cc ndebug/usbionode.cc ndebug/tcpionode.cc
NDEBUG_INCS := -I./ndebug/include -I../lib/ndebug/include
ndbg: $(NDEBUG_SRCS) $(NDEBUG_DEPS)
c++ -Wall -Werror -g -std=c++11 -o $@ $(NDEBUG_INCS) $(NDEBUG_SRCS) -lusb-1.0
clean::
rm -f lkboot mkimage ndbg
rm -f lkboot mkimage

View File

@@ -1,45 +0,0 @@
/*
* Copyright 2016 Google Inc. All Rights Reserved.
* Author: gkalsi@google.com (Gurjant Kalsi)
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files
* (the "Software"), to deal in the Software without restriction,
* including without limitation the rights to use, copy, modify, merge,
* publish, distribute, sublicense, and/or sell copies of the Software,
* and to permit persons to whom the Software is furnished to do so,
* subject to the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#pragma once
#include <cstdint>
#include <vector>
namespace NDebug {
enum class IONodeResult {
Failure, // I/O op failed
Success, // I/O op succeeded
Finished, // No more I/O ops remaining, perform graceful shutdown
NotConnected
};
class IONode {
public:
virtual IONodeResult readBuf(std::vector<uint8_t> *buf) = 0;
virtual IONodeResult writeBuf(const std::vector<uint8_t> &buf) = 0;
};
} // namespace NDebug

View File

@@ -1,55 +0,0 @@
/*
* Copyright 2016 Google Inc. All Rights Reserved.
* Author: gkalsi@google.com (Gurjant Kalsi)
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files
* (the "Software"), to deal in the Software without restriction,
* including without limitation the rights to use, copy, modify, merge,
* publish, distribute, sublicense, and/or sell copies of the Software,
* and to permit persons to whom the Software is furnished to do so,
* subject to the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#pragma once
#include <cstdint>
#include <ionode.h>
#include <mutex>
namespace NDebug {
class TCPIONode : public IONode {
public:
TCPIONode(uint16_t port);
virtual ~TCPIONode();
IONodeResult readBuf(std::vector<uint8_t> *buf) override;
IONodeResult writeBuf(const std::vector<uint8_t> &buf) override;
bool listenAndAccept();
bool open();
private:
void swapConnectionSocket(const int newSocket);
// All public methods are protected by this global lock.
std::mutex lock_;
const uint16_t port_;
int connectionSocket_;
int listenerSocket_;
};
} // namespace ndebug

View File

@@ -1,62 +0,0 @@
/*
* Copyright 2016 Google Inc. All Rights Reserved.
* Author: gkalsi@google.com (Gurjant Kalsi)
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files
* (the "Software"), to deal in the Software without restriction,
* including without limitation the rights to use, copy, modify, merge,
* publish, distribute, sublicense, and/or sell copies of the Software,
* and to permit persons to whom the Software is furnished to do so,
* subject to the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#pragma once
#include <cstdint>
#include <ionode.h>
struct libusb_context;
struct libusb_device_handle;
namespace NDebug {
class USBIONode : public IONode {
public:
USBIONode(const uint16_t vendorId, const uint16_t productId);
virtual ~USBIONode();
IONodeResult readBuf(std::vector<uint8_t> *buf) override;
IONodeResult writeBuf(const std::vector<uint8_t> &buf) override;
bool connect();
private:
bool openDeviceByParams(const uint16_t vid, const uint16_t pid,
const uint8_t interfaceClass,
const uint8_t interfaceSubClass,
const uint8_t interfaceProtocol);
const uint16_t vendorId_;
const uint16_t productId_;
uint8_t epOut_;
uint8_t epIn_;
uint8_t iface_;
libusb_context *ctx_;
libusb_device_handle *dev_;
};
} // namespace ndebug

View File

@@ -1,87 +0,0 @@
/*
* Copyright 2016 Google Inc. All Rights Reserved.
* Author: gkalsi@google.com (Gurjant Kalsi)
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files
* (the "Software"), to deal in the Software without restriction,
* including without limitation the rights to use, copy, modify, merge,
* publish, distribute, sublicense, and/or sell copies of the Software,
* and to permit persons to whom the Software is furnished to do so,
* subject to the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#include <cstdint>
#include <iostream>
#include <thread>
#include <vector>
#include "ionode.h"
#include "tcpionode.h"
#include "usbionode.h"
const uint16_t kVendorId = 0x9999;
const uint16_t kProductId = 0x9999;
const uint16_t kListenPort = 9091;
void IOWorkerThread(NDebug::IONode *in, NDebug::IONode *out)
{
std::vector<uint8_t> buf;
NDebug::IONodeResult res;
while (true) {
res = in->readBuf(&buf);
if (res == NDebug::IONodeResult::Finished) {
break;
} else if (res == NDebug::IONodeResult::Failure) {
continue;
}
res = out->writeBuf(buf);
if (res == NDebug::IONodeResult::Finished) {
break;
} else if (res == NDebug::IONodeResult::Failure) {
continue;
}
}
}
int main(int argc, char *argv[])
{
NDebug::USBIONode usb(kVendorId, kProductId);
if (!usb.connect()) {
std::cerr << "Could not connect to USB device." << std::endl;
return -1;
}
NDebug::TCPIONode tcp(kListenPort);
if (!tcp.open()) {
std::cerr << "Could not open TCP connection." << std::endl;
return -1;
}
std::thread deviceToHost(IOWorkerThread, &usb, &tcp);
std::thread hostToDevice;
while (true) {
tcp.listenAndAccept();
hostToDevice = std::thread(IOWorkerThread, &tcp, &usb);
hostToDevice.join();
}
deviceToHost.join();
return 0;
}

View File

@@ -1,158 +0,0 @@
/*
* Copyright 2016 Google Inc. All Rights Reserved.
* Author: gkalsi@google.com (Gurjant Kalsi)
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files
* (the "Software"), to deal in the Software without restriction,
* including without limitation the rights to use, copy, modify, merge,
* publish, distribute, sublicense, and/or sell copies of the Software,
* and to permit persons to whom the Software is furnished to do so,
* subject to the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#include "tcpionode.h"
#include <arpa/inet.h>
#include <netinet/in.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <unistd.h>
namespace NDebug {
const int kSockFdClosed = -1;
TCPIONode::TCPIONode(uint16_t port)
: port_(port),
connectionSocket_(kSockFdClosed),
listenerSocket_(kSockFdClosed) {}
TCPIONode::~TCPIONode()
{
if (connectionSocket_ >= 0) {
shutdown(connectionSocket_, SHUT_RDWR);
close(connectionSocket_);
connectionSocket_ = kSockFdClosed;
}
if (listenerSocket_ >= 0) {
shutdown(listenerSocket_, SHUT_RDWR);
close(listenerSocket_);
listenerSocket_ = kSockFdClosed;
}
}
IONodeResult TCPIONode::readBuf(std::vector<uint8_t> *buf)
{
std::lock_guard<std::mutex> g(lock_);
if (connectionSocket_ == kSockFdClosed) {
return IONodeResult::NotConnected;
}
buf->clear();
buf->resize(64);
ssize_t bytes = read(connectionSocket_, &(*buf)[0], 64);
if (bytes == 0) {
return IONodeResult::Finished;
} else if (bytes > 0) {
buf->resize(bytes);
return IONodeResult::Success;
}
return IONodeResult::Failure;
}
IONodeResult TCPIONode::writeBuf(const std::vector<uint8_t> &buf)
{
std::lock_guard<std::mutex> g(lock_);
if (connectionSocket_ == kSockFdClosed) {
return IONodeResult::NotConnected;
}
size_t written = 0;
do {
ssize_t bytes = write(connectionSocket_, &buf[written], buf.size() - written);
if (bytes < 0) {
return IONodeResult::Failure;
} else if (bytes == 0) {
return IONodeResult::Finished;
}
written += bytes;
} while (written < buf.size());
return IONodeResult::Success;
}
bool TCPIONode::open()
{
struct sockaddr_in sa;
listenerSocket_ = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
if (listenerSocket_ == -1) {
return false;
}
memset(&sa, 0, sizeof sa);
sa.sin_family = AF_INET;
sa.sin_port = htons(port_);
sa.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
if (bind(listenerSocket_, (struct sockaddr *)&sa, sizeof sa) == -1) {
close(listenerSocket_);
listenerSocket_ = kSockFdClosed;
return false;
}
return true;
}
void TCPIONode::swapConnectionSocket(const int newSocket)
{
std::lock_guard<std::mutex> g(lock_);
if (connectionSocket_ != -1) {
// Drop the previous connection.
shutdown(connectionSocket_, SHUT_RDWR);
close(connectionSocket_);
}
connectionSocket_ = newSocket;
}
bool TCPIONode::listenAndAccept()
{
if (kSockFdClosed == listenerSocket_)
return false;
if (listen(listenerSocket_, 1) == -1) {
return false;
}
int client = accept(listenerSocket_, NULL, NULL);
if (client < 0) {
return false;
}
swapConnectionSocket(client);
return true;
}
} // namespace NDebug

View File

@@ -1,239 +0,0 @@
/*
* Copyright 2016 Google Inc. All Rights Reserved.
* Author: gkalsi@google.com (Gurjant Kalsi)
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files
* (the "Software"), to deal in the Software without restriction,
* including without limitation the rights to use, copy, modify, merge,
* publish, distribute, sublicense, and/or sell copies of the Software,
* and to permit persons to whom the Software is furnished to do so,
* subject to the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#include "usbionode.h"
#include <cassert>
#include <vector>
#include <libusb-1.0/libusb.h>
#include "lib/ndebug/shared_structs.h"
namespace NDebug {
const size_t kConnectRetryLimit = 5;
const unsigned int kDefaultUSBTimeoutMS = 5000;
const size_t kMaxUSBPacketSize = 64;
USBIONode::USBIONode(const uint16_t vendorId, const uint16_t productId)
: vendorId_(vendorId),
productId_(productId),
ctx_(nullptr),
dev_(nullptr) {}
USBIONode::~USBIONode()
{
if (dev_) {
libusb_release_interface(dev_, 0);
libusb_close(dev_);
dev_ = nullptr;
}
}
IONodeResult USBIONode::readBuf(std::vector<uint8_t> *buf)
{
assert(buf != nullptr);
if (dev_ == nullptr) {
return IONodeResult::NotConnected;
}
// Create a buffer long enough to hold the USB packet.
std::vector<uint8_t> readBuffer(kMaxUSBPacketSize);
int xfer = kMaxUSBPacketSize;
int rc = libusb_bulk_transfer(dev_, epIn_, &readBuffer[0],
kMaxUSBPacketSize, &xfer,
kDefaultUSBTimeoutMS);
if (rc < 0) {
return IONodeResult::Failure;
}
// Packet must be long enought to contain at least the header.
if (xfer < (int)sizeof(ndebug_ctrl_packet_t)) {
return IONodeResult::Failure;
}
// Make sure the packet is well formed.
ndebug_ctrl_packet_t *pkt =
reinterpret_cast<ndebug_ctrl_packet_t *>(&readBuffer[0]);
if (pkt->magic != NDEBUG_CTRL_PACKET_MAGIC) {
return IONodeResult::Failure;
}
if (pkt->type == NDEBUG_CTRL_CMD_RESET) {
return IONodeResult::Finished;
} else if (pkt->type != NDEBUG_CTRL_CMD_DATA) {
return IONodeResult::Failure;
}
buf->clear();
buf->reserve(xfer);
std::copy(readBuffer.begin() + sizeof(ndebug_ctrl_packet_t),
readBuffer.begin() + xfer, std::back_inserter(*buf));
return IONodeResult::Success;
}
IONodeResult USBIONode::writeBuf(const std::vector<uint8_t> &buf)
{
if (dev_ == nullptr) {
return IONodeResult::NotConnected;
}
std::vector<uint8_t> writeBuffer(kMaxUSBPacketSize);
ndebug_ctrl_packet_t pkt;
pkt.magic = NDEBUG_CTRL_PACKET_MAGIC;
pkt.type = NDEBUG_CTRL_CMD_DATA;
uint8_t *packetCursor = reinterpret_cast<uint8_t *>(&pkt);
std::copy(packetCursor, packetCursor + sizeof(pkt), writeBuffer.begin());
size_t stride = 0;
for (size_t bufCursor = 0; bufCursor < buf.size(); bufCursor += stride) {
stride =
std::min(kMaxUSBPacketSize - sizeof(pkt), buf.size() - bufCursor);
std::copy(buf.begin() + bufCursor, buf.begin() + bufCursor + stride,
writeBuffer.begin() + sizeof(pkt));
int xfer = stride + sizeof(pkt);
int rc =
libusb_bulk_transfer(dev_, epOut_, &writeBuffer[0],
stride + sizeof(pkt), &xfer,
kDefaultUSBTimeoutMS);
if (rc < 0) {
return IONodeResult::Failure;
}
}
return IONodeResult::Success;
}
bool USBIONode::connect()
{
int rc = 0;
rc = libusb_init(&ctx_);
if (rc < 0) {
return false;
}
bool success = openDeviceByParams(
vendorId_, productId_, NDEBUG_USB_CLASS_USER_DEFINED,
NDEBUG_SUBCLASS, NDEBUG_PROTOCOL_SERIAL_PIPE);
if (!success) {
return false;
}
rc = libusb_claim_interface(dev_, iface_);
if (rc < 0) {
libusb_close(dev_);
dev_ = nullptr;
return false;
}
ndebug_ctrl_packet_t pkt;
uint8_t *buf = reinterpret_cast<uint8_t *>(&pkt);
for (size_t i = 0; i < kConnectRetryLimit; i++) {
// Send a connection RESET packet to the device.
int xfer = sizeof(pkt);
pkt.magic = NDEBUG_CTRL_PACKET_MAGIC;
pkt.type = NDEBUG_CTRL_CMD_RESET;
rc = libusb_bulk_transfer(dev_, epOut_, buf, sizeof(pkt), &xfer,
kDefaultUSBTimeoutMS);
// Allow the device to ACK the connection request.
rc = libusb_bulk_transfer(dev_, epIn_, buf, sizeof(pkt), &xfer,
kDefaultUSBTimeoutMS);
if (pkt.magic == NDEBUG_CTRL_PACKET_MAGIC &&
pkt.type == NDEBUG_CTRL_CMD_ESTABLISHED) {
return true;
}
}
return false;
}
bool USBIONode::openDeviceByParams(const uint16_t vid, const uint16_t pid,
const uint8_t interfaceClass,
const uint8_t interfaceSubClass,
const uint8_t interfaceProtocol)
{
libusb_device *device = nullptr;
bool success = false;
struct libusb_device **deviceList;
size_t numDevices = libusb_get_device_list(ctx_, &deviceList);
for (size_t i = 0; i < numDevices; i++) {
libusb_device_descriptor desc = {0};
libusb_get_device_descriptor(deviceList[i], &desc);
if (desc.idVendor != vid || desc.idProduct != pid) {
continue;
}
for (size_t j = 0; j < desc.bNumConfigurations; j++) {
struct libusb_config_descriptor *cfg;
libusb_get_config_descriptor(deviceList[i], j, &cfg);
for (size_t k = 0; k < cfg->bNumInterfaces; k++) {
libusb_interface_descriptor iface =
cfg->interface[k].altsetting[0];
if (iface.bInterfaceClass == interfaceClass &&
iface.bInterfaceSubClass == interfaceSubClass &&
iface.bInterfaceProtocol == interfaceProtocol) {
iface_ = k;
device = deviceList[i];
for (size_t l = 0; l < iface.bNumEndpoints; l++) {
if (iface.endpoint[l].bEndpointAddress & 0x80) {
epIn_ = iface.endpoint[l].bEndpointAddress;
} else {
epOut_ = iface.endpoint[l].bEndpointAddress;
}
}
}
}
libusb_free_config_descriptor(cfg);
}
}
if (device != nullptr) {
int rc = libusb_open(device, &dev_);
if (rc == 0) {
success = true;
}
}
libusb_free_device_list(deviceList, 0);
return success;
}
} // namespace NDebug;