├── .clang-format ├── .gitignore ├── .travis.yml ├── LICENSE ├── Makefile ├── README.md ├── arch ├── v7m-entry.S ├── v7m-faults.c ├── v7m-head.S └── v7m-svcall.S ├── docs ├── Makefile ├── api.rst ├── build.rst ├── conf.py ├── contribute.rst ├── debugging.rst ├── emulate.rst ├── index.rst ├── kernel.rst ├── make.bat ├── posix │ ├── parse.py │ ├── posix_opt │ │ ├── 01._POSIX_CLOCK_SELECTION │ │ ├── 02._POSIX_FSYNC │ │ ├── 03._POSIX_MEMLOCK │ │ ├── 04.POSIX_MEMLOCK_RANGE │ │ ├── 05._POSIX_MONOTONIC_CLOCK │ │ ├── 06._POSIX_NO_TRUNC │ │ ├── 07._POSIX_REALTIME_SIGNALS │ │ ├── 08._POSIX_SEMAPHORES │ │ ├── 09._POSIX_SHARED_MEMORY_OBJECTS │ │ ├── 10._POSIX_SYNCHRONIZED_IO │ │ ├── 11._POSIX_THREAD_ATTR_STACKADDR │ │ ├── 12._POSIX_THREAD_ATTR_STACKSIZE │ │ ├── 13._POSIX_THREAD_CPUTIME │ │ ├── 14._POSIX_THREAD_PRIO_INHERIT │ │ ├── 15._POSIX_THREAD_PRIO_PROTECT │ │ ├── 16._POSIX_THREAD_PRIORITY_SCHEDULING │ │ ├── 17._POSIX_THREAD_SPORADIC_SERVER │ │ └── 18._POSIX_TIMERS │ └── posix_req │ │ ├── 01.POSIX_C_LANG_SUPPORT │ │ ├── 02.POSIX_DEVICE_IO │ │ ├── 03.POSIX_FILE_LOCKING │ │ ├── 04.POSIX_SIGNALS │ │ ├── 05.POSIX_SINGLE_PROCESS │ │ ├── 06.POSIX_THREADS_BASE │ │ ├── 07.XSI_THREAD_MUTEX_EXT │ │ └── 08.XSI_THREADS_EXT └── test.rst ├── drivers ├── char │ ├── mem.c │ └── random.c ├── mtd │ ├── mtd.h │ ├── mtdchar.c │ ├── mtdcore.c │ └── mtdram.c ├── serial │ ├── serialchar.c │ ├── serialcore.c │ ├── stm32-uart.c │ └── stm32-uart.h └── timer │ ├── systick.c │ └── timercore.c ├── fs ├── proc.c ├── romfs.c └── tmpfs.c ├── include ├── arch │ ├── semihosting.h │ └── v7m-helper.h ├── fs │ └── romfs.h ├── kernel │ ├── bitmap.h │ ├── bitops.h │ ├── cbuf.h │ ├── compiler.h │ ├── cond.h │ ├── errno-base.h │ ├── faults.h │ ├── fs.h │ ├── hash.h │ ├── irq.h │ ├── kernel.h │ ├── linkage.h │ ├── log2.h │ ├── mm │ │ ├── page.h │ │ └── slab.h │ ├── mutex.h │ ├── sched.h │ ├── serial.h │ ├── signal.h │ ├── softirq.h │ ├── task.h │ ├── thread.h │ ├── time.h │ └── types.h ├── libc │ ├── pthread.h │ ├── ucontext.h │ └── utils.h ├── linux │ ├── compiler.h │ ├── list.h │ ├── poison.h │ ├── stddef.h │ └── types.h ├── piko │ ├── arpa │ │ └── inet.h │ ├── dirent.h │ ├── signal.h │ └── sys │ │ ├── mman.h │ │ ├── mount.h │ │ └── resource.h ├── platform │ └── compiler.h └── version.template.h ├── kernel ├── cond.c ├── config.c ├── faults.c ├── fs │ ├── fs.c │ ├── readdir.c │ └── vfs.c ├── irq.c ├── main.c ├── mm │ ├── mm.c │ ├── page.c │ └── slab.c ├── mutex.c ├── printk.c ├── resource.c ├── sched.c ├── sched │ ├── bitmap.c │ └── rr.c ├── signal.c ├── softirq.c ├── task.c ├── thread.c └── time.c ├── libc ├── fcntl.c ├── filesystem.c ├── piko │ ├── mman.c │ ├── stubs.c │ ├── syscalls.S │ └── syscalls.h ├── pthread.c ├── signal.c ├── stdio.c ├── stdlib.c ├── time.c ├── ucontext.c ├── unistd.c ├── utils.c └── v7m-pthread.S ├── mk ├── cmsis.mk ├── flags.mk └── rules.mk ├── piko.lds.S ├── platform ├── f429disco │ ├── Makefile │ ├── build.mk │ ├── halt.c │ ├── init.c │ ├── platform.h │ └── uart.c └── stm32p103 │ ├── Makefile │ ├── build.mk │ ├── halt.c │ ├── init.c │ ├── platform.h │ └── uart.c ├── scripts ├── gen-proc-version.py ├── gen-syscalls.py └── rstlint.py ├── tests ├── Makefile ├── __init__.py ├── __main__.py ├── bitops_1 │ └── main.c ├── cond_1 │ └── main.c ├── cond_2 │ └── main.c ├── cond_3 │ └── main.c ├── fs_1 │ └── main.c ├── fs_2 │ └── main.c ├── fs_3 │ ├── data │ │ ├── id_rsa │ │ └── id_rsa.pub │ └── main.c ├── fs_4 │ ├── data │ │ ├── id_rsa │ │ └── id_rsa.pub │ └── main.c ├── fs_5 │ └── main.c ├── fs_6 │ ├── data │ │ ├── id_rsa │ │ └── id_rsa.pub │ └── main.c ├── fs_7 │ ├── data │ │ └── .ssh │ │ │ ├── id_rsa │ │ │ └── id_rsa.pub │ └── main.c ├── getpid_1 │ └── main.c ├── itoa_1 │ └── main.c ├── lib │ └── unit.h ├── malloc_1 │ └── main.c ├── mm_1 │ └── main.c ├── mm_2 │ └── main.c ├── mmap_1 │ └── main.c ├── mmap_2 │ ├── data │ │ ├── id_rsa │ │ └── id_rsa.pub │ └── main.c ├── msleep_1 │ └── main.c ├── msleep_2 │ └── main.c ├── mtdram_1 │ └── main.c ├── mutex_1 │ └── main.c ├── mutex_2 │ └── main.c ├── mutex_3 │ └── main.c ├── mutex_4 │ └── main.c ├── mutex_5 │ └── main.c ├── page_3 │ └── main.c ├── raise_1 │ └── main.c ├── raise_2 │ └── main.c ├── raise_3 │ └── main.c ├── readdir_1 │ └── main.c ├── runner.py ├── slab_1 │ └── main.c ├── slab_2 │ └── main.c ├── softirq_1 │ └── main.c ├── softirq_2 │ └── main.c ├── softirq_3 │ └── main.c ├── sprintf_1 │ └── main.c ├── stat_1 │ ├── data │ │ ├── id_rsa │ │ └── id_rsa.pub │ └── main.c ├── syscall_1 │ ├── main.c │ └── trampoline.S ├── sysconf_1 │ └── main.c ├── test_1 │ └── main.c ├── test_2 │ └── main.c ├── thread_1 │ └── main.c ├── thread_2 │ └── main.c ├── thread_3 │ └── main.c ├── thread_4 │ └── main.c ├── thread_5 │ └── main.c ├── thread_6 │ └── main.c ├── timer_1 │ └── main.c ├── timer_2 │ └── main.c ├── timer_3 │ └── main.c ├── timer_4 │ └── main.c ├── timer_5 │ └── main.c └── ucontext_1 │ └── main.c └── user ├── cat.c ├── echo.c ├── exit.c ├── halt.c ├── ls.c ├── reboot.c ├── sh.c └── sh.h /.clang-format: -------------------------------------------------------------------------------- 1 | BasedOnStyle: Chromium 2 | Language: Cpp 3 | MaxEmptyLinesToKeep: 3 4 | IndentCaseLabels: false 5 | AllowShortIfStatementsOnASingleLine: false 6 | AllowShortCaseLabelsOnASingleLine: false 7 | AllowShortLoopsOnASingleLine: false 8 | DerivePointerAlignment: false 9 | PointerAlignment: Right 10 | SpaceAfterCStyleCast: true 11 | TabWidth: 4 12 | UseTab: Never 13 | IndentWidth: 4 14 | BreakBeforeBraces: Linux 15 | AccessModifierOffset: -4 16 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # external source 2 | external/ 3 | 4 | *~ 5 | *.o 6 | *.o.d 7 | *.elf 8 | *.map 9 | *.lds 10 | *.hex 11 | *.bin 12 | 13 | # generated 14 | fs/version 15 | include/kernel/syscalls.h 16 | kernel/syscall.c 17 | 18 | # QEMU generated 19 | DAC_OUT_PUT1.txt 20 | DAC_OUT_PUT2.txt 21 | 22 | # Python 23 | __pycache__ 24 | *.pyc 25 | 26 | # Sphinx 27 | _build 28 | 29 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | sudo: required 2 | dist: trusty 3 | os: linux 4 | language: python 5 | cache: pip 6 | stage: 7 | - docs 8 | - core 9 | 10 | jobs: 11 | include: 12 | - stage: docs 13 | env: TESTING=docs 14 | python: 3.6 15 | before_install: 16 | - sudo apt-get update -qq 17 | install: 18 | - sudo apt-get install cscope 19 | before_script: 20 | - cd docs 21 | - pip install sphinx 22 | script: 23 | - make check 24 | - make html 25 | - &core-stage 26 | stage: core 27 | python: 3.5 28 | env: TESTING=Piko/RT 29 | before_install: 30 | - sudo add-apt-repository -y ppa:team-gcc-arm-embedded/ppa 31 | - sudo apt-get update -qq 32 | install: 33 | - sudo apt install build-essential 34 | - sudo apt-get install -y gcc-arm-embedded 35 | # QEMU deps 36 | - sudo apt install libxenstore3.0 37 | - sudo apt install libxen-dev 38 | - sudo apt install genromfs 39 | - wget https://github.com/PikoRT/tools/raw/master/bin/x86_64-linux/qemu-system-arm 40 | - chmod 777 qemu-system-arm 41 | - export PATH=$PWD:$PATH 42 | before_script: 43 | - arm-none-eabi-gcc --version 44 | - python --version 45 | script: 46 | - make PLAT=stm32p103 47 | - make PLAT=stm32p103 check 48 | - <<: *core-stage 49 | python: 3.6 50 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Piko/RT is freely redistributable under the two-clause BSD License: 2 | 3 | Copyright (c) 2017 Piko/RT Developers. 4 | All rights reserved. 5 | 6 | Redistribution and use in source and binary forms, with or without 7 | modification, are permitted provided that the following conditions are met: 8 | 9 | * Redistributions of source code must retain the above copyright notice, this 10 | list of conditions and the following disclaimer. 11 | 12 | * Redistributions in binary form must reproduce the above copyright notice, 13 | this list of conditions and the following disclaimer in the documentation 14 | and/or other materials provided with the distribution. 15 | 16 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 17 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 19 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 20 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 22 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 23 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 24 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 25 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | NAME = piko 2 | 3 | # select QEMU when the platform is unspecified 4 | PLAT ?= f429disco 5 | CMSIS = external/cmsis 6 | 7 | # The platform Makefile contains hw details and flags 8 | include platform/$(PLAT)/Makefile 9 | 10 | # arch-specific 11 | SSRC += arch/v7m-head.S arch/v7m-entry.S arch/v7m-svcall.S 12 | CSRC += arch/v7m-faults.c 13 | 14 | LIBPIKO_CSRC = $(wildcard libc/*.c) 15 | LIBPIKO_SSRC = $(wildcard libc/*.S) $(wildcard libc/piko/*.S) 16 | 17 | SSRC += $(LIBPIKO_SSRC) 18 | 19 | CSRC += kernel/syscall.c 20 | CSRC += \ 21 | $(wildcard kernel/*.c) \ 22 | $(wildcard kernel/fs/*.c) \ 23 | $(wildcard kernel/mm/*.c) \ 24 | $(wildcard kernel/sched/*.c) \ 25 | $(wildcard fs/*.c) \ 26 | $(wildcard drivers/char/*.c) \ 27 | $(wildcard drivers/mtd/*.c) \ 28 | $(wildcard drivers/timer/timercore.c) \ 29 | $(wildcard drivers/serial/serial*.c) \ 30 | $(wildcard user/*.c) \ 31 | libc/piko/stubs.c \ 32 | libc/piko/mman.c \ 33 | $(LIBPIKO_CSRC) 34 | 35 | OBJS += $(SSRC:.S=.o) $(CSRC:.c=.o) 36 | OBJS := $(sort $(OBJS)) 37 | 38 | deps := $(OBJS:%.o=.%.o.d) 39 | 40 | .PHONY: all check clean distclean check_cc 41 | 42 | all: check_cc $(CMSIS)/$(PLAT) $(NAME).lds $(NAME).bin 43 | 44 | # generic build rules 45 | include mk/flags.mk 46 | include mk/rules.mk 47 | include mk/cmsis.mk 48 | 49 | prebuild: $(CMSIS)/$(PLAT) 50 | 51 | check: check_cc 52 | $(PYTHON) -m tests -p $(PLAT) --qemu $(QEMU_SYSTEM_ARM) --cc $(CC) 53 | 54 | check_cc: 55 | @$(eval PYTHON_VERSION=$(shell echo `$(PYTHON) --version 2>&1 | grep -oE '[^ ]+$$'`)) 56 | @$(eval PYTHON_VERSION=$(shell echo $(PYTHON_VERSION) | awk -F "." '{print $$1$$2 0}')) 57 | @if [ $(PYTHON_VERSION) -lt 350 ]; then \ 58 | echo "Error: Python version must >= 3.5, use PYTHON=/python/binary/path"; \ 59 | return 1;\ 60 | fi; 61 | 62 | clean: 63 | find . -name "*.o" -type f -delete 64 | find . -name "*.o.d" -type f -delete 65 | rm -f $(deps) 66 | ifneq "$(wildcard $(CMSIS) )" "" 67 | find $(CMSIS) -name "*.o" -type f -delete 68 | endif 69 | rm -f $(NAME).map $(NAME).lds 70 | rm -f $(NAME).elf $(NAME).bin 71 | # Remove GEN files 72 | rm -f include/kernel/syscalls.h 73 | rm -f kernel/syscall.c 74 | rm -f fs/version 75 | 76 | distclean: clean 77 | rm -f kernel/syscall.c include/kernel/syscalls.h fs/version 78 | rm -rf $(CMSIS) 79 | 80 | # platform build contains flashing and running rules 81 | include platform/$(PLAT)/build.mk 82 | 83 | -include $(deps) 84 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Piko/RT 2 | 3 | This is `Piko/RT`, a tiny Linux-like real-time operating system kernel, optimized for ARM Cortex-M series microprocessors. 4 | 5 | Prerequisites 6 | ------------- 7 | - [QEMU with an STM32 microcontroller implementation](https://beckus.github.io/qemu_stm32/) 8 | 9 | ## Run test suite 10 | 11 | * Run all test 12 | ```shell 13 | $ make PLAT=stm32p103 check 14 | ``` 15 | 16 | * Run all test with command line tools 17 | ```shell 18 | $ python -m tests 19 | ``` 20 | 21 | * Run specific test cases 22 | ```shell 23 | $ python -m tests fs_1 cond_2 24 | ``` 25 | 26 | ## External Source 27 | 28 | * `scripts/rstlint.py`: written by Georg Brandl 29 | -------------------------------------------------------------------------------- /arch/v7m-faults.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include "kernel.h" 5 | 6 | #define UFSR_DIVBYZERO (1 << 9) 7 | #define UFSR_UNALIGNED (1 << 8) 8 | #define UFSR_NOCP (1 << 3) 9 | #define UFSR_INVPC (1 << 2) 10 | #define UFSR_INVSTATE (1 << 1) 11 | #define UFSR_UNDEFINSTR 1 12 | 13 | void dump_frame(struct kernel_context_regs *noscratch, 14 | struct thread_context_regs *scratch, 15 | u32 exc_return) 16 | { 17 | printk(" r0: %08x r1: %08x r2: %08x r3: %08x\n", 18 | scratch->r0_r3__r12[0], scratch->r0_r3__r12[1], 19 | scratch->r0_r3__r12[2], scratch->r0_r3__r12[3]); 20 | printk(" r4: %08x r5: %08x r6: %08x r7: %08x\n", 21 | noscratch->r4_r12[0], noscratch->r4_r12[1], noscratch->r4_r12[2], 22 | noscratch->r4_r12[3]); 23 | printk(" r8: %08x r9: %08x r10: %08x r11: %08x\n", 24 | noscratch->r4_r12[4], noscratch->r4_r12[5], noscratch->r4_r12[6], 25 | noscratch->r4_r12[7]); 26 | printk("r12: %08x sp: %08x lr: %08x pc: %08x\n", 27 | scratch->r0_r3__r12[4], (u32) scratch, scratch->lr, 28 | scratch->ret_addr); 29 | printk("\nEXC_RETURN: %08x\n", exc_return); 30 | } 31 | 32 | void usagefault(struct kernel_context_regs *noscratch, 33 | struct thread_context_regs *scratch, 34 | u32 exc_return) 35 | { 36 | u32 ufsr = (*((volatile u32 *) 0xe000ed28)) >> 16; 37 | const char *cause = NULL; 38 | 39 | fault_enter("UsageFault"); 40 | dump_frame(noscratch, scratch, exc_return); 41 | if (ufsr & UFSR_DIVBYZERO) 42 | cause = "DIVBYZERO"; 43 | else if (ufsr & UFSR_UNALIGNED) 44 | cause = "UNALIGNED"; 45 | else if (ufsr & UFSR_NOCP) 46 | cause = "NOCP"; 47 | else if (ufsr & UFSR_INVPC) 48 | cause = "INVPC"; 49 | else if (ufsr & UFSR_INVSTATE) 50 | cause = "INVSTATE"; 51 | else if (ufsr & UFSR_UNDEFINSTR) 52 | cause = "UNDEFINSTR"; 53 | if (cause) 54 | printk(" ufsr: %08x <%s>\n", ufsr, cause); 55 | else 56 | printk(" ufsr: %08x\n", ufsr); 57 | fault_exit(); 58 | } 59 | 60 | void busfault(struct kernel_context_regs *noscratch, 61 | struct thread_context_regs *scratch, 62 | u32 exc_return) 63 | { 64 | fault_enter("BusFault"); 65 | dump_frame(noscratch, scratch, exc_return); 66 | fault_exit(); 67 | } 68 | 69 | void memmanage(struct kernel_context_regs *noscratch, 70 | struct thread_context_regs *scratch, 71 | u32 exc_return) 72 | { 73 | fault_enter("MemManage"); 74 | dump_frame(noscratch, scratch, exc_return); 75 | fault_exit(); 76 | } 77 | -------------------------------------------------------------------------------- /arch/v7m-svcall.S: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | .syntax unified 4 | .thumb 5 | 6 | @ offsets in the frame to the registers saved on interrupt-entry 7 | .set R0, 0 8 | .set RET_ADDRESS, 24 9 | .set xPSR, 0x1c 10 | 11 | ENTRY(svcall) 12 | push {lr} 13 | mrs lr, psp 14 | ldr r12, [lr, #RET_ADDRESS] 15 | ldrb r12, [r12, #-2] @ address of the SVC call site 16 | tbb [pc, r12] 17 | 18 | 0: .irpc argc, 0123456 19 | .byte ($\argc - 0b) / 2 20 | .endr 21 | .balign 2 22 | 23 | .balign 2 24 | $0: ldr r12, =syscall_vect 25 | ldr.w r12, [r12, r0, lsl #2] 26 | blx r12 27 | b 0f 28 | 29 | .balign 2 30 | $1: ldr r12, =syscall_vect 31 | ldr.w r12, [r12, r1, lsl #2] 32 | blx r12 33 | b 0f 34 | 35 | .balign 2 36 | $2: ldr r12, =syscall_vect 37 | ldr.w r12, [r12, r2, lsl #2] 38 | blx r12 39 | b 0f 40 | 41 | .balign 2 42 | $3: ldr r12, =syscall_vect 43 | ldr.w r12, [r12, r3, lsl #2] 44 | blx r12 45 | b 0f 46 | 47 | .balign 2 48 | $4: ldr r12, [lr, #xPSR] @ test stack alignment 49 | tst r12, #1 << 9 50 | ite eq 51 | ldreq lr, [lr, #0x20] @ load syscall id 52 | ldrne lr, [lr, #0x24] 53 | ldr r12, =syscall_vect 54 | ldr.w r12, [r12, lr, lsl #2] 55 | blx r12 56 | b 0f 57 | 58 | .balign 2 59 | $5: ldr r12, [lr, #xPSR] @ test stack alignment 60 | tst r12, #1 << 9 61 | ite eq 62 | addeq lr, #0x20 63 | addne lr, #0x24 64 | ldm lr, {r12, lr} @ load syscall id, arg4 65 | push {r12} @ copy arg4 to kernel stack 66 | ldr r12, =syscall_vect 67 | ldr.w r12, [r12, lr, lsl #2] 68 | blx r12 69 | add sp, #4 70 | b 0f 71 | 72 | .balign 2 73 | $6: ldr r12, [lr, #xPSR] @ test stack alignment 74 | tst r12, #1 << 9 75 | ite eq 76 | addeq lr, #0x20 77 | addne lr, #0x24 78 | ldm lr, {r11, r12, lr} @ load syscall id, arg4, arg5 79 | push {r11, r12} @ copy arg4, arg5 to kernel stack 80 | ldr r12, =syscall_vect 81 | ldr.w r12, [r12, lr, lsl #2] 82 | blx r12 83 | pop {r11, r12} //FIXME: pop {r11}; add sp, #4; 84 | 85 | .global syscall_return 86 | syscall_return: 87 | 0: mrs r1, psp 88 | str r0, [r1, #R0] @ update return value in exception frame 89 | pop {pc} 90 | ENDPROC(svcall) 91 | -------------------------------------------------------------------------------- /docs/Makefile: -------------------------------------------------------------------------------- 1 | # Piko/RT documentation 2 | 3 | # You can set these variables from the command line. 4 | SPHINXOPTS = 5 | SPHINXBUILD = sphinx-build 6 | SPHINXPROJ = piko 7 | SOURCEDIR = . 8 | BUILDDIR = _build 9 | 10 | # Put it first so that "make" without argument is like "make help". 11 | help: 12 | @$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) 13 | 14 | .PHONY: help clean Makefile 15 | 16 | # Catch-all target: route all unknown targets to Sphinx using the new 17 | # "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS). 18 | %: Makefile 19 | @$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) 20 | 21 | clean: 22 | -rm -rf _build/* posix/posix_*.rst 23 | 24 | check: 25 | python3 ../scripts/rstlint.py 26 | -------------------------------------------------------------------------------- /docs/api.rst: -------------------------------------------------------------------------------- 1 | .. _api: 2 | 3 | 4 | Piko/RT POSIX API 5 | ================= 6 | 7 | ``Piko/RT`` aim to fulfill IEEE 1003.13-2003 PSE51 standard, this is the list of 8 | POSIX API that ``Piko/RT`` implemented. 9 | 10 | Units of Functionality Requirements 11 | ----------------------------------- 12 | 13 | .. include:: posix/posix_req.rst 14 | 15 | POSIX.1 Option Requirements 16 | --------------------------- 17 | 18 | .. include:: posix/posix_opt.rst 19 | -------------------------------------------------------------------------------- /docs/build.rst: -------------------------------------------------------------------------------- 1 | .. _build: 2 | 3 | Build Piko/RT 4 | ============= 5 | 6 | This chapter will help you start to build ``Piko/RT``, you will need to prepare 7 | some pacakge and settings. 8 | 9 | 10 | Prerequisites 11 | ------------- 12 | 13 | * svn: used to checkout `CMSIS `_. 14 | * wget: used to download required files. 15 | * arm-none-eabi-gcc arm-none-eabi-newlib: cross-compile toolchain. 16 | 17 | Arch Linux:: 18 | 19 | $ pacman -S base-devel svn lsb-release wget 20 | $ pacman -S arm-none-eabi-gcc arm-none-eabi-newlib 21 | $ pacman -S python 22 | 23 | Ubuntu:: 24 | 25 | $ add-apt-repository -y ppa:team-gcc-arm-embedded/ppa 26 | $ apt update -qq 27 | $ apt install build-essential svn gcc-arm-embedded 28 | 29 | macOS:: 30 | 31 | # If you didn't build any thing on macOS before 32 | # please install xcode-select first 33 | $ xcode-select --install 34 | 35 | # install brew from https://brew.sh 36 | $ brew install subversion wget 37 | $ brew tap PX4/homebrew-px4 38 | $ brew install gcc-arm-none-eabi-49 39 | 40 | 41 | Build Piko/RT on Linux and macOS 42 | -------------------------------- 43 | 44 | Default make will build for ``f429disco``:: 45 | 46 | $ make 47 | 48 | You can change the target via ``PLAT``:: 49 | 50 | $ make PLAT=stm32p103 51 | 52 | You can build faster via passing ``-j`` flag:: 53 | 54 | $ make PLAT=stm32p103 -j8 55 | 56 | You can build with verbose output:: 57 | 58 | $ make PLAT=stm32p103 -j8 VERBOSE=1 59 | 60 | 61 | Troubleshooting 62 | --------------- 63 | 64 | If you concur problem when building Piko/RT, please help to fill the issue 65 | on `GitHub `_, 66 | and maybe help to improve the build process, or improve this troubleshooting 67 | part! 68 | -------------------------------------------------------------------------------- /docs/debugging.rst: -------------------------------------------------------------------------------- 1 | .. _debugging: 2 | 3 | Piko/RT Debugging 4 | ================= 5 | 6 | 7 | Using tmux 8 | ---------- 9 | 10 | `tmux `_ is a "terminal multiplexer", it allow you 11 | accessed and controllerd multiple terminals inside a signle terminal like this: 12 | 13 | .. image:: https://gifyu.com/images/asciicast.json.gif 14 | 15 | How to use tmux, please reference these pages: 16 | 17 | * `tmux wiki `_ 18 | * `A tmux Crash Course `_ 19 | * `A Quick and Easy Guide to tmux `_ 20 | 21 | Using OpenOCD 22 | ------------- 23 | 24 | XXX 25 | 26 | Using gdb scripts 27 | ----------------- 28 | 29 | Here are some debug scripts for gdb. You can copy and paste to your `.gdbinit`, 30 | then used in gdb. 31 | 32 | 1. Dump out bitmap scheduler active and expire queue:: 33 | 34 | define dump_bitmap 35 | set $prio = 0 36 | while $prio < 32 37 | if $arg0 == 1 38 | p (struct thread_info *)((char *)(sched_struct.active->queue[$prio].next) - 0x28) 39 | end 40 | if $arg0 == 0 41 | p (struct thread_info *)((char *)(sched_struct.expire->queue[$prio].next) - 0x28) 42 | end 43 | set $prio = $prio + 1 44 | end 45 | end 46 | 47 | how to use:: 48 | 49 | (gdb) dump_bitmap 1 # Dump active 50 | $1 = (struct thread_info *) 0x20000d2c 51 | $2 = (struct thread_info *) 0x20000d34 52 | $3 = (struct thread_info *) 0x20000d3c 53 | $4 = (struct thread_info *) 0x20000d44 54 | $5 = (struct thread_info *) 0x20000d4c 55 | $6 = (struct thread_info *) 0x20000d54 <_active+4> 56 | ... 57 | (gdb) dump_bitmap 0 # Dump expire 58 | 59 | 2. Dump out RR scheduler runqueue:: 60 | 61 | define dump_rr 62 | if list_empty(&rr_runq) 63 | p "empty rr" 64 | else 65 | set $pos = rr_runq->next 66 | while $pos != &rr_runq 67 | p (struct thread_info *)((char *)($pos)-0x28) 68 | set $pos = $pos->next 69 | end 70 | end 71 | end 72 | 73 | how to use:: 74 | 75 | (gdb) dump_rr 76 | -------------------------------------------------------------------------------- /docs/emulate.rst: -------------------------------------------------------------------------------- 1 | .. _emulate: 2 | 3 | Using QEMU to Develop Piko/RT 4 | ============================= 5 | 6 | 7 | Prepare QEMU 8 | ------------ 9 | 10 | You will need to prepare QEMU STM32 emulator from: 11 | `QEMU STM32 v0.1.3 `_ 12 | 13 | After download, compile the qemu_stm32 by:: 14 | 15 | $ ./configure --disable-werror --enable-debug \ 16 | --target-list="arm-softmmu" \ 17 | --extra-cflags=-DDEBUG_CLKTREE \ 18 | --extra-cflags=-DDEBUG_STM32_RCC \ 19 | --extra-cflags=-DDEBUG_STM32_UART \ 20 | --extra-cflags=-DSTM32_UART_NO_BAUD_DELAY \ 21 | --extra-cflags=-DSTM32_UART_ENABLE_OVERRUN --python=python2 22 | $ make -j8 23 | 24 | 25 | Make sure you have export the ``arm-softmmu`` to ``$PATH````:: 26 | 27 | $ export PATH=$PATH:~/qemu_stm32-stm32_v0.1.3/arm-softmmu 28 | 29 | 30 | Run Piko/RT on QEMU STM32-p103 31 | ------------------------------ 32 | 33 | You will need to run these command:: 34 | 35 | $ make PLAT=stm32p103 36 | $ make PLAT=stm32p103 run 37 | 38 | If you run correctly, then you will start Piko/RT and get the shell:: 39 | 40 | Memory map: 41 | .text = 00000140--0000315a 12314 Bytes 42 | .rodata = 00003190--00003a26 2198 Bytes 43 | .data = 20000000--20000514 1300 Bytes 44 | .bss = 20000518--20001298 3456 Bytes 45 | .heap = 200012a0--200022a0 4096 Bytes 46 | .pgmem = 20008000--2000f000 28672 Bytes 47 | Order Bitmap 48 | 0 00000000 00000000 00000000 00000000 49 | 1 00000000 00000000 50 | 2 00000000 51 | 3 00007fff 52 | Created idle_thread at <0x20008200> 53 | Created main_thread at <0x20008800> with priority=31 54 | Reclaim early stack's physical memory (2048 Bytes, order=3). 55 | Creating /proc/version 56 | Creating /proc/meminfo 57 | Creating /dev/mem 58 | Creating /dev/null 59 | Creating /dev/zero 60 | Creating /dev/random 61 | Creating MTD device mtd0 62 | Kernel bootstrap done. 63 | -- 64 | 65 | $ 66 | -------------------------------------------------------------------------------- /docs/index.rst: -------------------------------------------------------------------------------- 1 | Welcome to piko's documentation! 2 | ================================ 3 | 4 | .. toctree:: 5 | :maxdepth: 2 6 | :caption: Contents: 7 | 8 | build.rst 9 | emulate.rst 10 | kernel.rst 11 | test.rst 12 | contribute.rst 13 | debugging.rst 14 | 15 | .. toctree:: 16 | :caption: API: 17 | 18 | api.rst 19 | 20 | 21 | Indices and tables 22 | ================== 23 | 24 | * :ref:`genindex` 25 | * :ref:`modindex` 26 | * :ref:`search` 27 | -------------------------------------------------------------------------------- /docs/kernel.rst: -------------------------------------------------------------------------------- 1 | .. _kernel: 2 | 3 | Piko/RT Design & Concept 4 | ======================== 5 | 6 | Piko/RT is a tiny Linux-like real-time operating system kernel, optimized for 7 | Arm Cortex-M series microprocessors. 8 | 9 | Compatibility with Linux is **NOT** the goal of Piko/RT. Instead, PSE51 10 | (minimal real-time system profile) should be appropriately an analog from 11 | the perspective of design. 12 | -------------------------------------------------------------------------------- /docs/make.bat: -------------------------------------------------------------------------------- 1 | @ECHO OFF 2 | 3 | pushd %~dp0 4 | 5 | REM Command file for Sphinx documentation 6 | 7 | if "%SPHINXBUILD%" == "" ( 8 | set SPHINXBUILD=sphinx-build 9 | ) 10 | set SOURCEDIR=. 11 | set BUILDDIR=_build 12 | set SPHINXPROJ=piko 13 | 14 | if "%1" == "" goto help 15 | 16 | %SPHINXBUILD% >NUL 2>NUL 17 | if errorlevel 9009 ( 18 | echo. 19 | echo.The 'sphinx-build' command was not found. Make sure you have Sphinx 20 | echo.installed, then set the SPHINXBUILD environment variable to point 21 | echo.to the full path of the 'sphinx-build' executable. Alternatively you 22 | echo.may add the Sphinx directory to PATH. 23 | echo. 24 | echo.If you don't have Sphinx installed, grab it from 25 | echo.http://sphinx-doc.org/ 26 | exit /b 1 27 | ) 28 | 29 | %SPHINXBUILD% -M %1 %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% 30 | goto end 31 | 32 | :help 33 | %SPHINXBUILD% -M help %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% 34 | 35 | :end 36 | popd 37 | -------------------------------------------------------------------------------- /docs/posix/parse.py: -------------------------------------------------------------------------------- 1 | # Helper for generate POSIX API table 2 | # XXX: used from docs, not here 3 | 4 | import glob 5 | import os 6 | import tempfile 7 | import shutil 8 | import subprocess 9 | 10 | CSCOPE = shutil.which('cscope') if shutil.which('cscope') else '/usr/bin/cscope' 11 | CSCOPE_DB = tempfile.NamedTemporaryFile() 12 | BACKTO = '../' 13 | LIBC_PATH = BACKTO + 'libc' 14 | 15 | 16 | def read_file(path): 17 | # Return list of API 18 | return open(path).read().replace(' ', '').replace('\n', '').strip().split(',') 19 | 20 | 21 | def build_cscope(): 22 | CSCOPE_DB.write(subprocess.check_output("find %s -name '*.c'" % LIBC_PATH, shell=True)) 23 | CSCOPE_DB.write(subprocess.check_output("find %s -name '*.h'" % LIBC_PATH, shell=True)) 24 | CSCOPE_DB.write(subprocess.check_output("find %s -name '*.S'" % LIBC_PATH, shell=True)) 25 | CSCOPE_DB.flush() 26 | return CSCOPE_DB.name 27 | 28 | 29 | def cscope_search(name): 30 | return subprocess.check_output("%s -i %s -L1%s" % (CSCOPE, CSCOPE_DB.name, name), shell=True) 31 | 32 | 33 | def parse_path(s): 34 | return s.split('\n')[0].strip(BACKTO).split()[0:3:2] if s and s.startswith(LIBC_PATH) else ('', 0) 35 | 36 | 37 | def generate_table(name): 38 | header = ['.. table:: %s' % os.path.basename(name), ' :widths: 45 10 35', ''] 39 | longest_api_length = 10 40 | 41 | apis = read_file(name) 42 | result = [] 43 | 44 | for api in apis: 45 | if not api: 46 | continue 47 | longest_api_length = max(len(api), longest_api_length) 48 | 49 | s = cscope_search(api.strip('()')).decode('utf-8') 50 | result.append([api, s.startswith(LIBC_PATH), *parse_path(s)]) 51 | 52 | splitline = ' {:=>{}} ===== {}'.format('', longest_api_length, '=' * 30) 53 | header.append(splitline) 54 | header.append(' {:<{}} IMPL Path'.format('API Name', longest_api_length)) 55 | header.append(splitline) 56 | 57 | for i, r in enumerate(result): 58 | result[i] = (' {:<{}} {}'.format(r[0], longest_api_length, 'O' if r[1] else 'X') + 59 | ' {}'.format('{}:{}'.format(r[2], r[3]) if r[1] else '')) 60 | result.append(splitline) 61 | result = header + result 62 | 63 | return '\n'.join(result) 64 | 65 | 66 | if __name__ == '__main__': 67 | build_cscope() 68 | 69 | reqs = glob.glob('posix/posix_req/*') 70 | with open('posix/posix_req.rst', 'w') as f: 71 | for req in reqs: 72 | f.write(generate_table(req)) 73 | f.write('\n\n') 74 | 75 | opts = glob.glob('posix/posix_opt/*') 76 | with open('posix/posix_opt.rst', 'w') as f: 77 | for opt in opts: 78 | f.write(generate_table(opt)) 79 | f.write('\n\n') 80 | -------------------------------------------------------------------------------- /docs/posix/posix_opt/01._POSIX_CLOCK_SELECTION: -------------------------------------------------------------------------------- 1 | clock_nanosleep() 2 | -------------------------------------------------------------------------------- /docs/posix/posix_opt/02._POSIX_FSYNC: -------------------------------------------------------------------------------- 1 | fsync() 2 | -------------------------------------------------------------------------------- /docs/posix/posix_opt/03._POSIX_MEMLOCK: -------------------------------------------------------------------------------- 1 | m lockall(), m unlockall() 2 | -------------------------------------------------------------------------------- /docs/posix/posix_opt/04.POSIX_MEMLOCK_RANGE: -------------------------------------------------------------------------------- 1 | mlock(), munlock() 2 | -------------------------------------------------------------------------------- /docs/posix/posix_opt/05._POSIX_MONOTONIC_CLOCK: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PikoRT/pikoRT/569cee508b34c3831ee573daa4e2cccf4ab51cbb/docs/posix/posix_opt/05._POSIX_MONOTONIC_CLOCK -------------------------------------------------------------------------------- /docs/posix/posix_opt/06._POSIX_NO_TRUNC: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PikoRT/pikoRT/569cee508b34c3831ee573daa4e2cccf4ab51cbb/docs/posix/posix_opt/06._POSIX_NO_TRUNC -------------------------------------------------------------------------------- /docs/posix/posix_opt/07._POSIX_REALTIME_SIGNALS: -------------------------------------------------------------------------------- 1 | sigqueue(), sigtim edwait(), sigwaitinfo() 2 | -------------------------------------------------------------------------------- /docs/posix/posix_opt/08._POSIX_SEMAPHORES: -------------------------------------------------------------------------------- 1 | sem _close(), sem _destroy(), sem _getvalue(), sem _init(), sem _open(), sem _post(), 2 | sem _trywait(), sem _wait(), sem _unlink (), 3 | sem _tim edwait() 4 | -------------------------------------------------------------------------------- /docs/posix/posix_opt/09._POSIX_SHARED_MEMORY_OBJECTS: -------------------------------------------------------------------------------- 1 | shm _open(), shm _unlink() 2 | -------------------------------------------------------------------------------- /docs/posix/posix_opt/10._POSIX_SYNCHRONIZED_IO: -------------------------------------------------------------------------------- 1 | fdatasync() 2 | -------------------------------------------------------------------------------- /docs/posix/posix_opt/11._POSIX_THREAD_ATTR_STACKADDR: -------------------------------------------------------------------------------- 1 | pthread_attr_getstackaddr(), pthread_attr_setstackaddr() 2 | -------------------------------------------------------------------------------- /docs/posix/posix_opt/12._POSIX_THREAD_ATTR_STACKSIZE: -------------------------------------------------------------------------------- 1 | pthread_attr_getstack (), pthread_attr_setstack() 2 | -------------------------------------------------------------------------------- /docs/posix/posix_opt/13._POSIX_THREAD_CPUTIME: -------------------------------------------------------------------------------- 1 | pthread_getcpuclockid() 2 | -------------------------------------------------------------------------------- /docs/posix/posix_opt/14._POSIX_THREAD_PRIO_INHERIT: -------------------------------------------------------------------------------- 1 | pthread_m utexattr_getprotocol(), pthread_m utexattr_setprotocol() 2 | -------------------------------------------------------------------------------- /docs/posix/posix_opt/15._POSIX_THREAD_PRIO_PROTECT: -------------------------------------------------------------------------------- 1 | pthread_m utex_getprioceiling(), pthread_m utex_setprioceiling(), 2 | pthread_m utexattr_getprioceiling(), pthread_m utexattr_getprotocol(), 3 | pthread_m utexattr_setprioceiling(), pthread_m utexattr_setprotocol() 4 | -------------------------------------------------------------------------------- /docs/posix/posix_opt/16._POSIX_THREAD_PRIORITY_SCHEDULING: -------------------------------------------------------------------------------- 1 | pthread_attr_getinheritsched(), pthread_attr_getschedpolicy(), 2 | pthread_attr_getscope(), pthread_attr_setinheritsched(), 3 | pthread_attr_setschedpolicy(), pthread_attr_setscope(), 4 | pthread_getschedparam (), pthread_setschedparam (), pthread_setschedprio(), 5 | sched_get_priority_m ax(), sched_get_priority_m in(), sched_rr_get_interval() 6 | -------------------------------------------------------------------------------- /docs/posix/posix_opt/17._POSIX_THREAD_SPORADIC_SERVER: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PikoRT/pikoRT/569cee508b34c3831ee573daa4e2cccf4ab51cbb/docs/posix/posix_opt/17._POSIX_THREAD_SPORADIC_SERVER -------------------------------------------------------------------------------- /docs/posix/posix_opt/18._POSIX_TIMERS: -------------------------------------------------------------------------------- 1 | clock_getres(), clock_gettim e(), clock_settim e(), nanosleep(), tim er_create(), 2 | tim er_detele(), tim er_getoverrun(), tim er_gettim e(), tim er_settim e() 3 | -------------------------------------------------------------------------------- /docs/posix/posix_req/01.POSIX_C_LANG_SUPPORT: -------------------------------------------------------------------------------- 1 | abs(), asctime(), asctime_r(), atof(), atoi(), atol(), 2 | atoll(), bsearch(), calloc(), ctime(), ctime_r(), 3 | difftime(), div(), feclearexcept(), fegetenv(), 4 | fegetexceptflag(), fegetround(), feholdexcept(), 5 | feraiseexcept(), fesetenv(), fesetexceptflag(), 6 | fesetround(), fetestexcept(), feupdateenv(), free(), 7 | gmtime(), gmtime_r(), imaxabs(), imaxdiv(), 8 | isalnum(), isalpha(), isblank(), iscntrl(), isdigit(), 9 | isgraph(), islower(), isprint(), ispunct(), isspace(), 10 | isupper(), isxdigit(), labs(), ldiv(), llabs(), lldiv(), 11 | localeconv(), localtime(), localtime_r(), malloc(), 12 | memchr(), memcmp(), memcpy(), memmove(), 13 | memset(), mktime(), qsort(), rand(), rand_r(), 14 | realloc(), setlocale(), snprintf(), sprintf(), srand(), 15 | sscanf(), strcat(), strchr(), strcmp(), strcoll(), strcpy(), 16 | strcspn(), strerror(), strerror_r(), strftime(), strlen(), 17 | strncat(), strncmp(), strncpy(), strpbrk(), strrchr(), 18 | strspn(), strstr(), strtod(), strtof(), strtoimax(), 19 | strtok(), strtok_r(), strtol(), strtold(), strtoll(), 20 | strtoul(), strtoull(), strtoumax(), strxfrm(), time(), 21 | tolower(), toupper(), tzname, tzset(), va_arg(), 22 | va_copy(), va_end(), va_start(), vsnprintf(), vsprintf(), 23 | vsscanf() 24 | -------------------------------------------------------------------------------- /docs/posix/posix_req/02.POSIX_DEVICE_IO: -------------------------------------------------------------------------------- 1 | clearerr(), close(), fclose(), fdopen(), feof(), ferror(), 2 | fflush (), fgetc(), fgets(), fileno(), fopen(), fprintf(), 3 | fputc(), fputs(), fread(), freopen(), fscanf(), fwrite(), 4 | getc(), getchar(), gets(), open(), perror(), printf(), 5 | putc(), putchar(), puts(), read(), scanf(), setbuf(), 6 | setvbuf(), stderr, stdin, stdout, ungetc(), vfprintf(), 7 | vfscanf(), vprintf(), vscanf(), write() 8 | -------------------------------------------------------------------------------- /docs/posix/posix_req/03.POSIX_FILE_LOCKING: -------------------------------------------------------------------------------- 1 | flockfile(), ftrylockfile(), funlockfile(), getc_unlocked(), 2 | getchar_unlocked(), putc_unlocked(), 3 | putchar_unlocked() 4 | -------------------------------------------------------------------------------- /docs/posix/posix_req/04.POSIX_SIGNALS: -------------------------------------------------------------------------------- 1 | abort(), alarm(), kill(), pause(), raise(), sigaction(), 2 | sigaddset(), sigdelset(), sigemptyset(), sigfillset(), 3 | sigismember(), signal(), sigpending(), sigprocmask(), 4 | sigsuspend(), sigwait() 5 | -------------------------------------------------------------------------------- /docs/posix/posix_req/05.POSIX_SINGLE_PROCESS: -------------------------------------------------------------------------------- 1 | confstr(), environ, errno, getenv(), setenv(), sysconf(), 2 | uname(), unsetenv() 3 | -------------------------------------------------------------------------------- /docs/posix/posix_req/06.POSIX_THREADS_BASE: -------------------------------------------------------------------------------- 1 | pthread_atfork(), pthread_attr_destroy(), 2 | pthread_attr_getdetachstate(), 3 | pthread_attr_getschedparam(), pthread_attr_init(), 4 | pthread_attr_setdetachstate(), 5 | pthread_attr_setschedparam(), pthread_cancel(), 6 | pthread_cleanup_pop(), pthread_cleanup_push(), 7 | pthread_cond_broadcast(), pthread_cond_destroy(), 8 | pthread_cond_init(), pthread_cond_signal(), 9 | pthread_cond_timedwait(), pthread_cond_wait(), 10 | pthread_condattr_destroy(), pthread_condattr_init(), 11 | pthread_create(), pthread_detach(), pthread_equal(), 12 | pthread_exit(), pthread_getspecific(), pthread_join(), 13 | pthread_key_create(), pthread_key_delete(), 14 | pthread_kill(), pthread_mutex_destroy(), 15 | pthread_mutex_init(), pthread_mutex_lock(), 16 | pthread_mutex_trylock(), pthread_mutex_unlock(), 17 | pthread_mutexattr_destroy(), 18 | pthread_mutexattr_init(), pthread_once(), 19 | pthread_self(), pthread_setcalcelstate(), 20 | pthread_setcanceltype(), pthread_setspecific(), 21 | pthread_sigmask(), pthread_testcancel() 22 | -------------------------------------------------------------------------------- /docs/posix/posix_req/07.XSI_THREAD_MUTEX_EXT: -------------------------------------------------------------------------------- 1 | pthread_mutexattr_gettype(), 2 | pthread_mutexattr_settype() 3 | -------------------------------------------------------------------------------- /docs/posix/posix_req/08.XSI_THREADS_EXT: -------------------------------------------------------------------------------- 1 | pthread_attr_getguardsize(), pthread_attr_getstack(), 2 | pthread_attr_setguardsize(), 3 | pthread_attr_setstack(), pthread_getconcurrency(), 4 | pthread_setconcurrency() 5 | -------------------------------------------------------------------------------- /docs/test.rst: -------------------------------------------------------------------------------- 1 | .. _test: 2 | 3 | 4 | Piko/RT Test Suite 5 | ================== 6 | 7 | Piko/RT test suite is under ``tests`` directory, it contain a makefile, many test 8 | folder and it self is a python package. Each test folder represent a test case. 9 | 10 | 11 | Run Tests 12 | --------- 13 | 14 | Test suite can be run by top directory Makefile:: 15 | 16 | $ make PLAT=stm32p103 check 17 | 18 | This will run all test in the test suite, also, you can use ``tests`` as a python 19 | package, to run all test via python command line:: 20 | 21 | $ python -m tests 22 | 23 | You can also run partial via python:: 24 | 25 | $ python -m tests fs_1 stat_1 thread_5 26 | 27 | Python command line tool verbose default is disable, you can pass the flag ``-v`` 28 | to enable:: 29 | 30 | $ python -m tests -v 31 | $ python -m tests fs_1 -v 32 | -------------------------------------------------------------------------------- /drivers/char/random.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | //#include 6 | #include 7 | 8 | typedef unsigned long long u64; 9 | 10 | /* xorshift1024* generator, http://vigna.di.unimi.it/ftp/papers/xorshift.pdf */ 11 | static u64 next(void) 12 | { 13 | // clang-format off 14 | static u64 s[16] = { 15 | 0x84242f96eca9c41dull, 0xa3c65b8776f96855ull, 0x5b34a39f070b5837ull, 16 | 0x4489affce4f31a1eull, 0x2ffeeb0a48316f40ull, 0xdc2d9891fe68c022ull, 17 | 0x3659132bb12fea70ull, 0xaac17d8efa43cab8ull, 0xc4cb815590989b13ull, 18 | 0x5ee975283d71c93bull, 0x691548c86c1bd540ull, 0x7910c41d10a1e6a5ull, 19 | 0x0b5fc64563b3e2a8ull, 0x047f7684e9fc949dull, 0xb99181f2d8f685caull, 20 | 0x284600e3f30e38c3ull 21 | }; 22 | // clang-format on 23 | 24 | static int p; 25 | const u64 s0 = s[p]; 26 | u64 s1 = s[p = (p + 1) & 15]; 27 | 28 | s1 ^= s1 << 31; // a 29 | s[p] = s1 ^ s0 ^ (s1 >> 11) ^ (s0 >> 30); // b,c 30 | 31 | return s[p] * UINT64_C(1181783497276652981); 32 | } 33 | 34 | static int open_random(__unused struct inode *inode, __unused struct file *file) 35 | { 36 | return 0; 37 | } 38 | 39 | static ssize_t read_random(__unused struct file *file, 40 | char *buf, 41 | size_t count, 42 | __unused off_t offset) 43 | { 44 | static u64 m; 45 | static int remaining_bytes = 0; 46 | 47 | if ((int) count <= remaining_bytes) { 48 | memcpy(buf, (char *) &m + 8 - remaining_bytes, count); 49 | remaining_bytes -= count; 50 | } else { 51 | for (int i = count; i > 0; i -= 8, buf = (char *) buf + 8) { 52 | m = next(); 53 | memcpy(buf, &m, MIN(i, 8)); 54 | remaining_bytes = 8 - MIN(i, 8); 55 | } 56 | } 57 | 58 | return count; 59 | } 60 | 61 | const struct file_operations random_fops = { 62 | .open = open_random, 63 | .read = read_random, 64 | }; 65 | -------------------------------------------------------------------------------- /drivers/mtd/mtdchar.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | /* romfs depends on mtdchar */ 6 | 7 | static int mtdchar_open(struct inode *inode, struct file *file) 8 | { 9 | file->f_private = inode->i_private; 10 | 11 | return 0; 12 | } 13 | 14 | static ssize_t mtdchar_read(struct file *file, 15 | char *buf, 16 | size_t count, 17 | off_t offset) 18 | { 19 | size_t retlen; 20 | struct mtd_info *mtd = file->f_private; 21 | 22 | if (mtd_read(mtd, offset, count, &retlen, (unsigned char *) buf) < 0) 23 | return -1; 24 | 25 | return retlen; 26 | } 27 | 28 | static ssize_t mtdchar_write(struct file *file, 29 | const char *buf, 30 | size_t count, 31 | off_t *offset) 32 | { 33 | size_t retlen; 34 | struct mtd_info *mtd = file->f_private; 35 | 36 | if (mtd_write(mtd, *offset, count, &retlen, (const unsigned char *) buf) < 37 | 0) 38 | return -1; 39 | 40 | return retlen; 41 | } 42 | 43 | const struct file_operations mtdchar_fops = { 44 | .open = mtdchar_open, 45 | .read = mtdchar_read, 46 | .write = mtdchar_write, 47 | }; 48 | -------------------------------------------------------------------------------- /drivers/mtd/mtdcore.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | void mtd_erase_callback(struct erase_info *instr) 5 | { 6 | if (instr->callback) 7 | instr->callback(instr); 8 | } 9 | 10 | int mtd_erase(struct mtd_info *mtd, struct erase_info *instr) 11 | { 12 | if ((instr->addr >= mtd->size) || (instr->len > mtd->size - instr->addr)) 13 | return -EINVAL; 14 | if (!(mtd->flags & MTD_WRITEABLE)) 15 | return -EROFS; 16 | instr->fail_addr = MTD_FAIL_ADDR_UNKNOWN; 17 | if (!instr->len) { 18 | instr->state = MTD_ERASE_DONE; 19 | mtd_erase_callback(instr); 20 | return 0; 21 | } 22 | 23 | return mtd->mtd_erase(mtd, instr); 24 | } 25 | 26 | int mtd_point(struct mtd_info *mtd, 27 | off_t from, 28 | size_t len, 29 | size_t *retlen, 30 | void **virt /* , resource_size_t *phys */) 31 | { 32 | *retlen = 0; 33 | *virt = NULL; 34 | if (!mtd->mtd_point) 35 | return -1; // return -EOPNOTSUPP; 36 | if ((from < 0) || ((unsigned long) from >= mtd->size) || 37 | (len > mtd->size - from)) 38 | return -EINVAL; 39 | if (!len) 40 | return 0; 41 | 42 | return mtd->mtd_point(mtd, from, len, retlen, virt /* , phys */); 43 | } 44 | 45 | int mtd_read(struct mtd_info *mtd, 46 | off_t from, 47 | size_t len, 48 | size_t *retlen, 49 | unsigned char *buf) 50 | { 51 | *retlen = 0; 52 | if ((from < 0) || ((unsigned long) from >= mtd->size) || 53 | (len > mtd->size - from)) 54 | return -EINVAL; 55 | if (!len) 56 | return 0; 57 | 58 | return mtd->mtd_read(mtd, from, len, retlen, buf); 59 | } 60 | 61 | int mtd_write(struct mtd_info *mtd, 62 | off_t to, 63 | size_t len, 64 | size_t *retlen, 65 | const unsigned char *buf) 66 | { 67 | *retlen = 0; 68 | if ((to < 0) || ((unsigned long) to >= mtd->size) || (len > mtd->size - to)) 69 | return -EINVAL; 70 | if (!len) 71 | return 0; 72 | 73 | return mtd->mtd_write(mtd, to, len, retlen, buf); 74 | } 75 | -------------------------------------------------------------------------------- /drivers/mtd/mtdram.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | #define SIZE_1KB 1024 8 | 9 | static int mtdram_erase(struct mtd_info *mtd, struct erase_info *instr) 10 | { 11 | memset((char *) mtd->priv + instr->addr, 0xff, instr->len); 12 | instr->state = MTD_ERASE_DONE; 13 | mtd_erase_callback(instr); 14 | 15 | return 0; 16 | } 17 | 18 | static int mtdram_point(struct mtd_info *mtd, 19 | off_t from, 20 | size_t len, 21 | size_t *retlen, 22 | void **virt /* , resource_size_t *phys */) // void **at 23 | { 24 | *virt = mtd->priv + from; 25 | *retlen = len; 26 | 27 | return 0; 28 | } 29 | 30 | static int mtdram_unpoint(struct mtd_info *mtd, off_t from, size_t len) 31 | { 32 | (void) mtd, (void) from, (void) len; 33 | 34 | return 0; 35 | } 36 | 37 | int mtdram_write(struct mtd_info *mtd, 38 | off_t to, 39 | size_t len, 40 | size_t *retlen, 41 | const void *buf) 42 | { 43 | memcpy((char *) mtd->priv + to, buf, len); 44 | *retlen = len; 45 | 46 | return 0; 47 | } 48 | 49 | int mtdram_read(struct mtd_info *mtd, 50 | off_t from, 51 | size_t len, 52 | size_t *retlen, 53 | void *buf) 54 | { 55 | memcpy(buf, mtd->priv + from, len); 56 | *retlen = len; 57 | 58 | return 0; 59 | } 60 | 61 | int mtdram_init_device(struct mtd_info *mtd, 62 | void *mapped_address, 63 | unsigned long size, 64 | const char *name) 65 | { 66 | if (size % SIZE_1KB) 67 | return -1; 68 | mtd->name = name; 69 | mtd->size = size; 70 | mtd->erasesize = SIZE_1KB, mtd->priv = mapped_address; 71 | mtd->mtd_erase = mtdram_erase; 72 | mtd->mtd_point = mtdram_point; 73 | mtd->mtd_unpoint = mtdram_unpoint; 74 | mtd->mtd_read = mtdram_read; 75 | mtd->mtd_write = mtdram_write; 76 | 77 | return 0; 78 | } 79 | 80 | struct mtd_info mtdram; 81 | 82 | extern char __mtdram_start__; 83 | extern char __mtdram_size__; 84 | 85 | extern const struct file_operations mtdchar_fops; 86 | 87 | static struct inode mtd0_inode = { 88 | .i_fop = &mtdchar_fops, 89 | .i_private = &mtdram, 90 | }; 91 | 92 | void mtdram_init(void) 93 | { 94 | struct dentry dentry = {.d_inode = &mtd0_inode, .d_name = "mtd0"}; 95 | 96 | printk("Creating MTD device %s\n", dentry.d_name); 97 | mtdram_init_device(&mtdram, &__mtdram_start__, 98 | (unsigned long) &__mtdram_size__, dentry.d_name); 99 | 100 | init_tmpfs_inode(&mtd0_inode); 101 | vfs_link(NULL, dev_inode(), &dentry); 102 | } 103 | -------------------------------------------------------------------------------- /drivers/serial/serialchar.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | static void serialchar_callback(struct serial_info *serial) 8 | { 9 | sched_enqueue(serial->owner); 10 | } 11 | 12 | static int serialchar_open(struct inode *inode, struct file *file) 13 | { 14 | file->f_private = inode->i_private; 15 | struct serial_info *serial = file->f_private; 16 | CURRENT_THREAD_INFO(cur_thread); 17 | serial->owner = cur_thread; 18 | serial->ops->callback = serialchar_callback; 19 | 20 | return 0; 21 | } 22 | 23 | static ssize_t serialchar_read(struct file *file, 24 | char *buf, 25 | size_t count, 26 | __unused off_t offset) 27 | { 28 | size_t retlen; 29 | struct serial_info *serial = file->f_private; 30 | 31 | while (serial->rx_count < count) { 32 | CURRENT_THREAD_INFO(cur_thread); 33 | sched_dequeue(cur_thread); 34 | sched_elect(0); 35 | } 36 | if (count == 1) 37 | return serial_getc(serial, buf); 38 | if (serial_gets(serial, count, &retlen, buf) < 0) 39 | return -1; 40 | 41 | return retlen; 42 | } 43 | 44 | static ssize_t serialchar_write(struct file *file, 45 | const char *buf, 46 | size_t count, 47 | __unused off_t *offset) 48 | { 49 | struct serial_info *serial = file->f_private; 50 | 51 | return serial_puts(serial, count, buf); 52 | } 53 | 54 | const struct file_operations serialchar_fops = { 55 | .open = serialchar_open, 56 | .read = serialchar_read, 57 | .write = serialchar_write, 58 | }; 59 | -------------------------------------------------------------------------------- /drivers/serial/serialcore.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | 5 | void serial_init(void) 6 | { 7 | extern unsigned long __serial_hook_start__; 8 | extern unsigned long __serial_hook_end__; 9 | 10 | for (struct serial_hook *hook = (struct serial_hook *) &__serial_hook_start__; 11 | hook < (struct serial_hook *) &__serial_hook_end__; hook++) 12 | hook->init(); 13 | } 14 | 15 | void serial_activity_callback(struct serial_info *serial) 16 | { 17 | if (serial->ops->callback) 18 | serial->ops->callback(serial); 19 | } 20 | 21 | int serial_getc(struct serial_info *serial, char *c) 22 | { 23 | return serial->ops->serial_getc(serial, c); 24 | } 25 | 26 | int serial_gets(struct serial_info *serial, 27 | size_t len, 28 | size_t *retlen, 29 | char *buf) 30 | { 31 | return serial->ops->serial_gets(serial, len, retlen, buf); 32 | } 33 | 34 | int serial_putc(struct serial_info *serial, char c) 35 | { 36 | return serial->ops->serial_putc(serial, c); 37 | } 38 | 39 | int serial_puts(struct serial_info *serial, 40 | size_t len, 41 | const char *buf) 42 | { 43 | return serial->ops->serial_puts(serial, len, buf); 44 | } 45 | -------------------------------------------------------------------------------- /drivers/serial/stm32-uart.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | #include 11 | #include "platform.h" 12 | 13 | static struct cbuf_info cbuf; 14 | static char buf[16]; 15 | 16 | static int stm32_getc(struct serial_info *serial, char *c) 17 | { 18 | serial->rx_count--; 19 | cbuf_getc(&cbuf, c); 20 | 21 | return 0; 22 | } 23 | 24 | static int stm32_putc(struct serial_info *serial, char c) 25 | { 26 | if (!serial || c < 0) 27 | return EOF; 28 | 29 | USART_TypeDef *uart = serial->priv; 30 | 31 | while (!(uart->SR & USART_SR_TXE)) 32 | ; 33 | uart->DR = c; 34 | 35 | return c; 36 | } 37 | 38 | static int stm32_puts(struct serial_info *serial, 39 | size_t len, 40 | const char *buf) 41 | { 42 | int i = 0; 43 | 44 | for (i = 0; i < len; i++) 45 | if (stm32_putc(serial, buf[i]) == EOF) 46 | return EOF; 47 | 48 | return i; 49 | } 50 | 51 | static struct serial_ops stm32_ops = { 52 | .serial_getc = stm32_getc, 53 | .serial_putc = stm32_putc, 54 | .serial_puts = stm32_puts, 55 | }; 56 | 57 | struct serial_info stm32_info = { 58 | .priv = USARTx, 59 | .ops = &stm32_ops, 60 | }; 61 | 62 | static void stm32_uartx_isr(void) 63 | { 64 | if (USARTx->SR & USART_SR_RXNE) { 65 | char c = (char) USARTx->DR; 66 | cbuf_putc(&cbuf, c); 67 | stm32_info.rx_count++; 68 | serial_activity_callback(&stm32_info); 69 | } 70 | } 71 | 72 | extern const struct file_operations serialchar_fops; 73 | 74 | static struct inode stm32_inode = { 75 | .i_fop = &serialchar_fops, 76 | .i_private = &stm32_info, 77 | }; 78 | 79 | static int stm32_serial_init(void) 80 | { 81 | uart_init(); 82 | 83 | struct dentry dentry = {.d_inode = &stm32_inode, .d_name = "ttyS0"}; 84 | 85 | cbuf_init(&cbuf, buf, 16); 86 | 87 | init_tmpfs_inode(&stm32_inode); 88 | vfs_link(0, dev_inode(), &dentry); 89 | 90 | /* enable rx interrupt */ 91 | request_irq(USARTx_IRQn, stm32_uartx_isr); 92 | NVIC_SetPriority(USARTx_IRQn, 0xE); 93 | NVIC_EnableIRQ(USARTx_IRQn); 94 | 95 | return 0; 96 | } 97 | 98 | HOOK_SERIAL_INIT(UART, stm32_serial_init) 99 | -------------------------------------------------------------------------------- /drivers/serial/stm32-uart.h: -------------------------------------------------------------------------------- 1 | #ifndef _DRIVER_SERIAL_STM32_USART_H 2 | #define _DRIVER_SERIAL_STM32_USART_H 3 | 4 | #include "platform.h" 5 | 6 | struct stm32_uart_port { 7 | GPIO_TypeDef *gpio_tx; 8 | GPIO_TypeDef *gpio_rx; 9 | 10 | GPIO_InitTypeDef gpio_tx_init_info; 11 | GPIO_InitTypeDef gpio_rx_init_info; 12 | 13 | UART_HandleTypeDef uart_init_info; 14 | 15 | void (*gpio_init)(GPIO_TypeDef *GPIOx, GPIO_InitTypeDef *GPIO_Init); 16 | 17 | HAL_StatusTypeDef (*uart_init)(UART_HandleTypeDef *huart); 18 | 19 | void (*gpio_tx_clk_enable)(void); 20 | void (*gpio_rx_clk_enable)(void); 21 | void (*uart_clk_enable)(void); 22 | }; 23 | 24 | #endif /* !_DRIVER_SERIAL_STM32_USART_H */ 25 | -------------------------------------------------------------------------------- /drivers/timer/timercore.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #include 6 | #include 7 | 8 | static struct timer_operations *timer_operations; 9 | 10 | void config_timer_operations(struct timer_operations *tops) 11 | { 12 | timer_operations = tops; 13 | } 14 | 15 | struct timer_info *timer_alloc(void) 16 | { 17 | struct timer_info *timer; 18 | 19 | timer = malloc(sizeof(struct timer_info)); 20 | if (!timer) { 21 | errno = ENOMEM; 22 | return NULL; 23 | } 24 | timer->tops = timer_operations; // FIXME: get info from vnode or device 25 | if (timer->tops->timer_alloc(timer)) { 26 | free(timer); 27 | return NULL; 28 | } 29 | 30 | return timer; 31 | } 32 | 33 | int timer_set(struct timer_info *timer, const struct timespec *value) 34 | { 35 | return timer->tops->timer_set(timer, value); 36 | } 37 | 38 | int timer_get(struct timer_info *timer, struct itimerspec *value) 39 | { 40 | return timer->tops->timer_get(timer, value); 41 | } 42 | 43 | int timer_free(struct timer_info *timer) 44 | { 45 | if (!timer->disarmed) { 46 | const struct timespec zero_val = {0, 0}; 47 | timer_set(timer, &zero_val); 48 | } 49 | timer->tops->timer_free(timer); 50 | free(timer); 51 | 52 | return 0; 53 | } 54 | 55 | void timer_expire_callback(struct timer_info *timer) 56 | { 57 | if (timer->callback) 58 | timer->callback(timer); 59 | } 60 | -------------------------------------------------------------------------------- /fs/proc.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include 5 | #include 6 | 7 | // https://linux.die.net/lkmpg/x861.html 8 | // https://lwn.net/Articles/22355/ 9 | 10 | extern const char _version_ptr; 11 | extern const int _version_len; 12 | 13 | static int open_version(__unused struct inode *inode, 14 | __unused struct file *file) 15 | { 16 | return 0; 17 | } 18 | 19 | static ssize_t read_version(__unused struct file *file, 20 | char *buf, 21 | size_t count, 22 | off_t offset) 23 | { 24 | size_t n = MIN(count, (int) &_version_len - offset); 25 | 26 | strncpy(buf, &_version_ptr + offset, n); 27 | 28 | return n; 29 | } 30 | 31 | static int open_meminfo(__unused struct inode *inode, 32 | __unused struct file *file) 33 | { 34 | return 0; 35 | } 36 | 37 | static ssize_t read_meminfo(__unused struct file *file, 38 | char *buf, 39 | size_t count, 40 | off_t offset) 41 | { 42 | memcpy(buf, (void *) offset, count); 43 | 44 | return count; 45 | } 46 | 47 | static const struct file_operations version_fops = { 48 | .open = open_version, 49 | .read = read_version, 50 | }; 51 | 52 | static const struct file_operations meminfo_fops = { 53 | .open = open_meminfo, 54 | .read = read_meminfo, 55 | }; 56 | 57 | extern const struct inode_operations tmpfs_iops; 58 | 59 | static struct inode proc_inodes[] = { 60 | { 61 | /* /proc/version */ 62 | .i_ino = 1001, 63 | .i_op = &tmpfs_iops, 64 | .i_fop = &version_fops, 65 | }, 66 | { 67 | /* /proc/meminfo */ 68 | .i_ino = 1002, 69 | .i_op = &tmpfs_iops, 70 | .i_fop = &meminfo_fops, 71 | }, 72 | }; 73 | 74 | void proc_init(void) 75 | { 76 | struct dentry dentry; 77 | const char *names[] = { 78 | "version", "meminfo", 79 | }; 80 | 81 | for (int i = 0; i < 2; i++) { 82 | printk("Creating /proc/%s\n", names[i]); 83 | dentry.d_inode = &proc_inodes[i], strcpy(dentry.d_name, names[i]); 84 | vfs_link(0, proc_inode(), &dentry); 85 | } 86 | } 87 | -------------------------------------------------------------------------------- /include/arch/semihosting.h: -------------------------------------------------------------------------------- 1 | #ifndef _ARCH_SEMIHOSTING_H 2 | #define _ARCH_SEMIHOSTING_H 3 | 4 | void v7m_semihost_exit(int status); 5 | 6 | #endif /* !_ARCH_SEMIHOSTING_H */ 7 | -------------------------------------------------------------------------------- /include/arch/v7m-helper.h: -------------------------------------------------------------------------------- 1 | #ifndef _ARCH_V7M_HELPER_H 2 | #define _ARCH_V7M_HELPER_H 3 | 4 | #define V7M_EXC_RETURN_HANDLER_MAIN 0xfffffff1 5 | #define V7M_EXC_RETURN_THREAD_MAIN 0xfffffff9 6 | #define V7M_EXC_RETURN_THREAD_PROCESS 0xfffffffd 7 | 8 | static inline void *v7m_set_thumb_bit(void *addr) 9 | { 10 | return (void *) ((unsigned long) addr | 1ul); 11 | } 12 | 13 | static inline void *v7m_clear_thumb_bit(void *addr) 14 | { 15 | return (void *) ((unsigned long) addr & ~1ul); 16 | } 17 | 18 | #endif /* !_ARCH_V7M_HELPER_H */ 19 | -------------------------------------------------------------------------------- /include/fs/romfs.h: -------------------------------------------------------------------------------- 1 | #ifndef _KERNEL_FS_ROMFS_H 2 | #define _KERNEL_FS_ROMFS_H 3 | 4 | #include 5 | 6 | #include 7 | 8 | #define ROMFS_FILETYPE_MASK 0x7 9 | 10 | #define ROMFS_FILETYPE_HARD 0 11 | #define ROMFS_FILETYPE_DIR 1 12 | #define ROMFS_FILETYPE_REG 2 13 | #define ROMFS_FILETYPE_LNK 3 14 | #define ROMFS_FILETYPE_BLK 4 15 | #define ROMFS_FILETYPE_CHR 5 16 | #define ROMFS_FILETYPE_SOCKET 6 17 | #define ROMFS_FILETYPE_FIFO 7 18 | 19 | struct romfs_superblock { 20 | __u8 magic_number[8]; 21 | __u32 full_size; 22 | __u32 checksum; 23 | char volume_name[0]; 24 | }; 25 | 26 | struct romfs_inode { 27 | __u32 next_filehdr; 28 | __u32 spec_info; 29 | __u32 size; 30 | __u32 checksum; 31 | char file_name[0]; 32 | }; 33 | 34 | #define ROMFS_SUPER_BLOCK(sb) \ 35 | ({ \ 36 | struct mtd_info *mtd = (sb)->s_private; \ 37 | struct romfs_superblock *rs = mtd->priv; \ 38 | rs; \ 39 | }) 40 | 41 | #define ROMFS_INODE(rs, offset) \ 42 | ({ \ 43 | __u32 addr = (__u32)(rs) + (__u32)(offset); \ 44 | struct romfs_inode *ri = (struct romfs_inode *) addr; \ 45 | ri; \ 46 | }) 47 | 48 | int romfs_mount(const char *source, 49 | const char *target, 50 | const char *filesystemtype, 51 | unsigned long mountflags, 52 | const void *data); 53 | 54 | #endif /* !_KERNEL_FS_ROMFS_H */ 55 | -------------------------------------------------------------------------------- /include/kernel/bitops.h: -------------------------------------------------------------------------------- 1 | #ifndef KERNEL_BITOPS_H 2 | #define KERNEL_BITOPS_H 3 | 4 | #include 5 | 6 | #include 7 | #include 8 | 9 | #define BITS_PER_CHAR 8 10 | #define BITS_PER_LONG (BITS_PER_CHAR * sizeof(long)) 11 | 12 | static inline unsigned long flsl(unsigned long word) 13 | { 14 | return word ? sizeof(long) * BITS_PER_CHAR - __builtin_clz(word) : 0; 15 | } 16 | 17 | static inline void clear_bit(unsigned long bit, unsigned long *word) 18 | { 19 | *word &= ~(1 << bit); 20 | } 21 | 22 | static inline void set_bit(unsigned long bit, unsigned long *word) 23 | { 24 | *word |= (1 << bit); 25 | } 26 | 27 | static inline void bitmap_set_bit(unsigned long *map, unsigned long bit) 28 | { 29 | set_bit(bit % BITS_PER_LONG, &map[bit / BITS_PER_LONG]); 30 | } 31 | 32 | static inline void bitmap_clear_bit(unsigned long *map, unsigned long bit) 33 | { 34 | clear_bit(bit % BITS_PER_LONG, &map[bit / BITS_PER_LONG]); 35 | } 36 | 37 | static inline unsigned long bitmap_get_bit(unsigned long *map, 38 | unsigned long bit) 39 | { 40 | return (map[bit / BITS_PER_LONG] >> (bit % BITS_PER_LONG)) & 1; 41 | } 42 | 43 | static inline unsigned long find_first_bit(const unsigned long *addr, 44 | unsigned long size) 45 | { 46 | for (unsigned long i = 0; i * BITS_PER_LONG < size; i++) { 47 | if (addr[i]) 48 | return MIN(i * BITS_PER_LONG + __builtin_ffsl(addr[i]) - 1, size); 49 | } 50 | 51 | return size; 52 | } 53 | 54 | static inline unsigned long find_first_zero_bit(const unsigned long *addr, 55 | unsigned long size) 56 | { 57 | for (unsigned long i = 0; i * BITS_PER_LONG < size; i++) { 58 | if (addr[i] != ~0ul) 59 | return MIN(i * BITS_PER_LONG + __builtin_ffsl(~addr[i]) - 1, size); 60 | } 61 | 62 | return size; 63 | } 64 | 65 | #endif /* !KERNEL_BITOPS_H */ 66 | -------------------------------------------------------------------------------- /include/kernel/cbuf.h: -------------------------------------------------------------------------------- 1 | #ifndef _KERNEL_CBUF_H 2 | #define _KERNEL_CBUF_H 3 | 4 | #include 5 | 6 | struct cbuf_info { 7 | size_t len; 8 | int pos_begin; 9 | int pos_end; 10 | void *buf; 11 | }; 12 | 13 | static inline void cbuf_init(struct cbuf_info *cbuf, void *buf, size_t len) 14 | { 15 | cbuf->len = len; 16 | cbuf->pos_begin = 0; 17 | cbuf->pos_end = 0; 18 | cbuf->buf = buf; 19 | } 20 | 21 | static inline int cbuf_getc(struct cbuf_info *cbuf, char *c) 22 | { 23 | if (cbuf->pos_begin == cbuf->pos_end) 24 | return 0; 25 | *c = *((char *) cbuf->buf + cbuf->pos_begin); 26 | cbuf->pos_begin = (cbuf->pos_begin + 1) % cbuf->len; 27 | 28 | return 1; 29 | } 30 | 31 | static inline int cbuf_putc(struct cbuf_info *cbuf, char c) 32 | { 33 | *((char *) cbuf->buf + cbuf->pos_end) = c; 34 | cbuf->pos_end = (cbuf->pos_end + 1) % cbuf->len; 35 | 36 | return 0; 37 | } 38 | 39 | #endif /* !_KERNEL_CBUF_H */ 40 | -------------------------------------------------------------------------------- /include/kernel/compiler.h: -------------------------------------------------------------------------------- 1 | #ifndef _KERNEL_COMPILER_H 2 | #define _KERNEL_COMPILER_H 3 | 4 | /* GCC weak symbol declaration */ 5 | #ifndef __weak 6 | #define __weak __attribute__((weak)) 7 | #endif 8 | 9 | #endif /* !_KERNEL_COMPILER_H */ 10 | -------------------------------------------------------------------------------- /include/kernel/cond.h: -------------------------------------------------------------------------------- 1 | #ifndef KERNEL_COND_H 2 | #define KERNEL_COND_H 3 | 4 | #include 5 | 6 | int sys_pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex); 7 | int sys_pthread_cond_signal(pthread_cond_t *cond); 8 | 9 | #endif /* !KERNEL_COND_H */ 10 | -------------------------------------------------------------------------------- /include/kernel/errno-base.h: -------------------------------------------------------------------------------- 1 | #ifndef _KERNEL_ERRNO_BASE_H_ 2 | #define _KERNEL_ERRNO_BASE_H_ 3 | 4 | #define EPERM 1 /* Operation not permitted */ 5 | #define ENOENT 2 /* No such file or directory */ 6 | #define ESRCH 3 /* No such process */ 7 | #define EINTR 4 /* Interrupted system call */ 8 | #define EIO 5 /* I/O error */ 9 | #define ENXIO 6 /* No such device or address */ 10 | #define E2BIG 7 /* Argument list too long */ 11 | #define ENOEXEC 8 /* Exec format error */ 12 | #define EBADF 9 /* Bad file number */ 13 | #define ECHILD 10 /* No child processes */ 14 | #define EAGAIN 11 /* Try again */ 15 | #define ENOMEM 12 /* Out of memory */ 16 | #define EACCES 13 /* Permission denied */ 17 | #define EFAULT 14 /* Bad address */ 18 | #define ENOTBLK 15 /* Block device required */ 19 | #define EBUSY 16 /* Device or resource busy */ 20 | #define EEXIST 17 /* File exists */ 21 | #define EXDEV 18 /* Cross-device link */ 22 | #define ENODEV 19 /* No such device */ 23 | #define ENOTDIR 20 /* Not a directory */ 24 | #define EISDIR 21 /* Is a directory */ 25 | #define EINVAL 22 /* Invalid argument */ 26 | #define ENFILE 23 /* File table overflow */ 27 | #define EMFILE 24 /* Too many open files */ 28 | #define ENOTTY 25 /* Not a typewriter */ 29 | #define ETXTBSY 26 /* Text file busy */ 30 | #define EFBIG 27 /* File too large */ 31 | #define ENOSPC 28 /* No space left on device */ 32 | #define ESPIPE 29 /* Illegal seek */ 33 | #define EROFS 30 /* Read-only file system */ 34 | #define EMLINK 31 /* Too many links */ 35 | #define EPIPE 32 /* Broken pipe */ 36 | #define EDOM 33 /* Math argument out of domain of func */ 37 | #define ERANGE 34 /* Math result not representable */ 38 | 39 | #endif /* !_KERNEL_ERRNO_BASE_H_ */ 40 | -------------------------------------------------------------------------------- /include/kernel/faults.h: -------------------------------------------------------------------------------- 1 | #ifndef KERNEL_FAULTS_H 2 | #define KERNEL_FAULTS_H 3 | 4 | #include 5 | #include 6 | 7 | void fault_enter(const char *s); 8 | void fault_exit(void); 9 | 10 | /* arch-dependent */ 11 | void dump_frame(struct kernel_context_regs *noscratch, 12 | struct thread_context_regs *scratch, 13 | u32 exc_return); 14 | 15 | #endif /* !KERNEL_FAULTS_H */ 16 | -------------------------------------------------------------------------------- /include/kernel/hash.h: -------------------------------------------------------------------------------- 1 | #ifndef _KERNEL_HASH_H 2 | #define _KERNEL_HASH_H 3 | 4 | #include 5 | 6 | static inline unsigned long hash_djb2(unsigned char *str, size_t len) 7 | { 8 | unsigned long hash = 5381; 9 | 10 | for (int i = 0; i < (int) len; i++) { 11 | int c = str[i]; 12 | hash = ((hash << 5) + hash) + c; /* hash * 33 + c */ 13 | } 14 | 15 | return hash; 16 | } 17 | 18 | #endif /* _KERNEL_HASH_H */ 19 | -------------------------------------------------------------------------------- /include/kernel/irq.h: -------------------------------------------------------------------------------- 1 | #ifndef KERNEL_IRQ_H 2 | #define KERNEL_IRQ_H 3 | 4 | #define NR_IRQS 64 5 | 6 | /* irq status */ 7 | enum { 8 | IRQ_NOREQUEST = 1, 9 | }; 10 | 11 | /* irq data state(for per-chip) */ 12 | enum { 13 | IRQD_IRQ_DISABLED = 1, 14 | IRQD_INACTIVATED = 1 << 2, 15 | IRQD_ACTIVATED = 1 << 3, 16 | IRQD_PENDING = 1 << 4, 17 | }; 18 | 19 | /** 20 | * struct irq_data - per chip data 21 | * 22 | * @state: status information for irq chip 23 | * XXX: Thanks for CMSIS. We don't have to impl per chip function and data, 24 | * but this concept should be remained due to more precious description 25 | * of irqs and chips(HW). 26 | */ 27 | struct irq_data { 28 | unsigned int state; 29 | }; 30 | 31 | struct irqaction; 32 | 33 | /** 34 | * struct irq_desc - interrupt descriptor 35 | * 36 | * @action: the irq action chain 37 | * @status: status information 38 | * @irq_state: per irq state information 39 | */ 40 | struct irq_desc { 41 | struct irq_data irq_data; 42 | struct irqaction *action; 43 | unsigned int status; 44 | }; 45 | 46 | typedef void (*irq_handler_t)(void); 47 | /** 48 | * struct irqaction - per interrupt action descriptor 49 | * @handler: interrupt handler function 50 | * @irq: interrupt number 51 | */ 52 | struct irqaction { 53 | irq_handler_t handler; 54 | unsigned int irq; 55 | }; 56 | 57 | int request_irq(unsigned int irq, irq_handler_t hdlr); 58 | int free_irq(unsigned int irq); 59 | 60 | #endif /* !KERNEL_IRQ_H */ 61 | -------------------------------------------------------------------------------- /include/kernel/kernel.h: -------------------------------------------------------------------------------- 1 | #ifndef _KERNEL_KERNEL_H 2 | #define _KERNEL_KERNEL_H 3 | 4 | /* round-down to a power of 2 */ 5 | #define align(x, a) align_mask(x, (__typeof__(x))((a) -1)) 6 | #define align_mask(x, mask) ((x) & ~(mask)) 7 | 8 | /* round-up to a power of 2 */ 9 | #define align_next(x, a) align_next_mask(x, (__typeof__(x))((a) -1)) 10 | #define align_next_mask(x, mask) (((x) + (mask)) & ~(mask)) 11 | 12 | #define ARRAY_SIZE(arr) ((size_t)(sizeof(arr) / sizeof(*(arr)))) 13 | 14 | #define ARRAY_INDEX(elt, arr) \ 15 | ({ \ 16 | unsigned int _elt = (unsigned int) (elt); \ 17 | unsigned int _arr = (unsigned int) (arr); \ 18 | (_elt - _arr) / sizeof(*(elt)); \ 19 | }) 20 | 21 | #define container_of(ptr, type, member) \ 22 | ({ \ 23 | const __typeof__(((type *) 0)->member) *__mptr = (ptr); \ 24 | (type *) ((char *) __mptr - offsetof(type, member)); \ 25 | }) 26 | 27 | #define SWAP(x, y) \ 28 | { \ 29 | __typeof__(x) tmp = x; \ 30 | x = y; \ 31 | y = tmp; \ 32 | } \ 33 | while (0) 34 | 35 | int printk(const char *fmt, ...); 36 | 37 | #endif /* !_KERNEL_KERNEL_H */ 38 | -------------------------------------------------------------------------------- /include/kernel/linkage.h: -------------------------------------------------------------------------------- 1 | #ifndef _KERNEL_LINKAGE_H 2 | #define _KERNEL_LINKAGE_H 3 | 4 | #ifdef __ASSEMBLER__ 5 | 6 | #define ENTRY(name) \ 7 | .globl name; \ 8 | .align 4; \ 9 | name: 10 | 11 | #define END(name) .size name, .- name 12 | 13 | #define ENDPROC(name) \ 14 | .type name, % function; \ 15 | END(name) 16 | 17 | #endif /* __ASSEMBLER__ */ 18 | 19 | #endif /* !_KERNEL_LINKAGE_H */ 20 | -------------------------------------------------------------------------------- /include/kernel/log2.h: -------------------------------------------------------------------------------- 1 | #ifndef KERNEL_LOG2_H 2 | #define KERNEL_LOG2_H 3 | 4 | #include 5 | 6 | // clang-format off 7 | 8 | #define ilog2(x) \ 9 | ( \ 10 | __builtin_constant_p(x) ? ( \ 11 | (x) < 1 ? __ilog2_NaN() : \ 12 | (x) & (1ul << 31) ? 31 : \ 13 | (x) & (1ul << 30) ? 30 : \ 14 | (x) & (1ul << 29) ? 29 : \ 15 | (x) & (1ul << 28) ? 28 : \ 16 | (x) & (1ul << 27) ? 27 : \ 17 | (x) & (1ul << 26) ? 26 : \ 18 | (x) & (1ul << 25) ? 25 : \ 19 | (x) & (1ul << 24) ? 24 : \ 20 | (x) & (1ul << 23) ? 23 : \ 21 | (x) & (1ul << 22) ? 22 : \ 22 | (x) & (1ul << 21) ? 21 : \ 23 | (x) & (1ul << 20) ? 20 : \ 24 | (x) & (1ul << 19) ? 19 : \ 25 | (x) & (1ul << 18) ? 18 : \ 26 | (x) & (1ul << 17) ? 17 : \ 27 | (x) & (1ul << 16) ? 16 : \ 28 | (x) & (1ul << 15) ? 15 : \ 29 | (x) & (1ul << 14) ? 14 : \ 30 | (x) & (1ul << 13) ? 13 : \ 31 | (x) & (1ul << 12) ? 12 : \ 32 | (x) & (1ul << 11) ? 11 : \ 33 | (x) & (1ul << 10) ? 10 : \ 34 | (x) & (1ul << 9) ? 9 : \ 35 | (x) & (1ul << 8) ? 8 : \ 36 | (x) & (1ul << 7) ? 7 : \ 37 | (x) & (1ul << 6) ? 6 : \ 38 | (x) & (1ul << 5) ? 5 : \ 39 | (x) & (1ul << 4) ? 4 : \ 40 | (x) & (1ul << 3) ? 3 : \ 41 | (x) & (1ul << 2) ? 2 : \ 42 | (x) & (1ul << 1) ? 1 : \ 43 | (x) & (1ul << 0) ? 0 : \ 44 | __ilog2_NaN() \ 45 | ) : \ 46 | __ilog2(x) \ 47 | ) 48 | 49 | // clang-format on 50 | 51 | static inline unsigned long __ilog2(unsigned long x) 52 | { 53 | return flsl(x) - 1; 54 | } 55 | 56 | static inline __attribute__((noreturn)) unsigned long __ilog2_NaN(void) 57 | { 58 | for (;;) 59 | ; 60 | } 61 | 62 | #endif /* !KERNEL_LOG2_H */ 63 | -------------------------------------------------------------------------------- /include/kernel/mm/page.h: -------------------------------------------------------------------------------- 1 | #ifndef _KERNEL_MM_PAGE_H 2 | #define _KERNEL_MM_PAGE_H 3 | 4 | #define MAX_PAGE_ORDER 3 /* max page size is 2 KB */ 5 | #define MIN_PAGE_SIZE 256 /* min page size is 256 bytes */ 6 | 7 | void *alloc_pages(unsigned long order); 8 | void free_pages(unsigned long addr, unsigned long order); 9 | void show_page_bitmap(void); 10 | long size_to_page_order(unsigned long size); 11 | unsigned long page_alloc_signature(void); 12 | 13 | #endif /* !_KERNEL_MM_PAGE_H */ 14 | -------------------------------------------------------------------------------- /include/kernel/mm/slab.h: -------------------------------------------------------------------------------- 1 | #ifndef _KERNEL_MM_SLAB_H 2 | #define _KERNEL_MM_SLAB_H 3 | 4 | #include 5 | 6 | #include "linux/list.h" 7 | 8 | #define CACHE_PAGE_SIZE 256 9 | #define CACHE_NAMELEN 16 10 | 11 | #define CACHE_OPT_NONE 0 12 | /* OPT_FORCE: create a new cache, even when the object size matches a generic 13 | * cache (i.e. 8B, 16B, 32B...) 14 | * OPT_PERSIST: this cache cannot be destroyed (i.e. when a cache w/o OPT_FORCE 15 | * has been created and silently merged into a general object 16 | * cache and the user try to destroy the cache he created) 17 | */ 18 | 19 | struct kmem_cache { 20 | struct list_head slabs_free; 21 | struct list_head slabs_partial; 22 | struct list_head slabs_full; 23 | struct list_head list; /* linked list of caches */ 24 | unsigned short objsize; /* size of one object within a slab */ 25 | unsigned short objnum; /* number of objects per slab */ 26 | int opts; 27 | int alloc_succeed; 28 | int alloc_fail; 29 | char name[CACHE_NAMELEN]; 30 | }; 31 | 32 | struct slab { 33 | unsigned long free_bitmap[1]; 34 | int free_objects; /* number of free objects in that slab */ 35 | struct list_head list; /* pointer to prev/next slabs for that cache */ 36 | char data[0]; 37 | /* struct kmem_cache *backlink; // backlink to the cache structure */ 38 | }; 39 | 40 | #define KMEM_CACHE(objtype, name) \ 41 | kmem_cache_create(name, sizeof(objtype), 0, CACHE_OPT_NONE, NULL) 42 | 43 | struct kmem_cache *kmem_cache_create(const char *name, 44 | size_t size, 45 | __unused size_t align, 46 | __unused unsigned long flags, 47 | __unused void (*ctor)(void *)); 48 | void *kmem_cache_alloc(struct kmem_cache *cache, __unused unsigned long flags); 49 | void kmem_cache_free(struct kmem_cache *cache, void *obj); 50 | void kmem_cache_init(void); 51 | 52 | #endif /* _KERNEL_MM_SLAB_H */ 53 | -------------------------------------------------------------------------------- /include/kernel/mutex.h: -------------------------------------------------------------------------------- 1 | #ifndef _KERNEL_MUTEX_H 2 | #define _KERNEL_MUTEX_H 3 | 4 | typedef _Atomic int atomic_s32; 5 | 6 | typedef struct { 7 | atomic_s32 val; 8 | } kernel_mutex_t; 9 | 10 | int sys_pthread_mutex_lock(kernel_mutex_t *mutex); 11 | int sys_pthread_mutex_unlock(kernel_mutex_t *mutex); 12 | 13 | #endif /* !_KERNEL_MUTEX_H */ 14 | -------------------------------------------------------------------------------- /include/kernel/sched.h: -------------------------------------------------------------------------------- 1 | #ifndef KERNEL_SCHEDULER_H 2 | #define KERNEL_SCHEDULER_H 3 | 4 | #include_next 5 | 6 | struct thread_info; 7 | 8 | /* 0 <= PRI_MAX <= PRI_MIN */ 9 | #define PRI_MAX 0 10 | #define PRI_MIN 31 11 | 12 | #define SCHED_CLASS_RR 0 13 | #define SCHED_CLASS_BITMAP 1 14 | typedef int sched_class_t; 15 | 16 | #define SCHED_OPT_NONE 0 17 | #define SCHED_OPT_RESTORE_ONLY 1 18 | #define SCHED_OPT_RESET 2 19 | #define SCHED_OPT_TICK 3 20 | 21 | /* scheduler implementation hooks */ 22 | #define HOOK_SCHED_CLASS(name, sched_struct) \ 23 | static struct sched *sched_class_##name \ 24 | __attribute__((section(".sched.class"), aligned(sizeof(long)), \ 25 | used)) = sched_struct; 26 | 27 | struct sched { 28 | sched_class_t class_type; 29 | int (*init)(void); 30 | int (*enqueue)(struct thread_info *thread); 31 | int (*dequeue)(struct thread_info *thread); 32 | int (*elect)(int switch_type); 33 | }; 34 | 35 | int sched_init(); 36 | int sched_select(sched_class_t sched_type); 37 | int sched_enqueue(struct thread_info *thread); 38 | int sched_dequeue(struct thread_info *thread); 39 | int sched_elect(int flags); 40 | 41 | #endif /* !KERNEL_SCHEDULER_H */ 42 | -------------------------------------------------------------------------------- /include/kernel/serial.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Interface for serial devices (UART, ...) 3 | */ 4 | 5 | #ifndef _KERNEL_SERIAL_H 6 | #define _KERNEL_SERIAL_H 7 | 8 | #include 9 | #include 10 | 11 | struct serial_ops; 12 | struct device; 13 | struct thread_info; 14 | 15 | struct serial_info { 16 | void *priv; 17 | unsigned int rx_count; 18 | 19 | struct serial_ops *ops; 20 | 21 | // XXX: owner thread pointer could go to priv, and device pripheral 22 | // base address should be linked to private data for the device 23 | struct thread_info *owner; 24 | }; 25 | 26 | struct serial_ops { 27 | int (*serial_init)(struct serial_info *serial); 28 | 29 | int (*serial_getc)(struct serial_info *serial, char *c); 30 | int (*serial_gets)(struct serial_info *serial, 31 | size_t len, 32 | size_t *retlen, 33 | char *buf); 34 | int (*serial_putc)(struct serial_info *serial, char c); 35 | int (*serial_puts)(struct serial_info *serial, 36 | size_t len, 37 | const char *buf); 38 | 39 | /* callback on device activity, set by ioctl() */ 40 | void (*callback)(struct serial_info *self); 41 | }; 42 | 43 | 44 | struct serial_hook { 45 | char name[10]; 46 | int (*init)(void); 47 | }; 48 | 49 | /* serial hooks */ 50 | #define HOOK_SERIAL_INIT(dev, init_func) \ 51 | static struct serial_hook serial_##dev##_hook \ 52 | __attribute__((section(".serial.hook"), aligned(sizeof(long)), \ 53 | used)) = {#dev, init_func}; 54 | 55 | /* Generic uart setup */ 56 | void uart_init(void); 57 | /* Generic serial init */ 58 | void serial_init(void); 59 | 60 | /* XXX: All func below is callback function */ 61 | int serial_getc(struct serial_info *serial, char *c); 62 | int serial_gets(struct serial_info *serial, 63 | size_t len, 64 | size_t *retlen, 65 | char *buf); 66 | int serial_putc(struct serial_info *serial, char c); 67 | int serial_puts(struct serial_info *serial, 68 | size_t len, 69 | const char *buf); 70 | 71 | void serial_activity_callback(struct serial_info *serial); 72 | 73 | #endif /* !_KERNEL_SERIAL_H */ 74 | -------------------------------------------------------------------------------- /include/kernel/signal.h: -------------------------------------------------------------------------------- 1 | #ifndef _KERNEL_SIGNAL_H 2 | #define _KERNEL_SIGNAL_H 3 | 4 | #include 5 | 6 | #include 7 | 8 | #include 9 | 10 | #include "linux/types.h" 11 | 12 | #define SIGMAX 31 13 | 14 | struct signal_info { 15 | int signo; 16 | struct list_head list; 17 | struct sigaction act_storage; 18 | }; 19 | 20 | void do_sigevent(const struct sigevent *sigevent, struct thread_info *thread); 21 | 22 | #endif /* !_KERNEL_SIGNAL_H */ 23 | -------------------------------------------------------------------------------- /include/kernel/softirq.h: -------------------------------------------------------------------------------- 1 | #ifndef KERNEL_SOFTIRQ_H 2 | #define KERNEL_SOFTIRQ_H 3 | 4 | #include "linux/list.h" 5 | 6 | #define PRIO_TASKLET_VEC 32 7 | #define PRIO_TASKLET_MAXPRIO 0 8 | #define PRIO_TASKLET_MINPRIO 31 9 | 10 | /* softirq */ 11 | enum { 12 | TIMER_SOFTIRQ = 0, 13 | }; 14 | 15 | /* softirq default priority */ 16 | enum { 17 | TIMER_SOFTIRQ_PRIO = 0, 18 | }; 19 | 20 | /* softirq entry */ 21 | struct softirq_action { 22 | int (*action)(struct softirq_action *); 23 | }; 24 | 25 | /* FIXME: re-entrance */ 26 | /* dynamic task */ 27 | struct tasklet_struct { 28 | struct list_head tsk_q; 29 | unsigned long prio; 30 | // unsigned long state; 31 | void (*func)(void *); 32 | void *data; 33 | }; 34 | 35 | enum { 36 | TASKLET_STATE_SCHED, /* Tasklet is scheduled for execution */ 37 | TASKLET_STATE_RUN, /* Tasklet is running (SMP only) */ 38 | TASKLET_STATE_PENDING /* Tasklet is pending */ 39 | }; 40 | 41 | #define TASKLET_STATEF_SCHED (1 << TASKLET_STATE_SCHED) 42 | #define TASKLET_STATEF_RUN (1 << TASKLET_STATE_RUN) 43 | #define TASKLET_STATEF_PENDING (1 << TASKLET_STATE_PENDING) 44 | 45 | int open_softirq(unsigned int nr, int (*action)(struct softirq_action *)); 46 | int raise_softirq(unsigned int nr); 47 | 48 | int tasklet_schedule(struct tasklet_struct *task); 49 | struct tasklet_struct *tasklet_init(void(*func), 50 | void *data, 51 | unsigned long prio); 52 | int init_softirq(void); 53 | 54 | #endif /* KERNEL_SOFTIRQ_H */ 55 | -------------------------------------------------------------------------------- /include/kernel/task.h: -------------------------------------------------------------------------------- 1 | #ifndef _KERNEL_TASK_H 2 | #define _KERNEL_TASK_H 3 | 4 | #include 5 | 6 | #include 7 | 8 | #include "linux/list.h" 9 | 10 | #define PID_BASE 7000 11 | #define PID_MAX 32768 12 | 13 | struct task_info { 14 | pid_t pid; 15 | unsigned long filemap; 16 | struct file filetable[FILE_MAX]; 17 | struct list_head list; 18 | struct list_head thread_head; 19 | struct list_head signal_head; /* list of installed handlers */ 20 | }; 21 | 22 | struct task_info *task_init(struct task_info *task); 23 | struct task_info *task_create(void *(*start_routine)(void *), void *arg); 24 | void task_exit(struct task_info *task); 25 | struct task_info *current_task_info(void); 26 | 27 | #define CURRENT_TASK_INFO(var) struct task_info *var = current_task_info(); 28 | 29 | #endif /* !_KERNEL_TASK_H */ 30 | -------------------------------------------------------------------------------- /include/kernel/time.h: -------------------------------------------------------------------------------- 1 | #ifndef _KERNEL_TIME_H 2 | #define _KERNEL_TIME_H 3 | 4 | #include 5 | #include 6 | #include //FIXME: Why including this header explicitly? 7 | #include_next 8 | 9 | #include 10 | 11 | #include 12 | 13 | #include "linux/list.h" 14 | 15 | struct timer_info; 16 | 17 | enum timer_type { ONESHOT_TIMER, INTERVAL_TIMER }; 18 | 19 | struct timer_operations { 20 | int (*timer_alloc)(struct timer_info *timer /* , int flags */); 21 | int (*timer_free)(struct timer_info *timer); 22 | int (*timer_set)(struct timer_info *timer, const struct timespec *value); 23 | int (*timer_get)(struct timer_info *timer, struct itimerspec *value); 24 | }; 25 | 26 | struct timer_info { 27 | timer_t id; 28 | u32 flags; 29 | int disarmed; 30 | enum timer_type type; 31 | void (*callback)(struct timer_info *self); 32 | struct thread_info *owner; 33 | struct itimerspec value; 34 | struct sigevent sigev; 35 | struct list_head list; 36 | const struct timer_operations *tops; 37 | 38 | void *dev; 39 | }; 40 | 41 | struct timer_info *timer_alloc(void); 42 | int timer_free(struct timer_info *timer); 43 | int timer_set(struct timer_info *timer, const struct timespec *value); 44 | int timer_get(struct timer_info *timer, struct itimerspec *value); 45 | 46 | void timer_expire_callback(struct timer_info *timer); 47 | 48 | #endif /* !_KERNEL_TIME_H */ 49 | -------------------------------------------------------------------------------- /include/kernel/types.h: -------------------------------------------------------------------------------- 1 | #ifndef _KERNEL_TYPES_H 2 | #define _KERNEL_TYPES_H 3 | 4 | #ifndef _U32 5 | #define _U32 6 | typedef unsigned int u32; 7 | #endif 8 | 9 | #ifndef _S32 10 | #define _S32 11 | typedef int s32; 12 | #endif 13 | 14 | #ifndef _U16 15 | #define _U16 16 | typedef unsigned short u16; 17 | #endif 18 | 19 | #ifndef _S16 20 | #define _S16 21 | typedef short s16; 22 | #endif 23 | 24 | #ifndef _U8 25 | #define _U8 26 | typedef unsigned char u8; 27 | #endif 28 | 29 | #ifndef _S8 30 | #define _S8 31 | typedef char s8; 32 | #endif 33 | 34 | #ifndef _UMODE_T 35 | #define _UMODE_T 36 | typedef unsigned short umode_t; 37 | #endif 38 | 39 | typedef u32 __u32; 40 | typedef s32 __s32; 41 | typedef u16 __u16; 42 | typedef s16 __s16; 43 | typedef u8 __u8; 44 | typedef s8 __s8; 45 | 46 | /* import struct list_head */ 47 | #include "linux/types.h" 48 | 49 | #endif /* !_KERNEL_TYPES_H */ 50 | -------------------------------------------------------------------------------- /include/libc/pthread.h: -------------------------------------------------------------------------------- 1 | #ifndef PTHREAD_H 2 | #define PTHREAD_H 3 | 4 | #include_next 5 | 6 | extern int pthread_yield(void); 7 | 8 | #endif /* PTHREAD_H */ 9 | -------------------------------------------------------------------------------- /include/libc/ucontext.h: -------------------------------------------------------------------------------- 1 | #ifndef UCONTEXT_H 2 | #define UCONTEXT_H 3 | 4 | #include 5 | 6 | #include "linux/types.h" 7 | 8 | /* machine context on ARM */ 9 | typedef struct mcontext { 10 | u32 sp; // FIXME: reuse uc_stack.ss_sp 11 | u32 lr; 12 | u32 gprs[13]; /* r0-r12 */ 13 | u32 pc; 14 | } __attribute__((packed)) mcontext_t; 15 | 16 | typedef struct ucontext { 17 | struct ucontext *uc_link; 18 | /* sigset_t uc_sigmask; */ 19 | stack_t uc_stack; 20 | mcontext_t uc_mcontext; 21 | /* ... */ 22 | } ucontext_t; 23 | 24 | /* forward declarations */ 25 | 26 | void makecontext(ucontext_t *ucp, void (*func)(), int argc, ...); 27 | int swapcontext(ucontext_t *oucp, ucontext_t *ucp); 28 | 29 | #endif /* !UCONTEXT_H */ 30 | -------------------------------------------------------------------------------- /include/libc/utils.h: -------------------------------------------------------------------------------- 1 | #ifndef UTILS_H 2 | #define UTILS_H 3 | 4 | #ifndef __LINKER__ 5 | 6 | static inline void infinite_loop(void) 7 | { 8 | for (;;) 9 | ; 10 | } 11 | 12 | void strpad(char *buf, char pad_val, int count); 13 | char *itoa_base(int value, char *buf, int base); 14 | 15 | #endif /* !__LINKER__ */ 16 | 17 | #endif /* !UTILS_H */ 18 | -------------------------------------------------------------------------------- /include/linux/compiler.h: -------------------------------------------------------------------------------- 1 | #ifndef _LINUX_COMPILER_H 2 | #define _LINUX_COMPILER_H 3 | 4 | #define READ_ONCE(x) (x) 5 | #define WRITE_ONCE(x, val) \ 6 | ({ \ 7 | x = val; \ 8 | val; \ 9 | }) 10 | 11 | #endif /* !_LINUX_COMPILER_H */ 12 | -------------------------------------------------------------------------------- /include/linux/poison.h: -------------------------------------------------------------------------------- 1 | #ifndef LINUX_POISON_H 2 | #define LINUX_POISON_H 3 | 4 | /* 5 | * These are non-NULL pointers that will result in page faults 6 | * under normal circumstances, used to verify that nobody uses 7 | * non-initialized list entries. 8 | * Make sure the values raise faults when these addresses are 9 | * read/written. 10 | */ 11 | #define LIST_POISON1 ((void *) 0x100) 12 | #define LIST_POISON2 ((void *) 0x200) 13 | 14 | #endif /* !LINUX_POISON_H */ 15 | -------------------------------------------------------------------------------- /include/linux/stddef.h: -------------------------------------------------------------------------------- 1 | #ifndef _LINUX_STDDEF_H 2 | #define _LINUX_STDDEF_H 3 | 4 | #include 5 | 6 | /** 7 | * offsetofend(TYPE, MEMBER) 8 | * 9 | * @TYPE: The type of the structure 10 | * @MEMBER: The member within the structure to get the end offset of 11 | */ 12 | #define offsetofend(TYPE, MEMBER) \ 13 | (offsetof(TYPE, MEMBER) + sizeof(((TYPE *) 0)->MEMBER)) 14 | 15 | #endif 16 | -------------------------------------------------------------------------------- /include/linux/types.h: -------------------------------------------------------------------------------- 1 | #ifndef LINUX_TYPES_H 2 | #define LINUX_TYPES_H 3 | 4 | #define S32_MAX 2147483647 5 | 6 | typedef unsigned int u32; 7 | typedef int s32; 8 | 9 | typedef unsigned short u16; 10 | typedef short s16; 11 | 12 | typedef unsigned char u8; 13 | typedef char s8; 14 | 15 | typedef unsigned int size_t; 16 | 17 | struct list_head { 18 | struct list_head *next, *prev; 19 | }; 20 | 21 | struct hlist_head { 22 | struct hlist_node *first; 23 | }; 24 | 25 | struct hlist_node { 26 | struct hlist_node *next, **pprev; 27 | }; 28 | 29 | typedef struct { 30 | volatile s32 val; 31 | } atomic_t; 32 | 33 | #endif /* !LINUX_TYPES_H */ 34 | -------------------------------------------------------------------------------- /include/piko/arpa/inet.h: -------------------------------------------------------------------------------- 1 | #ifndef LIBC_ARPA_INET_H 2 | #define LIBC_ARPA_INET_H 3 | 4 | #include 5 | 6 | #include "platform.h" 7 | 8 | static inline uint32_t htonl(uint32_t hostlong) 9 | { 10 | return __REV(hostlong); 11 | } 12 | 13 | static inline uint16_t htons(uint16_t hostshort) 14 | { 15 | return __REV16(hostshort); 16 | } 17 | 18 | static inline uint32_t ntohl(uint32_t netlong) 19 | { 20 | return __REV(netlong); 21 | } 22 | 23 | static inline uint16_t ntohs(uint16_t netshort) 24 | { 25 | return __REV16(netshort); 26 | } 27 | 28 | #endif /* !LIBC_ARPA_INET_H */ 29 | -------------------------------------------------------------------------------- /include/piko/dirent.h: -------------------------------------------------------------------------------- 1 | #ifndef _LIBPIKO_DIRENT_H 2 | #define _LIBPIKO_DIRENT_H 3 | 4 | #include 5 | 6 | #define NAME_MAX 32 // FIXME: Include 7 | 8 | typedef void DIR; 9 | 10 | struct dirent { 11 | ino_t d_ino; /* inode number */ 12 | char d_name[NAME_MAX]; /* filename */ 13 | }; 14 | 15 | DIR *opendir(const char *dirname); 16 | 17 | int readdir_r(DIR *dirp, struct dirent *entry, struct dirent **result); 18 | 19 | int closedir(DIR *dirp); 20 | 21 | #endif /* !_LIBPIKO_DIRENT_H */ 22 | -------------------------------------------------------------------------------- /include/piko/signal.h: -------------------------------------------------------------------------------- 1 | #ifndef LIBC_SIGNAL_H 2 | #define LIBC_SIGNAL_H 3 | 4 | #include 5 | 6 | #include "linux/list.h" 7 | 8 | typedef struct { 9 | void *ss_sp; /* Base address of stack */ 10 | int ss_flags; /* Flags */ 11 | size_t ss_size; /* Number of bytes in stack */ 12 | } stack_t; 13 | 14 | /* sigevent - structure for notification from asynchronous routines */ 15 | 16 | union sigval { /* Data passed with notification */ 17 | int sival_int; /* Integer value */ 18 | void *sival_ptr; /* Pointer value */ 19 | }; 20 | 21 | struct sigevent { 22 | int sigev_notify; /* Notification method */ 23 | int sigev_signo; /* Notification signal */ 24 | 25 | /* Data passed with notification */ 26 | union sigval sigev_value; 27 | 28 | /* Function used for thread notification (SIGEV_THREAD) */ 29 | void (*sigev_notify_function)(union sigval); 30 | 31 | /* Attributes for notification thread (SIGEV_THREAD) */ 32 | void *sigev_notify_attributes; 33 | 34 | /* ID of thread to signal (SIGEV_THREAD_ID) */ 35 | pid_t sigev_notify_thread_id; 36 | }; 37 | 38 | /* sigaction - used to change the action taken by a process on receipt of a 39 | specific signal */ 40 | 41 | typedef struct { 42 | int si_signo; 43 | /* int si_code; */ 44 | union sigval si_value; 45 | /* int si_errno; */ 46 | pid_t si_pid; 47 | /* uid_t si_uid; */ 48 | /* void *si_addr; */ 49 | /* int si_status; */ 50 | /* int si_band; */ 51 | } siginfo_t; 52 | 53 | typedef int sigset_t; 54 | 55 | struct sigaction { 56 | union { 57 | void (*sa_handler)(int); 58 | void (*sa_sigaction)(int, siginfo_t *, void *); 59 | }; 60 | sigset_t sa_mask; 61 | int sa_flags; 62 | 63 | /* Storage for kernel fields. Not compliant with the POSIX specs. */ 64 | struct list_head sa_list; 65 | int sa_signo; 66 | }; 67 | 68 | #define SA_SIGINFO (1 << 0) 69 | 70 | #define SIGKILL 9 /* Kill (can't be caught or ignored) (POSIX) */ 71 | #define SIGUSR1 10 /* User defined signal 1 (POSIX) */ 72 | #define SIGUSR2 12 /* User defined signal 2 (POSIX) */ 73 | #define SIGSTOP 19 /* Stop executing(can't be caught or ignored) (POSIX) */ 74 | 75 | int sigaction(int sig, 76 | const struct sigaction *restrict act, 77 | struct sigaction *restrict oact); 78 | 79 | int raise(int sig); 80 | 81 | #endif /* !LIBC_SIGNAL_H */ 82 | -------------------------------------------------------------------------------- /include/piko/sys/mman.h: -------------------------------------------------------------------------------- 1 | #ifndef _SYS_MMAN_H 2 | #define _SYS_MMAN_H 3 | 4 | #include 5 | 6 | #define PROT_NONE 0x00 /* page can not be accessed */ 7 | #define PROT_READ 0x01 /* page can be read */ 8 | #define PROT_WRITE 0x02 /* page can be written */ 9 | #define PROT_EXEC 0x04 /* page can be executed */ 10 | 11 | #define MAP_FAILED ((void *) -1) 12 | 13 | #define MAP_ANONYMOUS 0x01 /* don't use a file */ 14 | #define MAP_UNINITIALIZED 0x02 /* anonymous memory can be uninitialized */ 15 | 16 | void *mmap(void *addr, 17 | size_t length, 18 | int prot, 19 | int flags, 20 | int fd, 21 | off_t offset); 22 | 23 | int munmap(void *addr, size_t length); 24 | 25 | #endif /* !_SYS_MMAN_H */ 26 | -------------------------------------------------------------------------------- /include/piko/sys/mount.h: -------------------------------------------------------------------------------- 1 | #ifndef _SYS_MOUNT_H 2 | #define _SYS_MOUNT_H 3 | 4 | int mount(const char *source, 5 | const char *target, 6 | const char *filesystemtype, 7 | unsigned long mountflags, 8 | const void *data); 9 | 10 | #endif /* !_SYS_MOUNT_H */ 11 | -------------------------------------------------------------------------------- /include/piko/sys/resource.h: -------------------------------------------------------------------------------- 1 | #ifndef SYS_RESOURCE_H 2 | #define SYS_RESOURCE_H 3 | 4 | /* http://pubs.opengroup.org/onlinepubs/9699919799/basedefs/sys_resource.h.html 5 | */ 6 | 7 | /* Unsigned integer type used for limit values. */ 8 | typedef unsigned int rlim_t; 9 | 10 | struct rlimit { 11 | rlim_t rlim_cur; /* Soft limit */ 12 | rlim_t rlim_max; /* Hard limit (ceiling for rlim_cur) */ 13 | }; 14 | 15 | #define RLIMIT_STACK 0 16 | 17 | #ifdef __KERNEL__ 18 | 19 | int sys_getrlimit(int resource, struct rlimit *rlim); 20 | 21 | int sys_setrlimit(int resource, const struct rlimit *rlim); 22 | 23 | #else /* !__KERNEL__ */ 24 | 25 | int getrlimit(int resource, struct rlimit *rlim); 26 | 27 | int setrlimit(int resource, const struct rlimit *rlim); 28 | 29 | #endif /* __KERNEL__ */ 30 | 31 | #endif /* !SYS_RESOURCE_H */ 32 | -------------------------------------------------------------------------------- /include/platform/compiler.h: -------------------------------------------------------------------------------- 1 | #ifndef _PLATFORM_COMPILER_H 2 | #define _PLATFORM_COMPILER_H 3 | 4 | #define PLAT_EVAL(macro) \ 5 | ({ \ 6 | void __wrapper__(void) {macro;} \ 7 | __wrapper__; \ 8 | }) 9 | 10 | #endif /* !_PLATFORM_COMPILER_H */ 11 | -------------------------------------------------------------------------------- /include/version.template.h: -------------------------------------------------------------------------------- 1 | #ifndef VERSION_H 2 | #define VERSION_H 3 | 4 | #define VER_MAJOR "0" 5 | #define VER_MINOR "0" 6 | #define VER_MICRO "0" 7 | 8 | #define VER_SLUG "piko-" VER_MAJOR "." VER_MINOR "." VER_MICRO 9 | 10 | #endif /* !VERSION_H */ 11 | -------------------------------------------------------------------------------- /kernel/cond.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | #include "linux/list.h" 8 | 9 | static LIST_HEAD(cond_head); 10 | 11 | static struct thread_info *find_other_thread(pthread_cond_t *cond) 12 | { 13 | struct thread_info *other; 14 | 15 | list_for_each_entry(other, &cond_head, ti_q) 16 | { 17 | if (other->ti_private == cond) 18 | return other; 19 | } 20 | 21 | return NULL; 22 | } 23 | 24 | int sys_pthread_cond_wait(pthread_cond_t *cond, kernel_mutex_t *mutex) 25 | { 26 | CURRENT_THREAD_INFO(curr_thread); 27 | curr_thread->ti_private = cond; 28 | curr_thread->ti_state = THREAD_STATE_BLOCKED; 29 | list_add_tail(&curr_thread->ti_q, &cond_head); 30 | sys_pthread_mutex_unlock(mutex); 31 | 32 | /* contend for the lock */ 33 | sys_pthread_mutex_lock(mutex); 34 | 35 | return 0; 36 | } 37 | 38 | int sys_pthread_cond_signal(pthread_cond_t *cond) 39 | { 40 | struct thread_info *other; 41 | 42 | other = find_other_thread(cond); 43 | if (!other) 44 | return 0; 45 | 46 | list_del(&other->ti_q); 47 | sched_enqueue(other); 48 | CURRENT_THREAD_INFO(curr_thread); 49 | if (other->ti_priority >= curr_thread->ti_priority) { 50 | sched_enqueue(curr_thread); 51 | sched_elect(SCHED_OPT_NONE); 52 | } 53 | 54 | return 0; 55 | } 56 | -------------------------------------------------------------------------------- /kernel/config.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | enum sc_varname { 4 | PAGESIZE, 5 | }; 6 | 7 | struct sys_param { 8 | const char *name; 9 | long value; 10 | }; 11 | 12 | struct sys_param sys_params[] = { 13 | {"pagesize", 2048}, 14 | {"clock_tick", 0}, // FIXME: set by systick_init() 15 | }; 16 | 17 | long sys_sysconf(int name) 18 | { 19 | switch (name) { 20 | case PAGESIZE: 21 | return sys_params[0].value; 22 | case _SC_CLK_TCK: 23 | return sys_params[1].value; 24 | } 25 | 26 | return -1; 27 | } 28 | -------------------------------------------------------------------------------- /kernel/faults.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include "kernel.h" 5 | #include "utils.h" 6 | #include "platform.h" 7 | 8 | void fault_enter(const char *s) 9 | { 10 | printk("\n-------------------------------------------------------------\n"); 11 | printk(" #%s\n\n", s); 12 | } 13 | 14 | void fault_exit(void) 15 | { 16 | printk("-------------------------------------------------------------\n"); 17 | __platform_halt(); 18 | } 19 | 20 | void hardfault(struct kernel_context_regs *noscratch, 21 | struct thread_context_regs *scratch, 22 | u32 exc_return) 23 | { 24 | fault_enter("HardFault"); 25 | dump_frame(noscratch, scratch, exc_return); 26 | fault_exit(); 27 | } 28 | -------------------------------------------------------------------------------- /kernel/fs/readdir.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include 5 | #include 6 | 7 | #include "linux/list.h" 8 | 9 | static int fillonedir(struct dir_context *ctx, 10 | const char *name, 11 | int namlen, 12 | __unused off_t offset, 13 | unsigned int ino, 14 | __unused unsigned int d_type) 15 | { 16 | struct readdir_callback *buf = 17 | container_of(ctx, struct readdir_callback, ctx); 18 | struct piko_dirent *dirent = buf->dirent; 19 | 20 | dirent->d_ino = ino; 21 | strncpy(dirent->d_name, name, namlen); 22 | dirent->d_name[namlen] = '\0'; 23 | 24 | return 0; 25 | } 26 | 27 | int sys_readdir_r(DIR *dirp, struct dirent *entry, struct dirent **result) 28 | { 29 | struct file *file = fd_to_file((int) dirp); 30 | struct readdir_callback buf = { 31 | .ctx = {.actor = fillonedir, .pos = 0}, 32 | .dirent = (struct piko_dirent *) entry, 33 | }; 34 | 35 | if (vfs_iterate(file, &buf.ctx)) 36 | *result = NULL; 37 | else 38 | *result = entry; 39 | 40 | return 0; 41 | } 42 | -------------------------------------------------------------------------------- /kernel/fs/vfs.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #include 6 | #include 7 | 8 | #include "linux/list.h" 9 | 10 | int vfs_iterate(struct file *file, struct dir_context *ctx) 11 | { 12 | if (!file->f_op->iterate) 13 | return -1; 14 | 15 | return file->f_op->iterate(file, ctx); 16 | } 17 | 18 | struct dentry *vfs_lookup(struct inode *dir, struct dentry *target) 19 | { 20 | if (!dir->i_op->lookup) 21 | return NULL; 22 | if (!S_ISDIR(dir->i_mode)) 23 | return NULL; 24 | 25 | return dir->i_op->lookup(dir, target); 26 | } 27 | 28 | int vfs_link(struct dentry *old_dentry, 29 | struct inode *dir, 30 | struct dentry *dentry) 31 | { 32 | if (!dir->i_op->link) 33 | return -1; 34 | 35 | return dir->i_op->link(old_dentry, dir, dentry); 36 | } 37 | 38 | int vfs_delete(struct dentry *dentry) 39 | { 40 | if (!dentry->d_op->delete) 41 | return -1; 42 | 43 | return dentry->d_op->delete (dentry); 44 | } 45 | 46 | void vfs_release(struct dentry *dentry) 47 | { 48 | if (dentry->d_op->release) 49 | return dentry->d_op->release(dentry); 50 | } 51 | 52 | int vfs_mmap(struct file *file, off_t offset, void **addr) 53 | { 54 | if (!file->f_op->mmap) 55 | return -1; 56 | 57 | return file->f_op->mmap(file, offset, addr); 58 | } 59 | -------------------------------------------------------------------------------- /kernel/irq.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | #define IRQ_MAX 64 7 | 8 | irq_handler_t irq_handler[IRQ_MAX]; 9 | 10 | // clang-format off 11 | static struct irq_desc irq_desc[NR_IRQS] = { 12 | [0 ... NR_IRQS - 1] = { 13 | .irq_data = {.state = 0x0}, 14 | .action = NULL, 15 | .status = 0x0, 16 | } 17 | }; 18 | // clang-format on 19 | 20 | static struct irq_desc *irq_to_desc(unsigned int irq) 21 | { 22 | if (irq < NR_IRQS) 23 | return irq_desc + irq; 24 | return NULL; 25 | } 26 | 27 | int request_irq(unsigned int irq, irq_handler_t hdlr) 28 | { 29 | struct irqaction *action; 30 | struct irq_desc *desc; 31 | 32 | desc = irq_to_desc(irq); 33 | 34 | if (desc && (desc->status & IRQ_NOREQUEST)) { 35 | action = (struct irqaction *) malloc(sizeof(struct irqaction)); 36 | if (!action) { 37 | // WARN_ON(!action, "malloc failed\n"); 38 | goto fail; 39 | } 40 | 41 | action->irq = irq; 42 | action->handler = hdlr; 43 | 44 | /* install to irq_desc */ 45 | desc->action = action; 46 | 47 | irq_handler[irq] = hdlr; 48 | 49 | return 0; 50 | } else 51 | fail: 52 | return -1; 53 | } 54 | 55 | int free_irq(unsigned int irq) 56 | { 57 | struct irq_desc *desc; 58 | 59 | desc = irq_to_desc(irq); 60 | 61 | if (desc && !(desc->status & IRQ_NOREQUEST)) { 62 | free(desc->action); 63 | desc->status |= IRQ_NOREQUEST; 64 | irq_handler[irq] = NULL; 65 | 66 | return 0; 67 | } 68 | 69 | return -1; 70 | } 71 | 72 | void early_irq_init(void) 73 | { 74 | for (int irq = 0; irq < NR_IRQS; irq++) 75 | irq_desc[irq].irq_data.state = IRQD_IRQ_DISABLED; 76 | } 77 | 78 | void init_IRQ(void) 79 | { 80 | for (int irq = 0; irq < NR_IRQS; irq++) 81 | irq_desc[irq].status = IRQ_NOREQUEST; 82 | } 83 | -------------------------------------------------------------------------------- /kernel/mm/mm.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | #include 8 | 9 | #include 10 | #include 11 | 12 | #define M_ISANON(f) (((f) &MAP_ANONYMOUS) == MAP_ANONYMOUS) 13 | #define M_ISUNINIT(f) (((f) &MAP_UNINITIALIZED) == MAP_UNINITIALIZED) 14 | 15 | static void *map_anon(void *addr, size_t length, __unused int prot, int flags) 16 | { 17 | int order; 18 | 19 | order = size_to_page_order(length); 20 | addr = alloc_pages(order); 21 | if (!addr) { 22 | printk("mmap: ENOMEM\n"); 23 | errno = ENOMEM; 24 | return MAP_FAILED; 25 | } 26 | if (!M_ISUNINIT(flags)) 27 | memset(addr, 0, length); 28 | 29 | return addr; 30 | } 31 | 32 | static void *map_file(__unused size_t length, 33 | __unused int prot, 34 | __unused int flags, 35 | int fd, 36 | off_t offset) 37 | { 38 | void *addr; 39 | struct file *file; 40 | 41 | file = fd_to_file(fd); 42 | if (!file) { 43 | printk("mmap: BADF\n"); 44 | errno = EBADF; 45 | return MAP_FAILED; 46 | } 47 | if (!S_ISREG(file->f_dentry->d_inode->i_mode)) { 48 | printk("mmap: ACCESS\n"); 49 | errno = EACCES; 50 | return MAP_FAILED; 51 | } 52 | if (vfs_mmap(file, offset, &addr)) { 53 | printk("mmap: failed in romfs_map\n"); 54 | for (;;) 55 | ; 56 | return MAP_FAILED; 57 | } 58 | 59 | return addr; 60 | } 61 | 62 | void *sys_mmap(void *addr, 63 | size_t length, 64 | int prot, 65 | int flags, 66 | int fd, 67 | off_t offset) 68 | { 69 | if (!length) { 70 | errno = EINVAL; 71 | printk("mmap: length is 0\n"); 72 | return MAP_FAILED; 73 | } 74 | if (prot & PROT_NONE) { 75 | errno = EACCES; 76 | printk("mmap: PROT_NONE\n"); 77 | return MAP_FAILED; 78 | } 79 | if (M_ISANON(flags)) 80 | addr = map_anon(addr, length, prot, flags); 81 | else 82 | addr = map_file(length, prot, flags, fd, offset); 83 | 84 | return addr; 85 | } 86 | 87 | int sys_munmap(__unused void *addr, __unused size_t length) 88 | { 89 | /* Closing the file descriptor does not unmap the region. */ 90 | return 0; 91 | } 92 | -------------------------------------------------------------------------------- /kernel/mutex.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | #include "linux/list.h" 7 | 8 | static LIST_HEAD(mutex_head); 9 | 10 | /* The thread owns the mutex on return. We also check the case when the lock 11 | * has been released between the test of the mutex and this syscall. */ 12 | int sys_pthread_mutex_lock(kernel_mutex_t *mutex) 13 | { 14 | mutex->val++; 15 | if (!mutex->val) 16 | return 0; 17 | CURRENT_THREAD_INFO(curr_thread); 18 | curr_thread->ti_private = mutex; 19 | curr_thread->ti_state = THREAD_STATE_BLOCKED; 20 | list_add_tail(&curr_thread->ti_q, &mutex_head); 21 | sched_elect(SCHED_OPT_NONE); 22 | 23 | return 0; 24 | } 25 | 26 | static struct thread_info *find_first_blocking_thread(kernel_mutex_t *mutex) 27 | { 28 | struct thread_info *thread; 29 | 30 | list_for_each_entry(thread, &mutex_head, ti_q) 31 | { 32 | if (thread->ti_private == mutex) 33 | return thread; 34 | } 35 | 36 | return NULL; 37 | } 38 | 39 | int sys_pthread_mutex_unlock(kernel_mutex_t *mutex) 40 | { 41 | struct thread_info *waiter = NULL; 42 | 43 | mutex->val--; 44 | if (mutex->val >= 0) { 45 | waiter = find_first_blocking_thread(mutex); 46 | if (!waiter) { 47 | printk("[mutex_unlock] No blocking threads for mutex=<%p>\n", 48 | mutex); 49 | return -1; 50 | } 51 | list_del(&waiter->ti_q); 52 | sched_enqueue(waiter); 53 | } 54 | CURRENT_THREAD_INFO(curr_thread); 55 | if (curr_thread->ti_state == THREAD_STATE_BLOCKED) { 56 | sched_elect(SCHED_OPT_NONE); 57 | } else if (waiter && (curr_thread->ti_priority <= waiter->ti_priority)) { 58 | sched_enqueue(curr_thread); 59 | sched_elect(SCHED_OPT_NONE); 60 | } 61 | 62 | return 0; 63 | } 64 | -------------------------------------------------------------------------------- /kernel/printk.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #define VSNPRINTF_BUF_SIZE 256 6 | 7 | static ucontext_t printk_context; 8 | static ucontext_t vsnprintf_context = {.uc_link = &printk_context}; 9 | static unsigned int ctx_stack[128]; 10 | static char vsnprintf_buf[VSNPRINTF_BUF_SIZE]; 11 | static int retval; 12 | 13 | /* not thread-safe, not reentrant */ 14 | static void co_vsnprintf(const char *format, va_list ap) 15 | { 16 | retval = vsnprintf(vsnprintf_buf, VSNPRINTF_BUF_SIZE, format, ap); 17 | } 18 | 19 | #include 20 | #include "platform.h" 21 | 22 | void __printk_init(void) 23 | { 24 | uart_init(); 25 | } 26 | 27 | void __printk_putchar(char c) 28 | { 29 | if (c == '\n') 30 | __printk_putchar('\r'); 31 | 32 | while (!(USARTx->SR & USART_SR_TXE)) 33 | ; 34 | USARTx->DR = (0xff) & c; 35 | } 36 | 37 | int printk(const char *format, ...) 38 | { 39 | /*FIXME: should be interruptable*/ 40 | __disable_irq(); 41 | va_list ap; 42 | 43 | va_start(ap, format); 44 | vsnprintf_context.uc_stack.ss_sp = &ctx_stack[128]; 45 | makecontext(&vsnprintf_context, co_vsnprintf, 2, format, ap); 46 | swapcontext(&printk_context, &vsnprintf_context); 47 | for (char *c = vsnprintf_buf; *c != '\0'; c++) 48 | __printk_putchar(*c); 49 | va_end(ap); 50 | 51 | /*FIXME: should be interruptable*/ 52 | __enable_irq(); 53 | return retval; 54 | } 55 | -------------------------------------------------------------------------------- /kernel/resource.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | // clang-format off 4 | static struct rlimit rlimits[] = { 5 | { .rlim_cur = 1024, .rlim_max = 1024 } /* RLIMIT_STACK */ 6 | }; 7 | 8 | int sys_getrlimit(int resource, struct rlimit *rlim) 9 | { 10 | rlim->rlim_cur = rlimits[resource].rlim_cur; 11 | rlim->rlim_max = rlimits[resource].rlim_max; 12 | 13 | return 0; 14 | } 15 | 16 | int sys_setrlimit(int resource, const struct rlimit *rlim) 17 | { 18 | rlimits[resource].rlim_cur = rlim->rlim_cur; 19 | rlimits[resource].rlim_max = rlim->rlim_max; 20 | 21 | return 0; 22 | } 23 | -------------------------------------------------------------------------------- /kernel/sched.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | extern unsigned long __sched_classes_start__; 5 | extern unsigned long __sched_classes_end__; 6 | 7 | /* static vars to repesent sched classes list */ 8 | static struct sched **sched_classes = 9 | (struct sched **) &__sched_classes_start__; 10 | static struct sched **sched_classes_end = 11 | (struct sched **) &__sched_classes_end__; 12 | 13 | static struct sched *sched; 14 | 15 | int sched_init() 16 | { 17 | int ret = 0; 18 | 19 | /* Initialize each scheduler class by traversing hooks */ 20 | for (struct sched **c = sched_classes; 21 | c < sched_classes_end; c++) { 22 | struct sched *class = *c; 23 | ret |= class->init(); 24 | } 25 | 26 | return ret; 27 | } 28 | 29 | int sched_select(sched_class_t sched_type) 30 | { 31 | int ret = -1; 32 | struct sched *class = NULL; 33 | 34 | /* Examine specified sched class in hooks or not */ 35 | for (struct sched **c = sched_classes; 36 | c < sched_classes_end; c++) 37 | if (sched_type == (*c)->class_type) 38 | class = *c; 39 | 40 | if (class) { 41 | sched = class; 42 | ret = 0; 43 | } 44 | 45 | return ret; 46 | } 47 | 48 | int sched_enqueue(struct thread_info *thread) 49 | { 50 | thread->ti_state = THREAD_STATE_ACTIVED; 51 | 52 | return sched->enqueue(thread); 53 | } 54 | 55 | int sched_dequeue(struct thread_info *thread) 56 | { 57 | return sched->dequeue(thread); 58 | } 59 | 60 | int sched_elect(int flags) 61 | { 62 | int r; 63 | CURRENT_THREAD_INFO(cur_thread); 64 | 65 | KERNEL_STACK_CHECKING; 66 | 67 | r = sched->elect(flags); 68 | cur_thread->ti_state = THREAD_STATE_RUNNING; 69 | 70 | return r; 71 | } 72 | -------------------------------------------------------------------------------- /kernel/sched/rr.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include "linux/list.h" 5 | #include "kernel.h" 6 | 7 | static LIST_HEAD(rr_runq); 8 | extern struct thread_info *thread_idle; 9 | 10 | int sched_rr_init(void) 11 | { 12 | return 0; 13 | } 14 | 15 | static struct thread_info *find_next_thread(struct thread_info *thread) 16 | { 17 | if (list_is_last(&thread->ti_q, &rr_runq)) 18 | return list_first_entry(&rr_runq, struct thread_info, ti_q); 19 | 20 | return list_next_entry(thread, ti_q); 21 | } 22 | 23 | int sched_rr_enqueue(struct thread_info *thread) 24 | { 25 | list_add(&thread->ti_q, &rr_runq); 26 | 27 | return 0; 28 | } 29 | 30 | int sched_rr_dequeue(struct thread_info *thread) 31 | { 32 | CURRENT_THREAD_INFO(current); 33 | 34 | if (current == thread) { 35 | struct thread_info *next = thread_idle; 36 | if (!list_is_singular(&rr_runq)) { 37 | next = find_next_thread(current); 38 | } 39 | list_del(&thread->ti_q); 40 | thread_restore(next); // FIXME: rename to switch_to_no_save 41 | } else { 42 | list_del(&thread->ti_q); 43 | } 44 | 45 | return 0; 46 | } 47 | 48 | /* This function is used when the runqueue has been modified externally, and it 49 | is not possible to fetch the next thread. */ 50 | static int sched_rr_elect_reset(void) 51 | { 52 | CURRENT_THREAD_INFO(current); 53 | struct thread_info *next = thread_idle; 54 | 55 | if (!list_empty(&rr_runq)) 56 | next = list_first_entry(&rr_runq, struct thread_info, ti_q); 57 | switch_to(next, current); 58 | 59 | return 0; 60 | } 61 | 62 | int sched_rr_elect(int switch_type) 63 | { 64 | CURRENT_THREAD_INFO(current); 65 | struct thread_info *next; 66 | 67 | if (switch_type & SCHED_OPT_RESET) 68 | return sched_rr_elect_reset(); 69 | 70 | if (list_empty(&rr_runq)) { 71 | // go to thread idle. 72 | next = thread_idle; 73 | } else { 74 | next = find_next_thread(current); 75 | } 76 | 77 | /* keep running the previous thread */ 78 | if (next == current) 79 | return -1; 80 | 81 | /* Leave _current_ thread for now. The _current_ thread will be elected 82 | again after _next_ thread has run. Inform the caller function (in 83 | _current_ context) that the thread gently gave way. */ 84 | switch_to(next, current); 85 | 86 | return 0; 87 | } 88 | 89 | // clang-format off 90 | static struct sched sched_rr = { 91 | .class_type = SCHED_CLASS_RR, 92 | .init = sched_rr_init, 93 | .enqueue = sched_rr_enqueue, 94 | .dequeue = sched_rr_dequeue, 95 | .elect = sched_rr_elect, 96 | }; 97 | // clang-format on 98 | 99 | HOOK_SCHED_CLASS(RR, &sched_rr) 100 | -------------------------------------------------------------------------------- /kernel/task.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | #include 5 | 6 | #include "linux/list.h" 7 | 8 | static LIST_HEAD(task_head); 9 | 10 | static pid_t alloc_pid() 11 | { 12 | static pid_t pid = 7000; 13 | pid_t retpid; 14 | 15 | retpid = pid; 16 | pid++; 17 | 18 | return retpid; 19 | } 20 | 21 | struct task_info *task_init(struct task_info *task) 22 | { 23 | task->pid = alloc_pid(); 24 | task->filemap = 0; 25 | INIT_LIST_HEAD(&task->thread_head); 26 | INIT_LIST_HEAD(&task->signal_head); 27 | list_add(&task->list, &task_head); 28 | 29 | return task; 30 | } 31 | 32 | void task_exit(struct task_info *task) 33 | { 34 | // this is called after last thread has exited, or when the 35 | // task is killed 36 | list_del(&task->list); 37 | free(task); 38 | } 39 | 40 | struct task_info *current_task_info(void) 41 | { 42 | CURRENT_THREAD_INFO(curr_thread); 43 | 44 | return curr_thread->ti_task; 45 | } 46 | 47 | int sys_getpid(void) 48 | { 49 | CURRENT_TASK_INFO(curr_task); 50 | 51 | return curr_task->pid; 52 | } 53 | -------------------------------------------------------------------------------- /libc/fcntl.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | extern int _open(const char *pathname, int flag); 4 | extern int _close(int fd); 5 | extern int _read(int fd, void *buf, size_t count); 6 | extern int _write(int fd, void *buf, size_t count); 7 | extern int _lseek(int fd, off_t offset, int whence); 8 | 9 | int open(const char *pathname, int flag) 10 | { 11 | return _open(pathname, flag); 12 | } 13 | 14 | int close(int fd) 15 | { 16 | return _close(fd); 17 | } 18 | 19 | int read(int fd, void *buf, size_t count) 20 | { 21 | return _read(fd, buf, count); 22 | } 23 | 24 | int write(int fd, void *buf, size_t count) 25 | { 26 | return _write(fd, buf, count); 27 | } 28 | 29 | int lseek(int fd, off_t offset, int whence) 30 | { 31 | return _lseek(fd, offset, whence); 32 | } 33 | -------------------------------------------------------------------------------- /libc/filesystem.c: -------------------------------------------------------------------------------- 1 | /* syscall wrappers */ 2 | 3 | #include 4 | #include 5 | 6 | #include 7 | #include 8 | #include "piko/syscalls.h" 9 | 10 | int _open(const char *pathname, int flags) 11 | { 12 | return do_syscall2((void *) pathname, (void *) flags, SYS_OPEN); 13 | } 14 | 15 | int _close(int fd) 16 | { 17 | return do_syscall1((void *) fd, SYS_CLOSE); 18 | } 19 | 20 | ssize_t _read(int fd, void *buf, size_t count) 21 | { 22 | return (ssize_t) do_syscall3((void *) fd, buf, (void *) count, SYS_READ); 23 | } 24 | 25 | ssize_t _write(int fd, void *buf, size_t count) 26 | { 27 | return (ssize_t) do_syscall3((void *) fd, buf, (void *) count, SYS_WRITE); 28 | } 29 | 30 | off_t _lseek(int fd, off_t offset, int whence) 31 | { 32 | return (off_t) do_syscall3((void *) fd, (void *) offset, (void *) whence, 33 | SYS_LSEEK); 34 | } 35 | 36 | int stat(const char *pathname, struct stat *buf) 37 | { 38 | return do_syscall2((void *) pathname, (void *) buf, SYS_STAT); 39 | } 40 | 41 | int mount(const char *source, 42 | const char *target, 43 | const char *filesystemtype, 44 | unsigned long mountflags, 45 | const void *data) 46 | { 47 | return do_syscall5((void *) source, (void *) target, 48 | (void *) filesystemtype, (void *) mountflags, 49 | (void *) data, SYS_MOUNT); 50 | } 51 | 52 | DIR *opendir(const char *name) 53 | { 54 | return (DIR *) do_syscall2((void *) name, (void *) O_DIRECTORY, SYS_OPEN); 55 | } 56 | 57 | int readdir_r(DIR *dirp, struct dirent *entry, struct dirent **result) 58 | { 59 | return do_syscall3((void *) dirp, (void *) entry, (void *) result, 60 | SYS_READDIR_R); 61 | } 62 | 63 | int closedir(DIR *dirp) 64 | { 65 | return do_syscall1((void *) dirp, SYS_CLOSE); 66 | } 67 | -------------------------------------------------------------------------------- /libc/piko/mman.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | 5 | #include "syscalls.h" 6 | 7 | void *mmap(void *addr, size_t length, int prot, int flags, int fd, off_t offset) 8 | { 9 | return (void *) do_syscall6((void *) addr, (void *) length, (void *) prot, 10 | (void *) flags, (void *) fd, (void *) offset, 11 | SYS_MMAP); 12 | } 13 | 14 | int munmap(__unused void *addr, __unused size_t length) 15 | { 16 | return do_syscall2((void *) addr, (void *) length, SYS_MUNMAP); 17 | } 18 | -------------------------------------------------------------------------------- /libc/piko/stubs.c: -------------------------------------------------------------------------------- 1 | /* Newlib stubs */ 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | #include 8 | #include 9 | 10 | #include "syscalls.h" 11 | 12 | #define HANGS_ON() \ 13 | ({ \ 14 | printk("error: Newlib needs %s", __func__); \ 15 | for (;;) \ 16 | ; \ 17 | }) 18 | 19 | int _isatty(__unused int file) 20 | { 21 | HANGS_ON(); 22 | 23 | return 1; 24 | } 25 | 26 | int _fstat() 27 | { 28 | HANGS_ON(); 29 | 30 | return -1; 31 | } 32 | 33 | void *_sbrk(__unused int incr) 34 | { 35 | HANGS_ON(); 36 | 37 | return NULL; 38 | } 39 | 40 | void _exit(__unused int status) 41 | { 42 | HANGS_ON(); 43 | } 44 | 45 | clock_t _times() 46 | { 47 | HANGS_ON(); 48 | 49 | return -1; 50 | } 51 | 52 | void _fini(void) 53 | { 54 | HANGS_ON(); 55 | } 56 | 57 | int _getpid(void) 58 | { 59 | return do_syscall0(SYS_GETPID); 60 | } 61 | -------------------------------------------------------------------------------- /libc/piko/syscalls.S: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | .syntax unified 5 | .thumb 6 | 7 | @ int do_syscall0(void, int no) 8 | ENTRY(do_syscall0) 9 | svc #0 10 | bx lr 11 | ENDPROC(do_syscall0) 12 | 13 | @ int do_syscall1(void *a0, int no) 14 | ENTRY(do_syscall1) 15 | svc #1 16 | bx lr 17 | ENDPROC(do_syscall1) 18 | 19 | @ int do_syscall2(void *a0, void *a1, int no) 20 | ENTRY(do_syscall2) 21 | svc #2 22 | bx lr 23 | ENDPROC(do_syscall2) 24 | 25 | @ int do_syscall3(void *a0, void *a1, void *a2, int no) 26 | ENTRY(do_syscall3) 27 | svc #3 28 | bx lr 29 | ENDPROC(do_syscall3) 30 | 31 | @ int do_syscall4(void *a0, void *a1, void *a2, void *a3, 32 | @ int no) 33 | ENTRY(do_syscall4) 34 | svc #4 35 | bx lr 36 | ENDPROC(do_syscall4) 37 | 38 | @ int do_syscall5(void *a0, void *a1, void *a2, void *a3, 39 | @ void *a4, int no) 40 | ENTRY(do_syscall5) 41 | svc #5 42 | bx lr 43 | ENDPROC(do_syscall5) 44 | 45 | @ int do_syscall6(void *a0, void *a1, void *a2, void *a3, 46 | @ void *a4, void *a5, int no) 47 | ENTRY(do_syscall6) 48 | svc #6 49 | bx lr 50 | ENDPROC(do_syscall6) 51 | -------------------------------------------------------------------------------- /libc/piko/syscalls.h: -------------------------------------------------------------------------------- 1 | /* libc/piko/syscalls.h */ 2 | 3 | #ifndef LIBC_SYSCALLS_H 4 | #define LIBC_SYSCALLS_H 5 | 6 | int do_syscall0(int no); 7 | int do_syscall1(void *a0, int no); 8 | int do_syscall2(void *a0, void *a1, int no); 9 | int do_syscall3(void *a0, void *a1, void *a2, int no); 10 | int do_syscall4(void *a0, void *a1, void *a2, void *a3, int no); 11 | int do_syscall5(void *a0, void *a1, void *a2, void *a3, void *a4, int no); 12 | int do_syscall6(void *a0, 13 | void *a1, 14 | void *a2, 15 | void *a3, 16 | void *a4, 17 | void *a5, 18 | int no); 19 | 20 | #endif /* !LIBC_SYSCALLS_H */ 21 | -------------------------------------------------------------------------------- /libc/pthread.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #include "linux/list.h" 6 | 7 | int pthread_attr_setstacksize(pthread_attr_t *attr, size_t stacksize) 8 | { 9 | if (!attr) 10 | return -1; 11 | attr->stacksize = stacksize; 12 | 13 | return 0; 14 | } 15 | 16 | int pthread_attr_getstacksize(const pthread_attr_t *attr, size_t *stacksize) 17 | { 18 | if (!attr) 19 | return -1; 20 | *stacksize = attr->stacksize; 21 | 22 | return 0; 23 | } 24 | 25 | const pthread_attr_t pthread_attr_default = {.stacksize = 1024}; 26 | 27 | int pthread_attr_init(pthread_attr_t *attr) 28 | { 29 | if (!attr) 30 | return -1; 31 | memcpy(attr, &pthread_attr_default, sizeof(pthread_attr_t)); 32 | 33 | return 0; 34 | } 35 | 36 | int pthread_mutex_init(pthread_mutex_t *mutex, 37 | __unused const pthread_mutexattr_t *attr) 38 | { 39 | *mutex = -1; 40 | 41 | return 0; 42 | } 43 | 44 | int pthread_cond_init(__unused pthread_cond_t *cond, 45 | __unused const pthread_condattr_t *attr) 46 | { 47 | return 0; 48 | } 49 | 50 | /* syscall wrappers */ 51 | 52 | #include 53 | 54 | #include "piko/syscalls.h" 55 | 56 | int sched_yield(void) 57 | { 58 | return do_syscall0(SYS_PTHREAD_YIELD); 59 | } 60 | 61 | int pthread_yield(void) __attribute__((alias("sched_yield"))); 62 | 63 | pthread_t pthread_self(void) 64 | { 65 | return (pthread_t) do_syscall0(SYS_PTHREAD_SELF); 66 | } 67 | 68 | void pthread_exit(void *retval) 69 | { 70 | do_syscall1((void *) retval, SYS_PTHREAD_EXIT); 71 | 72 | /* compiler complains about 'noreturn' function does return */ 73 | for (;;) 74 | ; 75 | } 76 | 77 | int pthread_detach(pthread_t thread) 78 | { 79 | return do_syscall1((void *) thread, SYS_PTHREAD_DETACH); 80 | } 81 | 82 | int pthread_create(pthread_t *thread, 83 | const pthread_attr_t *attr, 84 | void *(*start_routine)(void *), 85 | void *arg) 86 | { 87 | return do_syscall4((void *) thread, (void *) attr, (void *) start_routine, 88 | arg, SYS_PTHREAD_CREATE); 89 | } 90 | 91 | int pthread_join(pthread_t thread, void **retval) 92 | { 93 | return do_syscall2((void *) thread, (void *) retval, SYS_PTHREAD_JOIN); 94 | } 95 | 96 | int pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex) 97 | { 98 | return do_syscall2((void *) cond, (void *) mutex, SYS_PTHREAD_COND_WAIT); 99 | } 100 | 101 | int pthread_cond_signal(pthread_cond_t *cond) 102 | { 103 | return do_syscall1((void *) cond, SYS_PTHREAD_COND_SIGNAL); 104 | } 105 | -------------------------------------------------------------------------------- /libc/signal.c: -------------------------------------------------------------------------------- 1 | /* syscall wrappers */ 2 | 3 | #include 4 | 5 | #include 6 | #include "piko/syscalls.h" 7 | 8 | int sigaction(int sig, 9 | const struct sigaction *restrict act, 10 | struct sigaction *restrict oact) 11 | { 12 | return do_syscall3((void *) sig, (void *) act, (void *) oact, 13 | SYS_SIGACTION); 14 | } 15 | 16 | int _kill(pid_t pid, int sig) 17 | { 18 | return do_syscall2((void *) pid, (void *) sig, SYS_KILL); 19 | } 20 | -------------------------------------------------------------------------------- /libc/time.c: -------------------------------------------------------------------------------- 1 | /* syscall wrappers */ 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | #include 8 | #include "piko/syscalls.h" 9 | 10 | int timer_create(clockid_t clockid, struct sigevent *sevp, timer_t *timerid) 11 | { 12 | return do_syscall3((void *) clockid, (void *) sevp, (void *) timerid, 13 | SYS_TIMER_CREATE); 14 | } 15 | 16 | int timer_settime(timer_t timerid, 17 | int flags, 18 | const struct itimerspec *new_value, 19 | struct itimerspec *old_value) 20 | { 21 | return do_syscall4((void *) timerid, (void *) flags, (void *) new_value, 22 | (void *) old_value, SYS_TIMER_SETTIME); 23 | } 24 | 25 | int timer_gettime(timer_t timerid, struct itimerspec *curr_value) 26 | { 27 | return do_syscall2((void *) timerid, (void *) curr_value, 28 | SYS_TIMER_GETTIME); 29 | } 30 | -------------------------------------------------------------------------------- /libc/ucontext.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include "linux/types.h" 5 | 6 | void return_from_makecontext(); 7 | 8 | void makecontext(ucontext_t *ucp, void (*func)(), int argc, ...) 9 | { 10 | va_list ap; 11 | 12 | /* pass arguments to the context entry function */ 13 | if (argc) { 14 | va_start(ap, argc); 15 | 16 | /* the 4 first arguments go into registers r0-r3 */ 17 | for (int i = 0; (i < argc) && (i < 4); i++) 18 | ucp->uc_mcontext.gprs[i] = va_arg(ap, int); 19 | 20 | /* extra arguments go into the stack */ 21 | 22 | va_end(ap); 23 | } 24 | 25 | /* top of the stack has a back-link pointer to the context's struct */ 26 | ucp->uc_stack.ss_sp = (void *) ((u32) ucp->uc_stack.ss_sp - sizeof(u32)); 27 | *(u32 *) ucp->uc_stack.ss_sp = (u32) ucp; 28 | 29 | /* initialize the machine context */ 30 | // FIXME: ss_sp and mcontext_sp are mutually redundant 31 | ucp->uc_mcontext.sp = (u32) ucp->uc_stack.ss_sp; 32 | ucp->uc_mcontext.lr = (u32) return_from_makecontext; 33 | ucp->uc_mcontext.pc = (u32) func | 1; /* force Thumb_Mode */ 34 | } 35 | -------------------------------------------------------------------------------- /libc/unistd.c: -------------------------------------------------------------------------------- 1 | /* syscall wrappers */ 2 | 3 | #include 4 | #include "piko/syscalls.h" 5 | 6 | long sysconf(int name) 7 | { 8 | return do_syscall1((void *) name, SYS_SYSCONF); 9 | } 10 | 11 | unsigned int msleep(unsigned int msecs) 12 | { 13 | return do_syscall1((void *) msecs, SYS_MSLEEP); 14 | } 15 | 16 | /*int close(int fd) 17 | { 18 | return do_syscall1((void *) fd, SYS_CLOSE); 19 | }*/ 20 | -------------------------------------------------------------------------------- /libc/utils.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | static char *strrev(char *s) 5 | { 6 | char *t = s; 7 | char *u = s; 8 | 9 | if (!s || (*s == '\0')) 10 | return s; 11 | 12 | /* u points to the last char in the string */ 13 | while (*(u + 1) != '\0') 14 | u++; 15 | 16 | /* t moves forward, u moves backward */ 17 | while (t < u) { 18 | char tmp = *t; 19 | *t++ = *u; 20 | *u-- = tmp; 21 | } 22 | 23 | return s; 24 | } 25 | 26 | void strpad(char *buf, char pad_val, int count) 27 | { 28 | buf[count--] = '\0'; 29 | for (; count >= 0; count--) 30 | buf[count] = pad_val; 31 | } 32 | 33 | char *itoa_base(int value, char *buf, int base) 34 | { 35 | const char base36[] = "0123456789abcdefghijklmnopqrstuvwxyz"; 36 | int i = 0; 37 | int isneg = 0; 38 | unsigned int val = value; 39 | 40 | if (!buf || (base > 36)) 41 | return NULL; 42 | 43 | if ((value < 0) && (base == 10)) { 44 | val = abs(value); 45 | isneg = 1; 46 | } 47 | 48 | do { 49 | buf[i++] = base36[val % base]; 50 | val /= base; 51 | } while (val); 52 | 53 | if (isneg) 54 | buf[i++] = '-'; 55 | buf[i] = '\0'; 56 | 57 | return strrev(buf); 58 | } 59 | -------------------------------------------------------------------------------- /libc/v7m-pthread.S: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | .syntax unified 5 | .thumb 6 | 7 | // -1: unlocked, 0: locked, positive: locked, possible waiters 8 | 9 | /** 10 | * FIXME: In order to reduce the code base and we tend to keep just one 11 | * 'bx lr'. But it would make it not intuitional. Probably, we 12 | * could discard this optimization. 13 | */ 14 | @ int pthread_mutex_lock(pthread_mutex_t *mutex) 15 | ENTRY(pthread_mutex_lock) 16 | movs r2, #0 17 | 0: ldrex r1, [r0] 18 | teq r1, #-1 @ check locked? 19 | bne 1f 20 | strex r1, r2, [r0] 21 | teq r1, #0 @ 'strex' success? 22 | bne 0b 23 | dmb @ ARMv7-M ARM, A3.4.6 24 | movs r0, #0 @ it also update EQ flag 25 | 1: itt ne 26 | movne r1, #SYS_PTHREAD_MUTEX_LOCK 27 | svcne #1 28 | bx lr 29 | ENDPROC(pthread_mutex_lock) 30 | 31 | @ int pthread_mutex_trylock(pthread_mutex_t *mutex) 32 | ENTRY(pthread_mutex_trylock) 33 | movs r2, #0 34 | 0: ldrex r1, [r0] 35 | teq r1, #-1 @ check locked? 36 | bne 1f 37 | strex r1, r2, [r0] 38 | teq r1, #0 @ 'strex' success? 39 | bne 1f 40 | movs r0, #0 @ it also update EQ flag 41 | 1: it ne 42 | movne r0, #-1 43 | bx lr 44 | ENDPROC(pthread_mutex_trylock) 45 | 46 | @ int pthread_mutex_unlock(pthread_mutex_t *mutex) 47 | ENTRY(pthread_mutex_unlock) 48 | movs r2, #-1 49 | 0: ldrex r1, [r0] 50 | teq r1, #0 @ Just one hold lock? 51 | bne 1f 52 | strex r1, r2, [r0] 53 | teq r1, #0 @ 'strex' success? 54 | bne 0b 55 | dmb @ ARMv7-M ARM, A3.4.6 56 | movs r0, #0 @ it also update EQ flag 57 | 1: itt ne 58 | movne r1, #SYS_PTHREAD_MUTEX_UNLOCK 59 | svcne #1 60 | bx lr 61 | ENDPROC(pthread_mutex_unlock) 62 | -------------------------------------------------------------------------------- /mk/cmsis.mk: -------------------------------------------------------------------------------- 1 | SVN_REV = 27441 2 | 3 | ARM_CMSIS_ASSETS = \ 4 | mbed_toolchain.h \ 5 | mbed_preprocessor.h \ 6 | mbed_assert.h 7 | 8 | ARM_CMSIS_ASSETS := $(addprefix $(CMSIS)/util/, $(ARM_CMSIS_ASSETS)) 9 | 10 | $(CMSIS): 11 | @mkdir -p $@ 12 | 13 | $(CMSIS)/$(PLAT): $(CMSIS)/arm $(CMSIS)/TARGET_STM $(ARM_CMSIS_ASSETS) 14 | 15 | $(CMSIS)/arm: 16 | svn export -r$(SVN_REV) -q --force https://github.com/ARMmbed/mbed-os/trunk/cmsis/ $(CMSIS)/arm 17 | 18 | $(CMSIS)/TARGET_STM: 19 | svn export -r$(SVN_REV) -q --force https://github.com/ARMmbed/mbed-os/trunk/targets/TARGET_STM/ $(CMSIS)/TARGET_STM 20 | 21 | $(ARM_CMSIS_ASSETS): 22 | $(VECHO) " WGET\t\t$@\n" 23 | $(Q)$(WGET) -q https://raw.github.com/ARMmbed/mbed-os/master/platform/include/platform/$(notdir $@) -P $(CMSIS)/platform 24 | -------------------------------------------------------------------------------- /mk/flags.mk: -------------------------------------------------------------------------------- 1 | CROSS_COMPILE ?= arm-none-eabi- 2 | CC = $(CROSS_COMPILE)gcc 3 | AS = $(CROSS_COMPILE)as 4 | AR = $(CROSS_COMPILE)ar 5 | OBJCOPY = $(CROSS_COMPILE)objcopy 6 | GDB = $(CROSS_COMPILE)gdb 7 | HOSTCC = gcc 8 | WGET = wget 9 | PYTHON ?= python 10 | QEMU_SYSTEM_ARM ?= qemu-system-arm 11 | 12 | # FIXME: configurable via menuconfig or command line 13 | CFLAGS_OPT = -Os # -flto 14 | 15 | CFLAGS += \ 16 | -std=c99 \ 17 | -W -Wall \ 18 | -Iinclude -Iinclude/libc -I. \ 19 | -I$(CMSIS)/arm -I$(CMSIS)/$(PLAT) -I$(CMSIS)/$(PLAT)/hal \ 20 | -Iinclude/kernel \ 21 | -D_POSIX_THREADS=1 -D_POSIX_TIMERS=1 -D_POSIX_REALTIME_SIGNALS=1 \ 22 | -Wno-main -fdiagnostics-color \ 23 | -ffunction-sections -fdata-sections -ggdb \ 24 | $(CFLAGS_OPT) 25 | 26 | # FIXME: make Piko-specific build options configurable 27 | CFLAGS += \ 28 | -D CONFIG_KERNEL_STACK_CHECKING 29 | 30 | LDFLAGS += \ 31 | -nostartfiles -specs=nano.specs \ 32 | -Wl,-Map=$(NAME).map -Wl,-Tpiko.lds -Wl,--gc-sections 33 | 34 | CFLAGS += -mthumb -mcpu=$(CPU) 35 | LDFLAGS += -mthumb -march=$(ARCH) 36 | -------------------------------------------------------------------------------- /mk/rules.mk: -------------------------------------------------------------------------------- 1 | # Control the build verbosity 2 | ifeq ("$(VERBOSE)","1") 3 | Q := 4 | VECHO = @true 5 | else 6 | Q := @ 7 | VECHO = @printf 8 | endif 9 | 10 | $(NAME).elf: $(OBJS) fs/version.o 11 | $(VECHO) " LD\t\t$@\n" 12 | $(Q)$(CC) $(LDFLAGS) -o $@ $^ 13 | 14 | %.o: %.c 15 | $(VECHO) " CC\t\t$@\n" 16 | $(Q)$(CC) -o $@ $(CFLAGS) -c -D__KERNEL__ -MMD -MF $@.d $< 17 | 18 | %.o: %.S 19 | $(VECHO) " AS\t\t$@\n" 20 | $(Q)$(CC) -o $@ $(CFLAGS) -c $< 21 | 22 | %.lds: %.lds.S 23 | $(VECHO) " HOSTCC\t$@\n" 24 | $(Q)$(HOSTCC) -E -P -Iinclude -DROMSZ=$(ROMSZ) -DRAMSZ=$(RAMSZ) -o $@ $< 25 | 26 | kernel/syscall.c: include/kernel/syscalls.h 27 | $(VECHO) " GEN\t\t$@\n" 28 | $(Q)$(PYTHON) scripts/gen-syscalls.py --source > $@ 29 | 30 | include/kernel/syscalls.h: 31 | $(VECHO) " GEN\t\t$@\n" 32 | $(Q)$(PYTHON) scripts/gen-syscalls.py --header > $@ 33 | 34 | fs/version: 35 | $(VECHO) " GEN\t\t$@\n" 36 | $(Q)python3 scripts/gen-proc-version.py --cc-version \ 37 | --user $(shell whoami) --host $(shell hostname) \ 38 | -a $(ARCH) -c $(CPU) -n 'Piko' > $@ 39 | 40 | fs/version.o: fs/version 41 | $(VECHO) " OBJCOPY\t$@\n" 42 | $(Q)$(OBJCOPY) -I binary -O elf32-littlearm -B arm \ 43 | --rename-section .data=.rodata \ 44 | --redefine-sym _binary_$(subst /,_,$<)_start=_version_ptr \ 45 | --redefine-sym _binary_$(subst /,_,$<)_size=_version_len \ 46 | $< $@ 47 | 48 | %.bin: %.elf 49 | $(VECHO) " OBJCOPY\t$@\n" 50 | $(Q)$(OBJCOPY) -Obinary $< $@ 51 | -------------------------------------------------------------------------------- /piko.lds.S: -------------------------------------------------------------------------------- 1 | OUTPUT_FORMAT("elf32-littlearm") 2 | OUTPUT_ARCH(arm) 3 | 4 | #define RAMORG 0x20000000 5 | 6 | MEMORY 7 | { 8 | rom (rx) : ORIGIN = 0, LENGTH = ROMSZ 9 | ram (rwx) : ORIGIN = RAMORG, LENGTH = RAMSZ 10 | } 11 | 12 | SECTIONS 13 | { 14 | .vector 0 : { 15 | PROVIDE(__vector_start__ = .); 16 | KEEP(*(.vector)) 17 | } > rom 18 | 19 | .text BLOCK(8) : { 20 | PROVIDE(__text_start__ = .); 21 | *(.text*) 22 | PROVIDE(__text_end__ = .); 23 | . = ALIGN(8); 24 | PROVIDE(__shell_cmd_start__ = .); 25 | KEEP(*(.shell_cmd*)) 26 | PROVIDE(__shell_cmd_end__ = .); 27 | PROVIDE(__sched_classes_start__ = .); 28 | KEEP(*(.sched.class*)) 29 | PROVIDE(__sched_classes_end__ = .); 30 | PROVIDE(__serial_hook_start__ = .); 31 | KEEP(*(.serial.hook*)) 32 | PROVIDE(__serial_hook_end__ = .); 33 | PROVIDE(__rodata_start__ = .); 34 | *(.rodata*) 35 | PROVIDE(__rodata_end__ = .); 36 | } > rom 37 | 38 | /* Initialized data (.data* sections) are initially stored in Flash, 39 | but need to be copied to a volatile storage for they are not 40 | read-only. */ 41 | 42 | .data : AT (__rodata_end__) { 43 | PROVIDE(__data_start__ = .); 44 | *(.data*) 45 | PROVIDE(__data_end__ = .); 46 | } > ram 47 | 48 | PROVIDE(__data_size__ = SIZEOF(.data)); 49 | 50 | .bss : { 51 | PROVIDE(__bss_start__ = .); 52 | *(.bss*) 53 | *(COMMON) 54 | PROVIDE(__bss_end__ = .); 55 | } > ram 56 | 57 | PROVIDE(__bss_size__ = SIZEOF(.bss)); 58 | 59 | /* heap for the kernel's malloc */ 60 | .heap BLOCK(32) : { 61 | PROVIDE(__heap_start__ = .); 62 | . += 4k; 63 | PROVIDE(__heap_end__ = .); 64 | } > ram 65 | 66 | PROVIDE(__heap_size__ = SIZEOF(.heap)); 67 | 68 | .pgmem RAMORG + RAMSZ - 32k : { 69 | PROVIDE(__pgmem_start__ = .); 70 | . += 26k; 71 | 72 | /* Reserve the last page for the early stack. Must be of the biggest size 73 | * such that there will be no coalescing when freeing the page, for lower 74 | * booting time. */ 75 | PROVIDE(__early_stack_end__ = .); 76 | . += 2k; 77 | PROVIDE(__early_stack_start__ = .); 78 | 79 | PROVIDE(__pgmem_end__ = .); 80 | } > ram 81 | 82 | PROVIDE(__pgmem_size__ = SIZEOF(.pgmem)); 83 | 84 | .mtdram : { 85 | PROVIDE(__mtdram_start__ = .); 86 | . += 4k; 87 | } > ram 88 | 89 | PROVIDE(__mtdram_size__ = SIZEOF(.mtdram)); 90 | 91 | /DISCARD/ : 92 | { 93 | *(.ARM.exidx) 94 | *(.ARM.attributes) 95 | } 96 | } 97 | -------------------------------------------------------------------------------- /platform/f429disco/Makefile: -------------------------------------------------------------------------------- 1 | CPU = cortex-m4 2 | ARCH = armv7-m 3 | 4 | ROMSZ = 2048k 5 | RAMSZ = 192k 6 | 7 | CFLAGS += \ 8 | -Iplatform/f429disco \ 9 | -I$(CMSIS)\ 10 | -I$(CMSIS)/platform \ 11 | -I$(CMSIS)/arm \ 12 | -I$(CMSIS)/arm/TARGET_CORTEX_M \ 13 | -I$(CMSIS)/arm/TARGET_CORTEX_M/TOOLCHAIN_GCC \ 14 | -I$(CMSIS)/TARGET_STM \ 15 | -I$(CMSIS)/TARGET_STM//TARGET_STM32F4 \ 16 | -I$(CMSIS)/TARGET_STM//TARGET_STM32F4/device \ 17 | -I$(CMSIS)/TARGET_STM//TARGET_STM32F4/TARGET_STM32F429xI \ 18 | -I$(CMSIS)/TARGET_STM//TARGET_STM32F4/TARGET_STM32F429xI/device \ 19 | -I$(CMSIS)/TARGET_STM//TARGET_STM32F4/TARGET_STM32F429xI/TARGET_DISCO_F429ZI 20 | 21 | CSRC += \ 22 | platform/f429disco/halt.c \ 23 | platform/f429disco/init.c \ 24 | platform/f429disco/uart.c 25 | 26 | # CMSIS files 27 | ## STM32 HAL 28 | CSRC += $(CMSIS)/TARGET_STM/TARGET_STM32F4/device/system_stm32f4xx.c 29 | CSRC += $(CMSIS)/TARGET_STM/TARGET_STM32F4/device/stm32f4xx_hal_rcc.c 30 | CSRC += $(CMSIS)/TARGET_STM/TARGET_STM32F4/device/stm32f4xx_hal_rcc_ex.c 31 | CSRC += $(CMSIS)/TARGET_STM/TARGET_STM32F4/device/stm32f4xx_hal_gpio.c 32 | CSRC += $(CMSIS)/TARGET_STM/TARGET_STM32F4/device/stm32f4xx_hal_uart.c 33 | 34 | ## SystemInit() 35 | CSRC += $(CMSIS)/TARGET_STM/TARGET_STM32F4/TARGET_STM32F429xI/TARGET_DISCO_F429ZI/system_clock.c 36 | 37 | # Timer driver files 38 | CSRC += drivers/timer/systick.c 39 | 40 | # Serial driver files 41 | CFLAGS += -Idrivers/serial 42 | CSRC += drivers/serial/stm32-uart.c 43 | -------------------------------------------------------------------------------- /platform/f429disco/build.mk: -------------------------------------------------------------------------------- 1 | run: $(NAME).bin 2 | openocd -f interface/stlink-v2.cfg \ 3 | -f target/stm32f4x_stlink.cfg \ 4 | -c "init" \ 5 | -c "reset init" \ 6 | -c "reset halt" 7 | -c "reset run" 8 | 9 | st-flash: $(NAME).bin 10 | st-flash --reset write \ 11 | $(NAME).bin 0x08000000 12 | 13 | dbg: $(NAME).bin 14 | openocd -f board/stm32f429discovery.cfg 15 | 16 | gdb: $(NAME).elf 17 | $(Q)$(GDB) -q \ 18 | $< -ex "target remote :3333" \ 19 | -ex "monitor reset halt" 20 | 21 | wakeup: 22 | openocd -f interface/stlink-v2.cfg \ 23 | -f target/stm32f4x_stlink.cfg \ 24 | -c "init" \ 25 | -c "reset init" \ 26 | -c "reset run" \ 27 | -c "shutdown" 28 | -------------------------------------------------------------------------------- /platform/f429disco/halt.c: -------------------------------------------------------------------------------- 1 | 2 | #include 3 | 4 | void __platform_halt(void) 5 | { 6 | v7m_semihost_exit(0); 7 | } 8 | -------------------------------------------------------------------------------- /platform/f429disco/init.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include "platform.h" 5 | 6 | #define CPU_FREQ_IN_HZ 168000000 7 | #define SYSTICK_FREQ_IN_HZ 1000 8 | #define SYSTICK_PERIOD_IN_MSECS (SYSTICK_FREQ_IN_HZ / 1000) 9 | 10 | struct timer_operations; 11 | 12 | void config_timer_operations(struct timer_operations *tops); 13 | 14 | extern struct timer_operations systick_tops; 15 | 16 | __weak void __platform_init(void) 17 | { 18 | config_timer_operations(&systick_tops); 19 | 20 | /* SysTick running at 1kHz */ 21 | SysTick_Config(CPU_FREQ_IN_HZ / SYSTICK_FREQ_IN_HZ); 22 | } 23 | 24 | __weak void __platform_halt(void) 25 | { 26 | for (;;) 27 | ; 28 | } 29 | -------------------------------------------------------------------------------- /platform/f429disco/platform.h: -------------------------------------------------------------------------------- 1 | #ifndef _PLATFORM_STM32_PLATFORM_H 2 | #define _PLATFORM_STM32_PLATFORM_H 3 | 4 | #include 5 | 6 | void __platform_init(void); 7 | void __platform_halt(void); 8 | 9 | /* Default USART for output */ 10 | #define USARTx USART1 11 | #define USARTx_IRQn USART1_IRQn 12 | 13 | #endif /* !_PLATFORM_STM32_PLATFORM_H */ 14 | -------------------------------------------------------------------------------- /platform/stm32p103/Makefile: -------------------------------------------------------------------------------- 1 | CPU = cortex-m3 2 | ARCH = armv7-m 3 | 4 | ROMSZ = 128k 5 | RAMSZ = 64k 6 | 7 | CFLAGS += \ 8 | -Iplatform/stm32p103 \ 9 | -I$(CMSIS)\ 10 | -I$(CMSIS)/platform \ 11 | -I$(CMSIS)/arm \ 12 | -I$(CMSIS)/arm/TARGET_CORTEX_M \ 13 | -I$(CMSIS)/arm/TARGET_CORTEX_M/TOOLCHAIN_GCC \ 14 | -I$(CMSIS)/TARGET_STM \ 15 | -I$(CMSIS)/TARGET_STM//TARGET_STM32F1 \ 16 | -I$(CMSIS)/TARGET_STM//TARGET_STM32F1/device \ 17 | -I$(CMSIS)/TARGET_STM//TARGET_STM32F1/TARGET_NUCLEO_F103RB \ 18 | -I$(CMSIS)/TARGET_STM//TARGET_STM32F1/TARGET_NUCLEO_F103RB/device 19 | 20 | CSRC += \ 21 | platform/stm32p103/halt.c \ 22 | platform/stm32p103/init.c \ 23 | platform/stm32p103/uart.c 24 | 25 | # CMSIS files 26 | ## STM32 HAL 27 | CSRC += $(CMSIS)/TARGET_STM/TARGET_STM32F1/device/system_stm32f1xx.c 28 | CSRC += $(CMSIS)/TARGET_STM/TARGET_STM32F1/device/stm32f1xx_hal_rcc.c 29 | CSRC += $(CMSIS)/TARGET_STM/TARGET_STM32F1/device/stm32f1xx_hal_rcc_ex.c 30 | CSRC += $(CMSIS)/TARGET_STM/TARGET_STM32F1/device/stm32f1xx_hal_gpio.c 31 | CSRC += $(CMSIS)/TARGET_STM/TARGET_STM32F1/device/stm32f1xx_hal_uart.c 32 | 33 | ## SystemInit() 34 | CSRC += $(CMSIS)/TARGET_STM/TARGET_STM32F1/TARGET_NUCLEO_F103RB/device/system_clock.c 35 | 36 | # Timer driver files 37 | CSRC += drivers/timer/systick.c 38 | 39 | # Serial driver files 40 | CFLAGS += -Idrivers/serial 41 | CSRC += drivers/serial/stm32-uart.c 42 | -------------------------------------------------------------------------------- /platform/stm32p103/build.mk: -------------------------------------------------------------------------------- 1 | ifeq ($(shell lsb_release -c -s),trusty) 2 | REDIRECT_SERIAL = -serial stdio 3 | endif 4 | 5 | run: $(NAME).bin 6 | $(Q)$(QEMU_SYSTEM_ARM) \ 7 | -semihosting \ 8 | $(REDIRECT_SERIAL) \ 9 | -nographic \ 10 | -cpu cortex-m3 \ 11 | -machine stm32-p103 \ 12 | -kernel $< 13 | 14 | dbg: $(NAME).bin 15 | $(Q)$(QEMU_SYSTEM_ARM) \ 16 | -semihosting \ 17 | $(REDIRECT_SERIAL) \ 18 | -nographic \ 19 | -cpu cortex-m3 \ 20 | -machine stm32-p103 \ 21 | -kernel $< \ 22 | -S -s 23 | 24 | gdb: $(NAME).elf 25 | $(Q)$(GDB) -q \ 26 | $< -ex "target remote :1234" 27 | -------------------------------------------------------------------------------- /platform/stm32p103/halt.c: -------------------------------------------------------------------------------- 1 | 2 | #include 3 | 4 | void __platform_halt(void) 5 | { 6 | v7m_semihost_exit(0); 7 | } 8 | -------------------------------------------------------------------------------- /platform/stm32p103/init.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include "platform.h" 4 | 5 | #define CPU_FREQ_IN_HZ 72000000 6 | #define SYSTICK_FREQ_IN_HZ 1000 7 | #define SYSTICK_PERIOD_IN_MSECS (SYSTICK_FREQ_IN_HZ / 1000) 8 | 9 | struct timer_operations; 10 | 11 | void config_timer_operations(struct timer_operations *tops); 12 | 13 | extern struct timer_operations systick_tops; 14 | 15 | void rcc_clock_init(void); 16 | void __uart_enable(void); 17 | 18 | __weak void __platform_init(void) 19 | { 20 | config_timer_operations(&systick_tops); 21 | 22 | /* SysTick running at 1kHz */ 23 | SysTick_Config(CPU_FREQ_IN_HZ / SYSTICK_FREQ_IN_HZ); 24 | } 25 | 26 | __weak void __platform_halt(void) 27 | { 28 | for (;;) 29 | ; 30 | } 31 | -------------------------------------------------------------------------------- /platform/stm32p103/platform.h: -------------------------------------------------------------------------------- 1 | #ifndef _PLATFORM_STM32_PLATFORM_H 2 | #define _PLATFORM_STM32_PLATFORM_H 3 | 4 | #include 5 | 6 | void __platform_init(void); 7 | void __platform_halt(void); 8 | 9 | 10 | /* Default USART for outputing */ 11 | #define USARTx USART2 12 | #define USARTx_IRQn USART2_IRQn 13 | 14 | #endif /* !_PLATFORM_STM32_PLATFORM_H */ 15 | -------------------------------------------------------------------------------- /scripts/gen-proc-version.py: -------------------------------------------------------------------------------- 1 | import subprocess 2 | import string 3 | from datetime import datetime 4 | import argparse 5 | 6 | def run_cmd(cmd): 7 | res = subprocess.run(cmd, universal_newlines=True, 8 | stdout=subprocess.PIPE, 9 | stderr=subprocess.STDOUT) 10 | if res.returncode == 0: 11 | return res.stdout.strip() 12 | return 'unknown' 13 | 14 | def cc_version(cc): 15 | cmd = [ cc, '--version' ] 16 | return run_cmd(cmd).splitlines()[0] 17 | 18 | parser = argparse.ArgumentParser() 19 | 20 | parser.add_argument("-n", "--name", action="store", dest="name") 21 | parser.add_argument("-a", "--arch", action="store", dest="arch") 22 | parser.add_argument("-c", "--cpu", action="store", dest="cpu") 23 | parser.add_argument("-u", "--user", action="store", dest="user", default="unknown") 24 | parser.add_argument( "--host", action="store", dest="host", default="unknown") 25 | parser.add_argument( "--major", action="store", dest="major", default=0) 26 | parser.add_argument( "--minor", action="store", dest="minor", default=0) 27 | parser.add_argument( "--micro", action="store", dest="micro", default=0) 28 | parser.add_argument( "--cc-version", action="store_true", dest="cc_version") 29 | 30 | args = parser.parse_args() 31 | 32 | version = '.'.join(map(lambda x: str(x), [args.major, args.minor, args.micro])) 33 | hostname = '@'.join([args.user, args.host]) 34 | platform = ', '.join(filter(lambda x: x is not None, [args.arch, args.cpu])) 35 | 36 | print('{} version {} ({}) ({}) #{}'.format(args.name, version, hostname, platform, 37 | datetime.now().strftime("%c"))) 38 | if (args.cc_version): 39 | print(cc_version('arm-none-eabi-gcc')) 40 | -------------------------------------------------------------------------------- /scripts/gen-syscalls.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | import string 4 | import argparse 5 | 6 | xs = [ 7 | # 8 | 'pthread_exit', 9 | 'pthread_self', 10 | 'pthread_yield', 11 | 'pthread_create', 12 | 'pthread_join', 13 | 'pthread_detach', 14 | 'pthread_mutex_lock', 15 | 'pthread_mutex_unlock', 16 | 'pthread_cond_signal', 17 | 'pthread_cond_wait', 18 | 19 | # 20 | 'timer_create', 21 | 'timer_settime', 22 | 'timer_gettime', 23 | 24 | # 25 | 'msleep', 26 | 'sysconf', 27 | 28 | # 29 | 'sigaction', 30 | 'kill', 31 | 32 | # , , ... 33 | 'open', 34 | 'close', 35 | 'read', 36 | 'write', 37 | 'lseek', 38 | 'stat', 39 | 'mount', 40 | 'readdir_r', 41 | 42 | # 43 | 'getpid', 44 | 45 | # 46 | 'mmap', 47 | 'munmap', 48 | ] 49 | 50 | parser = argparse.ArgumentParser() 51 | 52 | parser.add_argument("--header", action="store_true", dest="header") 53 | parser.add_argument("--source", action="store_true", dest="source") 54 | 55 | args = parser.parse_args() 56 | 57 | import datetime 58 | print('// GENERATED. DO NOT EDIT FROM HERE!') 59 | print('// Change definitions in scripts/gen-syscalls.py') 60 | print('// Created on ' + 61 | datetime.datetime.now().strftime("%Y-%m-%d %H:%M")) 62 | 63 | print('') 64 | 65 | #for x in list(enumerate(xs)): 66 | # name = 'sys_' + x[1] 67 | # print('[{}] = {},'.format(name.upper(), name)) 68 | 69 | if (args.header): 70 | print('#ifndef KERNEL_SYSCALLS_H') 71 | print('#define KERNEL_SYSCALLS_H') 72 | for x in list(enumerate(xs)): 73 | name = 'sys_' + x[1] 74 | print('#define {} {}'.format(name.upper(), x[0])) 75 | print('') 76 | print('#endif /* !KERNEL_SYSCALLS_H */') 77 | 78 | 79 | if (args.source): 80 | print('#include ') 81 | print('') 82 | for x in list(enumerate(xs)): 83 | name = 'sys_' + x[1] 84 | print('int {}();'.format(name)) 85 | print('#define SYS_MAX 48') 86 | print('') 87 | print('void *syscall_vect[SYS_MAX] = {') 88 | for x in list(enumerate(xs)): 89 | name = 'sys_' + x[1] 90 | print(' [{}] = {},'.format(name.upper(), name)) 91 | print('};'); 92 | print('') 93 | print('int syscall_register(unsigned ix, void *(*fn)()) {') 94 | print(' if (ix >= SYS_MAX) return -1;') 95 | print(' syscall_vect[ix] = fn;') 96 | print('return 0;') 97 | print('}'); 98 | -------------------------------------------------------------------------------- /tests/Makefile: -------------------------------------------------------------------------------- 1 | CSRC = $(wildcard tests/$(TEST)/*.c) 2 | SSRC = $(wildcard tests/$(TEST)/*.S) 3 | 4 | TEST_OBJ = $(wildcard tests/$(TEST)/*.o) 5 | LIB_OBJ = $(wildcard tests/lib/*.o) 6 | 7 | CFLAGS = -Itests/lib 8 | 9 | # Build a romFS drive if there is a /data directory at the root 10 | # of the testcase directory. 11 | ifneq ("$(wildcard tests/$(TEST)/data)","") 12 | OBJS = tests/$(TEST)/sda1.o 13 | endif 14 | 15 | include Makefile 16 | 17 | %sda1: 18 | $(VECHO) "GENROMFS $@" 19 | $(Q)genromfs -f tests/$(TEST)/sda1 -d tests/$(TEST)/data -V sda1 20 | 21 | %sda1.o: %sda1 22 | $(VECHO) "BUILDFS\t$@" 23 | $(Q)$(OBJCOPY) -I binary -O elf32-littlearm -B arm \ 24 | --rename-section .data=.rodata \ 25 | --redefine-sym _binary_$(subst /,_,$<)_start=_binary_sda1_start \ 26 | --redefine-sym _binary_$(subst /,_,$<)_end=_binary_sda1_end \ 27 | --redefine-sym _binary_$(subst /,_,$<)_size=_binary_sda1_size \ 28 | tests/$(TEST)/sda1 tests/$(TEST)/sda1.o 29 | 30 | clean: 31 | rm -f $(TEST_OBJ) $(LIB_OBJ) tests/$(TEST)/sda1 tests/$(TEST)/sda1.o 32 | 33 | clean_test: 34 | rm -f $(NAME).elf $(TEST_OBJ) tests/$(TEST)/sda1 tests/$(TEST)/sda1.o 35 | -------------------------------------------------------------------------------- /tests/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PikoRT/pikoRT/569cee508b34c3831ee573daa4e2cccf4ab51cbb/tests/__init__.py -------------------------------------------------------------------------------- /tests/__main__.py: -------------------------------------------------------------------------------- 1 | import sys 2 | if sys.version_info < (3, 5): 3 | print ("Only support python version >= 3.5") 4 | exit(1) 5 | 6 | import argparse 7 | import tests.runner as runner 8 | from tests.runner import PikoTest 9 | 10 | 11 | if __name__ == '__main__': 12 | parser = argparse.ArgumentParser() 13 | parser.add_argument('test', nargs='*') 14 | parser.add_argument('-v', '--verbose', action='store_true', help='Verbose output') 15 | parser.add_argument('--quiet', action='store_true', default=False, 16 | help='no output unless one or more tests fail') 17 | parser.add_argument('--debug', action='store_true', help='Run test and wait for gdb connect') 18 | parser.add_argument('-p', '--platform', default='stm32p103') 19 | parser.add_argument('--qemu', default='qemu-system-arm') 20 | parser.add_argument('--cc', default='arm-none-eabi-gcc') 21 | parser.add_argument('--timeout', type=int, default=60) 22 | parser.add_argument('--slowest', action='store_true', dest='print_slow', 23 | help='print the slowest 10 tests') 24 | 25 | ns = parser.parse_args() 26 | if ns.test: 27 | PikoTest().main(ns.test, ns) 28 | else: 29 | # This will include all test 30 | runner.main(ns) 31 | -------------------------------------------------------------------------------- /tests/bitops_1/main.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include "unit.h" 4 | 5 | int main() 6 | { 7 | unsigned long j; 8 | unsigned long k[2] = {0, 1}; 9 | 10 | /* test first bit set */ 11 | for (unsigned long i = 0; i < 32; i++) { 12 | j = 1 << i; 13 | if (find_first_bit(&j, 32) != i) 14 | TEST_EXIT(1); 15 | } 16 | 17 | /* test first zero bit */ 18 | for (unsigned long i = 0; i < 32; i++) { 19 | j = ~(1 << i); 20 | if (find_first_zero_bit(&j, 32) != i) 21 | TEST_EXIT(1); 22 | } 23 | 24 | /* test boundaries */ 25 | if (find_first_bit(k, 32) != 32) 26 | TEST_EXIT(1); 27 | if (find_first_bit(k, 33) != 32) 28 | TEST_EXIT(1); 29 | 30 | TEST_EXIT(0); 31 | } 32 | -------------------------------------------------------------------------------- /tests/cond_1/main.c: -------------------------------------------------------------------------------- 1 | /* simple test for condition variable */ 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | #include "kernel.h" 9 | #include "unit.h" 10 | 11 | pthread_cond_t cond; 12 | pthread_mutex_t mutex; 13 | 14 | void *threadfunc(void *parm) 15 | { 16 | (void) parm; 17 | 18 | pthread_mutex_lock(&mutex); 19 | 20 | printk("Wait for signal\n"); 21 | pthread_cond_wait(&cond, &mutex); 22 | printk("Thread awake, finish work!\n"); 23 | 24 | pthread_mutex_unlock(&mutex); 25 | 26 | return NULL; 27 | } 28 | 29 | int main() 30 | { 31 | int rc = 0; 32 | pthread_t threadid; 33 | 34 | printk("Enter Testcase\n"); 35 | 36 | pthread_cond_init(&cond, NULL); 37 | pthread_mutex_init(&mutex, NULL); 38 | 39 | rc = pthread_create(&threadid, NULL, threadfunc, NULL); 40 | if (rc) { 41 | printk("failed: can't create new posix thread.\n"); 42 | TEST_EXIT(1); 43 | } 44 | 45 | pthread_yield(); 46 | 47 | printk("Wake up a worker, work to do...\n"); 48 | 49 | rc = pthread_mutex_lock(&mutex); 50 | 51 | rc = pthread_cond_signal(&cond); 52 | // checkResults("pthread_cond_broadcast()\n", rc); 53 | 54 | rc = pthread_mutex_unlock(&mutex); 55 | // checkResults("pthread_mutex_unlock()\n", rc); 56 | // sleep(5); /* Sleep is not a very robust way to serialize threads */ 57 | 58 | printk("Main completed\n"); 59 | 60 | TEST_EXIT(0); 61 | } 62 | -------------------------------------------------------------------------------- /tests/cond_3/main.c: -------------------------------------------------------------------------------- 1 | /* http://www.qnx.com/developers/docs/660/index.jsp?topic=%2Fcom.qnx.doc.neutrino.getting_started%2Ftopic%2Fs1_procs_condvar.html 2 | */ 3 | 4 | /* 5 | * cp1.c 6 | */ 7 | 8 | #include 9 | #include 10 | #include 11 | 12 | #include "unit.h" 13 | 14 | int count = 0; 15 | int data_ready = 0; 16 | pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; 17 | pthread_cond_t condvar; 18 | 19 | extern unsigned int msleep(unsigned int msec); 20 | 21 | void *consumer(void *notused) 22 | { 23 | (void) notused; 24 | 25 | printk("In consumer thread...\n"); 26 | while (1) { 27 | count++; 28 | pthread_mutex_lock(&mutex); 29 | while (!data_ready) { 30 | pthread_cond_wait(&condvar, &mutex); 31 | } 32 | // process data 33 | printk("consumer: got data from producer\n"); 34 | data_ready = 0; 35 | pthread_cond_signal(&condvar); 36 | pthread_mutex_unlock(&mutex); 37 | } 38 | } 39 | 40 | void *producer(void *notused) 41 | { 42 | (void) notused; 43 | 44 | printk("In producer thread...\n"); 45 | while (1) { 46 | // get data from hardware 47 | // we'll simulate this with a sleep (1) 48 | msleep(180); 49 | printk("producer: got data from h/w\n"); 50 | pthread_mutex_lock(&mutex); 51 | while (data_ready) { 52 | pthread_cond_wait(&condvar, &mutex); 53 | } 54 | data_ready = 1; 55 | pthread_cond_signal(&condvar); 56 | pthread_mutex_unlock(&mutex); 57 | } 58 | } 59 | 60 | int main(void) 61 | { 62 | printk("Starting consumer/producer example...\n"); 63 | 64 | pthread_cond_init(&condvar, NULL); 65 | 66 | // create the producer and consumer threads 67 | pthread_create(NULL, NULL, producer, NULL); 68 | pthread_create(NULL, NULL, consumer, NULL); 69 | 70 | while (count < 5) 71 | pthread_yield(); 72 | printk("Bye-bye!\n"); 73 | 74 | TEST_EXIT(0); 75 | } 76 | -------------------------------------------------------------------------------- /tests/fs_1/main.c: -------------------------------------------------------------------------------- 1 | /* test /dev/random */ 2 | 3 | #include 4 | 5 | #include 6 | #include 7 | 8 | #include "unit.h" 9 | 10 | int main() 11 | { 12 | unsigned int n, p = 0; 13 | 14 | int fd = open("/dev/random", 0); 15 | if (fd < 0) { 16 | printk("error: failed to open /dev/random\n"); 17 | TEST_EXIT(1); 18 | } 19 | 20 | for (int j = 0; j < 1000; j++) { 21 | read(fd, &n, 4); 22 | if (j < 40) 23 | printk("%08x\n", n); 24 | if (n == p) { 25 | printk("error: got same random number %d twice in a row\n", n); 26 | TEST_EXIT(1); 27 | } 28 | p = n; 29 | } 30 | 31 | TEST_EXIT(0); 32 | } 33 | -------------------------------------------------------------------------------- /tests/fs_2/main.c: -------------------------------------------------------------------------------- 1 | /* test /dev/zero */ 2 | 3 | #include 4 | #include 5 | 6 | #include 7 | #include 8 | 9 | #include "unit.h" 10 | 11 | char buf[128]; 12 | 13 | int main() 14 | { 15 | int fd = open("/dev/zero", 0); 16 | if (fd < 0) { 17 | printk("error: failed to open /dev/zero\n"); 18 | TEST_EXIT(1); 19 | } 20 | 21 | memset(buf, 0xff, 128); 22 | read(fd, &buf, 128); 23 | for (int j = 0; j < 128; j++) { 24 | if (buf[j]) { 25 | printk("error: got a non-zero value\n"); 26 | TEST_EXIT(1); 27 | } 28 | } 29 | 30 | TEST_EXIT(0); 31 | } 32 | -------------------------------------------------------------------------------- /tests/fs_3/data/id_rsa: -------------------------------------------------------------------------------- 1 | -----BEGIN RSA PRIVATE KEY----- 2 | MIIBOgIBAAJBAI/rmTOBknHe2ro+8sUNl1MjNTRopU1/WJTcYvsrFML10Z2IBrFi 3 | fc3Q1x92uTvyFU21cn+/ekU8L+8qK+V98fMCAwEAAQJAe4uw+REa6Nt5Ana1KsmP 4 | BNRtgO7wMEXIgglqgtipuu3CE9CIZ4OyrvELNbI6RiczGYgMmUHcWEmLuBZ+tjQu 5 | 4QIhAORy2CQio1J3O2gGdkk2eY2cLIzoMEdig9su/NILvSqDAiEAoUcD1FeM1iub 6 | SiUq3ZDIf1FFTgtv9Si0lzJyBY+IP9ECIHi8zclDWUhDZe1TxP5qwRF74fvS13lS 7 | 8tdL3SjyNVcbAiEAhZU3o8r8mWy3DFvqvGiu2V3shK9OhYa4xj9/WAHB/fECIH9u 8 | Nq1Ww0stz2Oq7Wpn7ywcNemkot/+sO8l8gxXPcqw 9 | -----END RSA PRIVATE KEY----- 10 | -------------------------------------------------------------------------------- /tests/fs_3/data/id_rsa.pub: -------------------------------------------------------------------------------- 1 | -----BEGIN PUBLIC KEY----- 2 | MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBAI/rmTOBknHe2ro+8sUNl1MjNTRopU1/ 3 | WJTcYvsrFML10Z2IBrFifc3Q1x92uTvyFU21cn+/ekU8L+8qK+V98fMCAwEAAQ== 4 | -----END PUBLIC KEY----- 5 | -------------------------------------------------------------------------------- /tests/fs_3/main.c: -------------------------------------------------------------------------------- 1 | /* test simple romFS */ 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | #include 8 | 9 | #include 10 | #include 11 | 12 | #include 13 | 14 | #include "unit.h" 15 | 16 | extern char _binary_sda1_start; 17 | struct mtd_info mtd1; 18 | 19 | static struct inode inode = { 20 | .i_private = &mtd1, 21 | }; 22 | 23 | void flash_init(void) 24 | { 25 | struct dentry dentry = {.d_inode = &inode, .d_name = "mtd1"}; 26 | 27 | printk("Creating MTD device %s\n", dentry.d_name); 28 | if (mtdram_init_device(&mtd1, &_binary_sda1_start, 1024, dentry.d_name)) 29 | printk("error: mtdram init device failed\n"); 30 | vfs_link(NULL, dev_inode(), &dentry); 31 | } 32 | 33 | int main() 34 | { 35 | int fd; 36 | char buffer[128]; 37 | 38 | init_tmpfs_inode(&inode); 39 | flash_init(); 40 | mount("/dev/mtd1", "/dev/flash", "romfs", 0, 0); 41 | 42 | fd = open("/dev/flash/id_rsa.pub", 0); 43 | if (fd < 0) { 44 | printk("error: failed to open /data/id_rsa.pub\n"); 45 | TEST_EXIT(1); 46 | } 47 | 48 | memset(buffer, 0, 128); 49 | read(fd, buffer, 27); 50 | printk("read(): %s\n", buffer); 51 | if (strncmp(buffer, "-----BEGIN PUBLIC KEY-----", 26)) 52 | TEST_EXIT(1); 53 | 54 | memset(buffer, 0, 128); 55 | read(fd, buffer, 65); 56 | printk("read(): %s\n", buffer); 57 | if (strncmp( 58 | buffer, 59 | "MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBAI/rmTOBknHe2ro+8sUNl1MjNTRopU1/", 60 | 64)) 61 | TEST_EXIT(1); 62 | 63 | memset(buffer, 0, 128); 64 | read(fd, buffer, 65); 65 | printk("read(): %s\n", buffer); 66 | if (strncmp( 67 | buffer, 68 | "WJTcYvsrFML10Z2IBrFifc3Q1x92uTvyFU21cn+/ekU8L+8qK+V98fMCAwEAAQ==", 69 | 64)) 70 | TEST_EXIT(1); 71 | 72 | /* rewind the file */ 73 | lseek(fd, 0, SEEK_SET); 74 | memset(buffer, 0, 128); 75 | read(fd, buffer, 27); 76 | printk("read(): %s\n", buffer); 77 | if (strncmp(buffer, "-----BEGIN PUBLIC KEY-----", 26)) 78 | TEST_EXIT(1); 79 | 80 | TEST_EXIT(0); 81 | } 82 | -------------------------------------------------------------------------------- /tests/fs_4/data/id_rsa: -------------------------------------------------------------------------------- 1 | -----BEGIN RSA PRIVATE KEY----- 2 | MIIBOgIBAAJBAI/rmTOBknHe2ro+8sUNl1MjNTRopU1/WJTcYvsrFML10Z2IBrFi 3 | fc3Q1x92uTvyFU21cn+/ekU8L+8qK+V98fMCAwEAAQJAe4uw+REa6Nt5Ana1KsmP 4 | BNRtgO7wMEXIgglqgtipuu3CE9CIZ4OyrvELNbI6RiczGYgMmUHcWEmLuBZ+tjQu 5 | 4QIhAORy2CQio1J3O2gGdkk2eY2cLIzoMEdig9su/NILvSqDAiEAoUcD1FeM1iub 6 | SiUq3ZDIf1FFTgtv9Si0lzJyBY+IP9ECIHi8zclDWUhDZe1TxP5qwRF74fvS13lS 7 | 8tdL3SjyNVcbAiEAhZU3o8r8mWy3DFvqvGiu2V3shK9OhYa4xj9/WAHB/fECIH9u 8 | Nq1Ww0stz2Oq7Wpn7ywcNemkot/+sO8l8gxXPcqw 9 | -----END RSA PRIVATE KEY----- 10 | -------------------------------------------------------------------------------- /tests/fs_4/data/id_rsa.pub: -------------------------------------------------------------------------------- 1 | -----BEGIN PUBLIC KEY----- 2 | MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBAI/rmTOBknHe2ro+8sUNl1MjNTRopU1/ 3 | WJTcYvsrFML10Z2IBrFifc3Q1x92uTvyFU21cn+/ekU8L+8qK+V98fMCAwEAAQ== 4 | -----END PUBLIC KEY----- 5 | -------------------------------------------------------------------------------- /tests/fs_4/main.c: -------------------------------------------------------------------------------- 1 | /* test overreading a file */ 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | #include 8 | 9 | #include 10 | #include 11 | 12 | #include 13 | 14 | #include "unit.h" 15 | 16 | extern char _binary_sda1_start; 17 | struct mtd_info mtd1; 18 | 19 | static struct inode inode = { 20 | .i_private = &mtd1, 21 | }; 22 | 23 | void flash_init(void) 24 | { 25 | struct dentry dentry = {.d_inode = &inode, .d_name = "mtd1"}; 26 | 27 | printk("Creating MTD device %s\n", dentry.d_name); 28 | if (mtdram_init_device(&mtd1, &_binary_sda1_start, 1024, dentry.d_name)) 29 | printk("error: mtdram init device failed\n"); 30 | vfs_link(NULL, dev_inode(), &dentry); 31 | } 32 | 33 | int main() 34 | { 35 | int fd; 36 | char buffer[256]; 37 | 38 | memset(buffer, 0, 256); 39 | init_tmpfs_inode(&inode); 40 | flash_init(); 41 | mount("/dev/mtd1", "/dev/flash", "romfs", 0, 0); 42 | 43 | /* file contains -Lorem ipsum\n- */ 44 | fd = open("/dev/flash/id_rsa.pub", 0); 45 | if (fd < 0) { 46 | printk("error: failed to open /data/id_rsa.pub\n"); 47 | TEST_EXIT(1); 48 | } 49 | 50 | /* overread the file */ 51 | int r = read(fd, buffer, 256); 52 | if (r != 182) { 53 | printk("error: read incorrect number of char (%d)\n", r); 54 | TEST_EXIT(1); 55 | } 56 | if (strncmp(buffer, "-----BEGIN PUBLIC KEY-----\n", 26)) 57 | TEST_EXIT(1); 58 | 59 | /* try to read again */ 60 | r = read(fd, buffer, 1); 61 | if (r != 0) { 62 | printk("error: read incorrect number of char (%d)\n", r); 63 | TEST_EXIT(1); 64 | } 65 | 66 | TEST_EXIT(0); 67 | } 68 | -------------------------------------------------------------------------------- /tests/fs_5/main.c: -------------------------------------------------------------------------------- 1 | /* test multiple opening/closing /dev/random */ 2 | 3 | #include 4 | #include 5 | 6 | #include 7 | #include 8 | 9 | #include "unit.h" 10 | 11 | int main() 12 | { 13 | int fd; 14 | 15 | for (int i = 0; i < 10000; i++) { 16 | /* printk("% 3d/9999\n", i); */ 17 | fd = open("/dev/random", 0); 18 | if (fd < 0) { 19 | printk("error: failed to open /dev/random\n"); 20 | TEST_EXIT(1); 21 | } 22 | if (close(fd)) { 23 | printk("error: failed to close /dev/random\n"); 24 | TEST_EXIT(1); 25 | } 26 | } 27 | 28 | TEST_EXIT(0); 29 | } 30 | -------------------------------------------------------------------------------- /tests/fs_6/data/id_rsa: -------------------------------------------------------------------------------- 1 | -----BEGIN RSA PRIVATE KEY----- 2 | MIIBOgIBAAJBAI/rmTOBknHe2ro+8sUNl1MjNTRopU1/WJTcYvsrFML10Z2IBrFi 3 | fc3Q1x92uTvyFU21cn+/ekU8L+8qK+V98fMCAwEAAQJAe4uw+REa6Nt5Ana1KsmP 4 | BNRtgO7wMEXIgglqgtipuu3CE9CIZ4OyrvELNbI6RiczGYgMmUHcWEmLuBZ+tjQu 5 | 4QIhAORy2CQio1J3O2gGdkk2eY2cLIzoMEdig9su/NILvSqDAiEAoUcD1FeM1iub 6 | SiUq3ZDIf1FFTgtv9Si0lzJyBY+IP9ECIHi8zclDWUhDZe1TxP5qwRF74fvS13lS 7 | 8tdL3SjyNVcbAiEAhZU3o8r8mWy3DFvqvGiu2V3shK9OhYa4xj9/WAHB/fECIH9u 8 | Nq1Ww0stz2Oq7Wpn7ywcNemkot/+sO8l8gxXPcqw 9 | -----END RSA PRIVATE KEY----- 10 | -------------------------------------------------------------------------------- /tests/fs_6/data/id_rsa.pub: -------------------------------------------------------------------------------- 1 | -----BEGIN PUBLIC KEY----- 2 | MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBAI/rmTOBknHe2ro+8sUNl1MjNTRopU1/ 3 | WJTcYvsrFML10Z2IBrFifc3Q1x92uTvyFU21cn+/ekU8L+8qK+V98fMCAwEAAQ== 4 | -----END PUBLIC KEY----- 5 | -------------------------------------------------------------------------------- /tests/fs_6/main.c: -------------------------------------------------------------------------------- 1 | /* open files in romFS multiple times */ 2 | 3 | #include 4 | 5 | #include 6 | 7 | #include 8 | #include 9 | 10 | #include 11 | 12 | #include "unit.h" 13 | 14 | extern char _binary_sda1_start; 15 | struct mtd_info mtd1; 16 | 17 | static struct inode inode = { 18 | .i_private = &mtd1, 19 | }; 20 | 21 | void flash_init(void) 22 | { 23 | struct dentry dentry = {.d_inode = &inode, .d_name = "mtd1"}; 24 | 25 | printk("Creating MTD device %s\n", dentry.d_name); 26 | if (mtdram_init_device(&mtd1, &_binary_sda1_start, 1024, dentry.d_name)) 27 | printk("error: mtdram init device failed\n"); 28 | vfs_link(NULL, dev_inode(), &dentry); 29 | } 30 | 31 | int main() 32 | { 33 | int fd1, fd2; 34 | 35 | init_tmpfs_inode(&inode); 36 | flash_init(); 37 | mount("/dev/mtd1", "/dev/flash", "romfs", 0, 0); 38 | 39 | for (int i = 0; i < 1000; i++) { 40 | fd1 = open("/dev/flash/id_rsa", 0); 41 | fd2 = open("/dev/flash/id_rsa.pub", 0); 42 | if (fd1 < 0 || fd2 < 0) { 43 | printk("error: failed to open file in flash\n"); 44 | TEST_EXIT(1); 45 | } 46 | close(fd1); 47 | close(fd2); 48 | } 49 | 50 | TEST_EXIT(0); 51 | } 52 | -------------------------------------------------------------------------------- /tests/fs_7/data/.ssh/id_rsa: -------------------------------------------------------------------------------- 1 | -----BEGIN RSA PRIVATE KEY----- 2 | MIIBOgIBAAJBAI/rmTOBknHe2ro+8sUNl1MjNTRopU1/WJTcYvsrFML10Z2IBrFi 3 | fc3Q1x92uTvyFU21cn+/ekU8L+8qK+V98fMCAwEAAQJAe4uw+REa6Nt5Ana1KsmP 4 | BNRtgO7wMEXIgglqgtipuu3CE9CIZ4OyrvELNbI6RiczGYgMmUHcWEmLuBZ+tjQu 5 | 4QIhAORy2CQio1J3O2gGdkk2eY2cLIzoMEdig9su/NILvSqDAiEAoUcD1FeM1iub 6 | SiUq3ZDIf1FFTgtv9Si0lzJyBY+IP9ECIHi8zclDWUhDZe1TxP5qwRF74fvS13lS 7 | 8tdL3SjyNVcbAiEAhZU3o8r8mWy3DFvqvGiu2V3shK9OhYa4xj9/WAHB/fECIH9u 8 | Nq1Ww0stz2Oq7Wpn7ywcNemkot/+sO8l8gxXPcqw 9 | -----END RSA PRIVATE KEY----- 10 | -------------------------------------------------------------------------------- /tests/fs_7/data/.ssh/id_rsa.pub: -------------------------------------------------------------------------------- 1 | -----BEGIN PUBLIC KEY----- 2 | MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBAI/rmTOBknHe2ro+8sUNl1MjNTRopU1/ 3 | WJTcYvsrFML10Z2IBrFifc3Q1x92uTvyFU21cn+/ekU8L+8qK+V98fMCAwEAAQ== 4 | -----END PUBLIC KEY----- 5 | -------------------------------------------------------------------------------- /tests/fs_7/main.c: -------------------------------------------------------------------------------- 1 | /* test directory hierarchy in RomFS */ 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | #include 8 | 9 | #include 10 | #include 11 | 12 | #include 13 | 14 | #include "unit.h" 15 | 16 | extern char _binary_sda1_start; 17 | struct mtd_info mtd1; 18 | 19 | static struct inode inode = { 20 | .i_private = &mtd1, 21 | }; 22 | 23 | void flash_init(void) 24 | { 25 | struct dentry dentry = {.d_inode = &inode, .d_name = "mtd1"}; 26 | 27 | printk("Creating MTD device %s\n", dentry.d_name); 28 | if (mtdram_init_device(&mtd1, &_binary_sda1_start, 1024, dentry.d_name)) 29 | printk("error: mtdram init device failed\n"); 30 | vfs_link(NULL, dev_inode(), &dentry); 31 | } 32 | 33 | int main() 34 | { 35 | int fd; 36 | const char filename[] = "/dev/flash/.ssh/id_rsa.pub"; 37 | char buffer[32]; 38 | 39 | init_tmpfs_inode(&inode); 40 | flash_init(); 41 | mount("/dev/mtd1", "/dev/flash", "romfs", 0, 0); 42 | 43 | fd = open(filename, 0); 44 | if (fd < 0) { 45 | printk("error: failed to open %s\n", filename); 46 | TEST_EXIT(1); 47 | } 48 | 49 | memset(buffer, 0, 32); 50 | if (read(fd, buffer, 11) != 11) 51 | TEST_EXIT(1); 52 | if (strncmp(buffer, "-----BEGIN", 10)) 53 | TEST_EXIT(1); 54 | 55 | memset(buffer, 0, 32); 56 | if (read(fd, buffer, 10) != 10) 57 | TEST_EXIT(1); 58 | if (strncmp(buffer, "PUBLIC KEY", 10)) 59 | TEST_EXIT(1); 60 | 61 | TEST_EXIT(0); 62 | } 63 | -------------------------------------------------------------------------------- /tests/getpid_1/main.c: -------------------------------------------------------------------------------- 1 | /* simple test for getpid */ 2 | 3 | #include 4 | #include "unit.h" 5 | 6 | int main() 7 | { 8 | pid_t pid = getpid(); 9 | 10 | if (!pid) 11 | TEST_EXIT(1); 12 | 13 | TEST_EXIT(0); 14 | } 15 | -------------------------------------------------------------------------------- /tests/itoa_1/main.c: -------------------------------------------------------------------------------- 1 | #include "unit.h" 2 | #include "utils.h" 3 | #include 4 | 5 | #include 6 | 7 | int itoa_base_00(void) 8 | { 9 | char buf[64]; 10 | if (strcmp("0", itoa_base(0, buf, 1))) 11 | return -1; 12 | return 0; 13 | } 14 | 15 | int itoa_base_01(void) 16 | { 17 | char buf[64]; 18 | if (strcmp("0", itoa_base(0, buf, 8))) 19 | return -1; 20 | return 0; 21 | } 22 | 23 | int itoa_base_02(void) 24 | { 25 | char buf[64]; 26 | if (strcmp("1234567890", itoa_base(1234567890, buf, 10))) 27 | return -1; 28 | return 0; 29 | } 30 | 31 | int itoa_base_03(void) 32 | { 33 | char buf[64]; 34 | if (strcmp("20", itoa_base(32, buf, 16))) 35 | return -1; 36 | return 0; 37 | } 38 | 39 | int itoa_base_04(void) 40 | { 41 | char buf[64]; 42 | if (strcmp("21", itoa_base(33, buf, 16))) 43 | return -1; 44 | return 0; 45 | } 46 | 47 | int itoa_base_05(void) 48 | { 49 | char buf[64]; 50 | if (itoa_base(458, buf, 2048)) 51 | return -1; 52 | return 0; 53 | } 54 | 55 | int itoa_base_06(void) 56 | { 57 | char buf[64]; 58 | if (strcmp("ffffffff", itoa_base(0xffffffff, buf, 16))) 59 | return -1; 60 | return 0; 61 | } 62 | 63 | int itoa_base_07(void) 64 | { 65 | char buf[64]; 66 | if (strcmp("-1", itoa_base(0xffffffff, buf, 10))) 67 | return -1; 68 | return 0; 69 | } 70 | 71 | int itoa_base_08(void) 72 | { 73 | char buf[64]; 74 | if (strcmp("1000", itoa_base(0x1000, buf, 16))) 75 | return -1; 76 | return 0; 77 | } 78 | 79 | int itoa_base_09(void) 80 | { 81 | char buf[64]; 82 | if (strcmp("-752", itoa_base(-752, buf, 10))) 83 | return -1; 84 | return 0; 85 | } 86 | 87 | int itoa_base_10(void) 88 | { 89 | char buf[64]; 90 | if (strcmp("0", itoa_base(0, buf, 10))) 91 | return -1; 92 | return 0; 93 | } 94 | 95 | int main() 96 | { 97 | int status = 0; 98 | int (*test[])(void) = {itoa_base_00, itoa_base_01, itoa_base_02, 99 | itoa_base_03, itoa_base_04, itoa_base_05, 100 | itoa_base_06, itoa_base_07, itoa_base_08, 101 | itoa_base_09, itoa_base_10}; 102 | 103 | for (int i = 0; i < (int) ARRAY_SIZE(test); i++) { 104 | int r = test[i](); 105 | /* printk("itoa test #%d %s\n", i, r ? "(failed)" : ""); */ 106 | status += r; 107 | } 108 | if (status) 109 | TEST_EXIT(1); 110 | 111 | TEST_EXIT(0); 112 | } 113 | -------------------------------------------------------------------------------- /tests/lib/unit.h: -------------------------------------------------------------------------------- 1 | #ifndef TEST_LIB_UNIT_H 2 | #define TEST_LIB_UNIT_H 3 | 4 | #include "kernel.h" 5 | 6 | #define C_GREEN "\033[1;32m" 7 | #define C_RED "\033[1;31m" 8 | #define C_NORMAL "\033[0m" 9 | 10 | #define printk_green(format, ...) \ 11 | printk(C_GREEN format C_NORMAL, ##__VA_ARGS__); 12 | 13 | #define printk_red(format, ...) printk(C_RED format C_NORMAL, ##__VA_ARGS__); 14 | 15 | #include 16 | 17 | #define TEST_EXIT(status) \ 18 | ({ \ 19 | if (status) { \ 20 | printk_red("test failed: %d", (status)); \ 21 | printk("\n"); \ 22 | } else { \ 23 | printk_green("test passed"); \ 24 | printk("\n"); \ 25 | } \ 26 | v7m_semihost_exit(status); \ 27 | }) 28 | 29 | #endif /* !TEST_LIB_UNIT_H */ 30 | -------------------------------------------------------------------------------- /tests/malloc_1/main.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include "unit.h" 5 | #include "kernel.h" 6 | 7 | int main() 8 | { 9 | char *p[3], *q[3]; 10 | 11 | p[0] = malloc(48); 12 | p[1] = malloc(64); 13 | p[2] = malloc(96); 14 | 15 | for (int i = 0; i < 3; i++) 16 | printk("allocated %p\n", p[i]); 17 | 18 | memset(p[0], 'a', 48); 19 | memset(p[1], 'b', 64); 20 | memset(p[2], 'c', 96); 21 | 22 | for (int i = 0; i < 48; i++) { 23 | if (p[0][i] != 'a') 24 | TEST_EXIT(1); 25 | } 26 | for (int i = 0; i < 64; i++) { 27 | if (p[1][i] != 'b') 28 | TEST_EXIT(1); 29 | } 30 | for (int i = 0; i < 96; i++) { 31 | if (p[2][i] != 'c') 32 | TEST_EXIT(1); 33 | } 34 | 35 | /* free all pointers */ 36 | free(p[0]); 37 | free(p[1]); 38 | free(p[2]); 39 | 40 | /* Realloc the same memory mapping, should return the same allocation 41 | * mapping. */ 42 | q[0] = malloc(48); 43 | q[1] = malloc(64); 44 | q[2] = malloc(96); 45 | 46 | for (int i = 0; i < 3; i++) 47 | printk("allocated %p\n", p[i]); 48 | 49 | for (int i = 0; i < 3; i++) { 50 | if (p[i] != q[i]) 51 | TEST_EXIT(1); 52 | } 53 | 54 | TEST_EXIT(0); 55 | } 56 | -------------------------------------------------------------------------------- /tests/mm_1/main.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | #include "unit.h" 5 | 6 | int main() 7 | { 8 | void *p, *q; 9 | unsigned long order = size_to_page_order(256); 10 | 11 | if ((p = alloc_pages(order)) == NULL) 12 | TEST_EXIT(1); 13 | free_pages((unsigned long) p, order); 14 | 15 | /* same page should be reallocated */ 16 | if ((q = alloc_pages(order)) != p) 17 | TEST_EXIT(1); 18 | 19 | TEST_EXIT(0); 20 | } 21 | -------------------------------------------------------------------------------- /tests/mm_2/main.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | #include "unit.h" 5 | 6 | int main() 7 | { 8 | void *p[14]; 9 | int sz[] = {256, 1024, 2048, 256, 256, 256, 512, 10 | 512, 1024, 512, 2048, 256, 512, 1024}; 11 | 12 | for (int j = 0; j < 30; j++) { 13 | printk("Iteration #%d\n", j); 14 | for (int i = 0; i < 14; i++) { 15 | if ((p[i] = alloc_pages(size_to_page_order(sz[i]))) == NULL) 16 | TEST_EXIT(1); 17 | } 18 | for (int i = 0; i < 14; i++) 19 | free_pages((unsigned long) p[i], size_to_page_order(sz[i])); 20 | } 21 | 22 | TEST_EXIT(0); 23 | } 24 | -------------------------------------------------------------------------------- /tests/mmap_1/main.c: -------------------------------------------------------------------------------- 1 | /* simple mmap() test, check non-nil memory is allocated */ 2 | 3 | #include 4 | 5 | #include 6 | 7 | #include "unit.h" 8 | 9 | int main() 10 | { 11 | void *p; 12 | 13 | p = mmap(0, 256, 0, MAP_ANONYMOUS, 0, 0); 14 | if (p == MAP_FAILED) 15 | TEST_EXIT(1); 16 | 17 | TEST_EXIT(0); 18 | } 19 | -------------------------------------------------------------------------------- /tests/mmap_2/data/id_rsa: -------------------------------------------------------------------------------- 1 | -----BEGIN RSA PRIVATE KEY----- 2 | MIIBOgIBAAJBAI/rmTOBknHe2ro+8sUNl1MjNTRopU1/WJTcYvsrFML10Z2IBrFi 3 | fc3Q1x92uTvyFU21cn+/ekU8L+8qK+V98fMCAwEAAQJAe4uw+REa6Nt5Ana1KsmP 4 | BNRtgO7wMEXIgglqgtipuu3CE9CIZ4OyrvELNbI6RiczGYgMmUHcWEmLuBZ+tjQu 5 | 4QIhAORy2CQio1J3O2gGdkk2eY2cLIzoMEdig9su/NILvSqDAiEAoUcD1FeM1iub 6 | SiUq3ZDIf1FFTgtv9Si0lzJyBY+IP9ECIHi8zclDWUhDZe1TxP5qwRF74fvS13lS 7 | 8tdL3SjyNVcbAiEAhZU3o8r8mWy3DFvqvGiu2V3shK9OhYa4xj9/WAHB/fECIH9u 8 | Nq1Ww0stz2Oq7Wpn7ywcNemkot/+sO8l8gxXPcqw 9 | -----END RSA PRIVATE KEY----- 10 | -------------------------------------------------------------------------------- /tests/mmap_2/data/id_rsa.pub: -------------------------------------------------------------------------------- 1 | -----BEGIN PUBLIC KEY----- 2 | MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBAI/rmTOBknHe2ro+8sUNl1MjNTRopU1/ 3 | WJTcYvsrFML10Z2IBrFifc3Q1x92uTvyFU21cn+/ekU8L+8qK+V98fMCAwEAAQ== 4 | -----END PUBLIC KEY----- 5 | -------------------------------------------------------------------------------- /tests/mmap_2/main.c: -------------------------------------------------------------------------------- 1 | /* test mapping file to memory */ 2 | 3 | #include 4 | #include 5 | 6 | #include 7 | #include 8 | 9 | #include 10 | #include 11 | 12 | #include 13 | 14 | #include "unit.h" 15 | 16 | extern char _binary_sda1_start; 17 | struct mtd_info mtd1; 18 | 19 | static struct inode inode = { 20 | .i_private = &mtd1, 21 | }; 22 | 23 | void flash_init(void) 24 | { 25 | struct dentry dentry = {.d_inode = &inode, .d_name = "mtd1"}; 26 | 27 | printk("Creating MTD device %s\n", dentry.d_name); 28 | if (mtdram_init_device(&mtd1, &_binary_sda1_start, 1024, dentry.d_name)) 29 | printk("error: mtdram init device failed\n"); 30 | vfs_link(NULL, dev_inode(), &dentry); 31 | } 32 | 33 | int main() 34 | { 35 | init_tmpfs_inode(&inode); 36 | flash_init(); 37 | mount("/dev/mtd1", "/dev/flash", "romfs", 0, 0); 38 | 39 | int fd = open("/dev/flash/id_rsa.pub", 0); 40 | if (fd < 0) { 41 | printk("error: failed to open /data/id_rsa.pub\n"); 42 | TEST_EXIT(1); 43 | } 44 | 45 | void *p = mmap(NULL, 256, 0, 0, fd, 0); 46 | if (p == MAP_FAILED) 47 | TEST_EXIT(1); 48 | if (strncmp((char *) p, "-----BEGIN PUBLIC KEY-----", 26)) 49 | TEST_EXIT(1); 50 | 51 | p = mmap(NULL, 256, 0, 0, fd, 27); 52 | if (p == MAP_FAILED) 53 | TEST_EXIT(1); 54 | if (strncmp( 55 | (char *) p, 56 | "MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBAI/rmTOBknHe2ro+8sUNl1MjNTRopU1/", 57 | 64)) 58 | TEST_EXIT(1); 59 | 60 | TEST_EXIT(0); 61 | } 62 | -------------------------------------------------------------------------------- /tests/msleep_1/main.c: -------------------------------------------------------------------------------- 1 | #include "unit.h" 2 | #include "kernel.h" 3 | 4 | extern void msleep(unsigned int); 5 | 6 | int main() 7 | { 8 | for (int i = 1; i < 6; i++) { 9 | printk("%d...", i); 10 | msleep(1000); 11 | } 12 | printk("\n"); 13 | 14 | TEST_EXIT(0); 15 | } 16 | -------------------------------------------------------------------------------- /tests/msleep_2/main.c: -------------------------------------------------------------------------------- 1 | // simple thread create and thread yield 2 | 3 | #include 4 | #include 5 | #include "kernel.h" 6 | #include "unit.h" 7 | 8 | extern void msleep(unsigned int); 9 | 10 | static int val; 11 | 12 | static void *fn(void *arg) 13 | { 14 | // msleep(30 * (1 + (int) arg)); 15 | msleep(30); 16 | val++; 17 | 18 | return 0; 19 | } 20 | 21 | int main() 22 | { 23 | pthread_t tip; 24 | 25 | for (int i = 0; i < 3; i++) { 26 | if (pthread_create(&tip, NULL, fn, (void *) i)) { 27 | printk("failed: can't create new posix thread.\n"); 28 | TEST_EXIT(1); 29 | } 30 | } 31 | while (val != 3) 32 | pthread_yield(); 33 | 34 | TEST_EXIT(0); 35 | } 36 | -------------------------------------------------------------------------------- /tests/mtdram_1/main.c: -------------------------------------------------------------------------------- 1 | /* test simple romFS */ 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | #include 8 | #include 9 | 10 | #include "unit.h" 11 | 12 | int main() 13 | { 14 | char str[] = "Hello World!"; 15 | char buf[32]; 16 | ssize_t len = strlen(str); 17 | int fd; 18 | 19 | printk("Opening /dev/mtd0...\n"); 20 | fd = open("/dev/mtd0", 0); 21 | if (write(fd, str, len) != len) 22 | TEST_EXIT(1); 23 | lseek(fd, 0, SEEK_SET); 24 | if (read(fd, buf, len) != len) 25 | TEST_EXIT(1); 26 | printk("Read /dev/mtd0: %s\n", buf); 27 | if (strcmp(str, buf)) 28 | TEST_EXIT(1); 29 | 30 | TEST_EXIT(0); 31 | } 32 | -------------------------------------------------------------------------------- /tests/mutex_1/main.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include "kernel.h" 4 | #include "pthread.h" 5 | #include "unit.h" 6 | 7 | int main(void) 8 | { 9 | pthread_mutex_t lock; 10 | 11 | pthread_mutex_init(&lock, NULL); 12 | 13 | if (pthread_mutex_lock(&lock)) 14 | TEST_EXIT(1); 15 | printk("mutex locked...\n"); 16 | if (pthread_mutex_unlock(&lock)) 17 | TEST_EXIT(1); 18 | printk("mutex unlocked...\n"); 19 | 20 | TEST_EXIT(0); 21 | } 22 | -------------------------------------------------------------------------------- /tests/mutex_2/main.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #include "kernel.h" 6 | #include "pthread.h" 7 | #include "unit.h" 8 | 9 | pthread_mutex_t lock; 10 | int has_waited; 11 | 12 | void *fn(__unused void *arg) 13 | { 14 | printk("thread 2: acquire mutex...\n"); 15 | if (pthread_mutex_lock(&lock)) 16 | return NULL; 17 | has_waited = 1; 18 | printk("thread 2: OK, mutex locked...\n"); 19 | if (pthread_mutex_unlock(&lock)) 20 | return NULL; 21 | printk("thread 2: mutex released...\n"); 22 | 23 | return NULL; 24 | } 25 | 26 | int main(void) 27 | { 28 | pthread_t tid; 29 | 30 | pthread_mutex_init(&lock, NULL); 31 | 32 | if (pthread_create(&tid, NULL, fn, NULL)) 33 | printk("error: Could not create new thread.\n"); 34 | 35 | if (pthread_mutex_lock(&lock)) 36 | TEST_EXIT(1); 37 | printk("thread 1: mutex locked, yield now...\n"); 38 | sched_yield(); 39 | if (has_waited) 40 | TEST_EXIT(1); 41 | printk("thread 1: return from yield.\n"); 42 | if (pthread_mutex_unlock(&lock)) 43 | TEST_EXIT(1); 44 | printk("thread 1: mutex released...\n"); 45 | 46 | /* re-acquire the mutex to check the thread released the mutex 47 | correctly */ 48 | if (pthread_mutex_lock(&lock)) 49 | TEST_EXIT(1); 50 | 51 | TEST_EXIT(0); 52 | } 53 | -------------------------------------------------------------------------------- /tests/mutex_3/main.c: -------------------------------------------------------------------------------- 1 | /* test the trylock interface */ 2 | 3 | #include 4 | 5 | #include "kernel.h" 6 | #include "pthread.h" 7 | #include "unit.h" 8 | 9 | int main(void) 10 | { 11 | pthread_mutex_t lock; 12 | 13 | pthread_mutex_init(&lock, NULL); 14 | 15 | if (pthread_mutex_lock(&lock)) 16 | TEST_EXIT(1); 17 | printk("mutex is now locked...\n"); 18 | if (!pthread_mutex_trylock(&lock)) 19 | TEST_EXIT(1); 20 | printk("tried to lock a locked mutex...\n"); 21 | if (pthread_mutex_unlock(&lock)) 22 | TEST_EXIT(1); 23 | printk("mutex unlocked, trylock should succeed...\n"); 24 | if (pthread_mutex_trylock(&lock)) 25 | TEST_EXIT(1); 26 | 27 | TEST_EXIT(0); 28 | } 29 | -------------------------------------------------------------------------------- /tests/mutex_4/main.c: -------------------------------------------------------------------------------- 1 | /* strong mutex test, mixing lock/unlock/trylock */ 2 | #include 3 | #include 4 | #include 5 | 6 | #include "kernel.h" 7 | #include "pthread.h" 8 | #include "unit.h" 9 | 10 | pthread_mutex_t lock; 11 | 12 | void *fn(__unused void *arg) 13 | { 14 | printk("thread 2: acquire mutex...\n"); 15 | if (!pthread_mutex_trylock(&lock)) 16 | return NULL; 17 | printk("thread 2: mutex was locked...\n"); 18 | sched_yield(); 19 | printk("thread 2: re-acquire mutex...\n"); 20 | if (pthread_mutex_trylock(&lock)) 21 | return NULL; 22 | sched_yield(); 23 | if (pthread_mutex_unlock(&lock)) 24 | return NULL; 25 | 26 | return NULL; 27 | } 28 | 29 | int main(void) 30 | { 31 | pthread_t tid; 32 | 33 | pthread_mutex_init(&lock, NULL); 34 | 35 | if (pthread_create(&tid, NULL, fn, NULL)) 36 | printk("error: Could not create new thread.\n"); 37 | 38 | if (pthread_mutex_trylock(&lock)) 39 | TEST_EXIT(1); 40 | printk("thread 1: mutex locked, yield now...\n"); 41 | sched_yield(); 42 | printk("thread 1: return from yield.\n"); 43 | if (pthread_mutex_unlock(&lock)) 44 | TEST_EXIT(1); 45 | printk("thread 1: mutex released...\n"); 46 | sched_yield(); 47 | 48 | /* re-acquire the mutex to check the thread released the mutex 49 | correctly */ 50 | if (!pthread_mutex_trylock(&lock)) 51 | TEST_EXIT(1); 52 | if (pthread_mutex_lock(&lock)) 53 | TEST_EXIT(1); 54 | 55 | TEST_EXIT(0); 56 | } 57 | -------------------------------------------------------------------------------- /tests/mutex_5/main.c: -------------------------------------------------------------------------------- 1 | /* test mutexs' waitqueue */ 2 | #include 3 | #include 4 | #include 5 | 6 | #include "kernel.h" 7 | #include "pthread.h" 8 | #include "unit.h" 9 | 10 | static pthread_mutex_t m; 11 | 12 | void *fn(__unused void *arg) 13 | { 14 | printk("thread %d locking...\n", (int) arg); 15 | pthread_mutex_lock(&m); 16 | printk("OK, thread %d got the mutex!\n", (int) arg); 17 | pthread_mutex_unlock(&m); 18 | 19 | return NULL; 20 | } 21 | 22 | int main() 23 | { 24 | pthread_t tips[4]; 25 | 26 | pthread_mutex_init(&m, NULL); 27 | pthread_mutex_lock(&m); 28 | 29 | for (int i = 0; i < 4; i++) { 30 | if (pthread_create(&tips[i], NULL, fn, (void *) i)) { 31 | printk("failed: can't create new posix thread.\n"); 32 | TEST_EXIT(1); 33 | } 34 | } 35 | 36 | printk("locked the mutex, now yielding...\n"); 37 | sched_yield(); 38 | 39 | printk("unlocking the mutex...\n"); 40 | pthread_mutex_unlock(&m); 41 | 42 | printk("relocking the mutex...\n"); 43 | pthread_mutex_lock(&m); 44 | 45 | TEST_EXIT(0); 46 | } 47 | -------------------------------------------------------------------------------- /tests/page_3/main.c: -------------------------------------------------------------------------------- 1 | /* stress test of page alloc/free */ 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | #include 8 | #include 9 | #include "unit.h" 10 | 11 | struct alloc_info { 12 | void *addr; 13 | int order; 14 | }; 15 | 16 | struct alloc_info alloc_info[128]; 17 | 18 | int main() 19 | { 20 | int i; 21 | int fd; 22 | unsigned int order; 23 | unsigned long hash; 24 | size_t sz; 25 | 26 | fd = open("/dev/random", 0); 27 | if (fd < 0) { 28 | printk("error: failed to open /dev/random\n"); 29 | TEST_EXIT(1); 30 | } 31 | 32 | /* take a snapshot of memory state bgefore the test */ 33 | hash = page_alloc_signature(); 34 | 35 | for (int k = 0; k < 1000; k++) { 36 | sz = 0; 37 | for (i = 0; i < 40; i++) { 38 | read(fd, &order, 1); 39 | order = order % 4; 40 | alloc_info[i].addr = alloc_pages(order); 41 | alloc_info[i].order = order; 42 | if (!alloc_info[i].addr) 43 | break; 44 | sz += 1 << (order + 8); 45 | /* printk(" %p (order=%d)\n", alloc_info[i].addr, */ 46 | /* alloc_info[i].order); */ 47 | } 48 | /* printk("Allocated %d bytes (%d bytes available)\n", sz, 32 * 1024); 49 | */ 50 | 51 | /* pseudo-randomish freeing of the memory.. */ 52 | for (int j = 0; j < i; j += 3) 53 | free_pages((unsigned long) alloc_info[j].addr, alloc_info[j].order); 54 | for (int j = 1; j < i; j += 3) 55 | free_pages((unsigned long) alloc_info[j].addr, alloc_info[j].order); 56 | for (int j = 2; j < i; j += 3) 57 | free_pages((unsigned long) alloc_info[j].addr, alloc_info[j].order); 58 | 59 | if (page_alloc_signature() != hash) { 60 | printk("error: Memory not correctly restored\n"); 61 | TEST_EXIT(1); 62 | } 63 | } 64 | 65 | TEST_EXIT(0); 66 | } 67 | -------------------------------------------------------------------------------- /tests/raise_1/main.c: -------------------------------------------------------------------------------- 1 | /*simple signal test */ 2 | 3 | #include 4 | #include 5 | #include "kernel.h" 6 | #include "unit.h" 7 | 8 | int val; 9 | int signo = SIGUSR1; 10 | 11 | void handler(int n) 12 | { 13 | printk("In signal handler, received signal %d\n", n); 14 | 15 | if (n != signo) 16 | TEST_EXIT(1); 17 | val = 1; 18 | } 19 | 20 | int main(void *arg) 21 | { 22 | (void) arg; 23 | 24 | const struct sigaction act = {.sa_handler = handler, .sa_flags = 0}; 25 | 26 | sigaction(signo, &act, NULL); 27 | if (raise(signo)) 28 | TEST_EXIT(1); 29 | if (!val) 30 | TEST_EXIT(1); 31 | 32 | TEST_EXIT(0); 33 | } 34 | -------------------------------------------------------------------------------- /tests/raise_2/main.c: -------------------------------------------------------------------------------- 1 | /* test raise() return code */ 2 | 3 | #include 4 | #include 5 | 6 | #include 7 | #include "kernel.h" 8 | #include "unit.h" 9 | 10 | int main(void *arg) 11 | { 12 | (void) arg; 13 | 14 | sigaction(SIGUSR1, NULL, NULL); /* shall return -EINVAL */ 15 | int retval = raise(0); 16 | printk("Got return value %d (negative)\n", -retval); 17 | if (retval != -EINVAL) 18 | TEST_EXIT(1); 19 | 20 | TEST_EXIT(0); 21 | } 22 | -------------------------------------------------------------------------------- /tests/raise_3/main.c: -------------------------------------------------------------------------------- 1 | /* test signal handler with SA_SIGINFO set */ 2 | 3 | #include 4 | #include 5 | #include "kernel.h" 6 | #include "unit.h" 7 | 8 | int val; 9 | int signo = SIGUSR1; 10 | 11 | void sigact(int sig, siginfo_t *siginfo, void *unused) 12 | { 13 | (void) unused; 14 | 15 | printk("In a sigaction handler (signo=%d, sival=0x%x)\n", sig, 16 | siginfo->si_value.sival_int); 17 | if (sig != signo) 18 | TEST_EXIT(1); 19 | 20 | val = 1; 21 | } 22 | 23 | int main(void *arg) 24 | { 25 | (void) arg; 26 | 27 | const struct sigaction act = {.sa_sigaction = sigact, 28 | .sa_flags = SA_SIGINFO}; 29 | 30 | sigaction(signo, &act, NULL); 31 | int retval = raise(signo); 32 | if (retval) { 33 | printk("Syscall returned %d, expected 0\n", retval); 34 | TEST_EXIT(1); 35 | } 36 | if (!val) 37 | TEST_EXIT(1); 38 | 39 | TEST_EXIT(0); 40 | } 41 | -------------------------------------------------------------------------------- /tests/readdir_1/main.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include 5 | 6 | #include 7 | #include 8 | 9 | #include "unit.h" 10 | 11 | int found_dot; 12 | int found_dotdot; 13 | int found_null; 14 | int found_zero; 15 | 16 | int main() 17 | { 18 | struct dirent dirent; 19 | struct dirent *result; 20 | 21 | DIR *dir = opendir("/dev"); 22 | do { 23 | readdir_r(dir, &dirent, &result); 24 | if (result != NULL) 25 | printk("% 6d %s\n", dirent.d_ino, dirent.d_name); 26 | if (!strcmp(result->d_name, ".")) 27 | found_dot++; 28 | if (!strcmp(result->d_name, "..")) 29 | found_dotdot++; 30 | if (!strcmp(result->d_name, "zero")) 31 | found_zero++; 32 | if (!strcmp(result->d_name, "null")) 33 | found_null++; 34 | } while (result != NULL); 35 | closedir(dir); 36 | 37 | if (found_dot != 1) 38 | TEST_EXIT(1); 39 | if (found_dotdot != 1) 40 | TEST_EXIT(1); 41 | if (found_zero != 1) 42 | TEST_EXIT(1); 43 | if (found_null != 1) 44 | TEST_EXIT(1); 45 | 46 | TEST_EXIT(0); 47 | } 48 | -------------------------------------------------------------------------------- /tests/slab_1/main.c: -------------------------------------------------------------------------------- 1 | /* simple test for cache creation and allocation */ 2 | 3 | #include 4 | #include 5 | 6 | #include "unit.h" 7 | 8 | struct foo { 9 | int a; 10 | int b; 11 | }; 12 | 13 | int main(void) 14 | { 15 | struct kmem_cache *cache = KMEM_CACHE(struct foo, "cache-foo"); 16 | if (!cache) { 17 | printk("error: Cannot create cache\n"); 18 | TEST_EXIT(1); 19 | } 20 | 21 | struct foo *foo = kmem_cache_alloc(cache, CACHE_OPT_NONE); 22 | if (!foo) { 23 | printk("error: Cannot allocate from cache\n"); 24 | TEST_EXIT(1); 25 | } 26 | 27 | foo->a = 1; 28 | foo->b = 2; 29 | 30 | TEST_EXIT(0); 31 | } 32 | -------------------------------------------------------------------------------- /tests/slab_2/main.c: -------------------------------------------------------------------------------- 1 | /* test for cache creation, allocation, destruction */ 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | #include "unit.h" 8 | 9 | struct foo { 10 | int a; 11 | int b; 12 | }; 13 | 14 | int main(void) 15 | { 16 | unsigned long hash; 17 | 18 | struct kmem_cache *cache = KMEM_CACHE(struct foo, "cache-foo"); 19 | 20 | if (!cache) { 21 | printk("error: Cannot create cache\n"); 22 | TEST_EXIT(1); 23 | } 24 | 25 | hash = page_alloc_signature(); 26 | 27 | struct foo *fp[40]; 28 | for (int i = 0; i < 40; i++) { 29 | fp[i] = kmem_cache_alloc(cache, CACHE_OPT_NONE); 30 | fp[i]->a = i; 31 | } 32 | 33 | if (page_alloc_signature() == hash) { 34 | printk("error: No memory allocated\n"); 35 | TEST_EXIT(1); 36 | } 37 | 38 | for (int i = 0; i < 40; i++) { 39 | if (fp[i]->a != i) { 40 | printk("error: Address allocated multiple times\n"); 41 | TEST_EXIT(1); 42 | } 43 | kmem_cache_free(cache, fp[i]); 44 | } 45 | 46 | if (page_alloc_signature() != hash) { 47 | printk("error: Memory not correctly restored\n"); 48 | TEST_EXIT(1); 49 | } 50 | 51 | TEST_EXIT(0); 52 | } 53 | -------------------------------------------------------------------------------- /tests/softirq_1/main.c: -------------------------------------------------------------------------------- 1 | /* simple softirq task create and rasie */ 2 | 3 | #include 4 | 5 | #include 6 | 7 | #include "unit.h" 8 | 9 | static volatile int val = 111; 10 | 11 | static void fn(void *arg) 12 | { 13 | val += (int) arg; 14 | } 15 | 16 | int main() 17 | { 18 | struct tasklet_struct *tsk = NULL; 19 | 20 | tsk = tasklet_init(fn, (void *) 666, PRIO_TASKLET_MAXPRIO); 21 | if (!tsk) { 22 | printk("failed: can't create new softirq task.\n"); 23 | TEST_EXIT(1); 24 | } 25 | 26 | if (tasklet_schedule(tsk) == -1) { 27 | printk("failed: can't rasie softirq task.\n"); 28 | TEST_EXIT(1); 29 | } 30 | 31 | while (val != 777) 32 | ; 33 | 34 | TEST_EXIT(0); 35 | } 36 | -------------------------------------------------------------------------------- /tests/softirq_2/main.c: -------------------------------------------------------------------------------- 1 | /* softirq task create/rasie 1000 times */ 2 | 3 | #include 4 | 5 | #include 6 | 7 | #include "unit.h" 8 | 9 | static volatile int val = 1111; 10 | 11 | static void fn(void *arg) 12 | { 13 | val += (int) arg; 14 | } 15 | 16 | int main() 17 | { 18 | int i; 19 | static struct tasklet_struct *tsk = NULL; 20 | 21 | /** 22 | * FIXME: modifing to 1000 times would fail to create. 23 | * Concludion with this problem is without freeing 24 | * softirq task. That's make sense, so we could avoid 25 | * it by testing tsk ptr. No more creation of same task. 26 | * FIXME: After patch above, we would get another problem about 27 | * same tsk with same addr space can concatenate two same tsk? 28 | * 29 | * ANS: Probably NOT 30 | */ 31 | for (i = 0; i < 100; i++) { 32 | tsk = tasklet_init(fn, (void *) 1, PRIO_TASKLET_MAXPRIO); 33 | 34 | if (!tsk) { 35 | printk("failed: can't create new softirq task.\n"); 36 | TEST_EXIT(1); 37 | } 38 | 39 | if (tasklet_schedule(tsk) == -1) { 40 | printk("failed: can't rasie softirq task.\n"); 41 | TEST_EXIT(1); 42 | } 43 | } 44 | 45 | while (val != 1211) 46 | ; 47 | 48 | TEST_EXIT(0); 49 | } 50 | -------------------------------------------------------------------------------- /tests/softirq_3/main.c: -------------------------------------------------------------------------------- 1 | /* test softirq task sequeniality */ 2 | 3 | #include 4 | 5 | #include 6 | 7 | #include "unit.h" 8 | 9 | static volatile int bucket[6] = {0}; 10 | 11 | #define DEFINE_FUNC(_id_) \ 12 | static void fn##_id_(void *arg) { bucket[_id_] = (int) arg; } 13 | DEFINE_FUNC(0) 14 | DEFINE_FUNC(1) 15 | DEFINE_FUNC(2) 16 | DEFINE_FUNC(3) 17 | DEFINE_FUNC(4) 18 | DEFINE_FUNC(5) 19 | 20 | int main() 21 | { 22 | #define SOFTIRQ_TASK_IMPL(_id_) \ 23 | do { \ 24 | struct tasklet_struct *tsk##_id_ = \ 25 | tasklet_init(fn##_id_, (void *) _id_, PRIO_TASKLET_MAXPRIO); \ 26 | if (!tsk##_id_) { \ 27 | printk("failed: can't create new softirq task" #_id_ ".\n"); \ 28 | TEST_EXIT(1); \ 29 | } \ 30 | \ 31 | if (tasklet_schedule(tsk##_id_) == -1) { \ 32 | printk("failed: can't rasie softirq task" #_id_ ".\n"); \ 33 | TEST_EXIT(1); \ 34 | } \ 35 | } while (0) 36 | 37 | SOFTIRQ_TASK_IMPL(0); 38 | SOFTIRQ_TASK_IMPL(1); 39 | SOFTIRQ_TASK_IMPL(2); 40 | SOFTIRQ_TASK_IMPL(3); 41 | SOFTIRQ_TASK_IMPL(4); 42 | SOFTIRQ_TASK_IMPL(5); 43 | 44 | for (int i = 0; i < 6; i++) // Test sequenciality 45 | while (!(bucket[i] == i)) 46 | ; 47 | 48 | 49 | TEST_EXIT(0); 50 | } 51 | -------------------------------------------------------------------------------- /tests/sprintf_1/main.c: -------------------------------------------------------------------------------- 1 | #include "unit.h" 2 | #include "utils.h" 3 | #include 4 | #include "kernel.h" 5 | #include 6 | 7 | int sprintf_00(void) 8 | { 9 | char buf[128]; 10 | 11 | sprintf(buf, "%d", 1789); 12 | if (strcmp(buf, "1789")) { 13 | printk("%s", buf); 14 | return -1; 15 | } 16 | 17 | return 0; 18 | } 19 | 20 | int sprintf_01(void) 21 | { 22 | char buf[128]; 23 | 24 | sprintf(buf, "%x", 0xdeadbeef); 25 | if (strcmp(buf, "deadbeef")) { 26 | printk("%s\n", buf); 27 | return -1; 28 | } 29 | 30 | return 0; 31 | } 32 | 33 | int sprintf_02(void) 34 | { 35 | char buf[128]; 36 | 37 | sprintf(buf, "Hello %s", "World!"); 38 | if (strcmp(buf, "Hello World!")) { 39 | printk("%s\n", buf); 40 | return -1; 41 | } 42 | 43 | return 0; 44 | } 45 | 46 | int sprintf_03(void) 47 | { 48 | char buf[128]; 49 | 50 | sprintf(buf, "abcdABCD0123 0x%x, %d, %d, 0x%x", 0xdeadbeef, 1983, 2014, 51 | 4096); 52 | if (strcmp(buf, "abcdABCD0123 0xdeadbeef, 1983, 2014, 0x1000")) { 53 | printk("%s\n", buf); 54 | return -1; 55 | } 56 | 57 | return 0; 58 | } 59 | 60 | int sprintf_04(void) 61 | { 62 | char buf[128]; 63 | 64 | sprintf(buf, "%w, %%, %s, %d", "foo", 1986); 65 | if (strcmp(buf, "%w, %, foo, 1986")) { 66 | printk("%s\n", buf); 67 | return -1; 68 | } 69 | 70 | return 0; 71 | } 72 | 73 | int sprintf_05(void) 74 | { 75 | char buf[128]; 76 | 77 | sprintf(buf, "%08d %06d %04d", 1986, 1986, 1986); 78 | if (strcmp(buf, "00001986 001986 1986")) { 79 | printk("%s\n", buf); 80 | return -1; 81 | } 82 | 83 | return 0; 84 | } 85 | 86 | int sprintf_06(void) 87 | { 88 | char buf[128]; 89 | 90 | sprintf(buf, "%08x %06x %04x %02x", 0xef, 0xef, 0xef, 0xef); 91 | if (strcmp(buf, "000000ef 0000ef 00ef ef")) { 92 | printk("%s\n", buf); 93 | return -1; 94 | } 95 | 96 | return 0; 97 | } 98 | 99 | int sprintf_07(void) 100 | { 101 | char buf[128]; 102 | 103 | sprintf(buf, "% 7d % 5x", 1986, 0x13); 104 | if (strcmp(buf, " 1986 13")) { 105 | printk("%s\n", buf); 106 | return -1; 107 | } 108 | 109 | return 0; 110 | } 111 | 112 | int main() 113 | { 114 | int status = 0; 115 | int (*test[])(void) = {sprintf_00, sprintf_01, sprintf_02, sprintf_03, 116 | sprintf_04, sprintf_05, sprintf_06, sprintf_07}; 117 | 118 | for (int i = 0; i <= 7; i++) { 119 | printk("sprintf test #%d\n", i); 120 | status += test[i](); 121 | } 122 | if (status) 123 | TEST_EXIT(1); 124 | 125 | TEST_EXIT(0); 126 | } 127 | -------------------------------------------------------------------------------- /tests/stat_1/data/id_rsa: -------------------------------------------------------------------------------- 1 | -----BEGIN RSA PRIVATE KEY----- 2 | MIIBOgIBAAJBAI/rmTOBknHe2ro+8sUNl1MjNTRopU1/WJTcYvsrFML10Z2IBrFi 3 | fc3Q1x92uTvyFU21cn+/ekU8L+8qK+V98fMCAwEAAQJAe4uw+REa6Nt5Ana1KsmP 4 | BNRtgO7wMEXIgglqgtipuu3CE9CIZ4OyrvELNbI6RiczGYgMmUHcWEmLuBZ+tjQu 5 | 4QIhAORy2CQio1J3O2gGdkk2eY2cLIzoMEdig9su/NILvSqDAiEAoUcD1FeM1iub 6 | SiUq3ZDIf1FFTgtv9Si0lzJyBY+IP9ECIHi8zclDWUhDZe1TxP5qwRF74fvS13lS 7 | 8tdL3SjyNVcbAiEAhZU3o8r8mWy3DFvqvGiu2V3shK9OhYa4xj9/WAHB/fECIH9u 8 | Nq1Ww0stz2Oq7Wpn7ywcNemkot/+sO8l8gxXPcqw 9 | -----END RSA PRIVATE KEY----- 10 | -------------------------------------------------------------------------------- /tests/stat_1/data/id_rsa.pub: -------------------------------------------------------------------------------- 1 | -----BEGIN PUBLIC KEY----- 2 | MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBAI/rmTOBknHe2ro+8sUNl1MjNTRopU1/ 3 | WJTcYvsrFML10Z2IBrFifc3Q1x92uTvyFU21cn+/ekU8L+8qK+V98fMCAwEAAQ== 4 | -----END PUBLIC KEY----- 5 | -------------------------------------------------------------------------------- /tests/stat_1/main.c: -------------------------------------------------------------------------------- 1 | /* simple test for stat() */ 2 | 3 | #include 4 | 5 | #include 6 | 7 | #include 8 | #include 9 | 10 | #include 11 | 12 | #include "unit.h" 13 | 14 | extern char _binary_sda1_start; 15 | struct mtd_info mtd1; 16 | 17 | static struct inode inode = { 18 | .i_private = &mtd1, 19 | }; 20 | 21 | void flash_init(void) 22 | { 23 | struct dentry dentry = {.d_inode = &inode, .d_name = "mtd1"}; 24 | 25 | printk("Creating MTD device %s\n", dentry.d_name); 26 | if (mtdram_init_device(&mtd1, &_binary_sda1_start, 1024, dentry.d_name)) 27 | printk("error: mtdram init device failed\n"); 28 | vfs_link(NULL, dev_inode(), &dentry); 29 | } 30 | 31 | int main() 32 | { 33 | init_tmpfs_inode(&inode); 34 | flash_init(); 35 | mount("/dev/mtd1", "/dev/flash", "romfs", 0, 0); 36 | 37 | struct stat st; 38 | if (stat("/dev/flash/id_rsa.pub", &st)) { 39 | printk("error: Wrong pathname\n"); 40 | TEST_EXIT(1); 41 | } 42 | printk("Opened file with inode number %d\n", st.st_ino); 43 | if (!S_ISREG(st.st_mode)) { 44 | printk("error: File is not a regular file\n"); 45 | TEST_EXIT(1); 46 | } 47 | if (st.st_size != 182) { 48 | printk("error: Wrong file size (%d != 182)\n", st.st_size); 49 | TEST_EXIT(1); 50 | } 51 | 52 | TEST_EXIT(0); 53 | } 54 | -------------------------------------------------------------------------------- /tests/syscall_1/trampoline.S: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | .syntax unified 4 | .thumb 5 | 6 | ENTRY(test_svcall0) 7 | ldr r0, =41 8 | svc #0 9 | bx lr 10 | ENDPROC(test_svcall0) 11 | 12 | ENTRY(test_svcall1) 13 | ldr r0, =0xbabe 14 | ldr r1, =42 15 | svc #1 16 | bx lr 17 | ENDPROC(test_svcall1) 18 | 19 | ENTRY(test_svcall2) 20 | ldr r0, =0xbabe 21 | ldr r1, =0xbeef 22 | ldr r2, =43 23 | svc #2 24 | bx lr 25 | ENDPROC(test_svcall2) 26 | 27 | ENTRY(test_svcall3) 28 | ldr r0, =0xbabe 29 | ldr r1, =0xbeef 30 | ldr r2, =0x123 31 | ldr r3, =44 32 | svc #3 33 | bx lr 34 | ENDPROC(test_svcall3) 35 | 36 | ENTRY(test_svcall4) 37 | ldr r3, =45 38 | push {r3} 39 | ldr r0, =0xbabe 40 | ldr r1, =0xbeef 41 | ldr r2, =0x123 42 | ldr r3, =0x456 43 | svc #4 44 | add sp, #4 45 | bx lr 46 | ENDPROC(test_svcall4) 47 | 48 | ENTRY(test_svcall5) 49 | ldr r2, =0xcafe 50 | ldr r3, =46 51 | push {r2, r3} 52 | ldr r0, =0xbabe 53 | ldr r1, =0xbeef 54 | ldr r2, =0x123 55 | ldr r3, =0x456 56 | svc #5 57 | add sp, #8 58 | bx lr 59 | ENDPROC(test_svcall5) 60 | 61 | ENTRY(test_svcall6) 62 | ldr r1, =0xcafe 63 | ldr r2, =0xfeed 64 | ldr r3, =47 65 | push {r1-r3} 66 | ldr r0, =0xbabe 67 | ldr r1, =0xbeef 68 | ldr r2, =0x123 69 | ldr r3, =0x456 70 | svc #6 71 | add sp, #12 72 | bx lr 73 | ENDPROC(test_svcall6) 74 | 75 | ENTRY(get_sp) 76 | mov r0, sp 77 | bx lr 78 | ENDPROC(get_sp) 79 | -------------------------------------------------------------------------------- /tests/sysconf_1/main.c: -------------------------------------------------------------------------------- 1 | #include "unit.h" 2 | #include "unistd.h" 3 | 4 | int main() 5 | { 6 | printk("system tick per seconds: %d\n", sysconf(_SC_CLK_TCK)); 7 | 8 | TEST_EXIT(0); 9 | } 10 | -------------------------------------------------------------------------------- /tests/test_1/main.c: -------------------------------------------------------------------------------- 1 | /* this test must pass */ 2 | 3 | #include "unit.h" 4 | 5 | int main() 6 | { 7 | TEST_EXIT(0); 8 | } 9 | -------------------------------------------------------------------------------- /tests/test_2/main.c: -------------------------------------------------------------------------------- 1 | /* this test must fail */ 2 | 3 | #include "unit.h" 4 | 5 | int main() 6 | { 7 | TEST_EXIT(1); 8 | } 9 | -------------------------------------------------------------------------------- /tests/thread_1/main.c: -------------------------------------------------------------------------------- 1 | /* simple thread create and thread yield */ 2 | 3 | #include 4 | 5 | #include 6 | 7 | #include "unit.h" 8 | 9 | static int val = 123; 10 | 11 | static void *fn(void *arg) 12 | { 13 | val += (int) arg; 14 | 15 | return 0; 16 | } 17 | 18 | int main() 19 | { 20 | pthread_t tip; 21 | 22 | if (pthread_create(&tip, NULL, fn, (void *) 321)) { 23 | printk("failed: can't create new posix thread.\n"); 24 | TEST_EXIT(1); 25 | } 26 | 27 | if (sched_yield()) { 28 | printk("failed: can't yield cpu to another thread.\n"); 29 | TEST_EXIT(1); 30 | } 31 | 32 | while (val != 444) 33 | ; 34 | 35 | TEST_EXIT(0); 36 | } 37 | -------------------------------------------------------------------------------- /tests/thread_2/main.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | 5 | #include "unit.h" 6 | 7 | int vals[] = {0, 0, 0, 0}; 8 | 9 | void *fn(void *arg) 10 | { 11 | for (;;) { 12 | vals[(int) arg]++; 13 | sched_yield(); 14 | } 15 | 16 | return 0; 17 | } 18 | 19 | int main() 20 | { 21 | pthread_t tips[4]; 22 | 23 | for (int i = 0; i < 4; i++) { 24 | if (pthread_create(&tips[i], NULL, fn, (void *) i)) { 25 | printk("failed: can't create new posix thread.\n"); 26 | TEST_EXIT(1); 27 | } 28 | } 29 | 30 | for (int i = 0; i < 4; i++) { 31 | while (vals[i] < 10) 32 | sched_yield(); 33 | } 34 | 35 | TEST_EXIT(0); 36 | } 37 | -------------------------------------------------------------------------------- /tests/thread_3/main.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | 5 | #include "unit.h" 6 | 7 | static int count; 8 | 9 | void *fn(void *arg) 10 | { 11 | (void) arg; 12 | printk("counter=%d\n", count); 13 | count++; 14 | 15 | return 0; 16 | } 17 | 18 | int main() 19 | { 20 | pthread_t tips[25]; 21 | 22 | /* reduce the thread stack size to 256 bytes */ 23 | pthread_attr_t attr; 24 | pthread_attr_setstacksize(&attr, 256); 25 | 26 | /* create 25 threads */ 27 | for (int i = 0; i < 25; i++) { 28 | if (pthread_create(&tips[i], &attr, fn, NULL)) { 29 | printk("failed: can't create new posix thread.\n"); 30 | TEST_EXIT(1); 31 | } 32 | } 33 | 34 | while (count < 24) 35 | sched_yield(); 36 | 37 | TEST_EXIT(0); 38 | } 39 | -------------------------------------------------------------------------------- /tests/thread_4/main.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | #include "unit.h" 9 | 10 | static int count; 11 | 12 | static void *fn(void *arg) 13 | { 14 | int i = (int) arg; 15 | 16 | if (i != count) 17 | TEST_EXIT(1); 18 | count++; 19 | 20 | return 0; 21 | } 22 | 23 | int main() 24 | { 25 | struct thread_info *t; 26 | CURRENT_TASK_INFO(curr_task); 27 | 28 | for (int i = 0; i < 15; i++) { 29 | t = thread_create(fn, (void *) i, THREAD_PRIV_USER, 256, curr_task); 30 | if (!t) { 31 | printk("failed: can't create new posix thread.\n"); 32 | TEST_EXIT(1); 33 | } 34 | thread_set_priority(t, i); 35 | sched_enqueue(t); 36 | } 37 | 38 | sched_yield(); 39 | 40 | if (count != 15) { 41 | printk("count != 15 (%d)\n", count); 42 | TEST_EXIT(1); 43 | } 44 | 45 | TEST_EXIT(0); 46 | } 47 | -------------------------------------------------------------------------------- /tests/thread_5/main.c: -------------------------------------------------------------------------------- 1 | /* test thread_join() */ 2 | 3 | #include "kernel.h" 4 | #include "pthread.h" 5 | #include "unit.h" 6 | #include "linux/stddef.h" 7 | 8 | void *fn(void *arg) 9 | { 10 | /* printk("Running thread with arg=%d\n", (int) arg); */ 11 | pthread_exit(arg); 12 | 13 | return 0; 14 | } 15 | 16 | int main() 17 | { 18 | void *retval; 19 | pthread_t tips[7]; 20 | 21 | printk("Creating a bunch of threads... "); 22 | for (int i = 0; i < 7; i++) { 23 | if (pthread_create(&tips[i], NULL, fn, (void *) i)) { 24 | printk("failed: can't create new posix thread.\n"); 25 | TEST_EXIT(1); 26 | } 27 | } 28 | printk("OK\n"); 29 | 30 | for (int i = 0; i < 7; i++) { 31 | printk("Joining thread with arg=%d... ", i); 32 | pthread_join(tips[i], &retval); 33 | if ((int) retval != i) { 34 | printk("pthread_join: wrong return value: got %d, expected %d\n", 35 | (int) retval, i); 36 | TEST_EXIT(1); 37 | } 38 | printk("OK\n"); 39 | } 40 | 41 | TEST_EXIT(0); 42 | } 43 | -------------------------------------------------------------------------------- /tests/thread_6/main.c: -------------------------------------------------------------------------------- 1 | /* create/delete 1000 threads */ 2 | 3 | #include 4 | #include 5 | #include 6 | #include "unit.h" 7 | 8 | static void *fn(void *arg) 9 | { 10 | (void) arg; 11 | printk("."); 12 | 13 | return 0; 14 | } 15 | 16 | int main() 17 | { 18 | pthread_t thread; 19 | 20 | for (int i = 0; i < 1000; i++) { 21 | if (pthread_create(&thread, NULL, fn, NULL)) { 22 | printk("failed: can't create new posix thread.\n"); 23 | TEST_EXIT(1); 24 | } 25 | pthread_detach(thread); 26 | sched_yield(); 27 | } 28 | printk("\n"); 29 | TEST_EXIT(0); 30 | } 31 | -------------------------------------------------------------------------------- /tests/timer_1/main.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include "unit.h" 5 | #include 6 | #include 7 | 8 | #define EXPECTED_VALUE 0xabadcafeul 9 | 10 | static volatile int received_signal; 11 | 12 | static void event(union sigval sival) 13 | { 14 | if (sival.sival_int != (int) EXPECTED_VALUE) { 15 | printk("error: Did not received expected value (%x != %x)\n", 16 | sival.sival_int, EXPECTED_VALUE); 17 | TEST_EXIT(1); 18 | } 19 | received_signal = 1; 20 | } 21 | 22 | int main() 23 | { 24 | struct sigevent sevp = {.sigev_notify_function = event, 25 | .sigev_value.sival_int = EXPECTED_VALUE}; 26 | struct itimerspec val = {.it_value = {.tv_sec = 1, .tv_nsec = 0}}; 27 | timer_t timerid; 28 | 29 | timer_create(1, &sevp, &timerid); 30 | timer_settime(timerid, 0, &val, NULL); 31 | 32 | while (!received_signal) 33 | ; 34 | 35 | TEST_EXIT(0); 36 | } 37 | -------------------------------------------------------------------------------- /tests/timer_2/main.c: -------------------------------------------------------------------------------- 1 | /* simple create multiple concurrent timers */ 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | #include "kernel.h" 8 | #include "unit.h" 9 | 10 | static volatile int vals[] = {0, 0, 0, 0}; 11 | 12 | static void event(union sigval sival) 13 | { 14 | printk("In event %d.\n", sival.sival_int); 15 | vals[sival.sival_int] = 1; 16 | } 17 | 18 | int main() 19 | { 20 | struct sigevent sevp = {.sigev_notify_function = event}; 21 | timer_t timerid[4]; 22 | 23 | for (int i = 0; i < 4; i++) { 24 | printk("Creating timer %d...\n", i); 25 | sevp.sigev_value.sival_int = i; 26 | timer_create(0, &sevp, &timerid[i]); 27 | 28 | unsigned long val_in_nsecs = 750 * (i + 1) * 1000000; 29 | struct itimerspec val = { 30 | .it_value = {.tv_sec = val_in_nsecs / 1000000000, 31 | .tv_nsec = val_in_nsecs % 1000000000}}; 32 | timer_settime(timerid[i], 0, &val, NULL); 33 | } 34 | printk("All timers armed.\n"); 35 | for (int i = 0; i < 4; i++) { 36 | while (vals[i] == 0) 37 | ; 38 | } 39 | 40 | TEST_EXIT(0); 41 | } 42 | -------------------------------------------------------------------------------- /tests/timer_3/main.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include "unit.h" 5 | #include 6 | #include 7 | 8 | static void event(union sigval sival) 9 | { 10 | (void) sival; 11 | } 12 | 13 | int main() 14 | { 15 | struct sigevent sevp = {.sigev_notify_function = event}; 16 | struct itimerspec val = {.it_value = {.tv_sec = 5, .tv_nsec = 0}}; 17 | timer_t timerid; 18 | 19 | timer_create(1, &sevp, &timerid); 20 | timer_settime(timerid, 0, &val, NULL); 21 | do { 22 | timer_gettime(timerid, &val); 23 | } while (val.it_value.tv_sec != 4); 24 | 25 | TEST_EXIT(0); 26 | } 27 | -------------------------------------------------------------------------------- /tests/timer_4/main.c: -------------------------------------------------------------------------------- 1 | /* simple test for interval timers */ 2 | 3 | #include 4 | #include 5 | 6 | #include 7 | #include 8 | 9 | #include "unit.h" 10 | 11 | static volatile int count; 12 | 13 | static void event(union sigval sival) 14 | { 15 | (void) sival; 16 | 17 | printk("Counter=%d\n", ++count); 18 | } 19 | 20 | int main() 21 | { 22 | timer_t timerid; 23 | struct sigevent sevp = { 24 | .sigev_notify_function = event, 25 | }; 26 | struct itimerspec val = { 27 | .it_value = {.tv_sec = 1, .tv_nsec = 0}, 28 | .it_interval = {.tv_sec = 1, .tv_nsec = 0}, 29 | }; 30 | 31 | timer_create(0, &sevp, &timerid); 32 | timer_settime(timerid, 0, &val, NULL); 33 | while (count < 4) 34 | ; 35 | 36 | TEST_EXIT(0); 37 | } 38 | -------------------------------------------------------------------------------- /tests/timer_5/main.c: -------------------------------------------------------------------------------- 1 | /* test cancellation of timer */ 2 | 3 | #include 4 | #include 5 | 6 | #include 7 | #include 8 | 9 | #include "unit.h" 10 | 11 | static volatile int canary; 12 | static volatile int count; 13 | 14 | static void event_should_not_happen(union sigval sival) 15 | { 16 | (void) sival; 17 | 18 | canary++; 19 | } 20 | 21 | static void event_check(union sigval sival) 22 | { 23 | (void) sival; 24 | 25 | count++; 26 | } 27 | 28 | int main() 29 | { 30 | timer_t timerid_a; 31 | struct sigevent sevp_a = { 32 | .sigev_notify_function = event_should_not_happen, 33 | }; 34 | timer_create(0, &sevp_a, &timerid_a); 35 | 36 | timer_t timerid_b; 37 | struct sigevent sevp_b = { 38 | .sigev_notify_function = event_check, 39 | }; 40 | timer_create(0, &sevp_b, &timerid_b); 41 | 42 | struct itimerspec val_a = { 43 | .it_value = {.tv_sec = 1, .tv_nsec = 0}, 44 | .it_interval = {.tv_sec = 0, .tv_nsec = 0}, 45 | }; 46 | struct itimerspec val_b = { 47 | .it_value = {.tv_sec = 2, .tv_nsec = 0}, 48 | .it_interval = {.tv_sec = 0, .tv_nsec = 0}, 49 | }; 50 | struct itimerspec val_zero = { 51 | .it_value = {.tv_sec = 0, .tv_nsec = 0}, 52 | .it_interval = {.tv_sec = 0, .tv_nsec = 0}, 53 | }; 54 | timer_settime(timerid_a, 0, &val_a, NULL); 55 | timer_settime(timerid_b, 0, &val_b, NULL); 56 | timer_settime(timerid_a, 0, &val_zero, NULL); 57 | 58 | while (!count) 59 | ; 60 | if (canary) 61 | TEST_EXIT(1); 62 | 63 | TEST_EXIT(0); 64 | } 65 | -------------------------------------------------------------------------------- /tests/ucontext_1/main.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include "unit.h" 4 | 5 | static int test_status; 6 | static ucontext_t main_context, other_context; 7 | static unsigned int ctx_stack[128]; 8 | 9 | void __printk_putchar(char c); 10 | 11 | static void pputs(const char *s) 12 | { 13 | for (; *s != '\0'; s++) 14 | __printk_putchar(*s); 15 | } 16 | 17 | void test(int a1, int a2, int a3, int a4) 18 | { 19 | pputs("Hello from a new context!\n"); 20 | 21 | if ((a1 != 9) || (a2 != 0xcafe) || (a3 != 13) || (a4 != 14)) { 22 | pputs("failed: incorrect correct arg.\n"); 23 | test_status = 1; 24 | } 25 | } 26 | 27 | int main() 28 | { 29 | other_context.uc_link = &main_context; 30 | other_context.uc_stack.ss_sp = &ctx_stack[128]; 31 | 32 | /* pass 4 arguments to the new context, and swap */ 33 | makecontext(&other_context, test, 4, 9, 0xcafe, 13, 14); 34 | swapcontext(&main_context, &other_context); 35 | 36 | pputs("And back to the main context.\n"); 37 | 38 | TEST_EXIT(test_status); 39 | } 40 | -------------------------------------------------------------------------------- /user/cat.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #include 6 | 7 | #include "sh.h" 8 | 9 | static int cat(__unused int argc, char *argv[]) 10 | { 11 | char buf[] = {0, 0}; 12 | int fd; 13 | int retval = 0; 14 | 15 | for (int i = 1; i < argc; i++) { 16 | fd = open(argv[i], 0); 17 | if (fd < 0) { 18 | printk("cat: %s: No such file or directory\n", argv[1]); 19 | retval = 1; 20 | } 21 | while (read(fd, &buf, 1)) 22 | printk("%s", buf); 23 | close(fd); 24 | } 25 | 26 | return retval; 27 | } 28 | 29 | HOOK_BUILTIN_CMD(cat, cat); 30 | -------------------------------------------------------------------------------- /user/echo.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include "sh.h" 4 | 5 | static int echo(int argc, char *argv[]) 6 | { 7 | if (argc == 1) 8 | return 0; 9 | for (int i = 1; i < argc; i++) { 10 | if (i == 1) 11 | printk("%s", argv[i]); 12 | else 13 | printk(" %s", argv[i]); 14 | } 15 | printk("\n"); 16 | 17 | return 0; 18 | } 19 | 20 | HOOK_BUILTIN_CMD(echo, echo); 21 | -------------------------------------------------------------------------------- /user/exit.c: -------------------------------------------------------------------------------- 1 | #include "sh.h" 2 | #include "platform.h" 3 | 4 | static int _exit(__unused int argc, __unused char *argv[]) 5 | { 6 | __platform_halt(); 7 | return 0; 8 | } 9 | 10 | HOOK_BUILTIN_CMD(exit, _exit); 11 | -------------------------------------------------------------------------------- /user/halt.c: -------------------------------------------------------------------------------- 1 | #include "sh.h" 2 | #include "platform.h" 3 | 4 | static int halt(__unused int argc, __unused char *argv[]) 5 | { 6 | __platform_halt(); 7 | return 0; 8 | } 9 | 10 | HOOK_BUILTIN_CMD(halt, halt); 11 | -------------------------------------------------------------------------------- /user/ls.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include 5 | 6 | #include 7 | #include 8 | 9 | #include "sh.h" 10 | 11 | static int ls(int argc, char *argv[]) 12 | { 13 | DIR *dir; 14 | struct dirent dirent; 15 | struct dirent *result; 16 | 17 | if (argc == 1) 18 | dir = opendir("/"); // FIXME: get current directory 19 | else 20 | dir = opendir(argv[1]); 21 | 22 | do { 23 | readdir_r(dir, &dirent, &result); 24 | if (result != NULL) 25 | printk("% 6d %s\n", dirent.d_ino, dirent.d_name); 26 | } while (result != NULL); 27 | closedir(dir); 28 | 29 | return 0; 30 | } 31 | 32 | HOOK_BUILTIN_CMD(ls, ls); 33 | -------------------------------------------------------------------------------- /user/reboot.c: -------------------------------------------------------------------------------- 1 | #include "sh.h" 2 | #include "platform.h" 3 | 4 | static int reboot(__unused int argc, __unused char *argv[]) 5 | { 6 | NVIC_SystemReset(); 7 | 8 | return -1; 9 | } 10 | 11 | HOOK_BUILTIN_CMD(reboot, reboot); 12 | -------------------------------------------------------------------------------- /user/sh.h: -------------------------------------------------------------------------------- 1 | #ifndef USER_SH_H 2 | #define USER_SH_H 3 | 4 | #define ARG_COUNT_MAX 8 5 | #define BUF_LINE_LEN 128 6 | 7 | enum ascii_control_char { 8 | ASCII_NULL = 000, 9 | ASCII_BACKSPACE = 010, 10 | ASCII_CARRIAGE_RETURN = 015, 11 | ASCII_ESCAPE = 033, 12 | ASCII_DELETE = 0177, 13 | }; 14 | 15 | struct shell_cmd { 16 | char *name; 17 | int (*func)(int argc, char *argv[]); 18 | }; 19 | 20 | #define HOOK_BUILTIN_CMD(_name, _func) \ 21 | static struct shell_cmd shell_##_name \ 22 | __attribute__((section(".shell_cmd"), aligned(sizeof(long)), \ 23 | used)) = {.name = #_name, .func = _func} 24 | 25 | #endif /* !USER_SH_H */ 26 | --------------------------------------------------------------------------------