├── LICENSE ├── Makefile ├── README.md ├── include ├── Clock.hpp ├── Foundation.hpp ├── Hardware │ ├── AXP803.hpp │ ├── AllwinnerA64.hpp │ ├── AllwinnerCCU.hpp │ ├── AllwinnerCPUCFG.hpp │ ├── AllwinnerDRAM.hpp │ ├── AllwinnerDRAMCOM.hpp │ ├── AllwinnerDRAMCTL.hpp │ ├── AllwinnerEMAC.hpp │ ├── AllwinnerHSTimer.hpp │ ├── AllwinnerPIO.hpp │ ├── AllwinnerPRCM.hpp │ ├── AllwinnerRSB.hpp │ ├── AllwinnerSMHC.hpp │ ├── AllwinnerSYSCTL.hpp │ ├── AllwinnerTimer.hpp │ ├── AllwinnerUART.hpp │ └── GICPL400.hpp ├── Kernel.hpp ├── Memory │ ├── AArch64Cache.hpp │ └── AArch64MMU.hpp └── Net │ ├── Icmp.hpp │ ├── Ip.hpp │ ├── Mac.hpp │ ├── Net.hpp │ ├── Tcp.hpp │ └── Udp.hpp ├── src32 └── Entry32.s ├── src64 ├── Bootloader.cpp ├── Entry64.s └── Kernel.cpp └── tools └── build_tool ├── Cargo.toml └── src └── main.rs /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2016 Alexander Meißner 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | HPP_SRC := $(wildcard include/*.hpp) $(wildcard include/Hardware/*.hpp) $(wildcard include/Memory/*.hpp) $(wildcard include/Net/*.hpp) 2 | ANALYZE = $(LLVM_BIN)llvm-objdump -print-imm-hex -d -s -t -triple 3 | COMPILE = $(LLVM_BIN)clang -O1 -Iinclude -c -mlittle-endian -Wall -Wsign-compare -target 4 | COMPILE_CPP = -fno-exceptions -fno-unwind-tables -fno-stack-protector -fno-rtti -ffreestanding -mno-unaligned-access -std=c++1z 5 | TARGET_32 = armv7a-none-eabi 6 | TARGET_64 = arm64 7 | 8 | build/%.o : src32/%.s 9 | $(COMPILE) $(TARGET_32) -o $@ $< 10 | 11 | build/%.o : src32/%.cpp $(HPP_SRC) 12 | $(COMPILE) $(TARGET_32) $(COMPILE_CPP) -o $@ $< 13 | 14 | build/%.o : src64/%.s 15 | $(COMPILE) $(TARGET_64) -o $@ $< 16 | 17 | build/%.o : src64/%.cpp $(HPP_SRC) 18 | $(COMPILE) $(TARGET_64) $(COMPILE_CPP) -o $@ $< 19 | 20 | build/Bootloader.bin: build/Entry32.o build/Entry64.o build/Bootloader.o 21 | LD=$(LLVM_BIN)lld tools/build_tool/target/release/build_tool 0x10000 0x2000 $@ $^ 22 | 23 | build/Kernel.bin: build/Kernel.o 24 | LD=$(LLVM_BIN)lld tools/build_tool/target/release/build_tool 0x40000000 0x0 $@ $^ 25 | 26 | analyze: build/Bootloader.bin 27 | $(ANALYZE) $(TARGET_32) build/Bootloader32.elf 28 | $(ANALYZE) $(TARGET_64) build/Bootloader64.elf 29 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # UnikernelExperiments 2 | TCP/IPv6-enabled [Pine64+](https://www.pine64.org/?product=pine-a64-board-2gb) bootloader 3 | 4 | This project provides you with the toolchain and resources needed to start developing your own unikernel. 5 | It is completely written from scratch and is thus still well structured without legacy code. 6 | 7 | 8 | ## Getting started 9 | 10 | You will need: 11 | - Make 12 | - LLVM 3.9 or higher: [Clang](http://clang.llvm.org/get_started.html), [LLD](http://lld.llvm.org), llvm-objdump (optional) 13 | - [Rust](https://www.rust-lang.org/en-US/) 14 | - Pine64+ with 2GB (other versions are untested) 15 | - Mirco-SD-card to store the bootloader 16 | - Micro-USB-cable for power supply 17 | - RJ45-cable for data transfer 18 | - UART for debugging (optional) 19 | 20 | ```bash 21 | make build/Bootloader.bin 22 | dd if=build/Bootloader.bin of=/dev/[Mirco-SD-Card] 23 | tools/screen /dev/[UART-USB] 24 | ping6 FE80::34C9:E3FF:FEF1:B805%[Interface] 25 | make build/Kernel.bin 26 | nc FE80::34C9:E3FF:FEF1:B805%[Interface] 1337 < build/Kernel.bin 27 | ``` 28 | 29 | 30 | ## Example Use Cases 31 | 32 | - (Self)-Education: Learn or teach how low level software works 33 | - Experimental development: Develop your own unikernel easily 34 | - Internet of Things: Leave behind all the bloatware 35 | - Security: Less code -> less breaches 36 | 37 | 38 | ## State of Affairs / Features 39 | 40 | - Hardware Driver 41 | - UART ✓ 42 | - RSB ✓ 43 | - AXP803 ✓ 44 | - DRAM 45 | - 2GB ✓ 46 | - Auto size detection 47 | - Ethernet ✓ 48 | - High Speed Timer ✓ 49 | - Timer 50 | - Real Time Clock 51 | - Interrupt Controller 52 | - SD-Card 53 | - Thermal Sensors 54 | - DVFS 55 | 56 | - Software Driver 57 | - 64 Bit: ARMv8 / ARM64 / AArch64 ✓ 58 | - Floating point unit ✓ 59 | - Caches ✓ 60 | - MMU 61 | - Interrupt Handling 62 | - Multi threading 63 | - IPv4 / ICMPv4 64 | - IPv6 / ICMPv6, implemented features: 65 | - Echo ✓ 66 | - Neighbor solicitation and advertisement ✓ 67 | - UDP ✓ 68 | - TCP 69 | - IPv4 70 | - IPv6 ✓ 71 | - Receiving payload ✓ 72 | - Sending payload 73 | - Connect / Listen / Close ✓ 74 | - Sequence number overflow 75 | - Receive and transmit ring buffer 76 | - Timestamps 77 | - Selective acknowledgment 78 | - Initial sequence numbers 79 | - Correct timings 80 | - Multiple connections 81 | 82 | 83 | ## Communication Interfaces 84 | 85 | UART is a nice and easy interface for debugging and as a interactive console. 86 | But it is too slow to upload large binaries. 87 | The firmware comes with a USB-OTG boot option but: 88 | - The protocol is complicated and badly documented 89 | - Ethernet can be faster: Up to 1 GBit/s instead of 0.48 GBits/s of USB2 90 | - RJ45-cables are more common than USB-OTG-TypeA-cables 91 | - You probably want to connect the board to a network anyway and thus don't need a extra USB connection only for booting 92 | 93 | 94 | ## References 95 | 96 | ### Wiki 97 | - http://linux-sunxi.org/Arm64 98 | - http://linux-sunxi.org/Pine64 99 | - http://linux-sunxi.org/BROM 100 | - http://linux-sunxi.org/FEL/USBBoot 101 | - http://linux-sunxi.org/Reduced_Serial_Bus 102 | - https://sourceware.org/binutils/docs/ld/Scripts.html 103 | - https://sourceware.org/binutils/docs/as/ARM-Directives.html 104 | - http://www.heyrick.co.uk/armwiki/The_Status_register 105 | - http://downloads.ti.com/docs/esd/SPNU118N/Content/SPNU118N_HTML/assembler_directives.html 106 | - https://developer.arm.com/docs/den0024/latest/12-the-memory-management-unit/124-translation-tables-in-armv8-a/1243-cache-configuration 107 | - https://en.wikipedia.org/wiki/Cache 108 | 109 | ### Tutorials 110 | - https://balau82.wordpress.com/2010/04/12/booting-linux-with-u-boot-on-qemu-arm/ 111 | - https://balau82.wordpress.com/2010/02/28/hello-world-for-bare-metal-arm-using-qemu/ 112 | - https://singpolyma.net/2012/01/writing-a-simple-os-kernel-part-1/ 113 | 114 | ### Code 115 | - https://github.com/allwinner-zh/bootloader 116 | - https://github.com/linux-sunxi/sunxi-tools/blob/master/uart0-helloworld-sdboot.c 117 | - https://github.com/apritzel/linux/commits/a64-wip 118 | - https://github.com/longsleep/linux-pine64/tree/pine64-hacks-2.0-experimental 119 | - https://github.com/torvalds/linux/blob/master/arch/arm64/kernel/setup.c 120 | - https://github.com/torvalds/linux/blob/master/arch/arm64/mm/cache.S 121 | - https://github.com/torvalds/linux/blob/master/arch/arm64/mm/proc.S 122 | 123 | ### Docs 124 | - http://infocenter.arm.com/help/topic/com.arm.doc.den0024a/index.html 125 | - http://dl.linux-sunxi.org/A64/A64_Datasheet_V1.1.pdf 126 | - http://linux-sunxi.org/images/4/4b/Allwinner_H3_Datasheet_V1.2.pdf 127 | - http://www.cl.cam.ac.uk/research/srg/han/ACS-P35/zynq/arm_gic_architecture_specification.pdf 128 | - http://infocenter.arm.com/help/topic/com.arm.doc.ddi0471a/DDI0471A_gic400_r0p0_trm.pdf 129 | - http://files.pine64.org/doc/datasheet/pine64/AXP803_Datasheet_V1.0.pdf 130 | - http://download3.dvd-driver.cz/realtek/datasheets/pdf/rtl8211e(g)-vb(vl)-cg_datasheet_1.6.pdf 131 | -------------------------------------------------------------------------------- /include/Clock.hpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | struct Clock { 4 | static Natural64 uptimeClockMetaTicks, uptimeClockTicks; 5 | static const Natural64 cycleInSeconds = 60; // TODO: Far higher 6 | 7 | static void initialize() { 8 | auto hsTimer = AllwinnerHSTimer::instances[0].address; 9 | hsTimer->load(cycleInSeconds*AllwinnerHSTimer::baseFrequency, false); 10 | } 11 | 12 | static void update() { 13 | auto hsTimer = AllwinnerHSTimer::instances[0].address; 14 | Natural64 hsTicks = cycleInSeconds*AllwinnerHSTimer::baseFrequency-hsTimer->getCurrentValue(); 15 | if(hsTicks < uptimeClockTicks) 16 | ++uptimeClockMetaTicks; 17 | uptimeClockTicks = hsTicks; 18 | } 19 | 20 | static Natural64 getUptimeScaledBy(Natural32 scale) { 21 | return uptimeClockMetaTicks*cycleInSeconds*scale+uptimeClockTicks/(AllwinnerHSTimer::baseFrequency/scale); 22 | } 23 | 24 | static void printUptime() { 25 | update(); 26 | auto uart = AllwinnerUART::instances[0].address; 27 | uart->putDec(getUptimeScaledBy(1000)); 28 | puts(" ms Uptime"); 29 | } 30 | 31 | static void setCycleCounterActive(bool active) { 32 | Natural64 performanceMonitorsControlRegister; 33 | asm volatile("mrs %x0, PMCR_EL0\n" : "=r"(performanceMonitorsControlRegister)); 34 | performanceMonitorsControlRegister |= (1<<0); 35 | asm volatile("msr PMCR_EL0, %x0\n" : : "r"(performanceMonitorsControlRegister)); 36 | if(active) 37 | asm volatile("msr PMCNTENSET_EL0, %x0\ndsb sy\n" : : "r"(1<<31)); 38 | else 39 | asm volatile("msr PMCNTENCLR_EL0, %x0\ndsb sy\n" : : "r"(1<<31)); 40 | } 41 | 42 | static Natural64 getCycleCounter() { 43 | Natural64 performanceMonitorsControlRegister, processorCycles; 44 | asm volatile("mrs %x0, PMCCNTR_EL0\n" : "=r"(processorCycles)); 45 | asm volatile("mrs %x0, PMCR_EL0\n" : "=r"(performanceMonitorsControlRegister)); 46 | performanceMonitorsControlRegister |= (1<<2); 47 | asm volatile("msr PMCR_EL0, %x0\ndsb sy\n" : : "r"(performanceMonitorsControlRegister)); 48 | return processorCycles; 49 | } 50 | }; 51 | 52 | Natural64 Clock::uptimeClockMetaTicks = 0, Clock::uptimeClockTicks = 0; 53 | -------------------------------------------------------------------------------- /include/Foundation.hpp: -------------------------------------------------------------------------------- 1 | static_assert(__LITTLE_ENDIAN__); 2 | 3 | template 4 | struct conditional { 5 | typedef F type; 6 | }; 7 | template 8 | struct conditional { 9 | typedef T type; 10 | }; 11 | 12 | typedef char unsigned Natural8; 13 | typedef char Integer8; 14 | typedef short unsigned Natural16; 15 | typedef short Integer16; 16 | typedef unsigned Natural32; 17 | typedef int Integer32; 18 | typedef float Float32; 19 | typedef long long unsigned Natural64; 20 | typedef long long int Integer64; 21 | typedef double Float64; 22 | // typedef unsigned __int128 Natural128; 23 | // typedef __int128 Integer128; 24 | // typedef long double Float128; 25 | 26 | const Natural8 architectureSize = sizeof(void*)*8; 27 | typedef conditional::type NativeNaturalType; 28 | typedef conditional::type NativeIntegerType; 29 | typedef conditional::type NativeFloatType; 30 | typedef NativeNaturalType PageRefType; 31 | typedef NativeNaturalType Symbol; 32 | 33 | template 34 | constexpr static DataType swapedEndian(DataType value); 35 | 36 | template<> 37 | constexpr Natural16 swapedEndian(Natural16 value) { 38 | return __builtin_bswap16(value); 39 | } 40 | 41 | template<> 42 | constexpr Natural32 swapedEndian(Natural32 value) { 43 | return __builtin_bswap32(value); 44 | } 45 | 46 | template<> 47 | constexpr Natural64 swapedEndian(Natural64 value) { 48 | return __builtin_bswap64(value); 49 | } 50 | 51 | template 52 | void swapEndian(DataType& value) { 53 | value = swapedEndian(value); 54 | } 55 | 56 | template 57 | constexpr T min(T a, T b) { 58 | return (a < b) ? a : b; 59 | } 60 | 61 | template 62 | constexpr T min(T c, Args... args) { 63 | return min(c, min(args...)); 64 | } 65 | 66 | template 67 | constexpr T max(T a, T b) { 68 | return (a > b) ? a : b; 69 | } 70 | 71 | template 72 | constexpr T max(T c, Args... args) { 73 | return max(c, max(args...)); 74 | } 75 | 76 | extern "C" { 77 | NativeNaturalType strlen(const char* str) { 78 | const char* pos; 79 | for(pos = str; *pos; ++pos); 80 | return pos-str; 81 | } 82 | NativeNaturalType memcpy(void* dst, const void* src, NativeNaturalType len) { 83 | for(NativeNaturalType i = 0; i < len; ++i) 84 | reinterpret_cast(dst)[i] = reinterpret_cast(src)[i]; 85 | return 0; 86 | } 87 | NativeNaturalType memset(void* dst, NativeNaturalType value, NativeNaturalType len) { 88 | for(NativeNaturalType i = 0; i < len; ++i) 89 | reinterpret_cast(dst)[i] = value; 90 | return 0; 91 | } 92 | Natural8 memcmp(const void* a, const void* b, NativeNaturalType length) { 93 | for(NativeNaturalType i = 0; i < length; ++i) { 94 | Natural8 diff = reinterpret_cast(a)[i]-reinterpret_cast(b)[i]; 95 | if(diff != 0) 96 | return diff; 97 | } 98 | return 0; 99 | } 100 | void __cxa_atexit(void(*)(void*), void*, void*) {} 101 | void __cxa_pure_virtual() {} 102 | void __cxa_deleted_virtual() {} 103 | } 104 | 105 | inline void* operator new(__SIZE_TYPE__, void* ptr) noexcept { 106 | return ptr; 107 | } 108 | 109 | NativeNaturalType fromPointer(void* ptr) { 110 | return reinterpret_cast(ptr); 111 | } 112 | 113 | template 114 | Type* toPointer(NativeNaturalType ptr) { 115 | return reinterpret_cast(ptr); 116 | } 117 | 118 | void puts(const char* str); 119 | -------------------------------------------------------------------------------- /include/Hardware/AXP803.hpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | struct AXP803 { 4 | static const struct Instance { 5 | Natural16 hardwareAddress; 6 | Natural8 runTimeAddress; 7 | } instances[]; 8 | 9 | static void initialize() { 10 | auto rsb = AllwinnerRSB::instances[0].address; 11 | rsb->deviceAddress.hardwareAddress = instances[0].hardwareAddress; 12 | rsb->deviceAddress.runTimeAddress = instances[0].runTimeAddress; 13 | rsb->setRunTimeAddress(); 14 | 15 | Natural8 type; 16 | if(!rsb->read(0x3, type)) 17 | return; 18 | if(type != 0x51) 19 | puts("[FAIL] AXP803"); 20 | else 21 | puts("[ OK ] AXP803"); 22 | } 23 | 24 | static void configureDCDC5() { 25 | auto rsb = AllwinnerRSB::instances[0].address; 26 | 27 | Natural8 value = 51; // 1500 mV 28 | if(!rsb->write(0x24, value)) // DRAM_VCC (DCDC5) 29 | return; 30 | } 31 | 32 | static void configureDC1SW() { 33 | auto rsb = AllwinnerRSB::instances[0].address; 34 | 35 | Natural8 value = (1<<7); // DC1SW (Ethernet PHY) 36 | if(!rsb->write(0x12, value)) // Output power on-off control 2 37 | return; 38 | } 39 | }; 40 | -------------------------------------------------------------------------------- /include/Hardware/AllwinnerA64.hpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | const struct AllwinnerCPUCFG::Instance AllwinnerCPUCFG::instances[] = { 4 | { reinterpret_cast(0x01700000) } 5 | }; 6 | 7 | const struct AllwinnerSYSCTL::Instance AllwinnerSYSCTL::instances[] = { 8 | { reinterpret_cast(0x01C00000) } 9 | }; 10 | 11 | const struct AllwinnerSMHC::Instance AllwinnerSMHC::instances[] = { 12 | { reinterpret_cast(0x01C0F000) }, 13 | { reinterpret_cast(0x01C10000) }, 14 | { reinterpret_cast(0x01C11000) } 15 | }; 16 | 17 | const struct AllwinnerCCU::Instance AllwinnerCCU::instances[] = { 18 | { reinterpret_cast(0x01C20000) } 19 | }; 20 | 21 | const struct AllwinnerTimer::Instance AllwinnerTimer::instances[] = { 22 | { reinterpret_cast(0x01C20C00), { 50, 51 } } 23 | }; 24 | 25 | const struct AllwinnerUART::Instance AllwinnerUART::instances[] = { 26 | { reinterpret_cast(0x01C28000), 32, 6 }, 27 | { reinterpret_cast(0x01C28400), 33, 7 }, 28 | { reinterpret_cast(0x01C28800), 34, 8 }, 29 | { reinterpret_cast(0x01C28C00), 35, 9 }, 30 | { reinterpret_cast(0x01C29000), 36, 10 } 31 | }; 32 | 33 | const struct AllwinnerEMAC::Instance AllwinnerEMAC::instances[] = { 34 | { reinterpret_cast(0x01C30000), 114 } 35 | }; 36 | 37 | const struct AllwinnerHSTimer::Instance AllwinnerHSTimer::instances[] = { 38 | { reinterpret_cast(0x01C60000), 83 } 39 | }; 40 | 41 | const struct AllwinnerDRAMCOM::Instance AllwinnerDRAMCOM::instances[] = { 42 | { reinterpret_cast(0x01C62000) } 43 | }; 44 | 45 | const struct AllwinnerDRAMCTL::Instance AllwinnerDRAMCTL::instances[] = { 46 | { reinterpret_cast(0x01C63000) } 47 | }; 48 | 49 | const struct GICPL400::Instance GICPL400::instances[] = { 50 | { reinterpret_cast(0x01C80000) } 51 | }; 52 | 53 | const struct AllwinnerPIO::Instance AllwinnerPIO::instances[] = { 54 | { reinterpret_cast(0x01C20800) }, // CPUx-PORT (PIO) 55 | { reinterpret_cast(0x01F02C00) } // CPUs-PORT (R_PIO) 56 | }; 57 | 58 | const struct AllwinnerPRCM::Instance AllwinnerPRCM::instances[] = { 59 | { reinterpret_cast(0x01F01400) } 60 | }; 61 | 62 | const struct AllwinnerRSB::Instance AllwinnerRSB::instances[] = { 63 | { reinterpret_cast(0x01F03400), 71 } 64 | }; 65 | 66 | const struct AXP803::Instance AXP803::instances[] = { 67 | { 0x3A3, 0x2D } 68 | }; 69 | 70 | const struct AllwinnerDRAM::Instance AllwinnerDRAM::instances[] = { 71 | { reinterpret_cast(0x40000000) } 72 | }; 73 | -------------------------------------------------------------------------------- /include/Hardware/AllwinnerCCU.hpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | struct AllwinnerCCU { 4 | static const struct Instance { 5 | volatile AllwinnerCCU* address; 6 | } instances[]; 7 | 8 | Natural32 9 | PLLCPUXControl, 10 | pad0, 11 | PLLAUDIOControl, 12 | pad1, 13 | PLLVIDEO0Control, 14 | pad2, 15 | PLLVEControl, 16 | pad3, 17 | PLLDDR0Control, 18 | pad4, 19 | PLLPERIPH0Control, 20 | PLLPERIPH1Control, 21 | PLLVIDEO1Control, 22 | pad5, 23 | PLLGPUControl, 24 | pad6, 25 | PLLMIPIControl, 26 | PLLHSICControl, 27 | PLLDEControl, 28 | PLLDDR1Control, 29 | CPUXAXIConfiguration, 30 | AHB1APB1Configuration, 31 | APB2Configuration, 32 | AHB2Configuration, 33 | BusClockGating[5], 34 | THSClock, 35 | pad7[2], 36 | NANDClock, 37 | pad8, 38 | SMHCClock[3], 39 | pad9, 40 | TSClock, 41 | CEClock, 42 | SPI0Clock, 43 | SPI1Clock, 44 | pad10[2], 45 | I2SPCM0Clock, 46 | I2SPCM1Clock, 47 | I2SPCM2Clock, 48 | pad11, 49 | SPDIFClock, 50 | pad12[2], 51 | USBPHYConfiguration, 52 | pad13[9], 53 | DRAMConfiguration, 54 | PLLDDRConfiguration, 55 | MBUSReset, 56 | DRAMClockGating, 57 | DEClock, 58 | pad14[5], 59 | TCON0Clock, 60 | TCON1Clock, 61 | pad15, 62 | DEINTERLACEClock, 63 | pad16[2], 64 | CSIMISCClock, 65 | CSIClock, 66 | VEClock, 67 | ACDigitalClock, 68 | AVSClock, 69 | pad17[2], 70 | HDMIClock, 71 | HDMISlowClock, 72 | pad18, 73 | MBUSClock, 74 | pad19[2], 75 | MIPIDSIClock, 76 | pad20[13], 77 | GPUClock, 78 | pad21[23], 79 | PLLStableTime0, 80 | PLLStableTime1, 81 | pad22[6], 82 | PLLCPUXBias, 83 | PLLAUDIOBias, 84 | PLLVIDEO0Bias, 85 | PLLVEBias, 86 | PLLDDR0Bias, 87 | PLLPERIPH0Bias, 88 | PLLVIDEO1Bias, 89 | PLLGPUBias, 90 | PLLMIPIBias, 91 | PLLHSICBias, 92 | PLLDEBias, 93 | PLLDDR1Bias, 94 | PLLCPUXTuning, 95 | pad23[3], 96 | PLLDDR0Tuning, 97 | pad24[3], 98 | PLLMIPITuning, 99 | pad25[2], 100 | PLLPERIPH1PatternControl, 101 | PLLCPUXPatternControl, 102 | PLLAUDIOPatternControl, 103 | PLLVIDEO0PatternControl, 104 | PLLVEPatternControl, 105 | PLLDDR0PatternControl, 106 | pad26, 107 | PLLVIDEO1PatternControl, 108 | PLLGPUPatternControl, 109 | PLLMIPIPatternControl, 110 | PLLHSICPatternControl, 111 | PLLDEPatternControl, 112 | PLLDDR1PatternControl0, 113 | PLLDDR1PatternControl1, 114 | pad27[3], 115 | BusSoftwareReset0, 116 | BusSoftwareReset1, 117 | BusSoftwareReset2, 118 | pad28, 119 | BusSoftwareReset3, 120 | pad29, 121 | BusSoftwareReset4, 122 | pad30[5], 123 | CCMSecuritySwitch, 124 | pad31[3], 125 | PSControl, 126 | PSCounter, 127 | pad32[6], 128 | PLLLockControl; 129 | 130 | void configureUART0() volatile { 131 | BusClockGating[3] |= (1<<16); 132 | BusSoftwareReset4 |= (1<<16); 133 | 134 | auto pio = AllwinnerPIO::instances[0].address; 135 | pio->banks[1].configure[1].slot0 = 4; // PB8 : UART0_TX 136 | pio->banks[1].configure[1].slot1 = 4; // PB9 : UART0_RX 137 | pio->banks[1].pull[0].slot9 = 1; // PB9 : PullUP 138 | } 139 | 140 | void configureRSB() volatile { 141 | auto prcm = AllwinnerPRCM::instances[0].address; 142 | prcm->APBSSoftwareReset |= 8; // 0x01F014B0 : R_RSB_RESET 143 | prcm->APBSClockGating |= 9; // 0x01F01428 : R_PIO_GATING, R_RSB_GATING 144 | 145 | auto pio = AllwinnerPIO::instances[1].address; 146 | pio->banks[0].configure[0].slot0 = 2; // PL0 : S_RSB_SCK 147 | pio->banks[0].configure[0].slot1 = 2; // PL1 : S_RSB_SDA 148 | pio->banks[0].multiDriving[0].slot0 = 2; // PL0 : MultiDrivingLevel 2 149 | pio->banks[0].multiDriving[0].slot1 = 2; // PL1 : MultiDrivingLevel 2 150 | } 151 | 152 | void configureEMAC() volatile { 153 | auto pio = AllwinnerPIO::instances[0].address; 154 | pio->banks[3].configure[1].slot7 = 4; // PD15 : RGMII_TXD3 | MII_TXD3 | RMII_NULL 155 | // pio->banks[3].configure[1].slot6 = 7; // PD14 : RGMII_NULL | MII_RXERR | RMII_RXER 156 | pio->banks[3].configure[1].slot5 = 4; // PD13 : RGMII_RXCTL | MII_RXDV | RMII_CRS_DV 157 | pio->banks[3].configure[1].slot4 = 4; // PD12 : RGMII_RXCK | MII_RXCK | RMII_NULL 158 | pio->banks[3].configure[1].slot3 = 4; // PD11 : RGMII_RXD0 | MII_RXD0 | RMII_RXD0 159 | pio->banks[3].configure[1].slot2 = 4; // PD10 : RGMII_RXD1 | MII_RXD1 | RMII_RXD1 160 | pio->banks[3].configure[1].slot1 = 4; // PD9 : RGMII_RXD2 | MII_RXD2 | RMII_NULL 161 | pio->banks[3].configure[1].slot0 = 4; // PD8 : RGMII_RXD3 | MII_RXD3 | RMII_NULL 162 | pio->banks[3].configure[2].slot7 = 4; // PD23 : MDIO 163 | pio->banks[3].configure[2].slot6 = 4; // PD22 : MDC 164 | pio->banks[3].configure[2].slot5 = 4; // PD21 : RGMII_CLKIN | MII_COL | RMII_NULL 165 | pio->banks[3].configure[2].slot4 = 4; // PD20 : RGMII_TXCTL | MII_TXEN | RMII_TXEN 166 | pio->banks[3].configure[2].slot3 = 4; // PD19 : RGMII_TXCK | MII_TXCK | RMII_TXCK 167 | pio->banks[3].configure[2].slot2 = 4; // PD18 : RGMII_TXD0 | MII_TXD0 | RMII_TXD0 168 | pio->banks[3].configure[2].slot1 = 4; // PD17 : RGMII_TXD1 | MII_TXD1 | RMII_TXD1 169 | pio->banks[3].configure[2].slot0 = 4; // PD16 : RGMII_TXD2 | MII_TXD2 | RMII_NULL 170 | 171 | auto sysCtl = AllwinnerSYSCTL::instances[0].address; 172 | BusClockGating[0] |= (1<<17); 173 | BusSoftwareReset0 |= (1<<17); 174 | 175 | sysCtl->EMACClock.clockSource = 2; 176 | sysCtl->EMACClock.phyInterface = 1; 177 | sysCtl->EMACClock.invertTransmitClock = 0; 178 | sysCtl->EMACClock.invertReceiveClock = 0; 179 | sysCtl->EMACClock.receiveClockDelayChain = 0; 180 | sysCtl->EMACClock.transmitClockDelayChain = 3; 181 | sysCtl->EMACClock.RMIIEnable = 0; 182 | } 183 | 184 | void configurePLL() volatile { 185 | PLLLockControl |= (1<<28); // 0x01C20320 : MODE_SEL New Mode 186 | 187 | // CPUXAXI init 188 | CPUXAXIConfiguration |= 2; // 0x01C20050 189 | PLLLockControl |= (1<<0); // 0x01C20320 190 | PLLCPUXControl |= (1<<31); // 0x01C20000 191 | while((PLLCPUXControl&(1<<28)) == 0); // 0x01C20000 192 | PLLLockControl &= ~(1<<0); // 0x01C20320 193 | CPUXAXIConfiguration &= ~(3<<16); // 0x01C20050 194 | CPUXAXIConfiguration |= (2<<16); // 0x01C20050 195 | 196 | // HSIC init 197 | PLLLockControl |= (1<<9); // 0x01C20320 198 | PLLHSICControl |= (1<<31); // 0x01C20044 199 | while((PLLHSICControl&(1<<28)) == 0); // 0x01C20044 200 | PLLLockControl &= ~(1<<9); // 0x01C20320 201 | 202 | // AHB1APB1 init 203 | AHB1APB1Configuration = (AHB1APB1Configuration&(3<<12))|(1<<12); // 0x01C20054 204 | PLLLockControl |= (1<<5); // 0x01C20320 205 | PLLPERIPH0Control |= (1<<31); // 0x01C20028 206 | while((PLLPERIPH0Control&(1<<28)) == 0); // 0x01C20028 207 | PLLLockControl &= ~(1<<5); // 0x01C20320 208 | AHB1APB1Configuration = 0x180; // 0x01C20054 209 | AHB1APB1Configuration |= (3<<12); // 0x01C20054 210 | 211 | // PLLDDR0 init 212 | // PLLDDR0Control &= ~(0x7F<<8); // 0x01C20020 213 | // PLLDDR0Control = (1<<31)|(27<<8); // 0x01C20020 : PLL_ENABLE, PLL_FACTOR_N: 28 (672 MHz) 214 | // PLLDDR0Control |= (1<<20); // 0x01C20020 : PLL_DDR0_CFG_UPDATE 215 | // PLLLockControl |= (1<<4); // 0x01C20320 : Lock Enable PLL_DDR0 216 | // while(((PLLDDR0Control>>20)&0x11) != 0x10); // 0x01C20020 : LOCK, PLL_DDR0_CFG_UPDATE 217 | // PLLLockControl &= ~(1<<4); // 0x01C20320 218 | 219 | // PLLDDR1 init 220 | PLLDDR1Control &= ~(0x7F<<8); // 0x01C2004C 221 | PLLDDR1Control |= (1<<31)|(55<<8); // 0x01C2004C : PLL_ENABLE, PLL_FACTOR_N: 55 (1320 MHz) 222 | PLLDDR1Control |= (1<<30); // 0x01C2004C : SDRPLL_UPD 223 | PLLLockControl |= (1<<11); // 0x01C20320 : PLL_DDR1 224 | while(((PLLDDR1Control>>28)&0x5) != 0x1); // 0x01C2004C : SDRPLL_UPD, LOCK 225 | PLLLockControl &= ~(1<<11); // 0x01C20320 226 | 227 | PLLLockControl &= ~(1<<28); // 0x01C20320 : MODE_SEL Old Mode 228 | } 229 | 230 | void configureDRAM() volatile { 231 | DRAMConfiguration |= (1<<20); // 0x01C200F4 : PLL_DDR1 232 | DRAMConfiguration |= (1<<16); // 0x01C200F4 : SDRCLK_UPD 233 | while(DRAMConfiguration&(1<<16)); 234 | BusSoftwareReset0 |= (1<<14); // 0x01C202C0 : SDRAM_RST 235 | BusClockGating[0] |= (1<<14); // 0x01C20060 : DRAM_GATING 236 | MBUSClock = 0x81000002; // 0x01C2015C 237 | DRAMConfiguration |= (1<<31); // 0x01C200F4 : DRAM_CTR_RST 238 | } 239 | 240 | void configureSMHC() volatile { 241 | BusClockGating[0] |= (7<<8); // 8, 9, 10 242 | BusSoftwareReset0 |= (7<<8); // 8, 9, 10 243 | 244 | // TODO: The recommended clock frequency is 200MHz. 245 | // SMHCClock[0] = ; 246 | // SMHCClock[1] = ; 247 | // SMHCClock[2] = ; 248 | } 249 | 250 | void configureHSTimer() volatile { 251 | BusClockGating[0] |= (1<<19); 252 | BusSoftwareReset0 |= (1<<19); 253 | } 254 | }; 255 | -------------------------------------------------------------------------------- /include/Hardware/AllwinnerCPUCFG.hpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | struct AllwinnerCPUCFG { 4 | static const struct Instance { 5 | volatile AllwinnerCPUCFG* address; 6 | } instances[]; 7 | 8 | union { 9 | struct { 10 | Natural32 pad0 : 4, 11 | L2ResetDisable : 1, 12 | pad1 : 3, 13 | CP15SDisable : 4, 14 | pad2 : 12, 15 | AArch64AfterColdReset : 4, 16 | cacheMaintenanceBroadcastingDownstream : 1, 17 | broadcastOuterShareableTransactions : 1, 18 | broadcastInnerShareableTransactions : 1, 19 | broadcastBarriersSystemBusDisable : 1; 20 | }; 21 | Natural32 raw; 22 | } clusterControl0; 23 | union { 24 | struct { 25 | Natural32 snoopInterfaceInactive : 1; 26 | }; 27 | Natural32 raw; 28 | } clusterControl1; 29 | union { 30 | struct { 31 | Natural32 L1IDDelay : 3, pad0 : 1, 32 | L1ITDelay : 3, pad1 : 1, 33 | L1DDDelay : 3, pad2 : 1, 34 | L1DTDelay : 3, pad3 : 1, 35 | L1DYDelay : 3, pad4 : 1, 36 | BTACDelay : 3, pad5 : 1, 37 | L1TLBDelay : 3, pad6 : 1, 38 | L1SDTDelay : 3; 39 | }; 40 | Natural32 raw; 41 | } cacheConfig0; 42 | union { 43 | struct { 44 | Natural32 pad0 : 4, 45 | L2TDelay : 3, pad1 : 5, 46 | L2VDelay : 3, pad2 : 1, 47 | EMA : 3, pad3 : 5, 48 | EMAW : 2; 49 | }; 50 | Natural32 raw; 51 | } cacheConfig1; 52 | Natural32 pad0[6]; 53 | union { 54 | struct { 55 | Natural32 pad0 : 4, 56 | GICCDisable : 1, 57 | pad1 : 3, 58 | L2FlushRequest : 1, 59 | pad2 : 3, 60 | cryptoDisable : 4, 61 | externalMonitorRequestClear : 1, 62 | pad3 : 3, 63 | EXMClear : 4, 64 | eventInput : 1; 65 | }; 66 | Natural32 raw; 67 | } generalControl; 68 | Natural32 pad1; 69 | union { 70 | struct { 71 | Natural32 StandByWFIL2 : 1, 72 | pad0 : 7, 73 | StandByWFE : 4, 74 | pad1 : 4, 75 | StandByWFI : 4, 76 | pad2 : 4, 77 | SMP : 4; 78 | }; 79 | Natural32 raw; 80 | } clusterCPUStatus; 81 | Natural32 pad2[2]; 82 | union { 83 | struct { 84 | Natural32 pad0 : 8, 85 | externalMonitorRequestClearAcknowledge : 1, 86 | eventOutput : 1, 87 | L2FlushDone : 1; 88 | }; 89 | Natural32 raw; 90 | } L2Status; 91 | Natural32 pad3[16]; 92 | union { 93 | struct { 94 | Natural32 coreReset : 4, 95 | pad0 : 4, 96 | L2Reset : 1, 97 | pad1 : 3, 98 | HReset : 1, 99 | pad2 : 7, 100 | MBISTReset : 1, 101 | pad3 : 3, 102 | socDebugReset : 1, 103 | pad4 : 3, 104 | DDRReset : 1; 105 | }; 106 | Natural32 raw; 107 | } clusterResetControl; 108 | Natural32 pad4[7]; 109 | Natural64 resetVector[4]; 110 | }; 111 | -------------------------------------------------------------------------------- /include/Hardware/AllwinnerDRAM.hpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | struct AllwinnerDRAM { 4 | static const struct Instance { 5 | AllwinnerDRAM* address; 6 | } instances[]; 7 | 8 | void initialize() { 9 | auto dramCom = AllwinnerDRAMCOM::instances[0].address; // 0x01C62000 10 | auto dramCtl = AllwinnerDRAMCTL::instances[0].address; // 0x01C63000 11 | 12 | // auto_set_timing_para 13 | dramCtl->clockEnable = 0xC00E; // 0x01C6300C 14 | dramCtl->mode[0] = 0x00001C70; // 0x01C63030 15 | dramCtl->mode[1] = 0x00000040; // 0x01C63034 16 | dramCtl->mode[2] = 0x00000018; // 0x01C63038 17 | dramCtl->mode[3] = 0x00000000; // 0x01C6303C 18 | dramCtl->timing[0] = 0x0C11180D; // 0x01C63058 19 | dramCtl->timing[1] = 0x00030412; // 0x01C6305C 20 | dramCtl->timing[2] = 0x0406050A; // 0x01C63060 21 | dramCtl->timing[3] = 0x0000400C; // 0x01C63064 22 | dramCtl->timing[4] = 0x06020406; // 0x01C63068 23 | dramCtl->timing[5] = 0x05050403; // 0x01C6306C 24 | dramCtl->timing[8] &= ~0xFFFF; // 0x01C63078 25 | dramCtl->timing[8] |= 0x6610; // 0x01C63078 26 | dramCtl->piTiming[0] = 0x02040102; // 0x01C63080 27 | dramCtl->PT[3] = 0x10D52081; // 0x01C63050 28 | dramCtl->PT[4] = 0x2A120D01; // 0x01C63054 29 | dramCtl->refreshTiming = 0x00510076; // 0x01C63090 30 | 31 | // set_master_priority 32 | dramCom->debugControl[1] = 0x0000018F; // 0x01C6200C 33 | dramCom->bandwidthControl = 0x00010000; // 0x01C62090 34 | const Natural32 bandwidthLimit[] = { 35 | 0x00A0000D, 0x06000009, 0x0200000D, 0x01000009, 0x07000009, 0x01000009, 36 | 0x01000009, 0x0100000D, 0x0100000D, 0x04000009, 0x20000209, 0x05000009 37 | }; 38 | const Natural32 port[] = { 39 | 0x00500064, 0x01000578, 0x00600100, 0x00500064, 0x01000640, 0x00000080, 40 | 0x00400080, 0x00400080, 0x00400080, 0x00400100, 0x08001800, 0x00400090 41 | }; 42 | for(Natural8 i = 0; i < 12; ++i) { 43 | dramCom->masterConfig[i].bandwidthLimit = bandwidthLimit[i]; // 0x01C62010 - 0x01C62068 44 | dramCom->masterConfig[i].port = port[i]; // 0x01C62014 - 0x01C6206C 45 | } 46 | dramCom->unknown0[39] = 0x81000004; // 0x01C62130 47 | 48 | // mctl_channel_init 49 | dramCtl->PGC[0] &= ~((1<<30)|0x3F); // 0x01C63100 50 | dramCtl->PGC[1] |= (1<<26); // 0x01C63104 51 | dramCtl->PGC[1] &= ~(1<<24); // 0x01C63104 52 | 53 | dramCom->debugControl[1] |= 0x0000018F; // 0x01C6200C 54 | dramCom->MCProtect = 0x94BE6FA3; // 0x01C62800 55 | dramCtl->MXUpdate[2] |= (0x50<<16); // 0x01C63888 56 | dramCom->MCProtect = 0; // 0x01C62800 57 | 58 | dramCtl->unknown0 |= (1<<9); // 0x01C630B8 59 | dramCtl->PGC[2] &= ~(0xF<<8); // 0x01C63108 60 | dramCtl->PGC[2] |= (0x3<<8); // 0x01C63108 61 | for(Natural8 i = 0; i < 4; ++i) 62 | dramCtl->DX[i].GC &= ~0xF03E; // 0x01C63344 + i*0x80 63 | dramCtl->ACIOC |= 2; // 0x01C63208 64 | dramCtl->PGC[2] &= ~0x2000; // 0x01C63108 65 | dramCtl->PGC[0] &= ~(1<<28); // 0x01C63100 66 | 67 | const Natural32 CAIOC[] = { 0x3352AD05, 0x00013330, 0x04143043, 0x045D1011 }; 68 | for(Natural8 j = 0; j < 4; ++j) 69 | for(Natural8 i = 0; i < 8; ++i) 70 | dramCtl->CAIOC[j*8+i] = ((CAIOC[j]>>(i*4))&0xF)<<8; // 0x01C63210 - 0x01C6328C 71 | 72 | dramCtl->DX[0].BDL6 = 0x01000000; // 0x01C6333C 73 | dramCtl->DX[0].DATXIOC[0] = 0x10; // 0x01C63310 74 | dramCtl->DX[0].DATXIOC[1] = 0x10; // 0x01C63314 75 | dramCtl->DX[0].DATXIOC[2] = 0x10; // 0x01C63318 76 | dramCtl->DX[0].DATXIOC[3] = 0x10; // 0x01C6331C 77 | dramCtl->DX[0].DATXIOC[4] = 0x11; // 0x01C63320 78 | dramCtl->DX[0].DATXIOC[5] = 0x10; // 0x01C63324 79 | dramCtl->DX[0].DATXIOC[6] = 0x10; // 0x01C63328 80 | dramCtl->DX[0].DATXIOC[7] = 0x11; // 0x01C6332C 81 | dramCtl->DX[0].DATXIOC[8] = 0x10; // 0x01C63330 82 | dramCtl->DX[0].DATXIOC[9] = 0xF01; // 0x01C63334 83 | 84 | dramCtl->DX[1].BDL6 = 0x01000000; // 0x01C633BC 85 | dramCtl->DX[1].DATXIOC[0] = 0x11; // 0x01C63390 86 | dramCtl->DX[1].DATXIOC[1] = 0x11; // 0x01C63394 87 | dramCtl->DX[1].DATXIOC[2] = 0x11; // 0x01C63398 88 | dramCtl->DX[1].DATXIOC[3] = 0x11; // 0x01C6339C 89 | dramCtl->DX[1].DATXIOC[4] = 0x111; // 0x01C633A0 90 | dramCtl->DX[1].DATXIOC[5] = 0x111; // 0x01C633A4 91 | dramCtl->DX[1].DATXIOC[6] = 0x111; // 0x01C633A8 92 | dramCtl->DX[1].DATXIOC[7] = 0x111; // 0x01C633AC 93 | dramCtl->DX[1].DATXIOC[8] = 0x11; // 0x01C633B0 94 | dramCtl->DX[1].DATXIOC[9] = 0xA01; // 0x01C633B4 95 | 96 | // dramCtl->DX[2].BDL6 = 0x01000000; // 0x01C6343C 97 | dramCtl->DX[2].DATXIOC[0] = 0x110; // 0x01C63410 98 | dramCtl->DX[2].DATXIOC[1] = 0x11; // 0x01C63414 99 | dramCtl->DX[2].DATXIOC[2] = 0x111; // 0x01C63418 100 | dramCtl->DX[2].DATXIOC[3] = 0x110; // 0x01C6341C 101 | dramCtl->DX[2].DATXIOC[4] = 0x110; // 0x01C63420 102 | dramCtl->DX[2].DATXIOC[5] = 0x110; // 0x01C63424 103 | dramCtl->DX[2].DATXIOC[6] = 0x110; // 0x01C63428 104 | dramCtl->DX[2].DATXIOC[7] = 0x110; // 0x01C6342C 105 | dramCtl->DX[2].DATXIOC[8] = 0x10; // 0x01C63430 106 | dramCtl->DX[2].DATXIOC[9] = 0xB00; // 0x01C63434 107 | 108 | dramCtl->DX[3].BDL6 = 0x01000000; // 0x01C634BC 109 | dramCtl->DX[3].DATXIOC[0] = 0x111; // 0x01C63490 110 | dramCtl->DX[3].DATXIOC[1] = 0x11; // 0x01C63494 111 | dramCtl->DX[3].DATXIOC[2] = 0x11; // 0x01C63498 112 | dramCtl->DX[3].DATXIOC[3] = 0x111; // 0x01C6349C 113 | dramCtl->DX[3].DATXIOC[4] = 0x111; // 0x01C634A0 114 | dramCtl->DX[3].DATXIOC[5] = 0x111; // 0x01C634A4 115 | dramCtl->DX[3].DATXIOC[6] = 0x111; // 0x01C634A8 116 | dramCtl->DX[3].DATXIOC[7] = 0x111; // 0x01C634AC 117 | dramCtl->DX[3].DATXIOC[8] = 0x11; // 0x01C634B0 118 | dramCtl->DX[3].DATXIOC[9] = 0xC01; // 0x01C634B4 119 | 120 | dramCtl->ZQ[0].C &= ~0x00FFFFFF; // 0x01C63140 121 | dramCtl->ZQ[0].C |= 0x003B3BBB; // 0x01C63140 122 | dramCtl->PI = 0x5F2; // 0x01C63000 123 | dramCtl->PI |= 1; // 0x01C63000 124 | while((dramCtl->PGS[0]&1) == 0); // 0x01C63010 125 | dramCom->unknown0[15] |= (1<<31); // 0x01C620D0 126 | while((dramCtl->status&1) == 0); // 0x01C63018 127 | dramCtl->PGC[3] &= ~(0x6<<24); // 0x01C6310C 128 | dramCtl->DTC &= ~(3<<24); // 0x01C630C0 129 | dramCtl->DTC |= (1<<24); // 0x01C630C0 130 | dramCtl->PI = 0x401; // 0x01C63000 131 | while((dramCtl->PGS[0]&1) == 0); // 0x01C63010 132 | dramCtl->ZQ[0].C |= (1<<31); // 0x01C63140 133 | 134 | if(dramCtl->PGS[0]&0xFF0000) // 0x01C63010 135 | puts("[FAIL] DRAM"); 136 | else { 137 | auto uart = AllwinnerUART::instances[0].address; 138 | uart->puts("[ OK ] DRAM: 2^"); 139 | uart->putDec(dramCom->getDRAMSize()); 140 | puts(" bytes"); 141 | } 142 | } 143 | }; 144 | -------------------------------------------------------------------------------- /include/Hardware/AllwinnerDRAMCOM.hpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | struct AllwinnerDRAMCOM { 4 | static const struct Instance { 5 | volatile AllwinnerDRAMCOM* address; 6 | } instances[]; 7 | 8 | union { 9 | struct { 10 | Natural32 rank : 2, 11 | bank : 2, 12 | rowWidth : 4, 13 | pageSize : 4, 14 | DQWidth : 3, 15 | unknown0 : 1, 16 | DRAMType : 3, 17 | unknown1 : 1, 18 | unknown2 : 8; 19 | }; 20 | Natural32 raw; 21 | } control; 22 | Natural32 pad0, 23 | debugControl[2]; 24 | struct { 25 | Natural32 bandwidthLimit, 26 | port; 27 | } masterConfig[12]; 28 | Natural32 pad1[8], 29 | bandwidthControl, 30 | unknown0[475], 31 | MCProtect; 32 | 33 | Natural8 getDRAMSize() volatile { 34 | return control.rank+control.bank+control.rowWidth+control.pageSize+6; 35 | } 36 | }; 37 | -------------------------------------------------------------------------------- /include/Hardware/AllwinnerDRAMCTL.hpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | struct AllwinnerDRAMCTL { 4 | static const struct Instance { 5 | volatile AllwinnerDRAMCTL* address; 6 | } instances[]; 7 | 8 | Natural32 9 | PI, 10 | powerControl, 11 | modeControl, 12 | clockEnable, 13 | PGS[2], 14 | status, 15 | pad0[5], 16 | mode[4], 17 | PLLGC, 18 | PT[5], 19 | timing[9], 20 | odtConfig, 21 | piTiming[2], 22 | pad1, 23 | refreshControl0, 24 | refreshTiming, 25 | refreshControl1, 26 | powerTiming, 27 | pad2[7], 28 | unknown0, 29 | DQSGM, 30 | DTC, 31 | DTA[4], 32 | DTD[2], 33 | DTM[2], 34 | DTBM, 35 | CAT[2], 36 | DTED[2], 37 | pad3[2], 38 | PGC[4], 39 | IOVC[2], 40 | DQSD, 41 | DXCC, 42 | odtMap, 43 | ZQCTL[2], 44 | pad4[5]; 45 | struct { 46 | Natural32 C, P, D, S; 47 | } ZQ[8]; 48 | Natural32 49 | SCHED, 50 | peripheralFHP[2], 51 | peripheralFLP[2], 52 | peripheralW[2], 53 | pad5[9], 54 | ACMDL, 55 | ACLCDL, 56 | ACIOC, 57 | pad6, 58 | CAIOC[60]; 59 | struct { 60 | Natural32 61 | MDL, 62 | LCDL[3], 63 | DATXIOC[11], 64 | BDL6, 65 | GT, 66 | GC, 67 | GS[3], 68 | pad0[11]; 69 | } DX[4]; 70 | Natural32 71 | pad7[192], 72 | BISTR, 73 | BISTWC, 74 | pad8[3], 75 | BISTLS, 76 | pad9[4], 77 | BISTGS, 78 | BISTWE, 79 | BISTBE[4], 80 | BISTWCS, 81 | BISTFW[3], 82 | pad10[12], 83 | MXUpdate[3]; 84 | }; 85 | -------------------------------------------------------------------------------- /include/Hardware/AllwinnerEMAC.hpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | struct AllwinnerEMAC { 4 | static const struct Instance { 5 | volatile AllwinnerEMAC* address; 6 | Natural8 interruptPort; 7 | } instances[]; 8 | 9 | enum DMAStatus { 10 | TransmitStopped = 0, 11 | TransmitFetchingDescriptor = 1, 12 | TransmitWaitingForStatus = 2, 13 | TransmitPassingFrame = 3, 14 | TransmitSuspended = 6, 15 | TransmitClosingDescriptor = 7, 16 | 17 | ReceiveStopped = 0, 18 | ReceiveFetchingDescriptor = 1, 19 | ReceiveWaitingForFrame = 3, 20 | ReceiveSuspended = 4, 21 | ReceiveClosingDescriptor = 5, 22 | ReceivePassingFrame = 7 23 | }; 24 | 25 | struct TransmitDescriptor { 26 | static const Natural32 errorMask = 0x00015706; // 0000 0000 0000 0001 0101 0111 0000 0110 27 | union { 28 | struct { 29 | Natural32 deferHalfDuplex : 1, 30 | underflowError : 1, 31 | deferError : 1, 32 | collisionCount : 4, 33 | pad0 : 1, 34 | collisionError : 1, 35 | contentionError : 1, 36 | carrierError : 1, 37 | pad1 : 1, 38 | payloadChecksumError : 1, 39 | pad2 : 1, 40 | lengthError : 1, 41 | pad3 : 1, 42 | headerChecksumError : 1, 43 | pad4 : 14, 44 | DMAOwnership : 1; 45 | }; 46 | Natural32 raw; 47 | } status; 48 | union { 49 | struct { 50 | Natural32 bufferSize : 11, 51 | pad0 : 13, 52 | chainMode : 1, 53 | pad1 : 1, 54 | CRCControl : 1, 55 | checksumControl : 2, 56 | first : 1, 57 | last : 1, 58 | completionInterruptEnable : 1; 59 | }; 60 | Natural32 raw; 61 | } control; 62 | Natural32 bufferAddress, 63 | next; 64 | }; 65 | 66 | struct ReceiveDescriptor { 67 | static const Natural32 errorMask = 0x000048DB; // 0000 0000 0000 0000 0100 1000 1101 1011 68 | union { 69 | struct { 70 | Natural32 payloadChecksumError : 1, 71 | CRCError : 1, 72 | pad0 : 1, 73 | phyError : 1, 74 | lengthError : 1, 75 | pad1 : 1, 76 | collisionHalfDuplex : 1, 77 | headerChecksumError : 1, 78 | last : 1, 79 | first : 1, 80 | pad2 : 1, 81 | overflowError : 1, 82 | pad3 : 1, 83 | SAFilterFail : 1, 84 | truncatinationOccured : 1, 85 | pad4 : 1, 86 | length : 14, 87 | DAFilterFail : 1, 88 | DMAOwnership : 1; 89 | }; 90 | Natural32 raw; 91 | } status; 92 | union { 93 | struct { 94 | Natural32 bufferSize : 11, 95 | pad0 : 13, 96 | chainMode : 1, 97 | pad1 : 6, 98 | completionInterruptDisable : 1; 99 | }; 100 | Natural32 raw; 101 | } control; 102 | Natural32 bufferAddress, 103 | next; 104 | }; 105 | 106 | union { 107 | struct { 108 | Natural32 fullDuplex : 1, 109 | loopBack : 1, 110 | speed : 2; 111 | }; 112 | Natural32 raw; 113 | } basicControl0; 114 | union { 115 | struct { 116 | Natural32 softReset : 1, 117 | prioritizeRX : 1, 118 | pad0 : 22, 119 | burstLength : 6; 120 | }; 121 | Natural32 raw; 122 | } basicControl1; 123 | const union { 124 | struct { 125 | Natural32 TXCompleted : 1, 126 | TXDMAStopped : 1, 127 | TXDMAOwnership : 1, 128 | TXTimeout : 1, 129 | TXUnderflow : 1, 130 | TXEarly : 1, 131 | pad0 : 2, 132 | RXCompleted : 1, 133 | RXDMAOwnership : 1, 134 | RXDMAStopped : 1, 135 | RXTimeout : 1, 136 | RXOverflow : 1, 137 | RXEarly : 1, 138 | pad1 : 2, 139 | RGMIIStatusChanged : 1; 140 | }; 141 | Natural32 raw; 142 | } interruptStatus, 143 | interruptEnable; 144 | union { 145 | struct { 146 | Natural32 pad0 : 30, 147 | frameLengthControl : 1, 148 | enableTransmitter : 1; 149 | }; 150 | Natural32 raw; 151 | } transmitControl0; 152 | union { 153 | struct { 154 | Natural32 flushFIFODisable : 1, 155 | DMAFIFOThresholdDisable : 1, 156 | undocumented0 : 1, 157 | pad0 : 5, 158 | DMAFIFOThresholdValue : 3, 159 | pad1 : 16, 160 | undocumented1 : 1, 161 | pad2 : 2, 162 | DMAEnable : 1, 163 | DMAStart : 1; 164 | }; 165 | Natural32 raw; 166 | } transmitControl1; 167 | Natural32 pad0; 168 | union { 169 | struct { 170 | Natural32 enable : 1, 171 | zeroQuantaPauseEnable : 1, 172 | pad0 : 2, 173 | pauseTime : 16, 174 | pauseFrameSlot : 2, 175 | pad1 : 9, 176 | pauseFrameActive : 1; 177 | }; 178 | Natural32 raw; 179 | } transmitFlowControl; 180 | Natural32 transmitDMA; 181 | union { 182 | struct { 183 | Natural32 pad0 : 16, 184 | flowControlEnable : 1, 185 | unicastPauseFrameEnable : 1, 186 | pad1 : 9, 187 | checksumEnable : 1, 188 | stripFCSOnShortFrames : 1, 189 | jumboFrameEnable : 1, 190 | truncateFramesDisable : 1, 191 | enableReceiver : 1; 192 | }; 193 | Natural32 raw; 194 | } receiveControl0; 195 | union { 196 | struct { 197 | Natural32 flushFrameDisable : 1, 198 | DMAFIFOThresholdDisable : 1, 199 | forwardShortFrames : 1, 200 | forwardErroredFrames : 1, 201 | DMAFIFOThresholdValue : 2, 202 | pad0 : 14, 203 | flowControlEnableThreshold : 2, 204 | flowControlDisableThreshold : 2, 205 | flowControlThresholdEnable : 1, 206 | pad1 : 5, 207 | DMAEnable : 1, 208 | DMAStart : 1; 209 | }; 210 | Natural32 raw; 211 | } receiveControl1; 212 | Natural32 pad1[2], receiveDMA; 213 | union { 214 | struct { 215 | Natural32 allPass : 1, 216 | hybridFilterMode: 1, 217 | pad0 : 2, 218 | invertDA : 1, 219 | invertSA : 1, 220 | filterSAEnable : 1, 221 | pad1 : 1, 222 | hashUnicastEnable : 1, 223 | hashMulticastEnable : 1, 224 | pad2 : 2, 225 | filterControlFrames : 2, 226 | pad3 : 2, 227 | allMulticastPass : 1, 228 | noBroadcastPass : 1, 229 | pad4 : 13, 230 | addressFilterDisable : 1; 231 | }; 232 | Natural32 raw; 233 | } receiveFrameFilter; 234 | Natural32 pad2, receiveHashTableUpper, receiveHashTableLower; 235 | union { 236 | struct { 237 | Natural32 busy : 1, 238 | writeMode : 1, 239 | pad0 : 2, 240 | registerAddress : 5, 241 | pad1 : 4, 242 | deviceAddress : 5, 243 | pad2 : 3, 244 | MDCClockDivisor : 3; 245 | }; 246 | Natural32 raw; 247 | } MIICommandRegister; 248 | Natural32 MIIData, 249 | MAC0High, MAC0Low; 250 | struct { 251 | struct { 252 | Natural32 high : 16, 253 | pad0 : 8, 254 | byteControlMask: 6, 255 | sourceAddressMode : 1, 256 | enable : 1; 257 | }; 258 | Natural32 low; 259 | } MACx[7]; 260 | Natural32 pad3[8]; 261 | union { 262 | struct { 263 | Natural32 status : 3; 264 | }; 265 | Natural32 raw; 266 | } transmitDMAStatus; 267 | const Natural32 transmitDMACurrentDescriptor; 268 | const Natural32 transmitDMACurrentBuffer; 269 | Natural32 pad4; 270 | union { 271 | struct { 272 | Natural32 status : 3; 273 | }; 274 | Natural32 raw; 275 | } receiveDMAStatus; 276 | const Natural32 receiveDMACurrentDescriptor; 277 | const Natural32 receiveDMACurrentBuffer; 278 | Natural32 pad5; 279 | union { 280 | struct { 281 | Natural32 fullDuplex : 1, 282 | linkSpeed : 2, 283 | linkUp : 1; 284 | }; 285 | Natural32 raw; 286 | } RGMIIStatus; 287 | 288 | void initialize() volatile { 289 | basicControl1.softReset = 1; 290 | while(basicControl1.softReset); 291 | 292 | basicControl0.fullDuplex = 1; 293 | basicControl0.loopBack = 0; 294 | basicControl0.speed = 0; 295 | basicControl1.burstLength = 8; 296 | MIICommandRegister.MDCClockDivisor = 1; 297 | 298 | if(MIIRead(0, 2) != 0x001C || MIIRead(0, 3) != 0xC915) { 299 | puts("[FAIL] RTL8211E-VB"); 300 | return; 301 | } else 302 | puts("[ OK ] RTL8211E-VB"); 303 | 304 | transmitControl0.frameLengthControl = 1; 305 | transmitControl1.flushFIFODisable = 1; 306 | transmitControl1.DMAFIFOThresholdDisable = 1; 307 | transmitControl1.DMAFIFOThresholdValue = 0; 308 | transmitFlowControl.enable = 0; 309 | transmitFlowControl.zeroQuantaPauseEnable = 0; 310 | transmitFlowControl.pauseTime = 0; 311 | transmitFlowControl.pauseFrameSlot = 0; 312 | transmitFlowControl.pauseFrameActive = 0; 313 | 314 | receiveControl0.flowControlEnable = 1; 315 | receiveControl0.unicastPauseFrameEnable = 1; 316 | receiveControl0.checksumEnable = 0; 317 | receiveControl0.stripFCSOnShortFrames = 0; 318 | receiveControl0.jumboFrameEnable = 1; 319 | receiveControl0.truncateFramesDisable = 0; 320 | receiveControl1.flushFrameDisable = 0; 321 | receiveControl1.DMAFIFOThresholdDisable = 0; 322 | receiveControl1.forwardShortFrames = 1; 323 | receiveControl1.forwardErroredFrames = 0; 324 | receiveControl1.DMAFIFOThresholdValue = 1; 325 | receiveControl1.flowControlEnableThreshold = 0; 326 | receiveControl1.flowControlDisableThreshold = 0; 327 | receiveControl1.flowControlThresholdEnable = 0; 328 | 329 | receiveFrameFilter.allPass = 0; 330 | receiveFrameFilter.hybridFilterMode = 0; 331 | receiveFrameFilter.invertDA = 0; 332 | receiveFrameFilter.invertSA = 0; 333 | receiveFrameFilter.filterSAEnable = 0; 334 | receiveFrameFilter.hashUnicastEnable = 0; 335 | receiveFrameFilter.hashMulticastEnable = 0; 336 | receiveFrameFilter.filterControlFrames = 0; 337 | receiveFrameFilter.allMulticastPass = 1; 338 | receiveFrameFilter.noBroadcastPass = 0; 339 | receiveFrameFilter.addressFilterDisable = 0; 340 | } 341 | 342 | Natural16 MIIRead(Natural8 deviceAddress, Natural8 registerAddress) volatile { 343 | MIICommandRegister.deviceAddress = deviceAddress; 344 | MIICommandRegister.registerAddress = registerAddress; 345 | MIICommandRegister.writeMode = 0; 346 | MIICommandRegister.busy = 1; 347 | while(MIICommandRegister.busy); 348 | return MIIData; 349 | } 350 | 351 | void MIIWrite(Natural8 deviceAddress, Natural8 registerAddress, Natural16 data) volatile { 352 | MIIData = data; 353 | MIICommandRegister.deviceAddress = deviceAddress; 354 | MIICommandRegister.registerAddress = registerAddress; 355 | MIICommandRegister.writeMode = 1; 356 | MIICommandRegister.busy = 1; 357 | while(MIICommandRegister.busy); 358 | } 359 | 360 | void enableTransmitter(bool enabled) volatile { 361 | transmitControl0.enableTransmitter = enabled; 362 | transmitControl1.DMAEnable = enabled; 363 | transmitControl1.DMAStart = enabled; 364 | } 365 | 366 | void enableReceiver(bool enabled) volatile { 367 | receiveControl0.enableReceiver = enabled; 368 | receiveControl1.DMAEnable = enabled; 369 | receiveControl1.DMAStart = enabled; 370 | } 371 | 372 | bool link() volatile { 373 | return MIIRead(0, 17)&(1<<10); 374 | } 375 | 376 | Natural32 linkSpeed() volatile { 377 | Natural32 speeds[] = { 10, 100, 1000, 0 }; 378 | return speeds[MIIRead(0, 17)>>14]; 379 | } 380 | 381 | void setMACAddress(Natural8 index, const void* buffer) volatile { 382 | auto dst = reinterpret_cast(&MAC0High)+index*8; 383 | auto src = reinterpret_cast(buffer); 384 | dst[4] = src[0]; 385 | dst[5] = src[1]; 386 | dst[6] = src[2]; 387 | dst[7] = src[3]; 388 | dst[0] = src[4]; 389 | dst[1] = src[5]; 390 | } 391 | 392 | void getMACAddress(Natural8 index, void* buffer) volatile { 393 | auto src = reinterpret_cast(&MAC0High)+index*8; 394 | auto dst = reinterpret_cast(buffer); 395 | dst[0] = src[4]; 396 | dst[1] = src[5]; 397 | dst[2] = src[6]; 398 | dst[3] = src[7]; 399 | dst[4] = src[0]; 400 | dst[5] = src[1]; 401 | } 402 | }; 403 | -------------------------------------------------------------------------------- /include/Hardware/AllwinnerHSTimer.hpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | struct AllwinnerHSTimer { 4 | static const struct Instance { 5 | volatile AllwinnerHSTimer* address; 6 | Natural8 interruptPort; 7 | } instances[]; 8 | static const Natural32 baseFrequency = 200000000; // AHB1 CLK 9 | 10 | union { 11 | struct { 12 | Natural32 hsTimer : 1; 13 | }; 14 | Natural32 raw; 15 | } timerIRQEnable, 16 | timerIRQStatus; 17 | Natural32 pad0[2]; 18 | union { 19 | struct { 20 | Natural32 enable : 1, 21 | reload : 1, 22 | pad0 : 2, 23 | preScale : 3, 24 | oneShot : 1, 25 | pad1 : 23, 26 | testMode : 1; 27 | }; 28 | Natural32 raw; 29 | } control; 30 | Natural32 intervalValueLow, intervalValueHigh, 31 | currentValueLow, currentValueHigh; 32 | 33 | void load(Natural64 value, bool oneShot) volatile { 34 | control.raw &= ~3; 35 | intervalValueLow = static_cast(value); 36 | intervalValueHigh = static_cast(value>>32); 37 | control.preScale = 0; 38 | control.oneShot = oneShot; 39 | control.raw |= 3; 40 | } 41 | 42 | Natural64 getCurrentValue() volatile { 43 | Natural64 currentValue = currentValueLow; 44 | currentValue |= (static_cast(currentValueHigh)<<32); 45 | return currentValue; 46 | } 47 | }; 48 | -------------------------------------------------------------------------------- /include/Hardware/AllwinnerPIO.hpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | struct AllwinnerPIO { 4 | static const struct Instance { 5 | volatile AllwinnerPIO* address; 6 | } instances[]; 7 | 8 | struct { 9 | union { 10 | struct { 11 | Natural32 slot0 : 3, pad0 : 1, slot1 : 3, pad1 : 1, 12 | slot2 : 3, pad2 : 1, slot3 : 3, pad3 : 1, 13 | slot4 : 3, pad4 : 1, slot5 : 3, pad5 : 1, 14 | slot6 : 3, pad6 : 1, slot7 : 3, pad7 : 1; 15 | }; 16 | Natural32 raw; 17 | } configure[4]; 18 | 19 | Natural32 data; 20 | union { 21 | struct { 22 | Natural32 slot0 : 2, slot1 : 2, slot2 : 2, slot3 : 2, 23 | slot4 : 2, slot5 : 2, slot6 : 2, slot7 : 2, 24 | slot8 : 2, slot9 : 2, slot10 : 2, slot11 : 2, 25 | slot12 : 2, slot13 : 2, slot14 : 2, slot15 : 2; 26 | }; 27 | Natural32 raw; 28 | } multiDriving[2]; 29 | union { 30 | struct { 31 | Natural32 slot0 : 2, slot1 : 2, slot2 : 2, slot3 : 2, 32 | slot4 : 2, slot5 : 2, slot6 : 2, slot7 : 2, 33 | slot8 : 2, slot9 : 2, slot10 : 2, slot11 : 2, 34 | slot12 : 2, slot13 : 2, slot14 : 2, slot15 : 2; 35 | }; 36 | Natural32 raw; 37 | } pull[2]; 38 | } banks[8]; 39 | Natural8 pad0[224]; 40 | struct { 41 | Natural32 42 | PIOInterrruptConfigure[4], 43 | PIOInterruptControl, 44 | PIOInterruptStatus, 45 | PIOInterruptDebounce, 46 | pad0; 47 | } interruptBanks[3]; 48 | }; 49 | -------------------------------------------------------------------------------- /include/Hardware/AllwinnerPRCM.hpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | struct AllwinnerPRCM { 4 | static const struct Instance { 5 | volatile AllwinnerPRCM* address; 6 | } instances[]; 7 | 8 | Natural32 9 | CPUSReset, 10 | Cluster0CPUXResetControl, 11 | Cluster1CPUXResetControl, 12 | pad0, 13 | CPUSClockConfiguration, 14 | pad1[2], 15 | APBSClockDivide, 16 | pad2[2], 17 | APBSClockGating, 18 | pad3[6], 19 | PLLControl, 20 | pad4[2], 21 | R_ONE_WIREClock, 22 | R_CIR_RXClock, 23 | R_DAUDIO0Clock, 24 | R_DAUDIO1Clock, 25 | pad5[20], 26 | APBSSoftwareReset, 27 | pad6[19], 28 | Cluster0CPUXPowerOffGating, 29 | Cluster1CPUXPowerOffGating, 30 | pad7[2], 31 | VDD_SYSPowerOffGating, 32 | pad8, 33 | GPUPowerOffGating, 34 | pad9, 35 | VDD_SYSReset, 36 | pad10[7], 37 | Cluster0CPUPowerSwitch[4], 38 | Cluster1CPUPowerSwitch[4], 39 | SuperStandbyFlag, 40 | CPUSoftwareEntry, 41 | SuperStandbySoftwareEntry, 42 | pad11[13], 43 | NMIIRQControl, 44 | NMIIRQEnable, 45 | NMIIRQStatus, 46 | pad12[5], 47 | PLL_AUDIOControl, 48 | PLL_AUDIOBias, 49 | PLL_AUDIOPatternControl, 50 | AUDIO_PLLControlSwitch, 51 | pad13[8], 52 | R_PIOHoldControl, 53 | OSC24MControl; 54 | }; 55 | -------------------------------------------------------------------------------- /include/Hardware/AllwinnerRSB.hpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | struct AllwinnerRSB { 4 | static const struct Instance { 5 | volatile AllwinnerRSB* address; 6 | Natural8 interruptPort; 7 | } instances[]; 8 | 9 | union { 10 | struct { 11 | Natural32 softReset : 1, 12 | globalInterruptEnable : 1, 13 | pad0 : 4, 14 | abortTransmission : 1, 15 | startTransmission : 1; 16 | }; 17 | Natural32 raw; 18 | } control; 19 | union { 20 | struct { 21 | Natural32 divisor : 8, 22 | delay : 3; 23 | }; 24 | Natural32 raw; 25 | } clockControl; 26 | union { 27 | struct { 28 | Natural32 transferComplete : 1, 29 | transferError : 1, 30 | loadingBusy : 1, 31 | pad0 : 5, 32 | errorData : 4, 33 | pad1 : 4, 34 | errorAcknowledgement : 1; 35 | }; 36 | Natural32 raw; 37 | } interruptEnable, 38 | status; 39 | union { 40 | Natural8 byte; 41 | Natural32 raw; 42 | } dataAddress; 43 | Natural32 pad0; 44 | union { 45 | struct { 46 | Natural32 bytesMinusOne : 3, 47 | pad0 : 1, 48 | read : 1; 49 | }; 50 | Natural32 raw; 51 | } dataLength; 52 | Natural32 dataBuffer, pad1; 53 | union { 54 | struct { 55 | Natural32 cdEnable : 1, 56 | cdBit : 1, 57 | ckEnable : 1, 58 | ckBit : 1, 59 | cdState : 1, 60 | ckState : 1; 61 | }; 62 | Natural32 raw; 63 | } lineControl; 64 | // PMU : performance monitoring unit 65 | union { 66 | struct { 67 | Natural32 deviceAddress : 8, 68 | modeControlRegisterAddress : 8, 69 | initialData : 8, 70 | pad0 : 7, 71 | start : 1; 72 | }; 73 | Natural32 raw; 74 | } pmuModeControl; 75 | union { 76 | Natural8 byte; 77 | Natural32 raw; 78 | } command; 79 | union { 80 | struct { 81 | Natural32 hardwareAddress : 16, 82 | runTimeAddress : 8; 83 | }; 84 | Natural32 raw; 85 | } deviceAddress; 86 | 87 | bool initialize() volatile { 88 | clockControl.divisor = 3; 89 | clockControl.delay = 1; 90 | control.softReset = 1; 91 | while(control.softReset); 92 | 93 | pmuModeControl.raw = 0x807C3E00; 94 | while(pmuModeControl.start); 95 | if(status.transferError || !status.transferComplete) { 96 | puts("[FAIL] RSB DMC"); 97 | return false; 98 | } else { 99 | puts("[ OK ] RSB DMC"); 100 | return true; 101 | } 102 | } 103 | bool transfer(Natural8 cmd) volatile { 104 | command.byte = cmd; 105 | control.startTransmission = 1; 106 | while(control.startTransmission); 107 | if(status.transferError || !status.transferComplete) { 108 | puts("[FAIL] RSB transfer"); 109 | return false; 110 | } else 111 | return true; 112 | } 113 | bool setRunTimeAddress() volatile { 114 | return transfer(0xE8); 115 | } 116 | bool transfer(Natural8 cmd, Natural8 address) volatile { 117 | dataAddress.byte = address; 118 | return transfer(cmd); 119 | } 120 | bool read(Natural8 address, Natural8& data) volatile { 121 | bool success = transfer(0x8B, address); 122 | data = dataBuffer; 123 | return success; 124 | } 125 | bool read(Natural8 address, Natural16& data) volatile { 126 | bool success = transfer(0x9C, address); 127 | data = dataBuffer; 128 | return success; 129 | } 130 | bool read(Natural8 address, Natural32& data) volatile { 131 | bool success = transfer(0xA6, address); 132 | data = dataBuffer; 133 | return success; 134 | } 135 | bool write(Natural8 address, Natural8 data) volatile { 136 | dataBuffer = data; 137 | return transfer(0x4E, address); 138 | } 139 | bool write(Natural8 address, Natural16 data) volatile { 140 | dataBuffer = data; 141 | return transfer(0x59, address); 142 | } 143 | bool write(Natural8 address, Natural32 data) volatile { 144 | dataBuffer = data; 145 | return transfer(0x63, address); 146 | } 147 | }; 148 | -------------------------------------------------------------------------------- /include/Hardware/AllwinnerSMHC.hpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | struct AllwinnerSMHC { 4 | static const struct Instance { 5 | volatile AllwinnerSMHC* address; 6 | } instances[]; 7 | 8 | struct Descriptor { 9 | union { 10 | struct { 11 | Natural32 pad0 : 1, 12 | interruptOnCompletionDisable : 1, 13 | last : 1, 14 | first : 1, 15 | chainMode : 1, 16 | pad1 : 25, 17 | error : 1, 18 | DMAOwnership : 1; 19 | }; 20 | Natural32 raw; 21 | } status; 22 | union { 23 | struct { 24 | Natural32 bufferSize : 15; 25 | }; 26 | Natural32 raw; 27 | } control; 28 | Natural32 bufferAddress, 29 | next; 30 | }; 31 | 32 | union { 33 | struct { 34 | Natural32 softwareReset : 1, 35 | FIFOReset : 1, 36 | DMAReset : 1, 37 | pad0 : 1, 38 | globalInterruptEnable : 1, 39 | globalDMAEnable : 1, 40 | pad1 : 2, 41 | deBounceEnable : 1, 42 | pad2 : 1, 43 | DDRModeSelect : 1, 44 | dataLineTimeUnit : 1, 45 | commandLineTimeUnit : 1, 46 | pad3 : 18, 47 | FIFOAccessMode : 1; 48 | }; 49 | Natural32 raw; 50 | } control; 51 | union { 52 | struct { 53 | Natural32 cardClockDivisor : 8, 54 | pad0 : 8, 55 | cardClockEnable : 1, 56 | cardClockOutputControl : 1, 57 | pad1 : 13, 58 | maskData0 : 1; 59 | }; 60 | Natural32 raw; 61 | } clockControl; 62 | union { 63 | struct { 64 | Natural32 response : 8, 65 | data : 24; 66 | }; 67 | Natural32 raw; 68 | } timeout; 69 | union { 70 | struct { 71 | Natural32 cardWidth : 2; 72 | }; 73 | Natural32 raw; 74 | } busWidth; 75 | union { 76 | struct { 77 | Natural32 blockSize : 16; 78 | }; 79 | Natural32 raw; 80 | } blockSize; 81 | Natural32 byteCount; 82 | union { 83 | struct { 84 | Natural32 commandIndex : 6, 85 | responseReceiveEnable : 1, 86 | longResponse : 1, 87 | checkResponseCRC : 1, 88 | dataTransferEnable : 1, 89 | writeMode : 1, 90 | transferMode : 1, 91 | stopAutomaticEnable : 1, 92 | waitForPending : 1, 93 | stopAbortCommand : 1, 94 | sendInitialization : 1, 95 | pad0 : 5, 96 | changeClock : 1, 97 | pad1 : 2, 98 | bootMode : 2, 99 | expectBootAcknowledge : 1, 100 | bootAbort : 1, 101 | voltageSwitch : 1, 102 | pad2 : 2, 103 | start : 1; 104 | }; 105 | Natural32 raw; 106 | } command; 107 | Natural32 commandArgument, response[4]; 108 | union { 109 | struct { 110 | Natural32 pad0 : 1, 111 | responseError : 1, 112 | commandComplete : 1, 113 | dataTransferComplete : 1, 114 | dataTransmitRequest : 1, 115 | dataReceiveRequest : 1, 116 | responseCRCError : 1, 117 | dataCRCError : 1, 118 | responseTimout : 1, 119 | dataTimeout : 1, 120 | dataStarvationTimeout : 1, 121 | FIFO : 1, 122 | commandBusy : 1, 123 | dataStartError : 1, 124 | autoCommandDone : 1, 125 | dataEndBitError : 1, 126 | SDIO : 1, 127 | pad1 : 13, 128 | cardInserted : 1, 129 | cardRemoved : 1; 130 | }; 131 | Natural32 raw; 132 | } interruptMask, 133 | maskedInterruptStatus, 134 | rawInterruptStatus; 135 | union { 136 | struct { 137 | Natural32 FIFOReceiveReachedThreshold : 1, 138 | FIFOTransmitReachedThreshold : 1, 139 | FIFOEmpty : 1, 140 | FIFOFull : 1, 141 | commandFSM : 4, 142 | cardPresent : 1, 143 | cardDataBusy : 1, 144 | dataFSMBusy : 1, 145 | responseIndex : 6, 146 | FIFOLevel : 9, 147 | pad0 : 5, 148 | DMARequestSignalState : 1; 149 | }; 150 | Natural32 raw; 151 | } status; 152 | union { 153 | struct { 154 | Natural32 transmitTriggerLevel : 8, 155 | pad0 : 8, 156 | receiveTriggerLevel : 8, 157 | pad1 : 4, 158 | burstSize : 4; 159 | }; 160 | Natural32 raw; 161 | } FIFOThreshold; 162 | union { 163 | struct { 164 | Natural32 hostSendMMCIRQResponse : 1, 165 | SDIOReadWait : 1, 166 | abortReadData : 1; 167 | }; 168 | Natural32 raw; 169 | } FIFOFunctionSelect; 170 | Natural32 transferredCounter[2], pad0; 171 | union { 172 | struct { 173 | Natural32 speedMode : 4; 174 | }; 175 | Natural32 raw; 176 | } CRCStatusDetectControl; 177 | union { 178 | struct { 179 | Natural32 argument : 16; 180 | }; 181 | Natural32 raw; 182 | } autoCommand12; 183 | union { 184 | struct { 185 | Natural32 pad0 : 4, 186 | sampleTimingPhase : 2, 187 | pad1 : 25, 188 | modeSelect : 1; 189 | }; 190 | Natural32 raw; 191 | } SDNewTimingSet; 192 | Natural32 pad1[6]; 193 | union { 194 | struct { 195 | Natural32 reset : 1; 196 | }; 197 | Natural32 raw; 198 | } hardware; 199 | Natural32 pad2; 200 | union { 201 | struct { 202 | Natural32 reset : 1, 203 | fixedBurst : 1, 204 | pad0 : 5, 205 | IDMACEnable : 1, 206 | pad1 : 23, 207 | start : 1; 208 | }; 209 | Natural32 raw; 210 | } DMAControl; 211 | Natural32 descriptorListBaseAddress; 212 | union { 213 | struct { 214 | Natural32 transmit : 1, 215 | receive : 1, 216 | fatalBusError : 1, 217 | pad0 : 1, 218 | DMAOwnership : 1, 219 | cardErrorSummary : 1, 220 | pad1 : 2, 221 | normalInterruptSummary : 1, 222 | abnormalInterruptSummary : 1, 223 | errorBits : 3; 224 | }; 225 | Natural32 raw; 226 | } DMACStatus, DMACInterruptEnable; 227 | Natural32 pad3[28]; 228 | union { 229 | struct { 230 | Natural32 cardReadThresholdEnable : 1, 231 | busyClearInterruptGeneration : 1, 232 | cardWriteThresholdEnable : 1, 233 | pad0 : 13, 234 | cardReadThreshold : 12; 235 | }; 236 | Natural32 raw; 237 | } cardThresholdControl; 238 | Natural32 pad4[2]; 239 | union { 240 | struct { 241 | Natural32 halfStart : 1, 242 | pad0 : 30, 243 | HS400Enable : 1; 244 | }; 245 | Natural32 raw; 246 | } eMMC45DDRStartBitDetectionControl; 247 | union { 248 | struct { 249 | Natural32 fromDevice : 7; 250 | }; 251 | Natural32 raw; 252 | } responseCRC; 253 | Natural32 CRCInDataFromDevice[8]; 254 | union { 255 | struct { 256 | Natural32 fromDeviceInWriteOperation : 3; 257 | }; 258 | Natural32 raw; 259 | } CRCStatus; 260 | Natural32 pad5[2]; 261 | union { 262 | struct { 263 | Natural32 pad0 : 16, 264 | commandDrivePhase : 1, 265 | dataDrivePhase : 1; 266 | }; 267 | Natural32 raw; 268 | } driveDelayControl; 269 | union { 270 | struct { 271 | Natural32 softwareSampleDelay : 6, 272 | pad0 : 1, 273 | softwareSampleDelayEnable : 1, 274 | sampleDelay : 6, 275 | sampleDelayCalibrationDone : 1, 276 | sampleDelayCalibrationStart : 1; 277 | }; 278 | Natural32 raw; 279 | } sampleDelayControl; 280 | union { 281 | struct { 282 | Natural32 softwareDataStrobeDelay : 6, 283 | pad0 : 1, 284 | softwareDataStrobeDelayEnable : 1, 285 | dataStrobeDelay : 6, 286 | dataStrobeDelayCalibrationDone : 1, 287 | dataStrobeDelayCalibrationStart : 1; 288 | }; 289 | Natural32 raw; 290 | } dataStrobeDelayControl; 291 | Natural32 pad6[45]; 292 | Natural32 readWriteFIFO; 293 | 294 | void initialize() volatile { 295 | // sampleDelayControl.raw = 0xA0; 296 | sampleDelayControl.softwareSampleDelay = 32; 297 | sampleDelayControl.softwareSampleDelayEnable = 1; 298 | sampleDelayControl.raw = 0; 299 | 300 | sampleDelayControl.sampleDelayCalibrationStart = 1; 301 | while(!sampleDelayControl.sampleDelayCalibrationDone); 302 | 303 | // TODO: Step6: Calculate the delay time of one delay cell according to the cycle of SMHC’s clock and the result of calibration. 304 | } 305 | }; 306 | -------------------------------------------------------------------------------- /include/Hardware/AllwinnerSYSCTL.hpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | struct AllwinnerSYSCTL { 4 | static const struct Instance { 5 | volatile AllwinnerSYSCTL* address; 6 | } instances[]; 7 | 8 | Natural32 pad0[9]; 9 | union { 10 | struct { 11 | Natural32 version : 8, 12 | bootSelectPinStatus : 1; 13 | }; 14 | Natural32 raw; 15 | } versionRegister; 16 | Natural32 pad1[2]; 17 | union { 18 | struct { 19 | Natural32 clockSource : 2, 20 | phyInterface : 1, 21 | invertTransmitClock : 1, 22 | invertReceiveClock : 1, 23 | receiveClockDelayChain : 5, 24 | transmitClockDelayChain : 3, 25 | RMIIEnable : 1; 26 | }; 27 | Natural32 raw; 28 | } EMACClock; 29 | }; 30 | -------------------------------------------------------------------------------- /include/Hardware/AllwinnerTimer.hpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | struct AllwinnerTimer { 4 | static const struct Instance { 5 | volatile AllwinnerTimer* address; 6 | Natural8 interruptPorts[2]; 7 | } instances[]; 8 | 9 | union { 10 | struct { 11 | Natural32 timer0 : 1, 12 | timer1 : 1; 13 | }; 14 | Natural32 raw; 15 | } timerIRQEnable, timerIRQStatus; 16 | Natural32 pad0[2]; 17 | struct { 18 | union { 19 | struct { 20 | Natural32 enable : 1, 21 | reload : 1, 22 | clockSource : 2, 23 | preScale : 3, 24 | mode : 1; 25 | }; 26 | Natural32 raw; 27 | } control; 28 | Natural32 intervalValue, currentValue, pad0; 29 | } timer[2]; 30 | Natural32 pad1[20]; 31 | union { 32 | struct { 33 | Natural32 counter0Enable : 1, 34 | counter1Enable : 1, 35 | pad0 : 6, 36 | counter0Pause : 1, 37 | counter1Pause : 1; 38 | }; 39 | Natural32 raw; 40 | } AVSControl; 41 | Natural32 AVSCounter[2]; 42 | union { 43 | struct { 44 | Natural32 counter0 : 12, 45 | pad0 : 4, 46 | counter1 : 12; 47 | }; 48 | Natural32 raw; 49 | } AVSDivisor; 50 | Natural32 pad2[4]; 51 | union { 52 | struct { 53 | Natural32 enable : 1; 54 | }; 55 | Natural32 raw; 56 | } watchdogIRQEnable; 57 | union { 58 | struct { 59 | Natural32 pending : 1; 60 | }; 61 | Natural32 raw; 62 | } watchdogIRQStatus; 63 | Natural32 pad3[2]; 64 | union { 65 | struct { 66 | Natural32 restart : 1, 67 | key : 12; // 0xA57 68 | }; 69 | Natural32 raw; 70 | } watchdogControl; 71 | union { 72 | struct { 73 | Natural32 configuration : 2; 74 | }; 75 | Natural32 raw; 76 | } watchdogConfiguration; 77 | union { 78 | struct { 79 | Natural32 enable : 1, 80 | pad : 3, 81 | intervalValue : 4; 82 | }; 83 | Natural32 raw; 84 | } watchdogMode; 85 | }; 86 | -------------------------------------------------------------------------------- /include/Hardware/AllwinnerUART.hpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | struct AllwinnerUART { 4 | static const struct Instance { 5 | volatile AllwinnerUART* address; 6 | Natural8 interruptPort, DMAPort; 7 | } instances[]; 8 | 9 | enum InterruptID { 10 | None = 1, 11 | ReceiverLineStatus = 6, 12 | ReceivedDataAvailable = 4, 13 | CharacterTimeoutIndication = 12, 14 | TransmitHoldingRegisterEmpty = 2, 15 | ModemStatus = 0, 16 | BusyDetectIndication = 7 17 | }; 18 | 19 | union { 20 | Natural8 receiverBuffer, transmitHolding, 21 | divisorLatchLow; 22 | Natural32 pad0; 23 | }; 24 | union { 25 | struct { 26 | Natural32 receivedDataAvailable : 1, 27 | transmitHoldingRegisterEmpty : 1, 28 | receiverLineStatus : 1, 29 | modemStatus : 1, 30 | pad0 : 3, 31 | programmableTHREInterruptMode : 1; 32 | } interruptEnable; 33 | Natural8 divisorLatchHigh; 34 | }; 35 | union { 36 | const struct { 37 | InterruptID interruptID : 4; 38 | Natural32 pad0 : 2, 39 | FIFOsEnabled : 2; 40 | } interruptIdentity; 41 | struct { 42 | Natural32 enable : 1, 43 | receiveReset : 1, 44 | transmitReset : 1, 45 | DMAMode : 1, 46 | transmitEmptyTrigger : 2, 47 | receiveTrigger : 2; 48 | } FIFOControl; 49 | }; 50 | union { 51 | struct { 52 | Natural32 dataLengthSelect : 2, 53 | numberOfStopBits : 1, 54 | parityEnable : 1, 55 | evenParitySelect : 2, 56 | breakControlBit : 1, 57 | divisorLatchAccessBit : 1; 58 | }; 59 | Natural32 raw; 60 | } lineControl; 61 | union { 62 | struct { 63 | Natural32 dataTerminalReady : 1, 64 | requestToSend : 1, 65 | pad0 : 2, 66 | loopBackMode : 1, 67 | autoFlowControlEnable : 1, 68 | IrDASIRModeEnable : 1; 69 | }; 70 | Natural32 raw; 71 | } modemControl; 72 | const union { 73 | struct { 74 | Natural32 dataReady : 1, 75 | overrunError : 1, 76 | parityError : 1, 77 | framingError : 1, 78 | breakInterrupt : 1, 79 | transmitHoldingRegisterEmpty : 1, 80 | transmitterEmpty : 1, 81 | receiveDataErrorInFIFO : 1; 82 | }; 83 | Natural32 raw; 84 | } lineStatus; 85 | const union { 86 | struct { 87 | Natural32 deltaClearToSend : 1, 88 | deltaDataSetReady : 1, 89 | trailingEdgeRingIndicator : 1, 90 | deltaDataCarrierDetect : 1, 91 | lineStateOfClearToSend : 1, 92 | lineStateOfDataSetReady : 1, 93 | lineStateOfRingIndicator : 1, 94 | lineStateOfDataCarrierDetect : 1; 95 | }; 96 | Natural32 raw; 97 | } modemStatus; 98 | const Natural8 pad1[96]; 99 | const union { 100 | struct { 101 | Natural32 busy : 1, 102 | transmitFIFONotFull : 1, 103 | transmitFIFOEmpty : 1, 104 | receiveFIFONotEmpty : 1, 105 | receiveFIFOFull : 1; 106 | }; 107 | Natural32 raw; 108 | } status; 109 | const union { 110 | struct { 111 | Natural32 level : 6; 112 | }; 113 | Natural32 raw; 114 | } transmitFIFOLevel, receiveFIFOLevel; 115 | const Natural8 pad2[28]; 116 | union { 117 | struct { 118 | Natural32 haltTransmit : 1, 119 | changeWhileBusyEnable : 1, 120 | changeWhileBusyUpdate : 1, 121 | pad0 : 1, 122 | SIRTransmitPulsePolarityInvert : 1, 123 | SIRReceivePulsePolarityInvert : 1; 124 | }; 125 | Natural32 raw; 126 | } halt; 127 | 128 | void initialize() volatile { 129 | halt.haltTransmit = 1; 130 | lineControl.divisorLatchAccessBit = 1; 131 | divisorLatchHigh = 0; 132 | divisorLatchLow = 13; // 24000000 Hz / (16 * 115200 baud) 133 | lineControl.divisorLatchAccessBit = 0; 134 | lineControl.dataLengthSelect = 3; 135 | // FIFOControl.enable = 1; 136 | // FIFOControl.receiveReset = 1; 137 | // FIFOControl.transmitReset = 1; 138 | halt.haltTransmit = 0; 139 | 140 | ::puts("[ OK ] UART0"); 141 | } 142 | Natural8 getc() volatile { 143 | while(!lineStatus.dataReady); 144 | return receiverBuffer; 145 | } 146 | void putc(Natural8 value) volatile { 147 | while(!lineStatus.transmitHoldingRegisterEmpty); 148 | transmitHolding = value; 149 | } 150 | template 151 | void putHex(Type value) volatile { 152 | static_assert(sizeof(value)*8 < 256); 153 | for(Natural8 i = sizeof(value)*8; i > 0; i -= 4) { 154 | Natural8 nibble = (value>>(i-4))&0xF; 155 | putc((nibble < 0xA) ? nibble+'0' : nibble-0xA+'A'); 156 | } 157 | } 158 | template 159 | void putDec(Type value) volatile { 160 | const Type base = 10; 161 | if(value == 0) { 162 | putc('0'); 163 | return; 164 | } 165 | if(value < 0) { 166 | putc('-'); 167 | value *= -1; 168 | } 169 | Type mask = 1; 170 | while(mask <= value) 171 | mask *= base; 172 | while(mask > 0.001) { 173 | if(mask == 1 && value > 0) 174 | putc('.'); 175 | mask /= base; 176 | if(mask == 0) 177 | break; 178 | Type digit = value/mask; 179 | digit = static_cast(digit); 180 | value -= digit*mask; 181 | putc('0'+digit); 182 | } 183 | } 184 | void puts(const char* str) volatile { 185 | while(*str) 186 | putc(*str++); 187 | } 188 | }; 189 | 190 | void puts(const char* str) { 191 | auto uart = AllwinnerUART::instances[0].address; 192 | uart->puts(str); 193 | uart->putc('\r'); 194 | uart->putc('\n'); 195 | } 196 | -------------------------------------------------------------------------------- /include/Hardware/GICPL400.hpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | struct GICPL400 { 4 | static const struct Instance { 5 | volatile GICPL400* address; 6 | } instances[]; 7 | 8 | Natural32 pad0[1024]; 9 | union { 10 | struct { 11 | Natural32 enable : 1; 12 | }; 13 | Natural32 raw; 14 | } distributorControl; 15 | union { 16 | struct { 17 | Natural32 ITLinesNumber : 5, 18 | CPUNumber : 3, 19 | pad0 : 2, 20 | securityExtensions : 1, 21 | LSPI : 5; 22 | }; 23 | Natural32 raw; 24 | } interruptControllerType; 25 | Natural32 distributorImplementerIdentification, 26 | pad1[29], 27 | interruptSecurity[32], 28 | interruptSetEnable[32], 29 | interruptClearEnable[32], 30 | interruptSetPending[32], 31 | interruptClearPending[32], 32 | activeBit[32], 33 | pad2[32], 34 | interruptPriority[256], 35 | interruptProcessorTargets[256], 36 | interruptConfiguration[64], 37 | privatePeripheralInterruptStatus, 38 | sharedPeripheralInterruptStatus[15], 39 | pad3[112]; 40 | union { 41 | struct { 42 | Natural32 SGIInterruptId : 4, 43 | pad0 : 11, 44 | SATT : 1, 45 | CPUTargetList : 8, 46 | targetListFilter : 2; 47 | }; 48 | Natural32 raw; 49 | } softwareGeneratedInterrupt; 50 | Natural32 softwareGeneratedInterruptClearPending, 51 | softwareGeneratedInterruptSetPending, 52 | pad4[61], 53 | CPUInterfaceControl, 54 | interruptPriorityMask, 55 | binaryPoint, 56 | interruptAcknowledge, 57 | endOfInterrupt, 58 | runningPriority, 59 | highestPendingInterrupt, 60 | aliasedBinaryPoint, 61 | aliasedInterruptAcknowledge, 62 | aliasedEndOfInterrupt, 63 | aliasedHighestPriorityPendingInterrupt, 64 | pad5[41], 65 | activePriority, 66 | pad6[3], 67 | nonSecureActivePriority, 68 | pad7[6], 69 | CPUInterfaceIdentification, 70 | pad8[960], 71 | deactivateInterrupt; 72 | }; 73 | -------------------------------------------------------------------------------- /include/Kernel.hpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | void main(); 4 | 5 | extern "C" { 6 | void _start() { 7 | main(); 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /include/Memory/AArch64Cache.hpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | namespace Cache { 4 | 5 | enum Level { 6 | L1UnifiedCache = 0, 7 | L1DataCache = 0, 8 | L1InstructionCache = 1, 9 | L2UnifiedCache = 2, 10 | L2DataCache = 2, 11 | L2InstructionCache = 3, 12 | L3UnifiedCache = 4, 13 | L3DataCache = 4, 14 | L3InstructionCache = 5 15 | }; 16 | 17 | void getSizesOfLevel(Level level, Natural32& setCountMinus1, Natural32& wayCountMinus1, Natural32& lineBytesLog2) { 18 | Natural32 cacheSizeIDRegister; 19 | asm volatile( 20 | "msr CSSELR_EL1, %x1\n" 21 | "isb\n" 22 | "mrs %x0, CCSIDR_EL1\n" : "=r"(cacheSizeIDRegister) : "r"(level) 23 | ); 24 | setCountMinus1 = (cacheSizeIDRegister>>13)&0x7FFF; 25 | wayCountMinus1 = (cacheSizeIDRegister>>3)&0x3FF; 26 | lineBytesLog2 = (cacheSizeIDRegister&0x7)+4; 27 | } 28 | 29 | #define offsetCountDownLoop(index, maxIndex, offset, inner) { \ 30 | index = maxIndex< 0); \ 35 | } 36 | 37 | void invalidateLevel(Level level) { 38 | if(level == L1InstructionCache) 39 | asm volatile("ic iallu\n"); 40 | else if((level&1) == 0) { 41 | Natural32 wayIndex, wayMaxIndex, wayOffset, setIndex, setMaxIndex, setOffset; 42 | getSizesOfLevel(level, setMaxIndex, wayMaxIndex, setOffset); 43 | wayOffset = __builtin_clz(wayMaxIndex); 44 | offsetCountDownLoop(wayIndex, wayMaxIndex, wayOffset, 45 | offsetCountDownLoop(setIndex, setMaxIndex, setOffset, 46 | asm volatile("dc isw, %x0\n" : : "r"(wayIndex|setIndex|level)); 47 | ); 48 | ); 49 | asm volatile("dsb sy\n"); 50 | } 51 | } 52 | 53 | void invalidateTLB() { 54 | asm volatile("tlbi alle3\n"); 55 | } 56 | 57 | void invalidateAll() { 58 | Natural32 cacheLevelIDRegister, level, levelEnd, cacheType; 59 | asm volatile("mrs %x0, CLIDR_EL1\n" : "=r"(cacheLevelIDRegister)); 60 | levelEnd = (cacheLevelIDRegister>>23)&0x7; 61 | for(level = 0; level < levelEnd; ++level) { 62 | cacheType = (cacheLevelIDRegister>>(level/2*3))&0x7; 63 | if(cacheType >= 2) 64 | invalidateLevel(static_cast(level)); 65 | } 66 | invalidateTLB(); 67 | } 68 | 69 | void setActive(bool mmu, bool data, bool instruction) { 70 | asm volatile( 71 | "msr SCTLR_EL3, %x0\n" 72 | "isb\n" : : "r"( 73 | (mmu<<0)| 74 | (1<<1)| // Enable alignment fault check 75 | (data<<2)| 76 | (1<<3)| // Enable stack alignment check 77 | (instruction<<12) 78 | )); 79 | } 80 | 81 | void preFetch(void* address) { 82 | asm volatile("prfm pldl1keep, [%x0]\n" : : "r"(address)); 83 | } 84 | 85 | void ensureRead(void* address) { 86 | asm volatile("dc ivac, %x0\n" : : "r"(address)); 87 | } 88 | 89 | void ensureWrite(void* address) { 90 | asm volatile("dmb st\ndc cvac, %x0\n" : : "r"(address)); 91 | } 92 | 93 | }; 94 | -------------------------------------------------------------------------------- /include/Memory/AArch64MMU.hpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | namespace MMU { 4 | const Natural64 attributePalette = 0x0000FFBB440C0400; 5 | 6 | enum AttributeIndex { 7 | DeviceNGNRNE = 0, 8 | DeviceNGNRE = 1, 9 | DeviceGRE = 2, 10 | NonCacheable = 3, 11 | WriteThrough = 4, // Outer and inner, read-write-allocate 12 | WriteBack = 5 // Outer and inner, read-write-allocate 13 | }; 14 | 15 | enum Shareability { 16 | NonShareable = 0, 17 | OuterShareable = 2, 18 | InnerShareable = 3 19 | }; 20 | 21 | union PageTableEntry { 22 | struct { 23 | Natural64 valid : 1, 24 | nextLevelEnabled : 1, 25 | lastLevelAttributeIndex : 3, 26 | lastLevelNonSecure : 1, 27 | lastLevelAccessPermissions : 2, 28 | lastLevelShareability : 2, 29 | lastLevelAccessFlag : 1, 30 | lastLevelNotGlobal : 1, 31 | address : 36, 32 | pad0 : 4, 33 | lastLevelContiguous : 1, 34 | lastLevelPrivilegedExecuteNever : 1, 35 | lastLevelExecuteNever : 1, 36 | lastLevelSoftwareDefined : 4, 37 | nextLevelPrivilegedExecuteNever : 1, 38 | nextLevelExecuteNever : 1, 39 | nextLevelAccessPermissions : 2, 40 | nextLevelNonSecure : 1; 41 | }; 42 | Natural64 raw; 43 | }; 44 | 45 | enum Granularity { 46 | Granule4KiB = 9, 47 | Granule16KiB = 11, 48 | Granule64KiB = 13 49 | }; 50 | 51 | template 52 | struct PageTable { 53 | PageTableEntry entries[1<(dram)+(1ULL<getDRAMSize()); 60 | auto level2Table = reinterpret_cast*>(dramEnd-sizeof(PageTable)); 61 | 62 | for(Natural16 index = 0; index < 8192; ++index) { 63 | auto entry = &level2Table->entries[index]; 64 | entry->raw = 0x20000000*index; 65 | entry->lastLevelAccessFlag = 1; 66 | } 67 | 68 | auto entry = &level2Table->entries[0]; 69 | entry->valid = 1; 70 | entry->lastLevelAttributeIndex = DeviceNGNRE; 71 | entry->lastLevelShareability = OuterShareable; 72 | 73 | for(Natural16 index = 2; index < 6; ++index) { 74 | entry = &level2Table->entries[index]; 75 | entry->valid = 1; 76 | entry->lastLevelAttributeIndex = WriteBack; 77 | entry->lastLevelShareability = InnerShareable; 78 | } 79 | 80 | entry = &level2Table->entries[5]; 81 | entry->lastLevelAttributeIndex = WriteThrough; // For DMA area 82 | 83 | asm volatile( 84 | "dmb st\n" 85 | "msr TTBR0_EL3, %x0\n" 86 | "msr MAIR_EL3, %x1\n" 87 | "msr TCR_EL3, %x2\n" 88 | "isb\n" : : "r"(level2Table), "r"(attributePalette), "r"( 89 | (64-32)| // Starting at level 2 90 | (3<< 8)| // Inner cacheability: Normal memory, Inner Write-Back no Write-Allocate Cacheable 91 | (3<<10)| // Outer cacheability: Normal memory, Outer Write-Back no Write-Allocate Cacheable 92 | (3<<12)| // Shareability: Inner shareable 93 | (1<<14)| // Granule size: 64 KiB 94 | (0<<16)| // Physical address space: 4 GiB 95 | (0<<20) // Top byte used in the address calculation 96 | )); 97 | 98 | Cache::setActive(true, true, true); 99 | puts("[ OK ] MMU, TLB and caches"); 100 | 101 | return reinterpret_cast(level2Table); 102 | } 103 | }; 104 | -------------------------------------------------------------------------------- /include/Net/Icmp.hpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #define IcmpReceivedCase(PayloadType) \ 4 | case PayloadType::type: \ 5 | reinterpret_cast(icmpPacket->payload)->received(macInterface, macFrame, ipPacket, icmpPacket); \ 6 | break; 7 | 8 | struct Icmpv4 { 9 | static constexpr Natural8 protocolID = 1; 10 | 11 | struct Packet { 12 | Natural8 type, code; 13 | Natural16 checksum; 14 | Natural8 payload[0]; 15 | 16 | void prepareTransmit(Ipv4::Packet* ipPacket, Natural16 payloadLength) { 17 | ipPacket->protocol = protocolID; 18 | ipPacket->totalLength = sizeof(Packet)+payloadLength; 19 | checksum = 0; 20 | checksum = ipPacket->payloadChecksum(); 21 | } 22 | }; 23 | 24 | static void received(Mac::Interface* macInterface, Mac::Frame* macFrame, Ipv4::Packet* ipPacket, Packet* icmpPacket); 25 | }; 26 | 27 | struct Icmpv6 { 28 | static constexpr Natural8 protocolID = 58; 29 | 30 | struct Option { 31 | enum Type { 32 | SourceLinkLayerAddress = 1, 33 | TargetLinkLayerAddress = 2, 34 | PrefixInformation = 3, 35 | RedirectedHeader = 4, 36 | MaximumTransmissionUnit = 5 37 | }; 38 | Natural8 type, chunks, payload[0]; 39 | }; 40 | 41 | struct Packet { 42 | Natural8 type, code; 43 | Natural16 checksum; 44 | Natural8 payload[0]; 45 | 46 | void prepareTransmit(Ipv6::Packet* ipPacket, Natural16 payloadLength) { 47 | ipPacket->nextHeader = protocolID; 48 | ipPacket->payloadLength = sizeof(Packet)+payloadLength; 49 | checksum = 0; 50 | checksum = ipPacket->payloadChecksum(); 51 | } 52 | }; 53 | 54 | struct DestinationUnreachable { 55 | static constexpr Natural8 type = 1; 56 | enum Code { 57 | NoRouteToDestination = 0, 58 | CommunicationProhibited = 1, 59 | BeyondScopeOfSourceAddress = 2, 60 | AddressUnreachable = 3, 61 | PortUnreachable = 4, 62 | SourceAddressFailedPolicy = 5, 63 | RejectRouteToDestination = 6 64 | }; 65 | Natural32 pad0; 66 | 67 | void correctEndian() { } 68 | 69 | void received(Mac::Interface* macInterface, Mac::Frame* macFrame, Ipv6::Packet* ipPacket, Packet* icmpPacket) { 70 | #ifdef NETWORK_DEBUG 71 | puts("DestinationUnreachable"); 72 | #endif 73 | correctEndian(); 74 | } 75 | }; 76 | 77 | struct PacketTooBig { 78 | static constexpr Natural8 type = 2; 79 | Natural32 maximumTransmissionUnit; 80 | 81 | void correctEndian() { 82 | swapEndian(maximumTransmissionUnit); 83 | } 84 | 85 | void received(Mac::Interface* macInterface, Mac::Frame* macFrame, Ipv6::Packet* ipPacket, Packet* icmpPacket) { 86 | #ifdef NETWORK_DEBUG 87 | puts("PacketTooBig"); 88 | #endif 89 | correctEndian(); 90 | } 91 | }; 92 | 93 | struct TimeExceeded { 94 | static constexpr Natural8 type = 3; 95 | enum Code { 96 | HopLimitExceeded = 0, 97 | FragmentReassembly = 1 98 | }; 99 | Natural32 pad0; 100 | 101 | void correctEndian() { } 102 | 103 | void received(Mac::Interface* macInterface, Mac::Frame* macFrame, Ipv6::Packet* ipPacket, Packet* icmpPacket) { 104 | #ifdef NETWORK_DEBUG 105 | puts("TimeExceeded"); 106 | #endif 107 | correctEndian(); 108 | } 109 | }; 110 | 111 | struct ParameterProblem { 112 | static constexpr Natural8 type = 4; 113 | enum Code { 114 | ErroneousHeaderField = 0, 115 | UnrecognizedNextHeaderType = 1, 116 | UnrecognizedIPv6Option = 2, 117 | }; 118 | Natural32 pointer; 119 | 120 | void correctEndian() { 121 | swapEndian(pointer); 122 | } 123 | 124 | void received(Mac::Interface* macInterface, Mac::Frame* macFrame, Ipv6::Packet* ipPacket, Packet* icmpPacket) { 125 | #ifdef NETWORK_DEBUG 126 | puts("ParameterProblem"); 127 | #endif 128 | correctEndian(); 129 | } 130 | }; 131 | 132 | struct EchoRequest { 133 | static constexpr Natural8 type = 128; 134 | Natural16 identifier, sequenceNumber; 135 | Natural8 payload[0]; 136 | 137 | void correctEndian() { 138 | swapEndian(identifier); 139 | swapEndian(sequenceNumber); 140 | } 141 | 142 | void received(Mac::Interface* macInterface, Mac::Frame* macFrame, Ipv6::Packet* ipPacket, Packet* icmpPacket) { 143 | #ifdef NETWORK_DEBUG 144 | puts("EchoRequest"); 145 | #endif 146 | correctEndian(); 147 | 148 | EchoReply::transmit(macInterface, ipPacket); 149 | } 150 | }; 151 | 152 | struct EchoReply { 153 | static constexpr Natural8 type = 129; 154 | Natural16 identifier, sequenceNumber; 155 | Natural8 payload[0]; 156 | 157 | void correctEndian() { 158 | swapEndian(identifier); 159 | swapEndian(sequenceNumber); 160 | } 161 | 162 | void received(Mac::Interface* macInterface, Mac::Frame* macFrame, Ipv6::Packet* ipPacket, Packet* icmpPacket) { 163 | #ifdef NETWORK_DEBUG 164 | puts("EchoReply"); 165 | #endif 166 | correctEndian(); 167 | } 168 | 169 | static bool transmit(Mac::Interface* macInterface, Ipv6::Packet* receivedIpPacket) { 170 | auto macFrame = macInterface->createFrame(sizeof(Ipv6::Packet)+receivedIpPacket->payloadLength); 171 | if(!macFrame) 172 | return false; 173 | auto ipPacket = reinterpret_cast(macFrame->payload); 174 | auto icmpPacket = reinterpret_cast(ipPacket->payload); 175 | auto echoReply = reinterpret_cast(icmpPacket->payload); 176 | auto echoRequest = reinterpret_cast(reinterpret_cast(receivedIpPacket->payload)->payload); 177 | echoReply->identifier = echoRequest->identifier; 178 | echoReply->sequenceNumber = echoRequest->sequenceNumber; 179 | echoReply->correctEndian(); 180 | ipPacket->destinationAddress = receivedIpPacket->sourceAddress; 181 | ipPacket->sourceAddress = macInterface->ipv6LinkLocalAddress; 182 | icmpPacket->type = type; 183 | icmpPacket->code = 0; 184 | icmpPacket->prepareTransmit(ipPacket, receivedIpPacket->payloadLength-sizeof(Packet)); 185 | ipPacket->prepareTransmit(); 186 | macInterface->transmitIpPacket(macFrame); 187 | return true; 188 | } 189 | }; 190 | 191 | struct MulticastListenerQuery { 192 | static constexpr Natural8 type = 130; 193 | Natural16 maximumResponseCode, pad0; 194 | Ipv6::Address multicastAddress; 195 | Natural8 queriersRobustnessVariable : 3, 196 | suppressRouterSideProcessing : 1, 197 | pad1 : 4; 198 | Natural8 queriersQueryIntervalCode; 199 | Natural16 numberOfSources; 200 | Ipv6::Address sourceAddress[0]; 201 | 202 | void correctEndian() { 203 | swapEndian(maximumResponseCode); 204 | swapEndian(numberOfSources); 205 | } 206 | 207 | void received(Mac::Interface* macInterface, Mac::Frame* macFrame, Ipv6::Packet* ipPacket, Packet* icmpPacket) { 208 | #ifdef NETWORK_DEBUG 209 | puts("MulticastListenerQuery"); 210 | #endif 211 | correctEndian(); 212 | } 213 | }; 214 | 215 | struct NeighborSolicitation { 216 | static constexpr Natural8 type = 135; 217 | Natural32 pad0; 218 | Ipv6::Address targetAddress; 219 | Option options[0]; 220 | 221 | void correctEndian() { } 222 | 223 | void received(Mac::Interface* macInterface, Mac::Frame* macFrame, Ipv6::Packet* ipPacket, Packet* icmpPacket) { 224 | #ifdef NETWORK_DEBUG 225 | puts("NeighborSolicitation"); 226 | #endif 227 | correctEndian(); 228 | 229 | if(targetAddress != macInterface->ipv6LinkLocalAddress) 230 | return; 231 | macInterface->addNeighbor(macFrame->sourceAddress, ipPacket->sourceAddress); 232 | NeighborAdvertisement::transmit(macInterface, ipPacket); 233 | } 234 | }; 235 | 236 | struct NeighborAdvertisement { 237 | static constexpr Natural8 type = 136; 238 | Natural32 pad0 : 5, 239 | overrideFlag : 1, 240 | solicitedFlag : 1, 241 | routerFlag : 1, 242 | pad1 : 24; 243 | Ipv6::Address targetAddress; 244 | Option options[0]; 245 | 246 | void correctEndian() { } 247 | 248 | void received(Mac::Interface* macInterface, Mac::Frame* macFrame, Ipv6::Packet* ipPacket, Packet* icmpPacket) { 249 | #ifdef NETWORK_DEBUG 250 | puts("NeighborAdvertisement"); 251 | #endif 252 | correctEndian(); 253 | } 254 | 255 | static bool transmit(Mac::Interface* macInterface, Ipv6::Packet* receivedIpPacket = nullptr) { 256 | auto macFrame = macInterface->createFrame(sizeof(Ipv6::Packet)+sizeof(Packet)+sizeof(NeighborAdvertisement)+8); 257 | if(!macFrame) 258 | return false; 259 | auto ipPacket = reinterpret_cast(macFrame->payload); 260 | auto icmpPacket = reinterpret_cast(ipPacket->payload); 261 | auto neighborAdvertisement = reinterpret_cast(icmpPacket->payload); 262 | neighborAdvertisement->routerFlag = 0; 263 | neighborAdvertisement->solicitedFlag = (receivedIpPacket) ? 1 : 0; 264 | neighborAdvertisement->overrideFlag = 1; 265 | neighborAdvertisement->pad0 = 0; 266 | neighborAdvertisement->pad1 = 0; 267 | neighborAdvertisement->targetAddress = (receivedIpPacket) 268 | ? reinterpret_cast(reinterpret_cast(receivedIpPacket->payload)->payload)->targetAddress 269 | : macInterface->ipv6LinkLocalAddress; 270 | neighborAdvertisement->options[0].type = Option::TargetLinkLayerAddress; 271 | neighborAdvertisement->options[0].chunks = 1; 272 | macInterface->getMACAddress(reinterpret_cast(neighborAdvertisement->options[0].payload)); 273 | neighborAdvertisement->correctEndian(); 274 | ipPacket->destinationAddress = (receivedIpPacket) ? receivedIpPacket->sourceAddress : Ipv6::localNetworkSegmentAllNodesMulticastAddress; 275 | ipPacket->sourceAddress = macInterface->ipv6LinkLocalAddress; 276 | icmpPacket->type = type; 277 | icmpPacket->code = 0; 278 | icmpPacket->prepareTransmit(ipPacket, sizeof(NeighborAdvertisement)+8); 279 | ipPacket->prepareTransmit(); 280 | macInterface->transmitIpPacket(macFrame); 281 | return true; 282 | } 283 | }; 284 | 285 | struct MulticastListenerReport { 286 | static constexpr Natural8 type = 143; 287 | Natural16 pad0, numberOfRecords; 288 | struct MulticastListenerRecord { 289 | enum Type { 290 | MODE_IS_INCLUDE = 1, 291 | MODE_IS_EXCLUDE = 2, 292 | CHANGE_TO_INCLUDE_MODE = 3, 293 | CHANGE_TO_EXCLUDE_MODE = 4, 294 | ALLOW_NEW_SOURCES = 5, 295 | BLOCK_OLD_SOURCES = 6 296 | }; 297 | Natural8 type, auxDataLength; 298 | Natural16 numberOfSources; 299 | Ipv6::Address multicastAddress, sourceAddress[0]; 300 | } records[0]; 301 | 302 | void correctEndian() { 303 | swapEndian(numberOfRecords); 304 | for(Natural16 i = 0; i < numberOfRecords; ++i) 305 | swapEndian(records[i].numberOfSources); 306 | } 307 | 308 | void received(Mac::Interface* macInterface, Mac::Frame* macFrame, Ipv6::Packet* ipPacket, Packet* icmpPacket) { 309 | #ifdef NETWORK_DEBUG 310 | puts("MulticastListenerReport"); 311 | #endif 312 | correctEndian(); 313 | } 314 | }; 315 | 316 | static void received(Mac::Interface* macInterface, Mac::Frame* macFrame, Ipv6::Packet* ipPacket, Packet* icmpPacket); 317 | }; 318 | 319 | void Icmpv4::received(Mac::Interface* macInterface, Mac::Frame* macFrame, Ipv4::Packet* ipPacket, Icmpv4::Packet* icmpPacket) { 320 | #ifdef NETWORK_DEBUG 321 | puts("ICMPv4"); 322 | #endif 323 | } 324 | 325 | void Icmpv6::received(Mac::Interface* macInterface, Mac::Frame* macFrame, Ipv6::Packet* ipPacket, Icmpv6::Packet* icmpPacket) { 326 | #ifdef NETWORK_DEBUG 327 | auto uart = AllwinnerUART::instances[0].address; 328 | puts("ICMPv6"); 329 | #endif 330 | 331 | switch(icmpPacket->type) { 332 | // IcmpReceivedCase(DestinationUnreachable) 333 | // IcmpReceivedCase(PacketTooBig) 334 | // IcmpReceivedCase(TimeExceeded) 335 | // IcmpReceivedCase(ParameterProblem) 336 | IcmpReceivedCase(EchoRequest) 337 | // IcmpReceivedCase(EchoReply) 338 | IcmpReceivedCase(MulticastListenerQuery) 339 | IcmpReceivedCase(NeighborSolicitation) 340 | // IcmpReceivedCase(NeighborAdvertisement) 341 | // IcmpReceivedCase(MulticastListenerReport) 342 | default: 343 | #ifdef NETWORK_DEBUG 344 | uart->putDec(icmpPacket->type); 345 | puts(" unknown type"); 346 | #endif 347 | break; 348 | } 349 | } 350 | -------------------------------------------------------------------------------- /include/Net/Ip.hpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | struct IpChecksumGenerator { 4 | Natural32 accumulator = 0; 5 | 6 | void input(Natural32 length, void* typelessBuffer) { 7 | auto buffer = reinterpret_cast(typelessBuffer); 8 | if(length&1) 9 | accumulator += buffer[--length]; 10 | auto pos = reinterpret_cast(buffer); 11 | auto bufferEnd = reinterpret_cast(buffer+length); 12 | while(pos != bufferEnd) 13 | accumulator += *(pos++); 14 | } 15 | 16 | Natural16 output() { 17 | while(accumulator>>16) 18 | accumulator = (accumulator>>16)+(accumulator&0xFFFF); 19 | return ~static_cast(accumulator); 20 | } 21 | }; 22 | 23 | struct Ipv4 { 24 | static constexpr Natural16 protocolID = 0x0800; 25 | 26 | struct Address { 27 | Natural8 bytes[4]; 28 | 29 | Address& operator=(const Address& other) { 30 | memcpy(this, &other, sizeof(other)); 31 | return *this; 32 | } 33 | 34 | bool operator==(const Address& other) { 35 | return memcmp(this, &other, sizeof(other)) == 0; 36 | } 37 | 38 | bool operator!=(const Address& other) { 39 | return memcmp(this, &other, sizeof(other)) != 0; 40 | } 41 | }; 42 | 43 | struct Packet { 44 | Natural8 internetHeaderLength : 4, 45 | version : 4; 46 | Natural8 typeOfService; 47 | Natural16 totalLength, 48 | identification; 49 | union { 50 | struct { 51 | Natural16 fragmentOffset : 13, 52 | pad0 : 1, 53 | doNotFragment : 1, 54 | moreFragments : 1; 55 | }; 56 | Natural16 swap0; 57 | }; 58 | Natural8 timeToLive, 59 | protocol; 60 | Natural16 checksum; 61 | Address sourceAddress, 62 | destinationAddress; 63 | Natural8 data[0]; 64 | 65 | Natural16 headerChecksum() { 66 | IpChecksumGenerator generator; 67 | generator.input(internetHeaderLength*4, this); 68 | return generator.output(); 69 | } 70 | 71 | Natural16 getPayloadLength() { 72 | return totalLength-internetHeaderLength*4; 73 | } 74 | 75 | Natural8* getPayload() { 76 | return &data[internetHeaderLength*4-20]; 77 | } 78 | 79 | template 80 | Natural16 payloadChecksum() { 81 | Natural16 payloadLength = getPayloadLength(); 82 | struct { 83 | Natural8 zeroPad, protocol; 84 | Natural16 length; 85 | } pseudoHeader = { 86 | 0, PayloadHeader::protocolID, 87 | swapedEndian(payloadLength) 88 | }; 89 | IpChecksumGenerator generator; 90 | generator.input(2*sizeof(Address), &sourceAddress); 91 | generator.input(sizeof(pseudoHeader), &pseudoHeader); 92 | generator.input(payloadLength, getPayload()); 93 | return generator.output(); 94 | } 95 | 96 | void correctEndian() { 97 | swapEndian(totalLength); 98 | swapEndian(identification); 99 | swapEndian(swap0); 100 | } 101 | 102 | void prepareTransmit() { 103 | version = 4; 104 | internetHeaderLength = 5; 105 | typeOfService = 0; 106 | totalLength += internetHeaderLength*4; 107 | identification = 0; 108 | fragmentOffset = 0; 109 | pad0 = 0; 110 | doNotFragment = 1; 111 | moreFragments = 0; 112 | timeToLive = 255; 113 | correctEndian(); 114 | checksum = 0; 115 | checksum = headerChecksum(); 116 | } 117 | }; 118 | static_assert(sizeof(Packet) == 20); 119 | 120 | static void received(Mac::Interface* macInterface, Mac::Frame* macFrame, Packet* packet); 121 | }; 122 | 123 | struct Ipv6 { 124 | static constexpr Natural16 protocolID = 0x86DD; 125 | 126 | struct Address { 127 | Natural8 bytes[16]; 128 | 129 | Address& operator=(const Address& other) { 130 | memcpy(this, &other, sizeof(other)); 131 | return *this; 132 | } 133 | 134 | bool operator==(const Address& other) { 135 | return memcmp(this, &other, sizeof(other)) == 0; 136 | } 137 | 138 | bool operator!=(const Address& other) { 139 | return memcmp(this, &other, sizeof(other)) != 0; 140 | } 141 | }; 142 | static constexpr Address localNetworkSegmentAllNodesMulticastAddress = {{ 0xFF, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01 }}; 143 | 144 | struct Packet { 145 | union { 146 | struct { 147 | Natural32 flowLabel : 20, 148 | trafficClass : 8, 149 | version : 4; 150 | }; 151 | Natural32 swap0; 152 | }; 153 | Natural16 payloadLength; 154 | Natural8 nextHeader, 155 | hopLimit; 156 | Address sourceAddress, 157 | destinationAddress; 158 | Natural8 payload[0]; 159 | 160 | template 161 | Natural16 payloadChecksum() { 162 | struct { 163 | Natural32 length; 164 | Natural8 zeroPad[3], protocol; 165 | } pseudoHeader = { 166 | swapedEndian(payloadLength), 167 | { 0, 0, 0 }, PayloadType::protocolID 168 | }; 169 | IpChecksumGenerator generator; 170 | generator.input(2*sizeof(Address), &sourceAddress); 171 | generator.input(sizeof(pseudoHeader), &pseudoHeader); 172 | generator.input(payloadLength, payload); 173 | return generator.output(); 174 | } 175 | 176 | void correctEndian() { 177 | swapEndian(swap0); 178 | swapEndian(payloadLength); 179 | } 180 | 181 | void prepareTransmit() { 182 | version = 6; 183 | trafficClass = 0; 184 | flowLabel = 0; 185 | hopLimit = 255; 186 | correctEndian(); 187 | } 188 | }; 189 | static_assert(sizeof(Packet) == 40); 190 | 191 | static void received(Mac::Interface* macInterface, Mac::Frame* macFrame, Packet* packet); 192 | }; 193 | 194 | union IpPacket { 195 | Ipv4::Packet v4; 196 | Ipv6::Packet v6; 197 | }; 198 | 199 | union IpAddress { 200 | Ipv4::Address v4; 201 | Ipv6::Address v6; 202 | 203 | static bool macToIpv4(Ipv4::Address& dst, const Mac::Address& src) { 204 | if(src.bytes[0] == 0x01 && src.bytes[1] == 0x00 && src.bytes[2] == 0x5E && !(src.bytes[3]&0x80)) { // Multicast Addresses 205 | dst.bytes[0] = 224; 206 | dst.bytes[1] = src.bytes[3]; 207 | dst.bytes[2] = src.bytes[4]; 208 | dst.bytes[3] = src.bytes[5]; 209 | return true; 210 | } 211 | for(Natural8 i = 0; i < 6; ++i) // Broadcast Address 212 | if(src.bytes[i] != 0xFF) 213 | return false; 214 | for(Natural8 i = 0; i < 4; ++i) 215 | dst.bytes[i] = 255; 216 | return true; 217 | } 218 | 219 | static bool ipv4ToMac(Mac::Address& dst, const Ipv4::Address& src) { 220 | if(src.bytes[0] >= 224 && src.bytes[0] <= 239) { // Multicast Addresses 221 | dst.bytes[0] = 0x01; 222 | dst.bytes[1] = 0x00; 223 | dst.bytes[2] = 0x5E; 224 | dst.bytes[3] = src.bytes[1]&0x7F; 225 | dst.bytes[4] = src.bytes[2]; 226 | dst.bytes[5] = src.bytes[3]; 227 | return true; 228 | } 229 | for(Natural8 i = 0; i < 4; ++i) // Broadcast Address 230 | if(src.bytes[i] != 255) 231 | return false; 232 | for(Natural8 i = 0; i < 6; ++i) 233 | dst.bytes[i] = 0xFF; 234 | return true; 235 | } 236 | 237 | static void ipv4ToIpv6(Ipv6::Address& dst, const Ipv4::Address& src) { 238 | for(Natural8 i = 0; i < 10; ++i) 239 | dst.bytes[i] = 0x00; 240 | dst.bytes[10] = 0xFF; 241 | dst.bytes[11] = 0xFF; 242 | for(Natural8 i = 0; i < 4; ++i) 243 | dst.bytes[i+12] = src.bytes[i]; 244 | } 245 | 246 | static void ipv6ToIpv4(Ipv4::Address& dst, const Ipv6::Address& src) { 247 | for(Natural8 i = 0; i < 4; ++i) 248 | dst.bytes[i] = src.bytes[i+12]; 249 | } 250 | 251 | static bool macToIpv6(Ipv6::Address& dst, const Mac::Address& src) { 252 | if(src.bytes[0] == 0x33 && src.bytes[1] == 0x33) { // Multicast Addresses 253 | dst.bytes[0] = 0xFF; 254 | for(Natural8 i = 1; i < 12; ++i) 255 | dst.bytes[i] = 0x00; 256 | for(Natural8 i = 2; i < 6; ++i) 257 | dst.bytes[i+10] = src.bytes[i]; 258 | return true; 259 | } 260 | if(!(src.bytes[0]&1)) { // EUI-64 261 | dst.bytes[0] = 0xFE; 262 | dst.bytes[1] = 0x80; 263 | for(Natural8 i = 2; i < 8; ++i) 264 | dst.bytes[i] = 0x00; 265 | dst.bytes[8] = src.bytes[0]^0x02; 266 | dst.bytes[9] = src.bytes[1]; 267 | dst.bytes[10] = src.bytes[2]; 268 | dst.bytes[11] = 0xFF; 269 | dst.bytes[12] = 0xFE; 270 | dst.bytes[13] = src.bytes[3]; 271 | dst.bytes[14] = src.bytes[4]; 272 | dst.bytes[15] = src.bytes[5]; 273 | return true; 274 | } 275 | return false; 276 | } 277 | 278 | static bool ipv6ToMac(Mac::Address& dst, const Ipv6::Address& src) { 279 | // TODO: Lookup addess scheme 280 | if(src.bytes[0] == 0xFF && (src.bytes[1]&0xF0) == 0x00) { // Multicast Addresses 281 | dst.bytes[0] = 0x33; 282 | dst.bytes[1] = 0x33; 283 | for(Natural8 i = 2; i < 6; ++i) 284 | dst.bytes[i] = src.bytes[i+10]; 285 | return true; 286 | } 287 | if(src.bytes[0] == 0xFE && src.bytes[1] == 0x80) { // LinkLocal Address 288 | for(Natural8 i = 2; i < 8; ++i) 289 | if(src.bytes[i] != 0x00) 290 | return false; 291 | if(src.bytes[11] != 0xFF || src.bytes[12] != 0xFE) // EUI-64 292 | return false; 293 | dst.bytes[0] = src.bytes[8]^0x02; 294 | dst.bytes[1] = src.bytes[9]; 295 | dst.bytes[2] = src.bytes[10]; 296 | dst.bytes[3] = src.bytes[13]; 297 | dst.bytes[4] = src.bytes[14]; 298 | dst.bytes[5] = src.bytes[15]; 299 | return true; 300 | } 301 | return false; 302 | } 303 | }; 304 | 305 | struct Mac::Interface { 306 | static const Natural8 neighborCacheEntryCount = 8; 307 | // Ipv4::Address ipv4LinkLocalAddress; 308 | Ipv6::Address ipv6LinkLocalAddress; 309 | struct NeighborCacheEntry { 310 | Ipv6::Address ipv6Address; 311 | Mac::Address macAddress; 312 | Natural16 usageCounter; 313 | } neighborCache[8]; 314 | bool linkStatus; 315 | // TODO: Tables 316 | // Multicast Listener (Report) 317 | // Destination Cache 318 | // Default Router List 319 | // Prefix List 320 | // MTU (IPv6 Packet Total Length): minimum is 1280 Bytes 321 | 322 | virtual bool initialize() { 323 | linkStatus = false; 324 | linkStatusChanged(); 325 | return true; 326 | } 327 | virtual bool poll() = 0; 328 | virtual Frame* createFrame(Natural16 payloadLength) = 0; 329 | virtual bool transmit(Mac::Frame* frame) = 0; 330 | 331 | virtual void setMACAddress(const Address& src) = 0; 332 | virtual void getMACAddress(Address& dst) = 0; 333 | 334 | void invalidateNeighbor(NeighborCacheEntry* entry) { 335 | entry->usageCounter = 0; 336 | memset(&entry->ipv6Address, 0, sizeof(Ipv6::Address)); 337 | memset(&entry->macAddress, 0, sizeof(Mac::Address)); 338 | } 339 | 340 | void invalidateNeighborCache() { 341 | for(NativeNaturalType i = 0; i < neighborCacheEntryCount; ++i) 342 | invalidateNeighbor(&neighborCache[i]); 343 | } 344 | 345 | NeighborCacheEntry* findNeighbor(const Ipv6::Address& ipv6Address) { 346 | NeighborCacheEntry* entry = nullptr; 347 | for(NativeNaturalType i = 0; i < neighborCacheEntryCount; ++i) { 348 | // neighborCache[i].usageCounter *= 0.99; // TODO: Reduce usageCounter 349 | if(neighborCache[i].usageCounter > 0 && neighborCache[i].ipv6Address == ipv6Address) { 350 | ++neighborCache[i].usageCounter; 351 | entry = &neighborCache[i]; 352 | } 353 | } 354 | return entry; 355 | } 356 | 357 | void addNeighbor(const Mac::Address& macAddress, const Ipv6::Address& ipv6Address) { 358 | NeighborCacheEntry* entry = findNeighbor(ipv6Address); 359 | if(entry) { 360 | entry->macAddress = macAddress; 361 | return; 362 | } 363 | entry = &neighborCache[0]; 364 | for(NativeNaturalType i = 1; i < neighborCacheEntryCount; ++i) 365 | if(neighborCache[i].usageCounter < entry->usageCounter) 366 | entry = &neighborCache[i]; 367 | entry->ipv6Address = ipv6Address; 368 | entry->macAddress = macAddress; 369 | entry->usageCounter = 1; 370 | } 371 | 372 | void prepareTransmit(Mac::Frame* macFrame) { 373 | getMACAddress(macFrame->sourceAddress); 374 | macFrame->correctEndian(); 375 | } 376 | 377 | bool transmitIpPacket(Mac::Frame* macFrame) { 378 | auto uart = AllwinnerUART::instances[0].address; 379 | switch(macFrame->payload[0]>>4) { 380 | case 4: { 381 | // auto ipv4Packet = reinterpret_cast(macFrame->payload); 382 | macFrame->type = Ipv4::protocolID; 383 | // TODO 384 | } return false; 385 | case 6: { 386 | auto ipv6Packet = reinterpret_cast(macFrame->payload); 387 | macFrame->type = Ipv6::protocolID; 388 | NeighborCacheEntry* entry = findNeighbor(ipv6Packet->destinationAddress); 389 | if(entry) 390 | macFrame->destinationAddress = entry->macAddress; 391 | else if(!IpAddress::ipv6ToMac(macFrame->destinationAddress, ipv6Packet->destinationAddress)) { 392 | for(Natural16 j = 0; j < 16; ++j) 393 | uart->putHex(ipv6Packet->destinationAddress.bytes[j]); 394 | puts(" Could not resolve mac address"); 395 | return false; 396 | } 397 | } break; 398 | default: 399 | uart->putHex(macFrame->type); 400 | puts(" unknown protocol"); 401 | return false; 402 | } 403 | prepareTransmit(macFrame); 404 | return transmit(macFrame); 405 | } 406 | 407 | void linkStatusChanged(); 408 | }; 409 | -------------------------------------------------------------------------------- /include/Net/Mac.hpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | struct Mac { 4 | struct Address { 5 | Natural8 bytes[6]; 6 | 7 | Address& operator=(const Address& other) { 8 | memcpy(this, &other, sizeof(other)); 9 | return *this; 10 | } 11 | 12 | bool operator==(const Address& other) { 13 | return memcmp(this, &other, sizeof(other)) == 0; 14 | } 15 | 16 | bool operator!=(const Address& other) { 17 | return memcmp(this, &other, sizeof(other)) != 0; 18 | } 19 | }; 20 | 21 | struct Frame { 22 | Address destinationAddress, sourceAddress; 23 | Natural16 type; 24 | Natural8 payload[0]; 25 | 26 | void correctEndian() { 27 | swapEndian(type); 28 | } 29 | }; 30 | static_assert(sizeof(Frame) == 14); 31 | 32 | struct Interface; 33 | }; 34 | -------------------------------------------------------------------------------- /include/Net/Net.hpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | void Mac::Interface::linkStatusChanged() { 4 | if(linkStatus) 5 | Icmpv6::NeighborAdvertisement::transmit(this); 6 | else 7 | invalidateNeighborCache(); 8 | } 9 | 10 | struct AllwinnerEMACDriver : public Mac::Interface { 11 | static const Natural16 transmitBufferCount = 128, receiveBufferCount = 128, bufferSize = 1536; 12 | 13 | AllwinnerEMAC::TransmitDescriptor transmitDescriptorRing[transmitBufferCount]; 14 | AllwinnerEMAC::ReceiveDescriptor receiveDescriptorRing[receiveBufferCount]; 15 | struct { 16 | Natural8 pad0[bufferSize]; 17 | } transmitBuffers[transmitBufferCount], receiveBuffers[receiveBufferCount]; 18 | struct AllwinnerEMAC::TransmitDescriptor *transmitedDescriptor, *transmitableDescriptor; 19 | struct AllwinnerEMAC::ReceiveDescriptor *receivedDescriptor; 20 | 21 | bool initialize() { 22 | Mac::Interface::initialize(); 23 | 24 | auto EMAC = AllwinnerEMAC::instances[0].address; 25 | Clock::printUptime(); 26 | EMAC->initialize(); 27 | 28 | for(Natural8 i = 0; i < transmitBufferCount; ++i) { 29 | auto descriptor = &transmitDescriptorRing[i]; 30 | descriptor->status.raw = 0; 31 | descriptor->control.raw = 0; 32 | descriptor->control.bufferSize = 0; 33 | descriptor->control.chainMode = 1; 34 | descriptor->control.completionInterruptEnable = 1; 35 | descriptor->bufferAddress = fromPointer(&transmitBuffers[i])+2; 36 | descriptor->next = fromPointer(&transmitDescriptorRing[(i+1)%transmitBufferCount]); 37 | } 38 | for(Natural8 i = 0; i < receiveBufferCount; ++i) { 39 | auto descriptor = &receiveDescriptorRing[i]; 40 | descriptor->status.raw = 0; 41 | descriptor->status.DMAOwnership = 1; 42 | descriptor->control.raw = 0; 43 | descriptor->control.bufferSize = bufferSize; 44 | descriptor->control.chainMode = 1; 45 | descriptor->control.completionInterruptDisable = 0; 46 | descriptor->bufferAddress = fromPointer(&receiveBuffers[i])+2; 47 | descriptor->next = fromPointer(&receiveDescriptorRing[(i+1)%receiveBufferCount]); 48 | } 49 | transmitedDescriptor = transmitableDescriptor = &transmitDescriptorRing[0]; 50 | receivedDescriptor = &receiveDescriptorRing[0]; 51 | EMAC->transmitDMA = fromPointer(transmitableDescriptor); 52 | EMAC->receiveDMA = fromPointer(receivedDescriptor); 53 | EMAC->enableReceiver(true); 54 | Clock::printUptime(); 55 | return true; 56 | } 57 | 58 | bool poll() { 59 | auto uart = AllwinnerUART::instances[0].address; 60 | auto EMAC = AllwinnerEMAC::instances[0].address; 61 | bool nextLinkStatus = EMAC->link(); 62 | if(linkStatus != nextLinkStatus) { 63 | linkStatus = nextLinkStatus; 64 | if(linkStatus) { 65 | uart->puts("[ OK ] "); 66 | uart->putDec(EMAC->linkSpeed()); 67 | puts(" Mbit/s ethernet link"); 68 | } else 69 | puts("[FAIL] Lost ethernet link"); 70 | linkStatusChanged(); 71 | Clock::printUptime(); 72 | } 73 | Natural32 length = 0, left = transmitBufferCount; 74 | AllwinnerEMAC::TransmitDescriptor* transmitPeekDescriptor = transmitedDescriptor; 75 | while(1) { 76 | if(transmitPeekDescriptor->status.DMAOwnership) // Pending Frame 77 | break; 78 | else if(transmitPeekDescriptor->control.bufferSize == 0) { // Vacant Frame 79 | EMAC->enableTransmitter(false); 80 | break; 81 | } 82 | length += transmitPeekDescriptor->control.bufferSize; 83 | if(transmitPeekDescriptor->control.last) { 84 | transmited( 85 | transmitPeekDescriptor->status.raw&AllwinnerEMAC::TransmitDescriptor::errorMask, 86 | length, 87 | reinterpret_cast(transmitedDescriptor->bufferAddress)); 88 | while(1) { 89 | transmitedDescriptor->status.raw = 0; 90 | transmitedDescriptor->control.bufferSize = 0; 91 | bool last = (transmitedDescriptor == transmitPeekDescriptor); 92 | transmitedDescriptor = reinterpret_cast(transmitedDescriptor->next); 93 | if(last) 94 | break; 95 | } 96 | --left; 97 | if(left == 0) 98 | break; 99 | length = 0; 100 | } 101 | transmitPeekDescriptor = reinterpret_cast(transmitPeekDescriptor->next); 102 | } 103 | if(EMAC->transmitDMAStatus.status == AllwinnerEMAC::TransmitSuspended) 104 | EMAC->enableTransmitter(false); 105 | length = 0; 106 | left = receiveBufferCount/2; 107 | AllwinnerEMAC::ReceiveDescriptor* receivePeekDescriptor = receivedDescriptor; 108 | while(1) { 109 | if(receivePeekDescriptor->status.DMAOwnership) // Vacant Frame 110 | break; 111 | length += receivePeekDescriptor->control.bufferSize; 112 | if(receivePeekDescriptor->status.last) { 113 | received( 114 | receivePeekDescriptor->status.raw&AllwinnerEMAC::ReceiveDescriptor::errorMask, 115 | length, 116 | reinterpret_cast(receivedDescriptor->bufferAddress)); 117 | while(1) { 118 | receivedDescriptor->status.DMAOwnership = 1; 119 | bool last = (receivedDescriptor == receivePeekDescriptor); 120 | receivedDescriptor = reinterpret_cast(receivedDescriptor->next); 121 | if(last) 122 | break; 123 | } 124 | --left; 125 | if(left == 0) 126 | break; 127 | length = 0; 128 | } 129 | receivePeekDescriptor = reinterpret_cast(receivePeekDescriptor->next); 130 | } 131 | if(EMAC->receiveDMAStatus.status == AllwinnerEMAC::ReceiveStopped || 132 | EMAC->receiveDMAStatus.status == AllwinnerEMAC::ReceiveSuspended) { 133 | EMAC->receiveDMA = fromPointer(receivedDescriptor); 134 | EMAC->enableReceiver(true); 135 | } 136 | return true; 137 | } 138 | 139 | Mac::Frame* createFrame(Natural16 payloadLength) { 140 | if(!linkStatus) 141 | return nullptr; 142 | auto descriptor = transmitableDescriptor; 143 | Natural16 totalLength = sizeof(Mac::Frame)+payloadLength, remainingLength = totalLength; 144 | while(1) { 145 | if(descriptor->control.bufferSize > 0) 146 | return nullptr; 147 | auto fragmentLength = min(remainingLength, bufferSize); 148 | remainingLength -= fragmentLength; 149 | if(remainingLength == 0) 150 | break; 151 | descriptor = reinterpret_cast(descriptor->next); 152 | } 153 | descriptor = transmitableDescriptor; 154 | transmitableDescriptor->control.first = true; 155 | remainingLength = totalLength; 156 | while(1) { 157 | transmitableDescriptor->control.bufferSize = min(remainingLength, bufferSize); 158 | remainingLength -= transmitableDescriptor->control.bufferSize; 159 | bool last = (remainingLength == 0); 160 | transmitableDescriptor->control.last = last; 161 | transmitableDescriptor->status.DMAOwnership = !transmitableDescriptor->control.first; 162 | transmitableDescriptor = reinterpret_cast(transmitableDescriptor->next); 163 | if(last) 164 | break; 165 | transmitableDescriptor->control.first = false; 166 | } 167 | return reinterpret_cast(descriptor->bufferAddress); 168 | } 169 | 170 | bool transmit(Mac::Frame* macFrame) { 171 | auto EMAC = AllwinnerEMAC::instances[0].address; 172 | /*auto uart = AllwinnerUART::instances[0].address; 173 | for(Natural16 j = 0; j < 150; ++j) 174 | uart->putHex(reinterpret_cast(macFrame)[j]); 175 | puts(" macFrame");*/ 176 | 177 | auto index = (fromPointer(macFrame)-2-fromPointer(transmitBuffers))/bufferSize; 178 | auto descriptor = &transmitDescriptorRing[index]; 179 | descriptor->status.DMAOwnership = 1; 180 | 181 | /* TODO: Holes in the transmit queue 182 | auto descriptorToClear = transmitedDescriptor; 183 | while(descriptorToClear != descriptor) { 184 | uart->putHex(reinterpret_cast(descriptorToClear)); 185 | puts(" descriptorToClear"); 186 | if(descriptorToClear->status.DMAOwnership == 0) { 187 | descriptorToClear->control.bufferSize = 0; 188 | descriptorToClear->status.raw = 0; 189 | descriptorToClear->status.DMAOwnership = 1; 190 | } 191 | descriptorToClear = reinterpret_cast(descriptorToClear->next); 192 | }*/ 193 | if(EMAC->transmitDMAStatus.status == AllwinnerEMAC::TransmitStopped || 194 | EMAC->transmitDMAStatus.status == AllwinnerEMAC::TransmitSuspended) 195 | EMAC->enableTransmitter(true); 196 | return true; 197 | } 198 | 199 | void setMACAddress(const Mac::Address& src) { 200 | auto EMAC = AllwinnerEMAC::instances[0].address; 201 | EMAC->setMACAddress(0, &src); 202 | IpAddress::macToIpv6(ipv6LinkLocalAddress, src); 203 | } 204 | 205 | void getMACAddress(Mac::Address& dst) { 206 | auto EMAC = AllwinnerEMAC::instances[0].address; 207 | EMAC->getMACAddress(0, &dst); 208 | } 209 | 210 | void transmited(Natural32 errors, Natural32 length, Mac::Frame* macFrame) { 211 | auto uart = AllwinnerUART::instances[0].address; 212 | #ifdef NETWORK_DEBUG 213 | uart->putHex(reinterpret_cast(transmitedDescriptor)); 214 | puts(" transmit success"); 215 | #endif 216 | if(errors) { 217 | Clock::printUptime(); 218 | uart->putHex(errors); 219 | puts(" transmit error\n"); 220 | return; 221 | } 222 | } 223 | 224 | void received(Natural32 errors, Natural32 length, Mac::Frame* macFrame) { 225 | auto uart = AllwinnerUART::instances[0].address; 226 | #ifdef NETWORK_DEBUG 227 | Clock::printUptime(); 228 | uart->putDec(length); 229 | puts(" receive success"); 230 | /*for(Natural16 j = 0; j < 1500; ++j) 231 | uart->putHex(reinterpret_cast(macFrame)[j]); 232 | puts(" macFrame");*/ 233 | for(Natural16 j = 0; j < 6; ++j) 234 | uart->putHex(macFrame->destinationAddress.bytes[j]); 235 | puts(" destination MAC"); 236 | for(Natural16 j = 0; j < 6; ++j) 237 | uart->putHex(macFrame->sourceAddress.bytes[j]); 238 | puts(" source MAC"); 239 | #endif 240 | 241 | if(errors) { 242 | uart->putHex(errors); 243 | puts(" receive error"); 244 | return; 245 | } 246 | 247 | macFrame->correctEndian(); 248 | switch(macFrame->type) { 249 | case Ipv4::protocolID: 250 | Ipv4::received(this, macFrame, reinterpret_cast(macFrame->payload)); 251 | break; 252 | case Ipv6::protocolID: 253 | Ipv6::received(this, macFrame, reinterpret_cast(macFrame->payload)); 254 | break; 255 | default: 256 | #ifdef NETWORK_DEBUG 257 | uart->putHex(macFrame->type); 258 | puts(" unknown protocol"); 259 | #endif 260 | break; 261 | } 262 | #ifdef NETWORK_DEBUG 263 | puts(""); 264 | #endif 265 | } 266 | }; 267 | 268 | #define Ipv4ReceivedCase(PayloadType) \ 269 | case PayloadType::protocolID: \ 270 | if(ipPacket->payloadChecksum() == 0) \ 271 | PayloadType::received(macInterface, macFrame, ipPacket, reinterpret_cast(ipPacket->getPayload())); \ 272 | /* else TODO */ \ 273 | break; 274 | 275 | #define Ipv6ReceivedCase(PayloadType) \ 276 | case PayloadType::protocolID: \ 277 | if(ipPacket->payloadChecksum() == 0) \ 278 | PayloadType::received(macInterface, macFrame, ipPacket, reinterpret_cast(ipPacket->payload)); \ 279 | /* else TODO */ \ 280 | break; 281 | 282 | void Ipv4::received(Mac::Interface* macInterface, Mac::Frame* macFrame, Ipv4::Packet* ipPacket) { 283 | #ifdef NETWORK_DEBUG 284 | auto uart = AllwinnerUART::instances[0].address; 285 | puts("IPv4"); 286 | for(Natural16 j = 0; j < 4; ++j) 287 | uart->putHex(ipPacket->destinationAddress.bytes[j]); 288 | puts(" destination IP"); 289 | for(Natural16 j = 0; j < 4; ++j) 290 | uart->putHex(ipPacket->sourceAddress.bytes[j]); 291 | puts(" source IP"); 292 | #endif 293 | 294 | if(ipPacket->headerChecksum() != 0) { 295 | #ifdef NETWORK_DEBUG 296 | puts("Checksum error"); 297 | #endif 298 | return; 299 | } 300 | ipPacket->correctEndian(); 301 | switch(ipPacket->protocol) { 302 | Ipv4ReceivedCase(Icmpv4) 303 | Ipv4ReceivedCase(Tcp) 304 | Ipv4ReceivedCase(Udp) 305 | default: 306 | #ifdef NETWORK_DEBUG 307 | uart->putDec(ipPacket->protocol); 308 | puts(" unknown protocol"); 309 | #endif 310 | break; 311 | } 312 | } 313 | 314 | void Ipv6::received(Mac::Interface* macInterface, Mac::Frame* macFrame, Ipv6::Packet* ipPacket) { 315 | #ifdef NETWORK_DEBUG 316 | auto uart = AllwinnerUART::instances[0].address; 317 | puts("IPv6"); 318 | for(Natural16 j = 0; j < 16; ++j) 319 | uart->putHex(ipPacket->destinationAddress.bytes[j]); 320 | puts(" destination IP"); 321 | for(Natural16 j = 0; j < 16; ++j) 322 | uart->putHex(ipPacket->sourceAddress.bytes[j]); 323 | puts(" source IP"); 324 | #endif 325 | 326 | ipPacket->correctEndian(); 327 | switch(ipPacket->nextHeader) { 328 | Ipv6ReceivedCase(Icmpv6) 329 | Ipv6ReceivedCase(Tcp) 330 | Ipv6ReceivedCase(Udp) 331 | default: 332 | #ifdef NETWORK_DEBUG 333 | uart->putDec(ipPacket->nextHeader); 334 | puts(" unknown protocol"); 335 | #endif 336 | break; 337 | } 338 | } 339 | -------------------------------------------------------------------------------- /include/Net/Tcp.hpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #define setEstablished() { \ 4 | localInitialSequenceNumber = ++localSequenceNumber; \ 5 | remoteInitialSequenceNumber = receivedTcpPacket->sequenceNumber; \ 6 | status = Established; \ 7 | } 8 | 9 | #define setTimedClose() { \ 10 | Natural64 now = Clock::getUptimeScaledBy(timerPrecisionScale); \ 11 | retryTimer = now+timerPrecisionScale; /* TODO: Timing */ \ 12 | status = TimedClose; \ 13 | } 14 | 15 | struct Tcp { 16 | static constexpr Natural8 protocolID = 6; 17 | static const Natural64 timerPrecisionScale = 1000; // 1 kHz = 1 ms 18 | 19 | enum OptionType { 20 | End = 0, 21 | Padding = 1, 22 | MaximumSegmentSize = 2, 23 | WindowScale = 3, 24 | SelectiveAcknowledgementPermitted = 4, 25 | SelectiveAcknowledgement = 5, 26 | Timestamp = 8 27 | }; 28 | 29 | struct Packet { 30 | Natural16 sourcePort, 31 | destinationPort; 32 | Natural32 sequenceNumber, 33 | acknowledgmentNumber; 34 | Natural16 ns : 1, 35 | pad0 : 3, 36 | dataOffset : 4, 37 | finish : 1, 38 | synchronize : 1, 39 | reset : 1, 40 | push : 1, 41 | acknowledgment : 1, 42 | urgent : 1, 43 | ece : 1, 44 | congestionWindowReduced : 1; 45 | Natural16 windowSize, 46 | checksum, 47 | urgentPointer; 48 | Natural8 options[0]; 49 | 50 | Natural8* getPayload() { 51 | return reinterpret_cast(this)+dataOffset*4; 52 | } 53 | 54 | void correctEndian() { 55 | swapEndian(sourcePort); 56 | swapEndian(destinationPort); 57 | swapEndian(sequenceNumber); 58 | swapEndian(acknowledgmentNumber); 59 | swapEndian(windowSize); 60 | swapEndian(checksum); 61 | swapEndian(urgentPointer); 62 | } 63 | 64 | void prepareTransmit(Ipv4::Packet* ipPacket, Natural16 optionsLength, Natural16 payloadLength) { 65 | ipPacket->protocol = protocolID; 66 | ipPacket->totalLength = sizeof(Packet)+optionsLength+payloadLength; 67 | dataOffset = (sizeof(Packet)+optionsLength+3)/4; 68 | correctEndian(); 69 | checksum = 0; 70 | checksum = ipPacket->payloadChecksum(); 71 | } 72 | 73 | void prepareTransmit(Ipv6::Packet* ipPacket, Natural16 optionsLength, Natural16 payloadLength) { 74 | ipPacket->nextHeader = protocolID; 75 | ipPacket->payloadLength = sizeof(Packet)+optionsLength+payloadLength; 76 | dataOffset = (sizeof(Packet)+optionsLength+3)/4; 77 | correctEndian(); 78 | checksum = 0; 79 | checksum = ipPacket->payloadChecksum(); 80 | } 81 | }; 82 | 83 | struct Connection { 84 | // Transmission Timestamps 85 | // Congestion control, Slow Start, Congestion Avoidance, TCP-Reno 86 | Mac::Interface* macInterface; 87 | Natural8 *receiveBuffer, *transmitBuffer; // TODO: Ring buffer 88 | Natural64 localSequenceNumber = 0, localAcknowledgment = 0, remoteAcknowledgment = 0, retryTimer = 0; // TODO: Handle sequence number overflow 89 | IpAddress localAddress, remoteAddress; 90 | Natural32 localMaximumSegmentSize = 1440, remoteMaximumSegmentSize = 1440, 91 | localWindowSize = 1024*32, remoteWindowSize = 0, 92 | localInitialSequenceNumber = 0, remoteInitialSequenceNumber = 0; 93 | Natural16 localPort = 0, remotePort = 0; 94 | Natural8 localWindowScale = 5, remoteWindowScale = 0, version = 6, retryCounter = 0; 95 | bool selectiveAcknowledgmentEnabled = false, remoteFinished = false; 96 | enum Status { 97 | Closed, 98 | Listen, 99 | SynSent, 100 | SynReceived, 101 | Established, 102 | FinSent, 103 | WaitingForRemoteToFinish, 104 | TimedClose, 105 | Finished 106 | } status = Closed; 107 | 108 | struct SelectiveAcknowledgmentBlock { 109 | Natural32 begin, end; 110 | }; 111 | // TODO: SACK Ring buffers 112 | 113 | bool transmit() { 114 | Natural8 optionsLength = (status == SynSent || status == SynReceived) ? 12 : 0; 115 | auto macFrame = macInterface->createFrame(sizeof(Ipv6::Packet)+sizeof(Packet)+optionsLength); 116 | if(!macFrame) 117 | return false; 118 | Packet* tcpPacket; 119 | Ipv4::Packet* ipv4Packet = reinterpret_cast(macFrame->payload); 120 | Ipv6::Packet* ipv6Packet = reinterpret_cast(macFrame->payload); 121 | switch(version) { 122 | case 4: { 123 | ipv4Packet->destinationAddress = remoteAddress.v4; 124 | ipv4Packet->sourceAddress = localAddress.v4; 125 | tcpPacket = reinterpret_cast(ipv4Packet->getPayload()); // TODO: Set internetHeaderLength first 126 | } break; 127 | case 6: { 128 | ipv6Packet->destinationAddress = remoteAddress.v6; 129 | ipv6Packet->sourceAddress = localAddress.v6; 130 | tcpPacket = reinterpret_cast(ipv6Packet->payload); 131 | } break; 132 | default: 133 | return false; 134 | } 135 | memset(tcpPacket, 0, sizeof(Packet)); 136 | tcpPacket->destinationPort = remotePort; 137 | tcpPacket->sourcePort = localPort; 138 | tcpPacket->windowSize = (optionsLength) ? min(65535U, localWindowSize) : localWindowSize>>localWindowScale; 139 | tcpPacket->sequenceNumber = localSequenceNumber; 140 | if(status != SynSent) { 141 | tcpPacket->acknowledgmentNumber = localAcknowledgment; 142 | tcpPacket->acknowledgment = 1; 143 | 144 | /*if(selectiveAcknowledgmentEnabled) { 145 | tcpPacket->options[0] = SelectiveAcknowledgement; 146 | tcpPacket->options[1] = 0; 147 | struct SelectiveAcknowledgmentBlock blocks[4]; 148 | // TODO 149 | tcpPacket->options[1] *= 8; 150 | memcpy(&tcpPacket->options[2], blocks, tcpPacket->options[1]); 151 | tcpPacket->options[1] += 2; 152 | }*/ 153 | } 154 | if(optionsLength) { 155 | tcpPacket->synchronize = 1; 156 | tcpPacket->options[0] = MaximumSegmentSize; 157 | tcpPacket->options[1] = 4; 158 | tcpPacket->options[2] = localMaximumSegmentSize>>8; 159 | tcpPacket->options[3] = localMaximumSegmentSize&0xFF; 160 | tcpPacket->options[4] = WindowScale; 161 | tcpPacket->options[5] = 3; 162 | tcpPacket->options[6] = localWindowScale; 163 | tcpPacket->options[7] = SelectiveAcknowledgementPermitted; 164 | tcpPacket->options[8] = 2; 165 | tcpPacket->options[9] = End; 166 | tcpPacket->options[10] = End; 167 | tcpPacket->options[11] = End; 168 | } else if(remoteAcknowledgment < localSequenceNumber) { 169 | // TODO: Transmit data here 170 | } else if(status == FinSent) 171 | tcpPacket->finish = 1; 172 | switch(version) { 173 | case 4: 174 | tcpPacket->prepareTransmit(ipv4Packet, optionsLength, 0); 175 | ipv4Packet->prepareTransmit(); 176 | break; 177 | case 6: 178 | tcpPacket->prepareTransmit(ipv6Packet, optionsLength, 0); 179 | ipv6Packet->prepareTransmit(); 180 | break; 181 | } 182 | macInterface->transmitIpPacket(macFrame); 183 | Natural64 now = Clock::getUptimeScaledBy(timerPrecisionScale); 184 | retryTimer = now+timerPrecisionScale; // TODO: Timing 185 | return true; 186 | } 187 | 188 | bool received(Mac::Interface* receivingMacInterface, IpPacket* receivedIpPacket) { 189 | if(status == Closed) 190 | return false; 191 | 192 | Packet* receivedTcpPacket; 193 | Natural32 payloadLength; 194 | switch(version) { 195 | case 4: 196 | receivedTcpPacket = reinterpret_cast(receivedIpPacket->v4.getPayload()); 197 | if(status != Listen && (remoteAddress.v4 != receivedIpPacket->v4.sourceAddress || remotePort != receivedTcpPacket->sourcePort)) 198 | return true; 199 | payloadLength = receivedIpPacket->v4.getPayloadLength(); 200 | localAddress.v4 = receivedIpPacket->v4.destinationAddress; 201 | break; 202 | case 6: 203 | receivedTcpPacket = reinterpret_cast(receivedIpPacket->v6.payload); 204 | if(status != Listen && (remoteAddress.v6 != receivedIpPacket->v6.sourceAddress || remotePort != receivedTcpPacket->sourcePort)) 205 | return true; 206 | payloadLength = receivedIpPacket->v6.payloadLength; 207 | localAddress.v6 = receivedIpPacket->v6.destinationAddress; 208 | break; 209 | } 210 | payloadLength -= receivedTcpPacket->dataOffset*4; 211 | macInterface = receivingMacInterface; 212 | 213 | remoteWindowSize = receivedTcpPacket->windowSize<options, 215 | *optionsEnd = reinterpret_cast(receivedTcpPacket)+receivedTcpPacket->dataOffset*4; 216 | while(pos < optionsEnd) { 217 | switch(*(pos++)) { 218 | case End: 219 | optionsEnd = pos; 220 | break; 221 | case Padding: 222 | break; 223 | case MaximumSegmentSize: 224 | ++pos; 225 | remoteMaximumSegmentSize = *(pos++)<<8; 226 | remoteMaximumSegmentSize |= *(pos++); 227 | break; 228 | case WindowScale: 229 | ++pos; 230 | remoteWindowScale = *(pos++); 231 | break; 232 | case SelectiveAcknowledgementPermitted: 233 | ++pos; 234 | selectiveAcknowledgmentEnabled = true; 235 | break; 236 | case SelectiveAcknowledgement: { 237 | Natural8 count = *(pos++)-2; 238 | struct SelectiveAcknowledgmentBlock blocks[4]; 239 | memcpy(blocks, pos, count); 240 | pos += count; 241 | count /= sizeof(SelectiveAcknowledgmentBlock); 242 | for(Natural8 i = 0; i < count; ++i) { 243 | swapEndian(blocks[i].begin); 244 | swapEndian(blocks[i].end); 245 | // TODO: remoteSelectiveAcknowledgment 246 | } 247 | } break; 248 | case Timestamp: { 249 | ++pos; 250 | Natural32 sender, echo; 251 | memcpy(&sender, pos, 8); 252 | swapEndian(sender); 253 | swapEndian(echo); 254 | // TODO 255 | pos += 8; 256 | } break; 257 | } 258 | } 259 | 260 | if(receivedTcpPacket->reset) { 261 | if(status == Listen || status == TimedClose) 262 | return true; // ERROR 263 | status = Closed; 264 | return true; 265 | } else if(receivedTcpPacket->synchronize) { 266 | if(status == Listen) { 267 | if(receivedTcpPacket->acknowledgment) 268 | return true; // ERROR 269 | remoteAddress.v6 = receivedIpPacket->v6.sourceAddress; 270 | remotePort = receivedTcpPacket->sourcePort; 271 | localSequenceNumber = 0; // TODO: generate sequence number 272 | status = SynReceived; 273 | } else if(status == SynSent) { 274 | if(!receivedTcpPacket->acknowledgment) 275 | status = SynReceived; 276 | else if(receivedTcpPacket->acknowledgmentNumber == localSequenceNumber+1) 277 | setEstablished() 278 | else 279 | return true; // ERROR 280 | } else if(status != SynReceived) 281 | return true; // ERROR 282 | localAcknowledgment = receivedTcpPacket->sequenceNumber+1; 283 | transmit(); 284 | return true; 285 | } else if(status == Listen || status == SynSent) 286 | return true; // ERROR 287 | else if(status == SynReceived) 288 | setEstablished() 289 | else if(status == FinSent && receivedTcpPacket->acknowledgmentNumber == localSequenceNumber+1) { 290 | ++localSequenceNumber; 291 | if(remoteFinished) 292 | setTimedClose() 293 | else 294 | status = WaitingForRemoteToFinish; 295 | } 296 | 297 | if(receivedTcpPacket->acknowledgmentNumber > remoteAcknowledgment) 298 | remoteAcknowledgment = receivedTcpPacket->acknowledgmentNumber; 299 | 300 | if(receivedTcpPacket->finish) { 301 | if(receivedTcpPacket->sequenceNumber != localAcknowledgment) 302 | return true; 303 | remoteFinished = true; 304 | if(status == WaitingForRemoteToFinish) 305 | setTimedClose() 306 | } 307 | 308 | auto remoteSequenceNumber = receivedTcpPacket->sequenceNumber+payloadLength; 309 | if(receivedTcpPacket->finish) 310 | ++remoteSequenceNumber; 311 | if(localAcknowledgment < remoteSequenceNumber) { 312 | if(receivedTcpPacket->sequenceNumber == localAcknowledgment) 313 | localAcknowledgment = remoteSequenceNumber; 314 | // TODO: localSelectiveAcknowledgment 315 | 316 | if(payloadLength > 0) { 317 | Natural8* dst = receiveBuffer+receivedTcpPacket->sequenceNumber-remoteInitialSequenceNumber; 318 | memcpy(dst, optionsEnd, payloadLength); 319 | } 320 | } 321 | 322 | if(receivedTcpPacket->finish || payloadLength > 0) 323 | transmit(); 324 | return true; 325 | } 326 | 327 | bool poll() { 328 | Natural64 now = Clock::getUptimeScaledBy(timerPrecisionScale); 329 | if(status == Closed) 330 | return false; 331 | if(now < retryTimer || 332 | status == Listen || 333 | status == WaitingForRemoteToFinish || 334 | (status == Established && remoteAcknowledgment == localSequenceNumber)) 335 | return true; 336 | if(status == TimedClose) { 337 | status = Finished; 338 | return true; 339 | } 340 | if(++retryCounter > 5) { 341 | status = Closed; 342 | return false; 343 | } 344 | transmit(); 345 | return true; 346 | } 347 | 348 | bool listen() { 349 | if(status != Closed) 350 | return false; 351 | status = Listen; 352 | return true; 353 | } 354 | 355 | bool connect() { 356 | if(status != Closed && status != Listen) 357 | return false; 358 | localSequenceNumber = 0; // TODO: generate sequence number 359 | status = SynSent; 360 | transmit(); 361 | return true; 362 | } 363 | 364 | bool close() { 365 | switch(status) { 366 | case Closed: 367 | case FinSent: 368 | case WaitingForRemoteToFinish: 369 | case TimedClose: 370 | return false; 371 | case Listen: 372 | case SynSent: 373 | case Finished: 374 | status = Closed; 375 | return true; 376 | case SynReceived: 377 | case Established: 378 | status = FinSent; 379 | transmit(); 380 | return true; 381 | } 382 | } 383 | }; 384 | 385 | static bool transmitReset(Mac::Interface* macInterface, Ipv6::Packet* receivedIpPacket) { 386 | auto receivedTcpPacket = reinterpret_cast(receivedIpPacket->payload); 387 | auto macFrame = macInterface->createFrame(sizeof(Ipv6::Packet)+sizeof(Packet)); 388 | if(!macFrame) 389 | return false; 390 | auto ipPacket = reinterpret_cast(macFrame->payload); 391 | ipPacket->destinationAddress = receivedIpPacket->sourceAddress; 392 | ipPacket->sourceAddress = ipPacket->destinationAddress; 393 | auto tcpPacket = reinterpret_cast(ipPacket->payload); 394 | memset(tcpPacket, 0, sizeof(Packet)); 395 | tcpPacket->destinationPort = receivedTcpPacket->sourcePort; 396 | tcpPacket->sourcePort = receivedTcpPacket->destinationPort; 397 | tcpPacket->prepareTransmit(ipPacket, 0, 0); 398 | ipPacket->prepareTransmit(); 399 | macInterface->transmitIpPacket(macFrame); 400 | return true; 401 | } 402 | 403 | static void poll() { 404 | connection->poll(); 405 | } 406 | 407 | static void received(Mac::Interface* macInterface, Mac::Frame* macFrame, Ipv4::Packet* ipPacket, Tcp::Packet* tcpPacket) { 408 | #ifdef NETWORK_DEBUG 409 | puts("TCP"); 410 | #endif 411 | tcpPacket->correctEndian(); 412 | } 413 | 414 | static void received(Mac::Interface* macInterface, Mac::Frame* macFrame, Ipv6::Packet* ipPacket, Tcp::Packet* tcpPacket) { 415 | #ifdef NETWORK_DEBUG 416 | puts("TCP"); 417 | #endif 418 | tcpPacket->correctEndian(); 419 | 420 | // Only one connection, which writes directly to receiveBuffer and closes after the remote finishes 421 | if(tcpPacket->destinationPort != connection->localPort) { 422 | transmitReset(macInterface, ipPacket); 423 | return; 424 | } 425 | connection->received(macInterface, reinterpret_cast(ipPacket)); 426 | if(connection->remoteFinished) 427 | connection->close(); 428 | } 429 | 430 | static Connection* connection; 431 | }; 432 | 433 | Tcp::Connection* Tcp::connection; 434 | -------------------------------------------------------------------------------- /include/Net/Udp.hpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | struct Udp { 4 | static constexpr Natural8 protocolID = 17; 5 | 6 | struct Packet { 7 | Natural16 sourcePort, 8 | destinationPort, 9 | totalLength, 10 | checksum; 11 | Natural8 payload[0]; 12 | 13 | void correctEndian() { 14 | swapEndian(sourcePort); 15 | swapEndian(destinationPort); 16 | swapEndian(totalLength); 17 | } 18 | 19 | void prepareTransmit(Ipv4::Packet* ipPacket, Natural16 payloadLength) { 20 | totalLength = payloadLength+sizeof(Packet); 21 | ipPacket->protocol = protocolID; 22 | ipPacket->totalLength = totalLength; 23 | correctEndian(); 24 | checksum = 0; 25 | checksum = ipPacket->payloadChecksum(); 26 | } 27 | 28 | void prepareTransmit(Ipv6::Packet* ipPacket, Natural16 payloadLength) { 29 | totalLength = payloadLength+sizeof(Packet); 30 | ipPacket->nextHeader = protocolID; 31 | ipPacket->payloadLength = totalLength; 32 | correctEndian(); 33 | checksum = 0; 34 | checksum = ipPacket->payloadChecksum(); 35 | } 36 | }; 37 | 38 | static void received(Mac::Interface* macInterface, Mac::Frame* macFrame, Ipv4::Packet* ipPacket, Packet* udpPacket); 39 | static void received(Mac::Interface* macInterface, Mac::Frame* macFrame, Ipv6::Packet* ipPacket, Packet* udpPacket); 40 | }; 41 | 42 | void Udp::received(Mac::Interface* macInterface, Mac::Frame* macFrame, Ipv4::Packet* ipPacket, Packet* udpPacket) { 43 | #ifdef NETWORK_DEBUG 44 | puts("UDP"); 45 | #endif 46 | udpPacket->correctEndian(); 47 | } 48 | 49 | void Udp::received(Mac::Interface* macInterface, Mac::Frame* macFrame, Ipv6::Packet* ipPacket, Packet* udpPacket) { 50 | #ifdef NETWORK_DEBUG 51 | puts("UDP"); 52 | #endif 53 | udpPacket->correctEndian(); 54 | 55 | if(udpPacket->destinationPort != 3824) 56 | return; 57 | 58 | auto responseMacFrame = macInterface->createFrame(sizeof(Ipv6::Packet)+ipPacket->payloadLength); 59 | if(!macFrame) 60 | return; 61 | auto responseIpPacket = reinterpret_cast(responseMacFrame->payload); 62 | auto responseUdpPacket = reinterpret_cast(responseIpPacket->payload); 63 | responseUdpPacket->sourcePort = udpPacket->destinationPort; 64 | responseUdpPacket->destinationPort = udpPacket->sourcePort; 65 | memcpy(responseUdpPacket->payload, udpPacket->payload, udpPacket->totalLength-sizeof(Packet)); 66 | responseIpPacket->destinationAddress = ipPacket->sourceAddress; 67 | responseIpPacket->sourceAddress = macInterface->ipv6LinkLocalAddress; 68 | responseUdpPacket->prepareTransmit(responseIpPacket, udpPacket->totalLength-sizeof(Packet)); 69 | responseIpPacket->prepareTransmit(); 70 | macInterface->transmitIpPacket(responseMacFrame); 71 | } 72 | -------------------------------------------------------------------------------- /src32/Entry32.s: -------------------------------------------------------------------------------- 1 | _start: 2 | .global _start 3 | 4 | mrs r0, cpsr // Read status register 5 | bic r0, r0, #0x001F // Clear mode 6 | orr r0, r0, #0x0013 // Set supervisor mode 7 | orr r0, r0, #0x00C0 // Disable IRQ and FIQ interrupts 8 | bic r0, r0, #0x0200 // Set little endian 9 | msr cpsr_c, r0 // Write status register 10 | 11 | // Write CPU0 AArch64 reset address 12 | ldr r1, =0x017000A0 13 | ldr r0, =0x00010050 14 | str r0, [r1] 15 | 16 | // Request warm reset to AArch64 17 | mov r0, #3 18 | mcr p15, 0, r0, c12, c0, 2 19 | wfi 20 | -------------------------------------------------------------------------------- /src64/Bootloader.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | struct BootFileHeader { 4 | constexpr static Natural8 magicSeed[] = {'e', 'G', 'O', 'N', '.', 'B', 'T', '0'}; 5 | constexpr static Natural32 checkSumSeed = 0x5F0A6C39, 6 | blockSize = 512; 7 | 8 | Natural32 jumpInstruction; 9 | Natural8 magic[8]; 10 | Natural32 checkSum, payloadLength; 11 | 12 | bool validate() { 13 | if(payloadLength == 0 || payloadLength%blockSize != 0) 14 | return false; 15 | if(memcmp(magic, magicSeed, sizeof(magic)) != 0) 16 | return false; 17 | Natural32 checkSumA = checkSum, checkSumB = 0; 18 | checkSum = checkSumSeed; 19 | for(Natural32 i = 0; i < payloadLength/4; ++i) 20 | checkSumB += reinterpret_cast(this)[i]; 21 | return checkSumA == checkSumB; 22 | } 23 | }; 24 | 25 | void main() { 26 | auto ccu = AllwinnerCCU::instances[0].address; 27 | ccu->configureHSTimer(); 28 | Clock::initialize(); 29 | 30 | Cache::invalidateAll(); 31 | Cache::setActive(false, false, true); 32 | 33 | auto uart = AllwinnerUART::instances[0].address; 34 | ccu->configureUART0(); 35 | uart->initialize(); 36 | 37 | auto rsb = AllwinnerRSB::instances[0].address; 38 | ccu->configureRSB(); 39 | rsb->initialize(); 40 | AXP803::initialize(); 41 | 42 | AXP803::configureDCDC5(); 43 | ccu->configurePLL(); 44 | ccu->configureDRAM(); 45 | auto dram = AllwinnerDRAM::instances[0].address; 46 | dram->initialize(); 47 | auto pageTable = MMU::initialize(); 48 | 49 | AXP803::configureDC1SW(); 50 | ccu->configureEMAC(); 51 | auto eth0 = new(pageTable-sizeof(AllwinnerEMACDriver))AllwinnerEMACDriver; 52 | eth0->initialize(); 53 | eth0->setMACAddress({{ 0x36, 0xC9, 0xE3, 0xF1, 0xB8, 0x05 }}); 54 | 55 | Tcp::connection = new(reinterpret_cast(eth0)-sizeof(Tcp::Connection))Tcp::Connection; 56 | Tcp::connection->receiveBuffer = reinterpret_cast(dram); 57 | Tcp::connection->localPort = 1337; 58 | Tcp::connection->listen(); 59 | 60 | while(Tcp::connection->status != Tcp::Connection::Finished) { 61 | Clock::update(); 62 | eth0->poll(); 63 | Tcp::poll(); 64 | } 65 | puts("[ OK ] TCP download"); 66 | 67 | auto bootFileHeader = reinterpret_cast(Tcp::connection->receiveBuffer); 68 | if(bootFileHeader->validate()) { 69 | puts("[ OK ] Payload validation"); 70 | reinterpret_cast(bootFileHeader)(); 71 | puts("[ OK ] Payload execution"); 72 | } else 73 | puts("[FAIL] Payload validation"); 74 | } 75 | -------------------------------------------------------------------------------- /src64/Entry64.s: -------------------------------------------------------------------------------- 1 | _start: 2 | .global _start 3 | 4 | // Setup stack pointer: 64 KiB space in SRAM A2 5 | ldr x0, =0x00054000 6 | mov sp, x0 7 | 8 | // Enable advanced SIMD and floating-point execution 9 | mov x0, #3<<20 10 | msr CPACR_EL1, x0 11 | 12 | // Start main execution 13 | bl _Z4mainv 14 | 15 | // Bumper to stop execution 16 | wfi 17 | -------------------------------------------------------------------------------- /src64/Kernel.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | void main() { 4 | puts("Kernel says: \"Hello, World!\""); 5 | } 6 | -------------------------------------------------------------------------------- /tools/build_tool/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "build_tool" 3 | version = "0.0.0" 4 | authors = ["Alexander Meißner "] 5 | 6 | [dependencies] 7 | byteorder = "1.0.0" 8 | elf = "0.0.10" 9 | -------------------------------------------------------------------------------- /tools/build_tool/src/main.rs: -------------------------------------------------------------------------------- 1 | extern crate byteorder; 2 | extern crate elf; 3 | use std::path::PathBuf; 4 | use std::fs::{File, OpenOptions}; 5 | use std::io::*; 6 | use byteorder::{LittleEndian, ReadBytesExt, WriteBytesExt}; 7 | use std::process::Command; 8 | 9 | static BOOT_FILE_BLOCK_SIZE :u32 = 512; 10 | static BOOT_FILE_HEADER_LENGTH :u32 = 20; 11 | 12 | macro_rules! try_IO { 13 | ($file_path:ident, $expr:expr) => (match $expr { 14 | Ok(value) => value, 15 | Err(error) => { 16 | println!("Error in {:?}: {:?}", $file_path, error); 17 | return; 18 | } 19 | }) 20 | } 21 | 22 | fn main() { 23 | let linker_path = match std::env::var("LD") { 24 | Ok(value) => value, 25 | Err(_) => { 26 | println!("Could not find linker"); 27 | return; 28 | }, 29 | }; 30 | let args: Vec<_> = std::env::args().collect(); 31 | if args.len() < 5 { 32 | println!("Usage: LD = [linker] build_tool [virtual_offset] [physical_offset] [out.bin] [in1.o] [in2.o] [in3.o] ..."); 33 | return; 34 | } 35 | 36 | let virtual_offset = u64::from_str_radix(&args[1][2..], 16).unwrap(); 37 | let physical_offset = u64::from_str_radix(&args[2][2..], 16).unwrap(); 38 | let target = &args[3]; 39 | if target.len() < 5 || &target[target.len()-4..target.len()] != ".bin" { 40 | println!("Output filename is invalid"); 41 | return; 42 | } 43 | 44 | let mut object_files :[Vec; 2] = [Vec::new(), Vec::new()]; 45 | for in_file_path_str in &args[4..] { 46 | let in_file_path = PathBuf::from(in_file_path_str); 47 | let in_file = try_IO!(in_file_path, elf::File::open_path(&in_file_path)); 48 | 49 | if in_file.ehdr.osabi != elf::types::ELFOSABI_NONE { 50 | println!("{:?} is of wrong ABI", in_file_path); 51 | return; 52 | } 53 | 54 | if in_file.ehdr.data != elf::types::ELFDATA2LSB { 55 | println!("{:?} is of wrong endianess", in_file_path); 56 | return; 57 | } 58 | 59 | match in_file.ehdr.class { 60 | elf::types::ELFCLASS32 => { 61 | if in_file.ehdr.machine != elf::types::EM_ARM { 62 | println!("{:?} is of wrong machine architecture", in_file_path); 63 | return; 64 | } 65 | object_files[0].push(in_file_path); 66 | }, 67 | elf::types::ELFCLASS64 => { 68 | if in_file.ehdr.machine != elf::types::EM_AARCH64 { 69 | println!("{:?} is of wrong machine architecture", in_file_path); 70 | return; 71 | } 72 | object_files[1].push(in_file_path); 73 | }, 74 | elf::types::Class(_) => { 75 | println!("{:?} is of unknown architecture size", in_file_path); 76 | return; 77 | }, 78 | }; 79 | } 80 | 81 | let binary_file_path = PathBuf::from(target); 82 | let mut binary_file = try_IO!(binary_file_path, OpenOptions::new().read(true).write(true).create(true).truncate(true).open(&binary_file_path)); 83 | let mut payload_length :u32 = BOOT_FILE_HEADER_LENGTH; 84 | let mut check_sum :u32 = 0; 85 | 86 | let mut entry_point :u64 = 0; 87 | let mut virtual_address = virtual_offset+BOOT_FILE_HEADER_LENGTH as u64; 88 | for architecture in 0..2 { 89 | if object_files[architecture].len() == 0 { 90 | continue; 91 | } 92 | 93 | let architecture_names = ["32", "64"]; 94 | let architecture_target = format!("{}{}", &target[..target.len()-4], architecture_names[architecture]); 95 | let linker_script_file_path = PathBuf::from(format!("{}.lds", architecture_target)); 96 | let elf_file_path = PathBuf::from(format!("{}.elf", architecture_target)); 97 | 98 | let mut linker_script = try_IO!(linker_script_file_path, File::create(&linker_script_file_path)); 99 | try_IO!(linker_script_file_path, linker_script.write(b"SECTIONS {\n")); 100 | try_IO!(linker_script_file_path, linker_script.write(format!(" . = 0x{:08X};", virtual_address).as_bytes())); 101 | try_IO!(linker_script_file_path, linker_script.write(b" 102 | .text : { *(.text) } 103 | .rodata : { *(.rodata) } 104 | .data : { *(.data) } 105 | .bss : { *(.bss) } 106 | /DISCARD/ : { *(.ARM.exidx*) } 107 | /DISCARD/ : { *(.comment) } 108 | }")); 109 | 110 | println!("Linking: {:?}", elf_file_path); 111 | try_IO!(linker_path, Command::new(&linker_path) 112 | .arg("-flavor").arg("gnu") 113 | .arg("-s") 114 | .arg("--script").arg(linker_script_file_path) 115 | .arg("-o").arg(&elf_file_path) 116 | .args(&object_files[architecture]) 117 | .status()); 118 | 119 | let in_file = try_IO!(elf_file_path, elf::File::open_path(&elf_file_path)); 120 | if entry_point == 0 { 121 | entry_point = in_file.ehdr.entry; 122 | } 123 | for section in &in_file.sections { 124 | if section.shdr.size == 0 || section.shdr.shtype != elf::types::SHT_PROGBITS { 125 | continue; 126 | } 127 | if section.shdr.addr < virtual_address { 128 | println!("{:?} section virtual addresses are in wrong order", elf_file_path); 129 | return; 130 | } 131 | 132 | let physical_address = section.shdr.addr-virtual_offset+physical_offset; 133 | payload_length += (section.shdr.addr-virtual_address) as u32; 134 | virtual_address = section.shdr.addr+section.shdr.size; 135 | println!(" {:08X} {:08X} {:08X} {}", section.shdr.addr, section.shdr.addr+section.shdr.size, physical_address, section.shdr.name); 136 | 137 | try_IO!(binary_file_path, binary_file.seek(SeekFrom::Start(physical_address))); 138 | try_IO!(binary_file_path, binary_file.write(§ion.data)); 139 | payload_length += section.shdr.size as u32; 140 | } 141 | } 142 | 143 | println!("Building: {:?}", binary_file_path); 144 | let needs_trailing_zeros = payload_length%BOOT_FILE_BLOCK_SIZE > 0; 145 | println!(" {} bytes", payload_length); 146 | payload_length = (payload_length+BOOT_FILE_BLOCK_SIZE-1)/BOOT_FILE_BLOCK_SIZE; 147 | println!(" {} blocks of {} bytes", payload_length, BOOT_FILE_BLOCK_SIZE); 148 | payload_length *= BOOT_FILE_BLOCK_SIZE; 149 | println!(" {:08X} entry point", entry_point); 150 | entry_point = (entry_point-virtual_offset)/4; 151 | if entry_point > 0xEFFFFF { 152 | println!("Entry point is out of reach"); 153 | return; 154 | } 155 | 156 | let mut boot_file_header = [0u8; 20]; 157 | let jump_instruction :u32 = if object_files[0].len() > 0 158 | { 0xEA000000|(entry_point as u32-2) } else 159 | { 0x14000000|(entry_point as u32) }; 160 | (&mut boot_file_header[0..4]).write_u32::(jump_instruction).unwrap(); 161 | (&mut boot_file_header[4..12]).clone_from_slice(b"eGON.BT0"); 162 | (&mut boot_file_header[12..16]).write_u32::(0x5F0A6C39).unwrap(); 163 | (&mut boot_file_header[16..20]).write_u32::(payload_length).unwrap(); 164 | try_IO!(binary_file_path, binary_file.seek(SeekFrom::Start(physical_offset))); 165 | try_IO!(binary_file_path, binary_file.write(&boot_file_header)); 166 | if needs_trailing_zeros { 167 | try_IO!(binary_file_path, binary_file.seek(SeekFrom::Start(physical_offset+payload_length as u64-1))); 168 | try_IO!(binary_file_path, binary_file.write(&[0u8])); 169 | } 170 | 171 | try_IO!(binary_file_path, binary_file.seek(SeekFrom::Start(physical_offset))); 172 | for _ in 0..payload_length/4 { 173 | let mut buffer = [0u8; 4]; 174 | try_IO!(binary_file_path, binary_file.read(&mut buffer)); 175 | check_sum = check_sum.wrapping_add((&buffer[0..4]).read_u32::().unwrap()); 176 | } 177 | (&mut boot_file_header[12..16]).write_u32::(check_sum).unwrap(); 178 | try_IO!(binary_file_path, binary_file.seek(SeekFrom::Start(physical_offset+12))); 179 | try_IO!(binary_file_path, binary_file.write(&boot_file_header[12..16])); 180 | println!(" {:08X} check sum", check_sum.swap_bytes()); 181 | } 182 | --------------------------------------------------------------------------------