From ba5b44d0c569956297e7d1498854f0be8e487c88 Mon Sep 17 00:00:00 2001 From: Saleem Rashid Date: Wed, 13 Dec 2017 18:38:51 +0000 Subject: [PATCH] emulator: Initial commit --- .gitignore | 1 + Makefile | 11 +++++ Makefile.include | 60 ++++++++++++++++++----- buttons.c | 8 +++- buttons.h | 1 + emulator/Makefile | 15 ++++++ emulator/buttons.c | 40 ++++++++++++++++ emulator/emulator.h | 40 ++++++++++++++++ emulator/flash.c | 114 ++++++++++++++++++++++++++++++++++++++++++++ emulator/oled.c | 90 ++++++++++++++++++++++++++++++++++ emulator/rng.c | 32 +++++++++++++ emulator/setup.c | 95 ++++++++++++++++++++++++++++++++++++ emulator/strl.c | 45 +++++++++++++++++ emulator/strl.h | 28 +++++++++++ emulator/timer.c | 32 +++++++++++++ emulator/udp.c | 85 +++++++++++++++++++++++++++++++++ firmware/Makefile | 5 ++ firmware/debug.c | 4 ++ firmware/fsm.c | 1 + firmware/layout2.c | 2 +- firmware/messages.c | 10 ++++ firmware/signing.c | 4 +- firmware/storage.c | 14 ++++++ firmware/trezor.c | 5 +- firmware/trezor.h | 5 ++ firmware/udp.c | 70 +++++++++++++++++++++++++++ firmware/usb.c | 4 +- memory.h | 4 ++ oled.c | 10 ++-- rng.c | 2 + timer.c | 3 -- timer.h | 15 ++++-- util.c | 6 --- util.h | 6 ++- 34 files changed, 830 insertions(+), 37 deletions(-) create mode 100644 emulator/Makefile create mode 100644 emulator/buttons.c create mode 100644 emulator/emulator.h create mode 100644 emulator/flash.c create mode 100644 emulator/oled.c create mode 100644 emulator/rng.c create mode 100644 emulator/setup.c create mode 100644 emulator/strl.c create mode 100644 emulator/strl.h create mode 100644 emulator/timer.c create mode 100644 emulator/udp.c create mode 100644 firmware/udp.c diff --git a/.gitignore b/.gitignore index 4490fece6..8a121b962 100644 --- a/.gitignore +++ b/.gitignore @@ -6,6 +6,7 @@ build/ *.bin *.elf *.hex +*.img *.list *.srec *.log diff --git a/Makefile b/Makefile index 27d58a0f4..81d418d9d 100644 --- a/Makefile +++ b/Makefile @@ -1,13 +1,24 @@ +ifneq ($(EMULATOR),1) OBJS += startup.o +endif + OBJS += buttons.o OBJS += layout.o OBJS += oled.o OBJS += rng.o OBJS += serialno.o + +ifneq ($(EMULATOR),1) OBJS += setup.o +endif + OBJS += util.o OBJS += memory.o + +ifneq ($(EMULATOR),1) OBJS += timer.o +endif + OBJS += gen/bitmaps.o OBJS += gen/fonts.o diff --git a/Makefile.include b/Makefile.include index 14d16a325..5f1aa605a 100644 --- a/Makefile.include +++ b/Makefile.include @@ -1,6 +1,18 @@ TOP_DIR := $(dir $(abspath $(lastword $(MAKEFILE_LIST)))) TOOLCHAIN_DIR ?= $(TOP_DIR)vendor/libopencm3 +ifeq ($(EMULATOR),1) +CC = gcc +LD = gcc +OBJCOPY = objcopy +OBJDUMP = objdump +AR = ar +AS = as + +OPTFLAGS ?= -O3 +DBGFLAGS ?= -g3 +CPUFLAGS ?= -m32 +else PREFIX ?= arm-none-eabi- CC = $(PREFIX)gcc LD = $(PREFIX)gcc @@ -15,6 +27,7 @@ OPTFLAGS ?= -O3 DBGFLAGS ?= -g -DNDEBUG CPUFLAGS ?= -mcpu=cortex-m3 -mthumb FPUFLAGS ?= -msoft-float +endif CFLAGS += $(OPTFLAGS) \ $(DBGFLAGS) \ @@ -55,6 +68,28 @@ CFLAGS += $(OPTFLAGS) \ -I$(TOP_DIR)vendor/trezor-crypto/ed25519-donna \ -I$(TOP_DIR)vendor/trezor-qrenc +ifeq ($(EMULATOR),1) +CFLAGS += -DEMULATOR=1 + +ifeq ($(HEADLESS),1) +CFLAGS += -DHEADLESS=1 +else +CFLAGS += -DHEADLESS=0 + +CFLAGS += $(shell pkg-config --cflags sdl2) +LDLIBS += $(shell pkg-config --libs sdl2) +endif + +CFLAGS += -include $(TOP_DIR)emulator/emulator.h +CFLAGS += -include stdio.h + +LDFLAGS += -L$(TOP_DIR) \ + -L$(TOP_DIR)emulator \ + $(CPUFLAGS) + +LDLIBS += -ltrezor -lemulator +LIBDEPS += $(TOP_DIR)/libtrezor.a $(TOP_DIR)emulator/libemulator.a +else ifdef APPVER CFLAGS += -DAPPVER=$(APPVER) LDSCRIPT = $(TOP_DIR)/memory_app_$(APPVER).ld @@ -62,17 +97,7 @@ else LDSCRIPT = $(TOP_DIR)/memory.ld endif -ifeq ($(MEMORY_PROTECT), 0) -CFLAGS += -DMEMORY_PROTECT=0 -else -CFLAGS += -DMEMORY_PROTECT=1 -endif - -ifeq ($(DEBUG_RNG), 1) -CFLAGS += -DDEBUG_RNG=1 -else -CFLAGS += -DDEBUG_RNG=0 -endif +CFLAGS += -DEMULATOR=0 LDFLAGS += --static \ -Wl,--start-group \ @@ -93,6 +118,19 @@ LIBDEPS += $(TOP_DIR)/libtrezor.a LDLIBS += -lopencm3_stm32f2 LIBDEPS += $(TOOLCHAIN_DIR)/lib/libopencm3_stm32f2.a +endif + +ifeq ($(MEMORY_PROTECT), 0) +CFLAGS += -DMEMORY_PROTECT=0 +else +CFLAGS += -DMEMORY_PROTECT=1 +endif + +ifeq ($(DEBUG_RNG), 1) +CFLAGS += -DDEBUG_RNG=1 +else +CFLAGS += -DDEBUG_RNG=0 +endif all: $(NAME).bin diff --git a/buttons.c b/buttons.c index 9207eac00..a6e64b5ad 100644 --- a/buttons.c +++ b/buttons.c @@ -21,12 +21,18 @@ struct buttonState button; +#if !EMULATOR +uint16_t buttonRead(void) { + return gpio_port_read(BTN_PORT); +} +#endif + void buttonUpdate() { uint16_t state; static uint16_t last_state = BTN_PIN_YES | BTN_PIN_NO; - state = gpio_port_read(BTN_PORT); + state = buttonRead(); if ((state & BTN_PIN_YES) == 0) { // Yes button is down if ((last_state & BTN_PIN_YES) == 0) { // last Yes was down diff --git a/buttons.h b/buttons.h index 140e380c6..fb24d58dd 100644 --- a/buttons.h +++ b/buttons.h @@ -32,6 +32,7 @@ struct buttonState { extern struct buttonState button; +uint16_t buttonRead(void); void buttonUpdate(void); #ifndef BTN_PORT diff --git a/emulator/Makefile b/emulator/Makefile new file mode 100644 index 000000000..e733d45bf --- /dev/null +++ b/emulator/Makefile @@ -0,0 +1,15 @@ +OBJS += setup.o + +OBJS += buttons.o +OBJS += flash.o +OBJS += oled.o +OBJS += rng.o +OBJS += timer.o +OBJS += udp.o + +OBJS += strl.o + +libemulator.a: $(OBJS) + $(AR) rcs $@ $(OBJS) + +include ../Makefile.include diff --git a/emulator/buttons.c b/emulator/buttons.c new file mode 100644 index 000000000..71b94a442 --- /dev/null +++ b/emulator/buttons.c @@ -0,0 +1,40 @@ +/* + * This file is part of the TREZOR project, https://trezor.io/ + * + * Copyright (C) 2017 Saleem Rashid + * + * This library is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This library 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library. If not, see . + */ + +#include "buttons.h" + +#if !HEADLESS +#include +#endif + +uint16_t buttonRead(void) { + uint16_t state = 0; + +#if !HEADLESS + const uint8_t *scancodes = SDL_GetKeyboardState(NULL); + if (scancodes[SDL_SCANCODE_LEFT]) { + state |= BTN_PIN_NO; + } + if (scancodes[SDL_SCANCODE_RIGHT]) { + state |= BTN_PIN_YES; + } +#endif + + return ~state; +} diff --git a/emulator/emulator.h b/emulator/emulator.h new file mode 100644 index 000000000..deaa73dea --- /dev/null +++ b/emulator/emulator.h @@ -0,0 +1,40 @@ +/* + * This file is part of the TREZOR project, https://trezor.io/ + * + * Copyright (C) 2017 Saleem Rashid + * + * This library is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This library 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library. If not, see . + */ + +#ifndef __EMULATOR_H__ +#define __EMULATOR_H__ + +#if EMULATOR + +#include "strl.h" + +#include + +extern void *emulator_flash_base; + +void emulatorPoll(void); +void emulatorRandom(void *buffer, size_t size); + +void emulatorSocketInit(void); +size_t emulatorSocketRead(void *buffer, size_t size); +size_t emulatorSocketWrite(const void *buffer, size_t size); + +#endif + +#endif diff --git a/emulator/flash.c b/emulator/flash.c new file mode 100644 index 000000000..708dd2598 --- /dev/null +++ b/emulator/flash.c @@ -0,0 +1,114 @@ +/* + * This file is part of the TREZOR project, https://trezor.io/ + * + * Copyright (C) 2017 Saleem Rashid + * + * This library is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This library 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library. If not, see . + */ + +#include + +#include + +#include "memory.h" + +void flash_lock(void) {} +void flash_unlock(void) {} + +void flash_clear_status_flags(void) {} + +void flash_lock_option_bytes(void) {} +void flash_unlock_option_bytes(void) {} + +void flash_program_option_bytes(uint32_t data) { + (void) data; +} + +static ssize_t sector_to_offset(uint8_t sector) { + switch (sector) { + case 0: + return 0x0; + case 1: + return 0x4000; + case 2: + return 0x8000; + case 3: + return 0xC000; + case 4: + return 0x10000; + case 5: + return 0x20000; + case 6: + return 0x40000; + case 7: + return 0x60000; + case 8: + return 0x80000; + default: + return -1; + } +} + +static void *sector_to_address(uint8_t sector) { + ssize_t offset = sector_to_offset(sector); + if (offset < 0) { + return NULL; + } + + return (void *) (FLASH_ORIGIN + offset); +} + +static ssize_t sector_to_size(uint8_t sector) { + ssize_t start = sector_to_offset(sector); + if (start < 0) { + return -1; + } + + ssize_t end = sector_to_offset(sector + 1); + if (end < 0) { + return -1; + } + + return end - start; +} + +void flash_erase_sector(uint8_t sector, uint32_t program_size) { + (void) program_size; + + void *address = sector_to_address(sector); + if (address == NULL) { + return; + } + + ssize_t size = sector_to_size(sector); + if (size < 0) { + return; + } + + memset(address, 0xFF, size); +} + +void flash_erase_all_sectors(uint32_t program_size) { + (void) program_size; + + memset(emulator_flash_base, 0xFF, FLASH_TOTAL_SIZE); +} + +void flash_program_word(uint32_t address, uint32_t data) { + MMIO32(address) = data; +} + +void flash_program_byte(uint32_t address, uint8_t data) { + MMIO8(address) = data; +} diff --git a/emulator/oled.c b/emulator/oled.c new file mode 100644 index 000000000..242408af0 --- /dev/null +++ b/emulator/oled.c @@ -0,0 +1,90 @@ +/* + * This file is part of the TREZOR project, https://trezor.io/ + * + * Copyright (C) 2017 Saleem Rashid + * + * This library is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This library 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library. If not, see . + */ + +#include "oled.h" + +#if HEADLESS + +void oledInit(void) {} +void oledRefresh(void) {} +void emulatorPoll(void) {} + +#else + +#include + +static SDL_Renderer *renderer = NULL; +static SDL_Texture *texture = NULL; + +void oledInit(void) { + if (SDL_Init(SDL_INIT_VIDEO) != 0) { + fprintf(stderr, "Failed to initialize SDL: %s\n", SDL_GetError()); + exit(1); + } + atexit(SDL_Quit); + + SDL_Window *window = SDL_CreateWindow("TREZOR", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, OLED_WIDTH, OLED_HEIGHT, 0); + if (window == NULL) { + fprintf(stderr, "Failed to create window: %s\n", SDL_GetError()); + exit(1); + } + + renderer = SDL_CreateRenderer(window, -1, SDL_RENDERER_ACCELERATED); + if (!renderer) { + fprintf(stderr, "Failed to create renderer: %s\n", SDL_GetError()); + exit(1); + } + + texture = SDL_CreateTexture(renderer, SDL_PIXELFORMAT_ARGB8888, SDL_TEXTUREACCESS_STREAMING, OLED_WIDTH, OLED_HEIGHT); + + oledClear(); + oledRefresh(); +} + +void oledRefresh(void) { + const uint8_t *buffer = oledGetBuffer(); + + static uint32_t data[OLED_HEIGHT][OLED_WIDTH]; + + for (size_t i = 0; i < OLED_BUFSIZE; i++) { + int x = (OLED_BUFSIZE - 1 - i) % OLED_WIDTH; + int y = (OLED_BUFSIZE - 1 - i) / OLED_WIDTH * 8 + 7; + + for (uint8_t shift = 0; shift < 8; shift++, y--) { + bool set = (buffer[i] >> shift) & 1; + data[y][x] = set ? 0xFFFFFFFF : 0xFF000000; + } + } + + SDL_UpdateTexture(texture, NULL, data, OLED_WIDTH * sizeof(uint32_t)); + SDL_RenderCopy(renderer, texture, NULL, NULL); + SDL_RenderPresent(renderer); +} + +void emulatorPoll(void) { + SDL_Event event; + + if (SDL_PollEvent(&event)) { + if (event.type == SDL_QUIT) { + exit(1); + } + } +} + +#endif diff --git a/emulator/rng.c b/emulator/rng.c new file mode 100644 index 000000000..8d53de28d --- /dev/null +++ b/emulator/rng.c @@ -0,0 +1,32 @@ +/* + * This file is part of the TREZOR project, https://trezor.io/ + * + * Copyright (C) 2017 Saleem Rashid + * + * This library is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This library 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library. If not, see . + */ + +#include "rng.h" + +uint32_t random32(void) { + static uint32_t last = 0; + uint32_t new; + + do { + emulatorRandom(&new, sizeof(new)); + } while (last == new); + + last = new; + return new; +} diff --git a/emulator/setup.c b/emulator/setup.c new file mode 100644 index 000000000..f994916d3 --- /dev/null +++ b/emulator/setup.c @@ -0,0 +1,95 @@ +/* + * This file is part of the TREZOR project, https://trezor.io/ + * + * Copyright (C) 2017 Saleem Rashid + * + * This library is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This library 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library. If not, see . + */ + +#include +#include +#include +#include +#include +#include + +#include + +#include "memory.h" +#include "oled.h" +#include "rng.h" +#include "setup.h" +#include "timer.h" + +#define EMULATOR_FLASH_FILE "emulator.img" + +void *emulator_flash_base = NULL; + +uint32_t __stack_chk_guard; + +static int urandom = -1; + +static void setup_urandom(void); +static void setup_flash(void); + +void setup(void) { + setup_urandom(); + setup_flash(); +} + +void emulatorRandom(void *buffer, size_t size) { + ssize_t n = read(urandom, buffer, size); + if (n < 0 || ((size_t) n) != size) { + perror("Failed to read /dev/urandom"); + exit(1); + } +} + +static void setup_urandom(void) { + urandom = open("/dev/urandom", O_RDONLY); + if (urandom < 0) { + perror("Failed to open /dev/urandom"); + exit(1); + } +} + +static void setup_flash(void) { + int fd = open(EMULATOR_FLASH_FILE, O_RDWR | O_SYNC | O_CREAT, 0644); + if (fd < 0) { + perror("Failed to open flash emulation file"); + exit(1); + } + + off_t length = lseek(fd, 0, SEEK_END); + if (length < 0) { + perror("Failed to read length of flash emulation file"); + exit(1); + } + + emulator_flash_base = mmap(NULL, FLASH_TOTAL_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); + if (emulator_flash_base == MAP_FAILED) { + perror("Failed to map flash emulation file"); + exit(1); + } + + if (length < FLASH_TOTAL_SIZE) { + if (ftruncate(fd, FLASH_TOTAL_SIZE) != 0) { + perror("Failed to initialize flash emulation file"); + exit(1); + } + + /* Initialize the flash */ + flash_erase_all_sectors(FLASH_CR_PROGRAM_X32); + } +} diff --git a/emulator/strl.c b/emulator/strl.c new file mode 100644 index 000000000..42323a3ab --- /dev/null +++ b/emulator/strl.c @@ -0,0 +1,45 @@ +/* + * This file is part of the TREZOR project, https://trezor.io/ + * + * Copyright (C) 2017 Saleem Rashid + * + * This library is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This library 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library. If not, see . + */ + +#include "strl.h" + +#include + +size_t strlcpy(char *dst, const char *src, size_t size) { + if (size == 0) { + return 0; + } + + for (size_t i = 0; i < size - 1; i++) { + dst[i] = src[i]; + + if (src[i] == '\0') { + return i; + } + } + + dst[size - 1] = '\0'; + return size - 2; +} + +size_t strlcat(char *dst, const char *src, size_t size) { + size_t n = strnlen(dst, size); + + return n + strlcpy(&dst[n], src, size - n); +} diff --git a/emulator/strl.h b/emulator/strl.h new file mode 100644 index 000000000..8b44e0454 --- /dev/null +++ b/emulator/strl.h @@ -0,0 +1,28 @@ +/* + * This file is part of the TREZOR project, https://trezor.io/ + * + * Copyright (C) 2017 Saleem Rashid + * + * This library is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This library 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library. If not, see . + */ + +#ifndef __STRL_H__ +#define __STRL_H__ + +#include + +size_t strlcpy(char *dst, const char *src, size_t size); +size_t strlcat(char *dst, const char *src, size_t size); + +#endif diff --git a/emulator/timer.c b/emulator/timer.c new file mode 100644 index 000000000..eadbf76cc --- /dev/null +++ b/emulator/timer.c @@ -0,0 +1,32 @@ +/* + * This file is part of the TREZOR project, https://trezor.io/ + * + * Copyright (C) 2017 Saleem Rashid + * + * This library is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This library 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library. If not, see . + */ + +#include + +#include "timer.h" + +void timer_init(void) {} + +uint32_t timer_ms(void) { + struct timespec t; + clock_gettime(CLOCK_MONOTONIC, &t); + + uint32_t msec = t.tv_sec * 1000 + (t.tv_nsec / 1000000); + return msec; +} diff --git a/emulator/udp.c b/emulator/udp.c new file mode 100644 index 000000000..b01ec66b6 --- /dev/null +++ b/emulator/udp.c @@ -0,0 +1,85 @@ +/* + * This file is part of the TREZOR project, https://trezor.io/ + * + * Copyright (C) 2017 Saleem Rashid + * + * This library is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This library 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library. If not, see . + */ + +#include +#include +#include +#include +#include +#include + +#define TREZOR_UDP_PORT 21324 + +static int fd = -1; +static struct sockaddr_in from; +static socklen_t fromlen; + +void emulatorSocketInit(void) { + fd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); + if (fd < 0) { + perror("Failed to create socket"); + exit(1); + } + + fromlen = 0; + + struct sockaddr_in addr; + addr.sin_family = AF_INET; + addr.sin_port = htons(TREZOR_UDP_PORT); + addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK); + + if (bind(fd, (struct sockaddr *) &addr, sizeof(addr)) != 0) { + perror("Failed to bind socket"); + exit(1); + } +} + +size_t emulatorSocketRead(void *buffer, size_t size) { + fromlen = sizeof(from); + ssize_t n = recvfrom(fd, buffer, size, MSG_DONTWAIT, (struct sockaddr *) &from, &fromlen); + + if (n < 0) { + if (errno != EAGAIN && errno != EWOULDBLOCK) { + perror("Failed to read socket"); + } + return 0; + } + + static const char msg_ping[] = { 'P', 'I', 'N', 'G', 'P', 'I', 'N', 'G' }; + static const char msg_pong[] = { 'P', 'O', 'N', 'G', 'P', 'O', 'N', 'G' }; + + if (n == sizeof(msg_ping) && memcmp(buffer, msg_ping, sizeof(msg_ping)) == 0) { + emulatorSocketWrite(msg_pong, sizeof(msg_pong)); + return 0; + } + + return n; +} + +size_t emulatorSocketWrite(const void *buffer, size_t size) { + if (fromlen > 0) { + ssize_t n = sendto(fd, buffer, size, MSG_DONTWAIT, (const struct sockaddr *) &from, fromlen); + if (n < 0 || ((size_t) n) != size) { + perror("Failed to write socket"); + return 0; + } + } + + return size; +} diff --git a/firmware/Makefile b/firmware/Makefile index 7a5a16a3e..577d20e34 100644 --- a/firmware/Makefile +++ b/firmware/Makefile @@ -7,7 +7,12 @@ endif NAME = trezor +ifeq ($(EMULATOR),1) +OBJS += udp.o +else OBJS += usb.o +endif + OBJS += u2f.o OBJS += messages.o OBJS += storage.o diff --git a/firmware/debug.c b/firmware/debug.c index b455f290c..a8519fd94 100644 --- a/firmware/debug.c +++ b/firmware/debug.c @@ -47,7 +47,11 @@ void debugLog(int level, const char *bucket, const char *text) { (void)level; (void)bucket; +#if EMULATOR + puts(text); +#else oledDebug(text); +#endif } char *debugInt(const uint32_t i) diff --git a/firmware/fsm.c b/firmware/fsm.c index 34211bebe..15359c8a3 100644 --- a/firmware/fsm.c +++ b/firmware/fsm.c @@ -234,6 +234,7 @@ void fsm_msgGetFeatures(GetFeatures *msg) } _Static_assert(pb_arraysize(Features, coins) >= COINS_COUNT, "Features.coins max_count not large enough"); + resp->coins_count = COINS_COUNT; for (int i = 0; i < COINS_COUNT; i++) { if (coins[i].coin_name) { diff --git a/firmware/layout2.c b/firmware/layout2.c index 84a48bed2..bb86b9aac 100644 --- a/firmware/layout2.c +++ b/firmware/layout2.c @@ -121,7 +121,7 @@ void layoutHome(void) oledRefresh(); // Reset lock screen timeout - system_millis_lock_start = system_millis; + system_millis_lock_start = timer_ms(); } void layoutConfirmOutput(const CoinInfo *coin, const TxOutputType *out) diff --git a/firmware/messages.c b/firmware/messages.c index d8411bfa8..6db0d54db 100644 --- a/firmware/messages.c +++ b/firmware/messages.c @@ -48,7 +48,12 @@ const pb_field_t *MessageFields(char type, char dir, uint16_t msg_id) { const struct MessagesMap_t *m = MessagesMap; while (m->type) { +#if EMULATOR + (void) type; + if (dir == m->dir && msg_id == m->msg_id) { +#else if (type == m->type && dir == m->dir && msg_id == m->msg_id) { +#endif return m->fields; } m++; @@ -60,7 +65,12 @@ void MessageProcessFunc(char type, char dir, uint16_t msg_id, void *ptr) { const struct MessagesMap_t *m = MessagesMap; while (m->type) { +#if EMULATOR + (void) type; + if (dir == m->dir && msg_id == m->msg_id) { +#else if (type == m->type && dir == m->dir && msg_id == m->msg_id) { +#endif m->process_func(ptr); return; } diff --git a/firmware/signing.c b/firmware/signing.c index e31078b65..c44975974 100644 --- a/firmware/signing.c +++ b/firmware/signing.c @@ -505,7 +505,7 @@ static bool signing_check_input(TxInputType *txinput) { tx_sequence_hash(&hashers[1], txinput); // hash prevout and script type to check it later (relevant for fee computation) tx_prevout_hash(&hashers[2], txinput); - hasher_Update(&hashers[2], &txinput->script_type, sizeof(&txinput->script_type)); + hasher_Update(&hashers[2], (const uint8_t *) &txinput->script_type, sizeof(&txinput->script_type)); return true; } @@ -962,7 +962,7 @@ void signing_txack(TransactionType *tx) } // check prevouts and script type tx_prevout_hash(&hashers[0], tx->inputs); - hasher_Update(&hashers[0], &tx->inputs[0].script_type, sizeof(&tx->inputs[0].script_type)); + hasher_Update(&hashers[0], (const uint8_t *) &tx->inputs[0].script_type, sizeof(&tx->inputs[0].script_type)); if (idx2 == idx1) { if (!compile_input_script_sig(&tx->inputs[0])) { fsm_sendFailure(FailureType_Failure_ProcessError, _("Failed to compile input")); diff --git a/firmware/storage.c b/firmware/storage.c index 1309196c9..8b982ea1a 100644 --- a/firmware/storage.c +++ b/firmware/storage.c @@ -55,7 +55,13 @@ _Static_assert(((uint32_t)&storageUpdate & 3) == 0, "storage unaligned"); _Static_assert((sizeof(storageUpdate) & 3) == 0, "storage unaligned"); #define STORAGE_ROM ((const Storage *)(FLASH_STORAGE_START + sizeof(storage_magic) + sizeof(storage_uuid))) + +#if EMULATOR +// TODO: Fix this for emulator +#define storageRom STORAGE_ROM +#else const Storage *storageRom = STORAGE_ROM; +#endif char storage_uuid_str[25]; @@ -92,7 +98,10 @@ be added to the storage u2f_counter to get the real counter value. #define FLASH_STORAGE_U2FAREA_LEN (0x100) #define FLASH_STORAGE_REALLEN (sizeof(storage_magic) + sizeof(storage_uuid) + sizeof(Storage)) +#if !EMULATOR +// TODO: Fix this for emulator _Static_assert(FLASH_STORAGE_START + FLASH_STORAGE_REALLEN <= FLASH_STORAGE_PINAREA, "Storage struct is too large for TREZOR flash"); +#endif /* Current u2f offset, i.e. u2f counter is * storage.u2f_counter + storage_u2f_offset. @@ -119,10 +128,12 @@ void storage_show_error(void) void storage_check_flash_errors(void) { +#if !EMULATOR // flash operation failed if (FLASH_SR & (FLASH_SR_PGAERR | FLASH_SR_PGPERR | FLASH_SR_PGSERR | FLASH_SR_WRPERR)) { storage_show_error(); } +#endif } bool storage_from_flash(void) @@ -197,7 +208,10 @@ bool storage_from_flash(void) flash_erase_sector(FLASH_META_SECTOR_LAST, FLASH_CR_PROGRAM_X32); flash_program_word(FLASH_STORAGE_PINAREA, 0xffffffff << pinctr); // erase storageRom.has_pin_failed_attempts and storageRom.pin_failed_attempts +#if !EMULATOR +// TODO: Fix this for emulator _Static_assert(((uint32_t)&STORAGE_ROM->pin_failed_attempts & 3) == 0, "storage.pin_failed_attempts unaligned"); +#endif flash_program_byte((uint32_t)&storageRom->has_pin_failed_attempts, 0); flash_program_word((uint32_t)&storageRom->pin_failed_attempts, 0); flash_lock(); diff --git a/firmware/trezor.c b/firmware/trezor.c index 861d7aff9..9bb013edc 100644 --- a/firmware/trezor.c +++ b/firmware/trezor.c @@ -32,6 +32,9 @@ #include "gettext.h" #include "fastflash.h" +/* Screen timeout */ +uint32_t system_millis_lock_start; + void check_lock_screen(void) { buttonUpdate(); @@ -73,7 +76,7 @@ void check_lock_screen(void) // if homescreen is shown for longer than 10 minutes, lock too if (layoutLast == layoutHome) { - if ((system_millis - system_millis_lock_start) >= 600000) { + if ((timer_ms() - system_millis_lock_start) >= 600000) { // lock the screen session_clear(true); layoutScreensaver(); diff --git a/firmware/trezor.h b/firmware/trezor.h index c240cbc69..c47e38306 100644 --- a/firmware/trezor.h +++ b/firmware/trezor.h @@ -20,6 +20,8 @@ #ifndef __TREZOR_H__ #define __TREZOR_H__ +#include + #define VERSION_MAJOR 1 #define VERSION_MINOR 6 #define VERSION_PATCH 0 @@ -35,4 +37,7 @@ #define DEBUG_LOG 0 #endif +/* Screen timeout */ +extern uint32_t system_millis_lock_start; + #endif diff --git a/firmware/udp.c b/firmware/udp.c new file mode 100644 index 000000000..04959aede --- /dev/null +++ b/firmware/udp.c @@ -0,0 +1,70 @@ +/* + * This file is part of the TREZOR project, https://trezor.io/ + * + * Copyright (C) 2017 Saleem Rashid + * + * This library is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This library 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library. If not, see . + */ + +#include + +#include "usb.h" + +#include "messages.h" +#include "timer.h" + +static volatile char tiny = 0; + +void usbInit(void) { + emulatorSocketInit(); +} + +void usbPoll(void) { + emulatorPoll(); + + static uint8_t buffer[64]; + if (emulatorSocketRead(buffer, sizeof(buffer)) > 0) { + if (!tiny) { + msg_read(buffer, sizeof(buffer)); + } else { + msg_read_tiny(buffer, sizeof(buffer)); + } + } + + const uint8_t *data = msg_out_data(); + +#if DEBUG_LINK + if (data == NULL) { + data = msg_debug_out_data(); + } +#endif + + if (data != NULL) { + emulatorSocketWrite(data, 64); + } +} + +char usbTiny(char set) { + char old = tiny; + tiny = set; + return old; +} + +void usbSleep(uint32_t millis) { + uint32_t start = timer_ms(); + + while ((timer_ms() - start) < millis) { + usbPoll(); + } +} diff --git a/firmware/usb.c b/firmware/usb.c index 55bd09517..7a59b6fa0 100644 --- a/firmware/usb.c +++ b/firmware/usb.c @@ -446,9 +446,9 @@ char usbTiny(char set) void usbSleep(uint32_t millis) { - uint32_t start = system_millis; + uint32_t start = timer_ms(); - while ((system_millis - start) < millis) { + while ((timer_ms() - start) < millis) { usbd_poll(usbd_dev); } } diff --git a/memory.h b/memory.h index fb5d8af5a..f6c4a8705 100644 --- a/memory.h +++ b/memory.h @@ -62,7 +62,11 @@ */ +#if EMULATOR +#define FLASH_ORIGIN ((uint32_t) emulator_flash_base) +#else #define FLASH_ORIGIN (0x08000000) +#endif #define FLASH_TOTAL_SIZE (512 * 1024) diff --git a/oled.c b/oled.c index 0b73db557..7b1d5fce0 100644 --- a/oled.c +++ b/oled.c @@ -105,10 +105,11 @@ void oledInvertPixel(int x, int y) _oledbuffer[OLED_OFFSET(x, y)] ^= OLED_MASK(x, y); } +#if !EMULATOR /* * Send a block of data via the SPI bus. */ -inline void SPISend(uint32_t base, uint8_t *data, int len) +static inline void SPISend(uint32_t base, const uint8_t *data, int len) { delay(1); for (int i = 0; i < len; i++) { @@ -123,7 +124,7 @@ inline void SPISend(uint32_t base, uint8_t *data, int len) */ void oledInit() { - static uint8_t s[25] = { + static const uint8_t s[25] = { OLED_DISPLAYOFF, OLED_SETDISPLAYCLOCKDIV, 0x80, @@ -169,6 +170,7 @@ void oledInit() oledClear(); oledRefresh(); } +#endif /* * Clears the display buffer (sets all pixels to black) @@ -184,9 +186,10 @@ void oledClear() * make the change visible. All other operations only change the buffer * not the content of the display. */ +#if !EMULATOR void oledRefresh() { - static uint8_t s[3] = {OLED_SETLOWCOLUMN | 0x00, OLED_SETHIGHCOLUMN | 0x00, OLED_SETSTARTLINE | 0x00}; + static const uint8_t s[3] = {OLED_SETLOWCOLUMN | 0x00, OLED_SETHIGHCOLUMN | 0x00, OLED_SETSTARTLINE | 0x00}; // draw triangle in upper right corner if (is_debug_link) { @@ -216,6 +219,7 @@ void oledRefresh() oledInvertPixel(OLED_WIDTH - 1, 4); } } +#endif const uint8_t *oledGetBuffer() { diff --git a/rng.c b/rng.c index 222094764..145f51b4b 100644 --- a/rng.c +++ b/rng.c @@ -23,6 +23,7 @@ #include "rng.h" +#if !EMULATOR uint32_t random32(void) { static uint32_t last = 0, new = 0; @@ -34,6 +35,7 @@ uint32_t random32(void) last = new; return new; } +#endif uint32_t random_uniform(uint32_t n) { diff --git a/timer.c b/timer.c index 7a3dfcfb3..d58855fef 100644 --- a/timer.c +++ b/timer.c @@ -27,9 +27,6 @@ /* 1 tick = 1 ms */ volatile uint32_t system_millis; -/* Screen timeout */ -uint32_t system_millis_lock_start; - /* * Initialise the Cortex-M3 SysTick timer */ diff --git a/timer.h b/timer.h index 235ba5f31..ac76d07e5 100644 --- a/timer.h +++ b/timer.h @@ -22,12 +22,17 @@ #include -/* 1 tick = 1 ms */ -extern volatile uint32_t system_millis; +void timer_init(void); -/* Screen timeout */ -extern uint32_t system_millis_lock_start; +#if EMULATOR +uint32_t timer_ms(void); +#else +static inline uint32_t timer_ms(void) { + /* 1 tick = 1 ms */ + extern volatile uint32_t system_millis; -void timer_init(void); + return system_millis; +} +#endif #endif diff --git a/util.c b/util.c index 09eba316e..197c45445 100644 --- a/util.c +++ b/util.c @@ -17,7 +17,6 @@ * along with this library. If not, see . */ -#include #include "util.h" inline void delay(uint32_t wait) @@ -72,8 +71,3 @@ void __attribute__((noreturn)) system_halt(void) { for (;;) {} // loop forever } - -void __attribute__((noreturn)) system_reset(void) -{ - scb_reset_system(); -} diff --git a/util.h b/util.h index 85961e64d..05d9c9a73 100644 --- a/util.h +++ b/util.h @@ -22,8 +22,10 @@ #include +#if !EMULATOR #include #include +#endif // Statement expressions make these macros side-effect safe #define MIN(a, b) ({ typeof(a) _a = (a); typeof(b) _b = (b); _a < _b ? _a : _b; }) @@ -42,9 +44,8 @@ uint32_t readprotobufint(uint8_t **ptr); // halt execution (or do an endless loop) void __attribute__((noreturn)) system_halt(void); -// reset system -void __attribute__((noreturn)) system_reset(void); +#if !EMULATOR // defined in memory.ld extern uint8_t _ram_start[], _ram_end[]; @@ -65,5 +66,6 @@ static inline void __attribute__((noreturn)) load_vector_table(const vector_tabl // Prevent compiler from generating stack protector code (which causes CPU fault because the stack is moved) for (;;); } +#endif #endif