├── .clang-format ├── .editorconfig ├── .github └── workflows │ ├── build.yml │ └── commitlint.yml ├── .gitignore ├── Kconfig ├── LICENSE.md ├── Makefile ├── README.md ├── SUMMARY.md ├── adr ├── ADR00-record-architecture-decisions.md ├── ADR01-munix-is-a-micro-kernel.md ├── TEMPLATE.md ├── adr01.png └── adr01.uxf ├── book.toml ├── brand ├── color-dark.png ├── color-light.png ├── cute-dark.png ├── cute-light.png ├── hot-dog.png ├── think-dark.png └── think-light.png ├── building.md ├── doc ├── pico │ ├── DDI0419E_armv6m_arm.pdf │ ├── DDI0484C_cortex_m0p_r0p1_trm.pdf │ └── rp2040-datasheet.pdf └── rpizero │ └── BCM2835-ARM-Peripherals.pdf ├── src ├── arch │ ├── Kconfig │ └── arm │ │ ├── Kconfig │ │ ├── bcm283x │ │ └── Kconfig │ │ └── rp2040 │ │ └── Kconfig ├── board │ ├── .build.mk │ ├── Kconfig │ ├── pico │ │ └── Kconfig │ └── rpizero │ │ └── Kconfig ├── common │ ├── .build.mk │ ├── elf.h │ ├── message.h │ └── syscall.h ├── kernel │ ├── .build.mk │ ├── ipc.c │ ├── ipc.h │ ├── link.ld │ ├── start.c │ ├── start.s │ ├── task.c │ └── task.h ├── library │ ├── .buid.mk │ ├── crt0.s │ ├── ctypes.c │ ├── ctypes.h │ ├── ipc.c │ ├── ipc.h │ ├── memory.c │ ├── memory.h │ ├── string.c │ ├── string.h │ ├── syscall.c │ ├── syscall.h │ └── uf2 │ │ └── uf2.h └── server │ ├── .build.mk │ ├── audio.c │ ├── flash.c │ ├── fs.c │ ├── init.c │ ├── io.c │ ├── process.c │ ├── uart.c │ └── usb.c └── tools ├── .build.mk ├── config.py └── elf2uf2.cpp /.clang-format: -------------------------------------------------------------------------------- 1 | AlignTrailingComments: true 2 | AlwaysBreakAfterReturnType: All 3 | AlignConsecutiveMacros: true 4 | BreakBeforeBraces: Allman 5 | ColumnLimit: 80 6 | ContinuationIndentWidth: 4 7 | Cpp11BracedListStyle: false 8 | FixNamespaceComments: true 9 | IndentCaseLabels: false 10 | IndentWidth: 4 11 | SortIncludes: true 12 | SpacesBeforeTrailingComments: 4 13 | TabWidth: 4 14 | UseTab: Always 15 | SortIncludes: true 16 | IncludeCategories: 17 | - Regex: '^' 18 | Priority: 10 19 | SortPriority: 10 20 | - Regex: '^ 2 |
3 |
4 |

5 | 6 |

7 |
8 |
9 | 10 | # The **µnix** Operating System 11 | 12 | [![GitHub issues](https://img.shields.io/github/issues/sleepy-monax/munix)](https://github.com/sleepy-monax/munix/issues) [![GitHub forks](https://img.shields.io/github/forks/sleepy-monax/munix)](https://github.com/sleepy-monax/munix/network) [![GitHub stars](https://img.shields.io/github/stars/sleepy-monax/munix)](https://github.com/sleepy-monax/munix/stargazers) [![GitHub license](https://img.shields.io/github/license/sleepy-monax/munix)](https://github.com/sleepy-monax/munix/blob/main/LICENSE.md) 13 | 14 | "µnix", "munix" or, "micro unix" aims to be a micro kernel based operating system targeting the Raspberry Pi Pico. 15 | 16 | "µnix" is an execise in minimalism to see if micro kernels are viable on such constrained systems. 17 | 18 | We want "µnix" to feel like any regular unix-like operating system. 19 | 20 | # Contributing 21 | 22 | The project is open to contribution but please note that architectural changes should go throught the [Architecture Decision Records Process](adr/ADR00-record-architecture-decisions.md) 23 | 24 | # License 25 | 26 | The "µnix" operating system is license under the BSD-3-Clause license. 27 | -------------------------------------------------------------------------------- /SUMMARY.md: -------------------------------------------------------------------------------- 1 | # Summary 2 | 3 | - [Read Me](README.md) 4 | - [Sumary](SUMMARY.md) 5 | - [Record Architecture Decisions](adr/ADR00-record-architecture-decisions.md) 6 | - [**ADR01** Munix Is A Micro Kernel](adr/ADR01-munix-is-a-micro-kernel.md) 7 | - [Template](adr/TEMPLATE.md) 8 | - [License](LICENSE.md) -------------------------------------------------------------------------------- /adr/ADR00-record-architecture-decisions.md: -------------------------------------------------------------------------------- 1 | # 00. Record architecture decisions 2 | 3 | Date: 2021-02-09 4 | 5 | ## Status 6 | 7 | Aproved 8 | 9 | ## Context 10 | 11 | We need to record the architectural decisions made on this project. 12 | 13 | ## Decision 14 | 15 | We will use Architecture Decision Records, as described by Michael Nygard in this article: http://thinkrelevance.com/blog/2011/11/15/documenting-architecture-decisions 16 | 17 | ## Consequences 18 | 19 | See Michael Nygard's article, linked above. 20 | -------------------------------------------------------------------------------- /adr/ADR01-munix-is-a-micro-kernel.md: -------------------------------------------------------------------------------- 1 | # munix is a micro kernel 2 | 3 | ## Status 4 | 5 | Working Draft 6 | 7 | ## Context 8 | 9 | 10 | 11 | ## Decision 12 | 13 | 14 | ## Consequences 15 | 16 | ![](adr01.png) 17 | -------------------------------------------------------------------------------- /adr/TEMPLATE.md: -------------------------------------------------------------------------------- 1 | # ADR template by Michael Nygard 2 | 3 | This is the template in [Documenting architecture decisions - Michael Nygard](http://thinkrelevance.com/blog/2011/11/15/documenting-architecture-decisions). 4 | You can use [adr-tools](https://github.com/npryce/adr-tools) for managing the ADR files. 5 | 6 | In each ADR file, write these sections: 7 | 8 | # Title 9 | 10 | ## Status 11 | 12 | What is the status, such as proposed, accepted, rejected, deprecated, superseded, etc.? 13 | 14 | ## Context 15 | 16 | What is the issue that we're seeing that is motivating this decision or change? 17 | 18 | ## Decision 19 | 20 | What is the change that we're proposing and/or doing? 21 | 22 | ## Consequences 23 | 24 | What becomes easier or more difficult to do because of this change? -------------------------------------------------------------------------------- /adr/adr01.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cute-engineering/munix-legacy/7112a162b25e2c31548473854948765661a81aca/adr/adr01.png -------------------------------------------------------------------------------- /adr/adr01.uxf: -------------------------------------------------------------------------------- 1 | 10Space for diagram notesUMLClass8039543030KernelUMLClass8031510030uart-serverUMLClass8035521030fs-severUMLClass19031510030io-serverUMLClass8027543030userspaceUMLClass30031510030usb-serverUMLClass41031510030flash-serverUMLClass30035521030process-managerUMLClass8043043030Hardware -------------------------------------------------------------------------------- /book.toml: -------------------------------------------------------------------------------- 1 | [book] 2 | authors = ["The µnix Contributors"] 3 | language = "en" 4 | multilingual = false 5 | src = "." 6 | title = "The µnix Operating System" 7 | -------------------------------------------------------------------------------- /brand/color-dark.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cute-engineering/munix-legacy/7112a162b25e2c31548473854948765661a81aca/brand/color-dark.png -------------------------------------------------------------------------------- /brand/color-light.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cute-engineering/munix-legacy/7112a162b25e2c31548473854948765661a81aca/brand/color-light.png -------------------------------------------------------------------------------- /brand/cute-dark.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cute-engineering/munix-legacy/7112a162b25e2c31548473854948765661a81aca/brand/cute-dark.png -------------------------------------------------------------------------------- /brand/cute-light.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cute-engineering/munix-legacy/7112a162b25e2c31548473854948765661a81aca/brand/cute-light.png -------------------------------------------------------------------------------- /brand/hot-dog.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cute-engineering/munix-legacy/7112a162b25e2c31548473854948765661a81aca/brand/hot-dog.png -------------------------------------------------------------------------------- /brand/think-dark.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cute-engineering/munix-legacy/7112a162b25e2c31548473854948765661a81aca/brand/think-dark.png -------------------------------------------------------------------------------- /brand/think-light.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cute-engineering/munix-legacy/7112a162b25e2c31548473854948765661a81aca/brand/think-light.png -------------------------------------------------------------------------------- /building.md: -------------------------------------------------------------------------------- 1 | # Building 2 | 3 | 1. **install** arm-none-eabi-binutils and arm-none-eabi-gcc 4 | 2. **install** kconfiglib using pip 5 | 3. **run** make defconfig 6 | 4. **run** make all 7 | -------------------------------------------------------------------------------- /doc/pico/DDI0419E_armv6m_arm.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cute-engineering/munix-legacy/7112a162b25e2c31548473854948765661a81aca/doc/pico/DDI0419E_armv6m_arm.pdf -------------------------------------------------------------------------------- /doc/pico/DDI0484C_cortex_m0p_r0p1_trm.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cute-engineering/munix-legacy/7112a162b25e2c31548473854948765661a81aca/doc/pico/DDI0484C_cortex_m0p_r0p1_trm.pdf -------------------------------------------------------------------------------- /doc/pico/rp2040-datasheet.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cute-engineering/munix-legacy/7112a162b25e2c31548473854948765661a81aca/doc/pico/rp2040-datasheet.pdf -------------------------------------------------------------------------------- /doc/rpizero/BCM2835-ARM-Peripherals.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cute-engineering/munix-legacy/7112a162b25e2c31548473854948765661a81aca/doc/rpizero/BCM2835-ARM-Peripherals.pdf -------------------------------------------------------------------------------- /src/arch/Kconfig: -------------------------------------------------------------------------------- 1 | choice 2 | prompt "Architecture" 3 | default ARM 4 | 5 | config ARM 6 | bool "ARM architecture" 7 | 8 | endchoice 9 | 10 | source "src/arch/arm/Kconfig" -------------------------------------------------------------------------------- /src/arch/arm/Kconfig: -------------------------------------------------------------------------------- 1 | menu "ARM architecture" 2 | depends on ARM 3 | 4 | config TARGET_ARCH 5 | string 6 | default "arm" 7 | 8 | choice 9 | prompt "Target select" 10 | default ARCH_RP2040 11 | 12 | config ARCH_RP2040 13 | bool "RP2040" 14 | 15 | config ARCH_BCM283X 16 | bool "bcm283x" 17 | 18 | endchoice 19 | 20 | endmenu 21 | 22 | source "src/arch/arm/rp2040/Kconfig" 23 | source "src/arch/arm/bcm283x/Kconfig" -------------------------------------------------------------------------------- /src/arch/arm/bcm283x/Kconfig: -------------------------------------------------------------------------------- 1 | if ARCH_BCM283X 2 | 3 | config TARGET_SOC 4 | string 5 | default "bcm283x" 6 | 7 | endif -------------------------------------------------------------------------------- /src/arch/arm/rp2040/Kconfig: -------------------------------------------------------------------------------- 1 | if ARCH_RP2040 2 | 3 | config TARGET_SOC 4 | string 5 | default "rp2040" 6 | 7 | endif -------------------------------------------------------------------------------- /src/board/.build.mk: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cute-engineering/munix-legacy/7112a162b25e2c31548473854948765661a81aca/src/board/.build.mk -------------------------------------------------------------------------------- /src/board/Kconfig: -------------------------------------------------------------------------------- 1 | choice 2 | prompt "Board" 3 | default BOARD_PICO 4 | 5 | source "src/board/pico/Kconfig" 6 | source "src/board/rpizero/Kconfig" 7 | 8 | endchoice 9 | -------------------------------------------------------------------------------- /src/board/pico/Kconfig: -------------------------------------------------------------------------------- 1 | config BOARD_PICO 2 | bool "Support Raspberry PI pico" 3 | depends on ARCH_RP2040 4 | 5 | if BOARD_PICO 6 | 7 | config TARGET_BOARD 8 | string 9 | default "pico" 10 | 11 | endif -------------------------------------------------------------------------------- /src/board/rpizero/Kconfig: -------------------------------------------------------------------------------- 1 | config BOARD_RPIZERO 2 | bool "Support Raspberry PI ZERO" 3 | depends on ARCH_BCM283X 4 | 5 | if BOARD_RPIZERO 6 | 7 | config TARGET_BOARD 8 | string 9 | default "rpizero" 10 | 11 | endif -------------------------------------------------------------------------------- /src/common/.build.mk: -------------------------------------------------------------------------------- 1 | CONFIG_HEADER=$(SRCDIR)/common/config.h 2 | 3 | $(CONFIG_HEADER): .config 4 | $(CONF) --genheader $@ -------------------------------------------------------------------------------- /src/common/elf.h: -------------------------------------------------------------------------------- 1 | #ifndef _MUNIX_COMMON_ELF_H 2 | #define _MUNIX_COMMON_ELF_H 3 | 4 | #include 5 | 6 | #define ELF_MAGIC 0x464c457fu 7 | 8 | #define EM_ARM 0x28u 9 | 10 | #define EF_ARM_ABI_FLOAT_HARD 0x00000400u 11 | 12 | #define PT_LOAD 0x00000001u 13 | 14 | #pragma pack(push, 1) 15 | 16 | struct elf_header 17 | { 18 | uint32_t magic; 19 | uint8_t arch_class; 20 | uint8_t endianness; 21 | uint8_t version; 22 | uint8_t abi; 23 | uint8_t abi_version; 24 | uint8_t _pad[7]; 25 | uint16_t type; 26 | uint16_t machine; 27 | uint32_t version2; 28 | }; 29 | 30 | struct elf32_header 31 | { 32 | struct elf_header common; 33 | uint32_t entry; 34 | uint32_t ph_offset; 35 | uint32_t sh_offset; 36 | uint32_t flags; 37 | uint16_t eh_size; 38 | uint16_t ph_entry_size; 39 | uint16_t ph_num; 40 | uint16_t sh_entry_size; 41 | uint16_t sh_num; 42 | uint16_t sh_str_index; 43 | }; 44 | 45 | struct elf32_ph_entry 46 | { 47 | uint32_t type; 48 | uint32_t offset; 49 | uint32_t vaddr; 50 | uint32_t paddr; 51 | uint32_t filez; 52 | uint32_t memsz; 53 | uint32_t flags; 54 | uint32_t align; 55 | }; 56 | #pragma pack(pop) 57 | 58 | #endif /* !_MUNIX_COMMON_ELF_H */ 59 | -------------------------------------------------------------------------------- /src/common/message.h: -------------------------------------------------------------------------------- 1 | #ifndef _MUNIX_COMMON_MESSAGE_H 2 | #define _MUNIX_COMMON_MESSAGE_H 3 | 4 | #include 5 | 6 | enum message_type 7 | { 8 | MSG_INVALID, 9 | MSG_ACK, 10 | MSG_ERROR, 11 | MSG_OPEN, 12 | MSG_CLOSE, 13 | MSG_READ, 14 | MSG_WRITE, 15 | MSG_DATA, 16 | MSG_END, 17 | }; 18 | 19 | struct message 20 | { 21 | enum message_type type; 22 | char payload[CONFIG_IPC_MESSAGE_SIZE - sizeof(enum message_type)]; 23 | }; 24 | 25 | #endif /* !_COMMON_MESSAGE_H */ 26 | -------------------------------------------------------------------------------- /src/common/syscall.h: -------------------------------------------------------------------------------- 1 | #ifndef _MUNIX_COMMON_SYSCALL_H 2 | #define _MUNIX_COMMON_SYSCALL_H 3 | 4 | enum syscall 5 | { 6 | SYS_INVALID, 7 | SYS_SEND, 8 | SYS_RECEIVE, 9 | SYS_SLEEP, 10 | SYS_WAIT, 11 | SYS_KILL, 12 | SYS_SPAWN, 13 | }; 14 | 15 | #endif /* !_MUNIX_COMMON_SYSCALL_H */ 16 | -------------------------------------------------------------------------------- /src/kernel/.build.mk: -------------------------------------------------------------------------------- 1 | KCFLAGS= \ 2 | -MD \ 3 | $(WARNINGS) \ 4 | $(INCLUDES) \ 5 | $(TARGET) 6 | 7 | KLDFLAGS= \ 8 | -T $(SRCDIR)/kernel/link.ld 9 | 10 | KERNEL_ELF=$(BINDIR)/kernel.elf 11 | KERNEL_UF2=$(BINDIR)/kernel.uf2 12 | KERNEL_SRC=$(wildcard $(SRCDIR)/kernel/*.c $(SRCDIR)/kernel/*.s) 13 | KERNEL_OBJ=$(patsubst $(SRCDIR)/%, $(BINDIR)/%.o, $(KERNEL_SRC)) 14 | 15 | $(BINDIR)/%.c.o: $(SRCDIR)/%.c $(CONFIG_HEADER) 16 | $(GUARD) 17 | $(TARGET_CC) $(KCFLAGS) -c -o $@ $< 18 | 19 | $(BINDIR)/%.s.o: $(SRCDIR)/%.s $(CONFIG_HEADER) 20 | $(GUARD) 21 | $(TARGET_CC) $(KCFLAGS) -c -o $@ $< 22 | 23 | $(KERNEL_ELF): $(KERNEL_OBJ) $(SRCDIR)/kernel/link.ld 24 | $(GUARD) 25 | $(TARGET_LD) $(KLDFLAGS) -o $@ $(KERNEL_OBJ) 26 | 27 | $(KERNEL_UF2): $(KERNEL_ELF) $(ELF2UF2) 28 | $(GUARD) 29 | $(ELF2UF2) $< $@ -------------------------------------------------------------------------------- /src/kernel/ipc.c: -------------------------------------------------------------------------------- 1 | #include -------------------------------------------------------------------------------- /src/kernel/ipc.h: -------------------------------------------------------------------------------- 1 | #ifndef _MUNIX_KERNEL_IPC_H 2 | #define _MUNIX_KERNEL_IPC_H 3 | 4 | #include 5 | #include 6 | 7 | struct ipc_channel 8 | { 9 | int reader; 10 | int writer; 11 | 12 | struct message messages[CONFIG_IPC_CHANNEL_LENGTH]; 13 | }; 14 | 15 | struct ipc_duplex 16 | { 17 | struct ipc_channel server; 18 | struct ipc_channel client; 19 | }; 20 | 21 | #endif /* !_MUNIX_KERNEL_IPC_H */ 22 | -------------------------------------------------------------------------------- /src/kernel/link.ld: -------------------------------------------------------------------------------- 1 | ENTRY(_entry_point) 2 | 3 | MEMORY 4 | { 5 | FLASH(rx) : ORIGIN = 0x10000000, LENGTH = 2048k 6 | RAM(rwx) : ORIGIN = 0x20000000, LENGTH = 256k 7 | SCRATCH_X(rwx) : ORIGIN = 0x20040000, LENGTH = 4k 8 | SCRATCH_Y(rwx) : ORIGIN = 0x20041000, LENGTH = 4k 9 | } -------------------------------------------------------------------------------- /src/kernel/start.c: -------------------------------------------------------------------------------- 1 | void 2 | kernel_main() 3 | {} -------------------------------------------------------------------------------- /src/kernel/start.s: -------------------------------------------------------------------------------- 1 | .global _entry_point 2 | _entry_point: 3 | -------------------------------------------------------------------------------- /src/kernel/task.c: -------------------------------------------------------------------------------- 1 | #include -------------------------------------------------------------------------------- /src/kernel/task.h: -------------------------------------------------------------------------------- 1 | #ifndef _MUNIX_KERNEL_TASK_H 2 | #define _MUNIX_KERNEL_TASK_H 3 | 4 | #include 5 | 6 | struct task 7 | { 8 | int id; 9 | char name[CONFIG_TASK_NAME_SIZE]; 10 | }; 11 | 12 | #endif /* !_MUNIX_KERNEL_TASK_H */ -------------------------------------------------------------------------------- /src/library/.buid.mk: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cute-engineering/munix-legacy/7112a162b25e2c31548473854948765661a81aca/src/library/.buid.mk -------------------------------------------------------------------------------- /src/library/crt0.s: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cute-engineering/munix-legacy/7112a162b25e2c31548473854948765661a81aca/src/library/crt0.s -------------------------------------------------------------------------------- /src/library/ctypes.c: -------------------------------------------------------------------------------- 1 | #include "ctype.h" 2 | 3 | int 4 | isspace(int c) 5 | { 6 | if (c == ' ' || c == '\n' || c == '\r' || c == '\t' || c == '\v') 7 | { 8 | return 1; 9 | } 10 | else 11 | { 12 | return 0; 13 | } 14 | } 15 | 16 | int 17 | isalnum(int c) 18 | { 19 | if (c <= 'z' && c >= 'a') 20 | { 21 | return 1; 22 | } 23 | if (c <= 'Z' && c >= 'A') 24 | { 25 | return 1; 26 | } 27 | if (c <= '9' && c >= '0') 28 | { 29 | return 1; 30 | } 31 | return 0; 32 | } 33 | 34 | int 35 | isdigit(int c) 36 | { 37 | if (c <= '9' && c >= '0') 38 | { 39 | return 1; 40 | } 41 | return 0; 42 | } 43 | 44 | int 45 | isalpha(int c) 46 | { 47 | if (c <= 'z' && c >= 'a') 48 | { 49 | return 1; 50 | } 51 | if (c <= 'Z' && c >= 'A') 52 | { 53 | return 1; 54 | } 55 | return 0; 56 | } 57 | 58 | int 59 | to_lower(int c) 60 | { 61 | if (c >= 'A' && c <= 'Z') 62 | { 63 | c -= 'A'; 64 | c += 'a'; 65 | } 66 | return c; 67 | } 68 | 69 | int 70 | to_upper(int c) 71 | { 72 | if (c >= 'a' && c <= 'z') 73 | { 74 | c -= 'a'; 75 | c += 'A'; 76 | } 77 | return c; 78 | } -------------------------------------------------------------------------------- /src/library/ctypes.h: -------------------------------------------------------------------------------- 1 | #ifndef _MUNIX_CTYPES_MATH_H 2 | #define _MUNIX_CTYPES_MATH_H 3 | 4 | int isspace(int c); 5 | int isalnum(int c); 6 | int isdigit(int c); 7 | int isalpha(int c); 8 | 9 | int to_lower(int c); 10 | int to_upper(int c); 11 | #endif /* !_MUNIX_CTYPES_MATH_H */ -------------------------------------------------------------------------------- /src/library/ipc.c: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cute-engineering/munix-legacy/7112a162b25e2c31548473854948765661a81aca/src/library/ipc.c -------------------------------------------------------------------------------- /src/library/ipc.h: -------------------------------------------------------------------------------- 1 | #ifndef _MUNIX_LIBRARY_IPC_H 2 | #define _MUNIX_LIBRARY_IPC_H 3 | 4 | #endif /*!_MUNIX_LIBRARY_IPC_H */ 5 | -------------------------------------------------------------------------------- /src/library/memory.c: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cute-engineering/munix-legacy/7112a162b25e2c31548473854948765661a81aca/src/library/memory.c -------------------------------------------------------------------------------- /src/library/memory.h: -------------------------------------------------------------------------------- 1 | #ifndef _MUNIX_LIBRARY_MEMORY_H 2 | #define _MUNIX_LIBRARY_MEMORY_H 3 | 4 | #endif /*!_MUNIX_LIBRARY_MEMORY_H */ 5 | -------------------------------------------------------------------------------- /src/library/string.c: -------------------------------------------------------------------------------- 1 | #include "string.h" 2 | 3 | size_t 4 | strlen(const char *s) 5 | { 6 | size_t i = 0; 7 | while (s[i] != '\0') 8 | { 9 | i++; 10 | } 11 | return i; 12 | } 13 | 14 | size_t 15 | strnlen(const char *s, size_t maxlen) 16 | { 17 | size_t i = 0; 18 | while (s[i] != '\0' && i < maxlen) 19 | { 20 | i++; 21 | } 22 | return i; 23 | } 24 | 25 | int 26 | strcmp(const char *s1, const char *s2) 27 | { 28 | size_t idx = 0; 29 | while (s1[idx] == s2[idx] && s1[idx]) 30 | { 31 | idx++; 32 | } 33 | return (int)s1[idx] - (int)s2[idx]; 34 | } 35 | 36 | int 37 | strncmp(const char *s1, const char *s2, size_t maxlen) 38 | { 39 | size_t idx = 0; 40 | while (s1[idx] == s2[idx] && s1[idx] && maxlen) 41 | { 42 | idx++; 43 | maxlen--; 44 | } 45 | if (maxlen == 0) 46 | { 47 | return 0; 48 | } 49 | return (int)s1[idx] - (int)s2[idx]; 50 | } 51 | 52 | void * 53 | memset(void *s, int c, size_t n) 54 | { 55 | unsigned char *v = (unsigned char *)s; 56 | for (int i = 0; i < n; i++) 57 | { 58 | v[i] = c; 59 | } 60 | return s; 61 | } 62 | 63 | void * 64 | memcpy(void *dest, const void *src, size_t n) 65 | { 66 | const unsigned char *c_src = (const unsigned char *)src; 67 | unsigned char *c_dest = (unsigned char *)dest; 68 | 69 | for (int i = 0; i < n; i++) 70 | { 71 | c_dest[i] = c_src[i]; 72 | } 73 | return dest; 74 | } -------------------------------------------------------------------------------- /src/library/string.h: -------------------------------------------------------------------------------- 1 | #ifndef _MUNIX_LIBRARY_STRING_H 2 | #define _MUNIX_LIBRARY_STRING_H 3 | 4 | #include 5 | 6 | size_t strlen(const char *s); 7 | size_t strnlen(const char *s, size_t maxlen); 8 | 9 | int strcmp(const char *s1, const char *s2); 10 | int strncmp(const char *s1, const char *s2, size_t maxlen); 11 | 12 | void * memset(void *s, int c, size_t n); 13 | void * memcpy(void *dest, const void *src, size_t n); 14 | #endif /* !_MUNIX_LIBRARY_STRING_H */ 15 | -------------------------------------------------------------------------------- /src/library/syscall.c: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cute-engineering/munix-legacy/7112a162b25e2c31548473854948765661a81aca/src/library/syscall.c -------------------------------------------------------------------------------- /src/library/syscall.h: -------------------------------------------------------------------------------- 1 | #ifndef _MUNIX_LIBRARY_SYSCALL_H 2 | #define _MUNIX_LIBRARY_SYSCALL_H 3 | 4 | #include 5 | 6 | #endif /* !_MUNIX_LIBRARY_SYSCALL_H */ 7 | -------------------------------------------------------------------------------- /src/library/uf2/uf2.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2020 Raspberry Pi (Trading) Ltd. 3 | * 4 | * SPDX-License-Identifier: BSD-3-Clause 5 | */ 6 | 7 | #ifndef _MUNIX_BOOT_UF2_H 8 | #define _MUNIX_BOOT_UF2_H 9 | 10 | #include 11 | #include 12 | 13 | #define UF2_MAGIC_START0 0x0A324655u 14 | #define UF2_MAGIC_START1 0x9E5D5157u 15 | #define UF2_MAGIC_END 0x0AB16F30u 16 | 17 | #define UF2_FLAG_NOT_MAIN_FLASH 0x00000001u 18 | #define UF2_FLAG_FILE_CONTAINER 0x00001000u 19 | #define UF2_FLAG_FAMILY_ID_PRESENT 0x00002000u 20 | #define UF2_FLAG_MD5_PRESENT 0x00004000u 21 | 22 | #define RP2040_FAMILY_ID 0xe48bff56 23 | 24 | struct uf2_block 25 | { 26 | // 32 byte header 27 | uint32_t magic_start0; 28 | uint32_t magic_start1; 29 | uint32_t flags; 30 | uint32_t target_addr; 31 | uint32_t payload_size; 32 | uint32_t block_no; 33 | uint32_t num_blocks; 34 | uint32_t file_size; // or familyID; 35 | uint8_t data[476]; 36 | uint32_t magic_end; 37 | }; 38 | 39 | static_assert(sizeof(struct uf2_block) == 512, "uf2_block not sector sized"); 40 | 41 | #endif /* !_MUNIX_BOOT_UF2_H */ 42 | -------------------------------------------------------------------------------- /src/server/.build.mk: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cute-engineering/munix-legacy/7112a162b25e2c31548473854948765661a81aca/src/server/.build.mk -------------------------------------------------------------------------------- /src/server/audio.c: -------------------------------------------------------------------------------- 1 | int 2 | main(int argc, char const *argv[]) 3 | { 4 | return 0; 5 | } 6 | -------------------------------------------------------------------------------- /src/server/flash.c: -------------------------------------------------------------------------------- 1 | int 2 | main(int argc, char const *argv[]) 3 | { 4 | return 0; 5 | } 6 | -------------------------------------------------------------------------------- /src/server/fs.c: -------------------------------------------------------------------------------- 1 | int 2 | main(int argc, char const *argv[]) 3 | { 4 | return 0; 5 | } 6 | -------------------------------------------------------------------------------- /src/server/init.c: -------------------------------------------------------------------------------- 1 | int 2 | main(int argc, char const *argv[]) 3 | { 4 | return 0; 5 | } 6 | -------------------------------------------------------------------------------- /src/server/io.c: -------------------------------------------------------------------------------- 1 | int 2 | main(int argc, char const *argv[]) 3 | { 4 | return 0; 5 | } 6 | -------------------------------------------------------------------------------- /src/server/process.c: -------------------------------------------------------------------------------- 1 | int 2 | main(int argc, char const *argv[]) 3 | { 4 | return 0; 5 | } 6 | -------------------------------------------------------------------------------- /src/server/uart.c: -------------------------------------------------------------------------------- 1 | int 2 | main(int argc, char const *argv[]) 3 | { 4 | return 0; 5 | } 6 | -------------------------------------------------------------------------------- /src/server/usb.c: -------------------------------------------------------------------------------- 1 | int 2 | main(int argc, char const *argv[]) 3 | { 4 | return 0; 5 | } 6 | -------------------------------------------------------------------------------- /tools/.build.mk: -------------------------------------------------------------------------------- 1 | ELF2UF2=$(BINDIR)/tools/elf2uf2 2 | CONF=$(TOOLDIR)/config.py 3 | 4 | $(ELF2UF2): $(TOOLDIR)/elf2uf2.cpp 5 | $(GUARD) 6 | $(CXX) $(CXXFLAGS) -o $@ $< 7 | -------------------------------------------------------------------------------- /tools/config.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | import sys 4 | import kconfiglib 5 | import menuconfig 6 | import argparse 7 | 8 | kconfig = kconfiglib.Kconfig("Kconfig") 9 | 10 | 11 | def generate_header(dest): 12 | kconfig.load_config('.config') 13 | kconfig.write_autoconf( 14 | dest, '#ifndef _MUNIX_COMMON_CONFIG_H\n' 15 | '#define _MUNIX_COMMON_CONFIG_H\n\n') 16 | # a bit hacky but there is no other way and I really hate '#pragma once' 17 | with open(dest, 'a') as f: 18 | f.write('\n#endif /* !_MUNIX_COMMON_CONFIG_H */\n') 19 | 20 | 21 | def generate_make(dest): 22 | kconfig.load_config('.config') 23 | kconfig.write_config(dest) 24 | 25 | 26 | def defconfig(): 27 | kconfig.write_config() 28 | 29 | 30 | if __name__ == '__main__': 31 | parser = argparse.ArgumentParser() 32 | parser.add_argument('--genheader', action='store', default=None) 33 | parser.add_argument('--genmake', action='store', default=None) 34 | parser.add_argument('--menuconfig', action='store_true') 35 | parser.add_argument('--defconfig', action='store_true') 36 | args = parser.parse_args() 37 | 38 | if args.genheader is not None: 39 | generate_header(args.genheader) 40 | 41 | if args.genmake is not None: 42 | generate_make(args.genmake) 43 | 44 | if args.menuconfig: 45 | menuconfig.menuconfig(kconfig) 46 | 47 | if args.defconfig: 48 | defconfig() 49 | -------------------------------------------------------------------------------- /tools/elf2uf2.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2020 Raspberry Pi (Trading) Ltd. 3 | * 4 | * SPDX-License-Identifier: BSD-3-Clause 5 | */ 6 | 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | 14 | #include "common/elf.h" 15 | #include "library/uf2/uf2.h" 16 | 17 | typedef unsigned int uint; 18 | 19 | #define ERROR_ARGS -1 20 | #define ERROR_FORMAT -2 21 | #define ERROR_INCOMPATIBLE -3 22 | #define ERROR_READ_FAILED -4 23 | #define ERROR_WRITE_FAILED -5 24 | 25 | static char error_msg[512]; 26 | static bool verbose; 27 | 28 | static int 29 | fail(int code, const char *format, ...) 30 | { 31 | va_list args; 32 | va_start(args, format); 33 | vsnprintf(error_msg, sizeof(error_msg), format, args); 34 | va_end(args); 35 | return code; 36 | } 37 | 38 | static int 39 | fail_read_error() 40 | { 41 | return fail(ERROR_READ_FAILED, "Failed to read input file"); 42 | } 43 | 44 | static int 45 | fail_write_error() 46 | { 47 | return fail(ERROR_WRITE_FAILED, "Failed to write output file"); 48 | } 49 | 50 | // we require 256 (as this is the page size supported by the device) 51 | #define LOG2_PAGE_SIZE 8u 52 | #define PAGE_SIZE (1u << LOG2_PAGE_SIZE) 53 | 54 | struct address_range 55 | { 56 | enum type 57 | { 58 | CONTENTS, // may have contents 59 | NO_CONTENTS, // must be uninitialized 60 | IGNORE // will be ignored 61 | }; 62 | address_range(uint32_t from, uint32_t to, type type) 63 | : from(from), to(to), type(type) 64 | {} 65 | address_range() : address_range(0, 0, IGNORE) {} 66 | type type; 67 | uint32_t to; 68 | uint32_t from; 69 | }; 70 | 71 | typedef std::vector address_ranges; 72 | 73 | #define MAIN_RAM_START 0x20000000u 74 | #define MAIN_RAM_END 0x20042000u 75 | #define FLASH_START 0x10000000u 76 | #define FLASH_END 0x15000000u 77 | #define XIP_SRAM_START 0x15000000u 78 | #define XIP_SRAM_END 0x15004000u 79 | 80 | const address_ranges rp2040_address_ranges_flash{ 81 | address_range(FLASH_START, FLASH_END, address_range::type::CONTENTS), 82 | address_range(MAIN_RAM_START, MAIN_RAM_END, 83 | address_range::type::NO_CONTENTS) 84 | }; 85 | 86 | const address_ranges rp2040_address_ranges_ram{ 87 | address_range(MAIN_RAM_START, MAIN_RAM_END, address_range::type::CONTENTS), 88 | address_range(XIP_SRAM_START, XIP_SRAM_END, address_range::type::CONTENTS), 89 | address_range(0x00000000u, 0x00004000u, 90 | address_range::type::IGNORE) // for now we ignore the 91 | // bootrom if present 92 | }; 93 | 94 | struct page_fragment 95 | { 96 | page_fragment(uint32_t file_offset, uint32_t page_offset, uint32_t bytes) 97 | : file_offset(file_offset), page_offset(page_offset), bytes(bytes) 98 | {} 99 | uint32_t file_offset; 100 | uint32_t page_offset; 101 | uint32_t bytes; 102 | }; 103 | 104 | static int 105 | usage() 106 | { 107 | fprintf(stderr, "Usage: elf2uf2 (-v) \n"); 108 | return ERROR_ARGS; 109 | } 110 | 111 | static int 112 | read_and_check_elf32_header(FILE *in, elf32_header &eh_out) 113 | { 114 | if (1 != fread(&eh_out, sizeof(eh_out), 1, in)) { 115 | return fail(ERROR_READ_FAILED, "Unable to read ELF header"); 116 | } 117 | if (eh_out.common.magic != ELF_MAGIC) { 118 | return fail(ERROR_FORMAT, "Not an ELF file"); 119 | } 120 | if (eh_out.common.version != 1 || eh_out.common.version2 != 1) { 121 | return fail(ERROR_FORMAT, "Unrecognized ELF version"); 122 | } 123 | if (eh_out.common.arch_class != 1 || eh_out.common.endianness != 1) { 124 | return fail(ERROR_INCOMPATIBLE, "Require 32 bit little-endian ELF"); 125 | } 126 | if (eh_out.eh_size != sizeof(struct elf32_header)) { 127 | return fail(ERROR_FORMAT, "Invalid ELF32 format"); 128 | } 129 | if (eh_out.common.machine != EM_ARM) { 130 | return fail(ERROR_FORMAT, "Not an ARM executable"); 131 | } 132 | if (eh_out.common.abi != 0) { 133 | return fail(ERROR_INCOMPATIBLE, "Unrecognized ABI"); 134 | } 135 | if (eh_out.flags & EF_ARM_ABI_FLOAT_HARD) { 136 | return fail(ERROR_INCOMPATIBLE, "HARD-FLOAT not supported"); 137 | } 138 | return 0; 139 | } 140 | 141 | int 142 | check_address_range(const address_ranges &valid_ranges, uint32_t addr, 143 | uint32_t vaddr, uint32_t size, bool uninitialized, 144 | address_range &ar) 145 | { 146 | for (const auto &range : valid_ranges) { 147 | if (range.from <= addr && range.to >= addr + size) { 148 | if (range.type == address_range::type::NO_CONTENTS && 149 | !uninitialized) { 150 | return fail( 151 | ERROR_INCOMPATIBLE, 152 | "ELF contains memory contents for uninitialized memory"); 153 | } 154 | ar = range; 155 | if (verbose) { 156 | printf("%s segment %08x->%08x (%08x->%08x)\n", 157 | uninitialized ? "Uninitialized" : "Mapped", addr, 158 | addr + size, vaddr, vaddr + size); 159 | } 160 | return 0; 161 | } 162 | } 163 | return fail(ERROR_INCOMPATIBLE, 164 | "Memory segment %08x->%08x is outside of valid address range " 165 | "for device", 166 | addr, addr + size); 167 | } 168 | 169 | int 170 | read_and_check_elf32_ph_entries( 171 | FILE *in, const elf32_header &eh, const address_ranges &valid_ranges, 172 | std::map> &pages) 173 | { 174 | if (eh.ph_entry_size != sizeof(elf32_ph_entry)) { 175 | return fail(ERROR_FORMAT, "Invalid ELF32 program header"); 176 | } 177 | if (eh.ph_num) { 178 | std::vector entries(eh.ph_num); 179 | if (eh.ph_num != 180 | fread(&entries[0], sizeof(struct elf32_ph_entry), eh.ph_num, in)) { 181 | return fail_read_error(); 182 | } 183 | for (uint i = 0; i < eh.ph_num; i++) { 184 | elf32_ph_entry &entry = entries[i]; 185 | if (entry.type == PT_LOAD && entry.memsz) { 186 | address_range ar; 187 | int rc; 188 | uint mapped_size = std::min(entry.filez, entry.memsz); 189 | if (mapped_size) { 190 | rc = check_address_range(valid_ranges, entry.paddr, 191 | entry.vaddr, mapped_size, false, 192 | ar); 193 | if (rc) 194 | return rc; 195 | // we don't download uninitialized, generally it is BSS and 196 | // should be zero-ed by crt0.S, or it may be COPY areas 197 | // which are undefined 198 | if (ar.type != address_range::type::CONTENTS) { 199 | if (verbose) 200 | printf(" ignored\n"); 201 | continue; 202 | } 203 | uint addr = entry.paddr; 204 | uint remaining = mapped_size; 205 | uint file_offset = entry.offset; 206 | while (remaining) { 207 | uint off = addr & (PAGE_SIZE - 1); 208 | uint len = std::min(remaining, PAGE_SIZE - off); 209 | auto &fragments = 210 | pages[addr - off]; // list of fragments 211 | // note if filesz is zero, we want zero init which is 212 | // handled because the statement above creates an empty 213 | // page fragment list check overlap with any existing 214 | // fragments 215 | for (const auto &fragment : fragments) { 216 | if ((off < fragment.page_offset + fragment.bytes) != 217 | ((off + len) <= fragment.page_offset)) { 218 | fail(ERROR_FORMAT, 219 | "In memory segments overlap"); 220 | } 221 | } 222 | fragments.push_back( 223 | page_fragment{ file_offset, off, len }); 224 | addr += len; 225 | file_offset += len; 226 | remaining -= len; 227 | } 228 | } 229 | if (entry.memsz > entry.filez) { 230 | // we have some uninitialized data too 231 | rc = check_address_range( 232 | valid_ranges, entry.paddr + entry.filez, 233 | entry.vaddr + entry.filez, entry.memsz - entry.filez, 234 | true, ar); 235 | if (rc) 236 | return rc; 237 | } 238 | } 239 | } 240 | } 241 | return 0; 242 | } 243 | 244 | int 245 | realize_page(FILE *in, const std::vector &fragments, 246 | uint8_t *buf, uint buf_len) 247 | { 248 | assert(buf_len >= PAGE_SIZE); 249 | for (auto &frag : fragments) { 250 | assert(frag.page_offset >= 0 && frag.page_offset < PAGE_SIZE && 251 | frag.page_offset + frag.bytes <= PAGE_SIZE); 252 | if (fseek(in, frag.file_offset, SEEK_SET)) { 253 | return fail_read_error(); 254 | } 255 | if (1 != fread(buf + frag.page_offset, frag.bytes, 1, in)) { 256 | return fail_read_error(); 257 | } 258 | } 259 | return 0; 260 | } 261 | 262 | static bool 263 | is_address_valid(const address_ranges &valid_ranges, uint32_t addr) 264 | { 265 | for (const auto &range : valid_ranges) { 266 | if (range.from <= addr && range.to > addr) { 267 | return true; 268 | } 269 | } 270 | return false; 271 | } 272 | 273 | static bool 274 | is_address_initialized(const address_ranges &valid_ranges, uint32_t addr) 275 | { 276 | for (const auto &range : valid_ranges) { 277 | if (range.from <= addr && range.to > addr) { 278 | return address_range::type::CONTENTS == range.type; 279 | } 280 | } 281 | return false; 282 | } 283 | 284 | static bool 285 | is_address_mapped(const std::map> &pages, 286 | uint32_t addr) 287 | { 288 | uint32_t page = addr & ~(PAGE_SIZE - 1); 289 | 290 | if (!pages.count(page)) 291 | return false; 292 | // todo check actual address within page 293 | return true; 294 | } 295 | 296 | int 297 | elf2uf2(FILE *in, FILE *out) 298 | { 299 | elf32_header eh; 300 | std::map> pages; 301 | int rc = read_and_check_elf32_header(in, eh); 302 | bool ram_style = false; 303 | address_ranges valid_ranges = {}; 304 | if (!rc) { 305 | ram_style = is_address_initialized(rp2040_address_ranges_ram, eh.entry); 306 | if (verbose) { 307 | if (ram_style) { 308 | printf("Detected RAM binary\n"); 309 | } else { 310 | printf("Detected FLASH binary\n"); 311 | } 312 | } 313 | valid_ranges = 314 | ram_style ? rp2040_address_ranges_ram : rp2040_address_ranges_flash; 315 | rc = read_and_check_elf32_ph_entries(in, eh, valid_ranges, pages); 316 | } 317 | if (rc) 318 | return rc; 319 | if (pages.empty()) { 320 | return fail(ERROR_INCOMPATIBLE, "The input file has no memory pages"); 321 | } 322 | uint page_num = 0; 323 | if (ram_style) { 324 | uint32_t expected_ep = pages.begin()->first | 0x1; 325 | if (eh.entry != expected_ep) { 326 | return fail(ERROR_INCOMPATIBLE, 327 | "A RAM binary should have an entry point at the " 328 | "beginning: %08x (not %08x)\n", 329 | expected_ep, eh.entry); 330 | } 331 | static_assert(0 == (MAIN_RAM_START & (PAGE_SIZE - 1)), ""); 332 | // currently don't require this as entry point is now at the start, we 333 | // don't know where reset vector is 334 | #if 0 335 | uint8_t buf[PAGE_SIZE]; 336 | rc = realize_page(in, pages[MAIN_RAM_START], buf, sizeof(buf)); 337 | if (rc) return rc; 338 | uint32_t sp = ((uint32_t *)buf)[0]; 339 | uint32_t ip = ((uint32_t *)buf)[1]; 340 | if (!is_address_mapped(pages, ip)) { 341 | return fail(ERROR_INCOMPATIBLE, "Vector table at %08x is invalid: reset vector %08x is not in mapped memory", 342 | MAIN_RAM_START, ip); 343 | } 344 | if (!is_address_valid(valid_ranges, sp - 4)) { 345 | return fail(ERROR_INCOMPATIBLE, "Vector table at %08x is invalid: stack pointer %08x is not in RAM", 346 | MAIN_RAM_START, sp); 347 | } 348 | #endif 349 | } 350 | uf2_block block; 351 | block.magic_start0 = UF2_MAGIC_START0; 352 | block.magic_start1 = UF2_MAGIC_START1; 353 | block.flags = UF2_FLAG_FAMILY_ID_PRESENT; 354 | block.payload_size = PAGE_SIZE; 355 | block.num_blocks = (uint32_t)pages.size(); 356 | block.file_size = RP2040_FAMILY_ID; 357 | block.magic_end = UF2_MAGIC_END; 358 | for (auto &page_entry : pages) { 359 | block.target_addr = page_entry.first; 360 | block.block_no = page_num++; 361 | if (verbose) { 362 | printf("Page %d / %d %08x\n", block.block_no, block.num_blocks, 363 | block.target_addr); 364 | } 365 | memset(block.data, 0, sizeof(block.data)); 366 | rc = 367 | realize_page(in, page_entry.second, block.data, sizeof(block.data)); 368 | if (rc) 369 | return rc; 370 | if (1 != fwrite(&block, sizeof(uf2_block), 1, out)) { 371 | return fail_write_error(); 372 | } 373 | } 374 | return 0; 375 | } 376 | 377 | int 378 | main(int argc, char **argv) 379 | { 380 | int arg = 1; 381 | if (arg < argc && !strcmp(argv[arg], "-v")) { 382 | verbose = true; 383 | arg++; 384 | } 385 | if (argc < arg + 2) { 386 | return usage(); 387 | } 388 | const char *in_filename = argv[arg++]; 389 | FILE *in = fopen(in_filename, "rb"); 390 | if (!in) { 391 | fprintf(stderr, "Can't open input file '%s'\n", in_filename); 392 | return ERROR_ARGS; 393 | } 394 | const char *out_filename = argv[arg++]; 395 | FILE *out = fopen(out_filename, "wb"); 396 | if (!out) { 397 | fprintf(stderr, "Can't open output file '%s'\n", out_filename); 398 | return ERROR_ARGS; 399 | } 400 | 401 | int rc = elf2uf2(in, out); 402 | fclose(in); 403 | fclose(out); 404 | if (rc) { 405 | remove(out_filename); 406 | if (error_msg[0]) { 407 | fprintf(stderr, "ERROR: %s\n", error_msg); 408 | } 409 | } 410 | return rc; 411 | } 412 | --------------------------------------------------------------------------------