├── .circleci └── config.yml ├── .gdbinit ├── .gdbinit-aarch64 ├── .gdbinit-riscv64 ├── .gdbinit-x86-64 ├── .github └── workflows │ └── main.yml ├── .gitignore ├── CHARTER.md ├── CONTRIBUTING.md ├── FAQ.md ├── LICENSE ├── Makefile ├── README.md ├── ROADMAP.md ├── SECURITY.md ├── doc ├── demo.gif ├── lock-profiling.txt ├── mem-map.txt ├── tracelog.txt └── virtio-balloon.txt ├── doxy.config ├── kernel.mk ├── klib ├── aws.c ├── aws.h ├── azure.c ├── azure.h ├── azure_diagnostics.c ├── cloud_azure.c ├── cloud_init.c ├── cloud_init.h ├── cloudwatch.c ├── crc.h ├── crc32.c ├── digitalocean.c ├── firewall.c ├── gcp.c ├── klib.h ├── klib.mk ├── mbedtls.c ├── mbedtls_conf.h ├── net_utils.c ├── net_utils.h ├── ntp.c ├── pledge.c ├── radar.c ├── sandbox.c ├── sandbox.h ├── shmem.c ├── special_files.c ├── strace.c ├── strace.h ├── strace_file.c ├── strace_mem.c ├── strace_misc.c ├── syslog.c ├── test │ ├── klib.c │ ├── lock.c │ └── page_table.c ├── tls.h ├── tmpfs.c ├── tmpfs.h ├── tun.c ├── umcg.c ├── unveil.c ├── xml.c └── xml.h ├── networking_setup ├── patches └── acpica.patch ├── platform ├── pc │ ├── .gdb │ ├── Makefile │ ├── boot │ │ ├── Makefile │ │ ├── csum.inc │ │ ├── def32.h │ │ ├── linker_script │ │ ├── longmode.inc │ │ ├── service32.s │ │ ├── stage1.s │ │ └── stage2.c │ ├── linker_script │ ├── pci.c │ ├── service.c │ └── test-libs ├── riscv-virt │ ├── Makefile │ ├── kernel_platform.h │ ├── linker_script │ ├── mbr.hex │ ├── pci.c │ ├── sbi_ecall_interface.h │ ├── service.c │ └── test-libs └── virt │ ├── Makefile │ ├── kernel_platform.h │ ├── linker_script │ ├── mbr.hex │ ├── pci.c │ ├── service.c │ └── test-libs ├── release.md ├── release.sh ├── rules.mk ├── scripts ├── apply-format ├── git-pre-commit-format └── readme.md ├── src ├── aarch64 │ ├── acpi.c │ ├── clock.c │ ├── crt0.S │ ├── def64.h │ ├── elf64.c │ ├── frame.h │ ├── gdb_machine.h │ ├── gic.c │ ├── gic.h │ ├── gpio.c │ ├── gpio.h │ ├── hyperv.c │ ├── interrupt.c │ ├── kernel_machine.c │ ├── kernel_machine.h │ ├── klib.lds │ ├── machine.h │ ├── page.c │ ├── page_machine.h │ ├── rtc.c │ ├── serial.c │ ├── serial.h │ ├── uefi-crt0.s │ ├── uefi.c │ ├── uefi.lds │ ├── unix_machine.c │ ├── unix_machine.h │ ├── unix_syscalls.h │ └── vdso.lds ├── aws │ ├── aws.h │ └── ena │ │ ├── ena.c │ │ ├── ena.h │ │ ├── ena_com │ │ ├── ena_com.c │ │ ├── ena_com.h │ │ ├── ena_defs │ │ │ ├── ena_admin_defs.h │ │ │ ├── ena_common_defs.h │ │ │ ├── ena_eth_io_defs.h │ │ │ ├── ena_includes.h │ │ │ └── ena_regs_defs.h │ │ ├── ena_eth_com.c │ │ ├── ena_eth_com.h │ │ └── ena_plat.h │ │ ├── ena_datapath.c │ │ └── ena_datapath.h ├── boot │ ├── boot.h │ ├── elf.c │ ├── uefi.c │ └── uefi.h ├── config.h ├── debug_all.h ├── devicetree │ ├── devicetree.c │ └── devicetree.h ├── drivers │ ├── acpi.c │ ├── acpi.h │ ├── acpica.mk │ ├── ata-pci.c │ ├── ata-pci.h │ ├── ata.c │ ├── ata.h │ ├── console.c │ ├── console.h │ ├── dmi.c │ ├── dmi.h │ ├── gve.c │ ├── gve.h │ ├── netconsole.c │ ├── netconsole.h │ ├── ns16550.c │ ├── ns16550.h │ ├── nvme.c │ ├── nvme.h │ ├── vga.c │ └── vga.h ├── fs │ ├── 9p.c │ ├── 9p.h │ ├── fs.c │ ├── fs.h │ ├── tfs.c │ ├── tfs.h │ ├── tfs_internal.h │ └── tlog.c ├── gdb │ ├── gdb.h │ ├── gdb_internal.h │ ├── gdbstub.c │ ├── gdbtcp.c │ └── gdbutil.c ├── http │ ├── http.c │ └── http.h ├── hyperv │ ├── include │ │ ├── ctassert.h │ │ ├── hyperv.h │ │ ├── hyperv_busdma.h │ │ ├── hyperv_internal.h │ │ ├── hyperv_platform.h │ │ ├── vmbus.h │ │ └── vmbus_xact.h │ ├── netvsc │ │ ├── hv_net_vsc.c │ │ ├── hv_net_vsc.h │ │ ├── hv_rndis.h │ │ ├── hv_rndis_filter.c │ │ ├── hv_rndis_filter.h │ │ └── netvsc.c │ ├── storvsc │ │ ├── hv_vstorage.h │ │ └── storvsc.c │ ├── utilities │ │ ├── vmbus_ic.c │ │ ├── vmbus_icreg.h │ │ ├── vmbus_icvar.h │ │ └── vmbus_shutdown.c │ └── vmbus │ │ ├── hyperv.c │ │ ├── hyperv_reg.h │ │ ├── hyperv_var.h │ │ ├── vmbus.c │ │ ├── vmbus_br.c │ │ ├── vmbus_brvar.h │ │ ├── vmbus_chan.c │ │ ├── vmbus_chanvar.h │ │ ├── vmbus_et.c │ │ ├── vmbus_reg.h │ │ ├── vmbus_var.h │ │ └── vmbus_xact.c ├── kernel │ ├── clock.c │ ├── dma.c │ ├── dma.h │ ├── elf.c │ ├── elf64.h │ ├── errno.h │ ├── flush.c │ ├── init.c │ ├── kernel.c │ ├── kernel.h │ ├── klib.c │ ├── klib.h │ ├── kvm_platform.c │ ├── kvm_platform.h │ ├── linear_backed_heap.c │ ├── locking_heap.c │ ├── lockstats.c │ ├── lockstats.h │ ├── lockstats_struct.h │ ├── log.c │ ├── log.h │ ├── ltrace.c │ ├── ltrace.h │ ├── management_telnet.c │ ├── mutex.c │ ├── mutex.h │ ├── page.c │ ├── page.h │ ├── page_backed_heap.c │ ├── pagecache.c │ ├── pagecache.h │ ├── pagecache_internal.h │ ├── pci.c │ ├── pci.h │ ├── pvclock.c │ ├── pvclock.h │ ├── region.h │ ├── schedule.c │ ├── stage3.c │ ├── storage.c │ ├── symtab.c │ ├── symtab.h │ ├── tracelog.c │ ├── tracelog.h │ ├── vdso-now.c │ ├── vdso.c │ ├── vdso.h │ └── xen_platform.h ├── net │ ├── arch │ │ ├── cc.h │ │ └── sys_arch.h │ ├── direct.c │ ├── lwip.h │ ├── lwipopts.h │ ├── net.c │ ├── net.h │ ├── net_system_structs.h │ ├── netsyscall.c │ ├── stdlib.h │ └── string.h ├── riscv64 │ ├── clock.c │ ├── crt0.S │ ├── elf64.c │ ├── frame.h │ ├── gdb_machine.h │ ├── init.S │ ├── interrupt.c │ ├── kernel_machine.c │ ├── kernel_machine.h │ ├── klib.lds │ ├── machine.h │ ├── page.c │ ├── page_machine.h │ ├── plic.c │ ├── plic.h │ ├── serial.c │ ├── serial.h │ ├── unix_machine.c │ ├── unix_machine.h │ ├── unix_syscalls.h │ └── vdso.lds ├── runtime │ ├── attributes.h │ ├── bitmap.c │ ├── bitmap.h │ ├── buffer.c │ ├── buffer.h │ ├── clock.h │ ├── closure.h │ ├── context.h │ ├── crypto │ │ ├── chacha.c │ │ └── chacha.h │ ├── extra_prints.c │ ├── files.mk │ ├── format.c │ ├── format.h │ ├── heap │ │ ├── debug_heap.c │ │ ├── freelist.c │ │ ├── heap.h │ │ ├── id.c │ │ ├── id.h │ │ ├── mcache.c │ │ ├── mem_debug.c │ │ ├── objcache.c │ │ ├── page.c │ │ ├── page.h │ │ └── reserve.c │ ├── ip.h │ ├── json.c │ ├── kernel_heaps.h │ ├── list.h │ ├── lock.h │ ├── management.c │ ├── management.h │ ├── memops.c │ ├── merge.c │ ├── metadata.h │ ├── pqueue.c │ ├── pqueue.h │ ├── predef.h │ ├── queue.c │ ├── queue.h │ ├── random.c │ ├── range.c │ ├── range.h │ ├── rbtree.c │ ├── rbtree.h │ ├── refcount.h │ ├── ringbuf.c │ ├── ringbuf.h │ ├── runtime.h │ ├── runtime_init.c │ ├── runtime_string.h │ ├── sg.c │ ├── sg.h │ ├── sha256.c │ ├── signature.c │ ├── sstring.h │ ├── status.h │ ├── storage.h │ ├── string.c │ ├── symbol.c │ ├── symbol.h │ ├── table.c │ ├── table.h │ ├── text.h │ ├── timer.c │ ├── timer.h │ ├── tuple.c │ ├── tuple.h │ ├── tuple_parser.c │ ├── vector.c │ └── vector.h ├── unix │ ├── aio.c │ ├── blockq.c │ ├── coredump.c │ ├── eventfd.c │ ├── exec.c │ ├── filesystem.c │ ├── filesystem.h │ ├── ftrace.c │ ├── ftrace.h │ ├── futex.c │ ├── inotify.c │ ├── io_uring.c │ ├── mktime.c │ ├── mktime.h │ ├── mmap.c │ ├── netlink.c │ ├── notify.c │ ├── notify.h │ ├── pipe.c │ ├── poll.c │ ├── signal.c │ ├── socket.c │ ├── socket.h │ ├── special.c │ ├── syscall.c │ ├── system_structs.h │ ├── thread.c │ ├── timer.c │ ├── unix.c │ ├── unix.h │ ├── unix_clock.c │ ├── unix_internal.h │ ├── vdso.c │ ├── vsock.c │ └── vsock.h ├── unix_process │ ├── mmap_heap.c │ ├── socket_user.c │ ├── socket_user.h │ ├── ssp.c │ ├── tiny_heap.c │ ├── unix_process_runtime.c │ └── unix_process_runtime.h ├── virtio │ ├── scsi.c │ ├── scsi.h │ ├── virtio.c │ ├── virtio.h │ ├── virtio_9p.c │ ├── virtio_9p.h │ ├── virtio_balloon.c │ ├── virtio_endian.h │ ├── virtio_internal.h │ ├── virtio_mmio.c │ ├── virtio_mmio.h │ ├── virtio_net.c │ ├── virtio_net.h │ ├── virtio_pci.c │ ├── virtio_pci.h │ ├── virtio_rng.c │ ├── virtio_scsi.c │ ├── virtio_socket.c │ ├── virtio_socket.h │ ├── virtio_storage.c │ └── virtqueue.c ├── vmware │ ├── pvscsi.c │ ├── pvscsi.h │ ├── vmware.h │ ├── vmxnet3_net.c │ ├── vmxnet3_net.h │ ├── vmxnet3_queue.c │ └── vmxnet3_queue.h ├── x86_64 │ ├── acpi.c │ ├── apic.c │ ├── apic.h │ ├── breakpoint.c │ ├── clock.c │ ├── crt0.s │ ├── debug.inc │ ├── def64.h │ ├── elf64.c │ ├── frame.h │ ├── ftrace.s │ ├── gdb_machine.h │ ├── hpet.c │ ├── hyperv.c │ ├── init.s │ ├── interrupt.c │ ├── io.h │ ├── kernel_machine.c │ ├── kernel_machine.h │ ├── klib.lds │ ├── machine.h │ ├── mp.c │ ├── page.c │ ├── page_machine.h │ ├── pvm.c │ ├── pvm.h │ ├── pvm_asm.s │ ├── rtc.c │ ├── segment.inc │ ├── serial.c │ ├── serial.h │ ├── synth.c │ ├── synth.h │ ├── uefi-crt0.s │ ├── uefi.c │ ├── uefi.lds │ ├── unix_machine.c │ ├── unix_machine.h │ ├── unix_syscalls.h │ ├── vdso.lds │ ├── x2apic.c │ ├── x86.h │ ├── x86.inc │ └── xapic.c └── xen │ ├── public │ ├── arch-x86 │ │ ├── cpuid.h │ │ ├── xen-x86_64.h │ │ └── xen.h │ ├── event_channel.h │ ├── features.h │ ├── grant_table.h │ ├── hvm │ │ ├── hvm_op.h │ │ └── params.h │ ├── hypercall.h │ ├── io │ │ ├── blkif.h │ │ ├── netif.h │ │ ├── protocols.h │ │ ├── ring.h │ │ ├── xenbus.h │ │ └── xs_wire.h │ ├── memory.h │ ├── physdev.h │ ├── platform.h │ ├── trace.h │ ├── vcpu.h │ ├── version.h │ ├── xen-compat.h │ └── xen.h │ ├── xen.c │ ├── xen_internal.h │ ├── xenblk.c │ └── xennet.c ├── test ├── Makefile ├── e2e │ ├── Makefile │ ├── cloud_init │ │ ├── config.json │ │ └── main.go │ ├── e2e.go │ ├── e2e_test.go │ ├── go.mod │ ├── go │ │ ├── config.json │ │ └── main.go │ ├── nginx_1.15.6 │ │ ├── config.json │ │ ├── index.html │ │ └── usr │ │ │ └── local │ │ │ └── nginx │ │ │ └── conf │ │ │ └── nginx.conf │ ├── node_alloc │ │ ├── alloc.js │ │ └── config.json │ ├── node_v11.5.0 │ │ ├── config.json │ │ └── hi.js │ ├── php_7.3.5 │ │ ├── b.php │ │ └── config.json │ ├── python_3.6.7 │ │ └── config.json │ ├── python_alloc │ │ ├── alloc.py │ │ └── config.json │ ├── ruby_3.1.2 │ │ ├── config.json │ │ └── myapp.rb │ ├── ruby_alloc │ │ ├── config.json │ │ └── myapp.rb │ ├── rust │ │ ├── config.json │ │ └── http_server.rs │ └── stressdisk │ │ ├── config.json │ │ └── main.go ├── extended_tests.py ├── functional.sh ├── go │ ├── Makefile │ ├── common.go │ ├── go.mod │ ├── go_test.go │ └── js │ │ └── hello.js ├── runtime │ ├── Makefile │ ├── README.md │ ├── aio.c │ ├── aio.manifest │ ├── aslr.c │ ├── aslr.manifest │ ├── creat.c │ ├── creat.manifest │ ├── dummy.manifest │ ├── dup.c │ ├── dup.manifest │ ├── epoll.c │ ├── epoll.manifest │ ├── eventfd.c │ ├── eventfd.manifest │ ├── fadvise.c │ ├── fadvise.manifest │ ├── fallocate.c │ ├── fallocate.manifest │ ├── fcntl.c │ ├── fcntl.manifest │ ├── fs_full.c │ ├── fs_full.manifest │ ├── fst.go │ ├── fst.manifest │ ├── ftrace.c │ ├── ftrace.manifest │ ├── futex.c │ ├── futex.manifest │ ├── futexrobust.c │ ├── futexrobust.manifest │ ├── getdents.c │ ├── getdents.manifest │ ├── getdents_contents │ │ ├── a │ │ │ └── hello │ │ └── b │ │ │ └── stuff │ ├── getrandom.c │ ├── getrandom.manifest │ ├── hw.c │ ├── hw.manifest │ ├── hwg.go │ ├── hwg.manifest │ ├── hws.manifest │ ├── inotify.c │ ├── inotify.manifest │ ├── io_uring.c │ ├── io_uring.manifest │ ├── ktest.c │ ├── ktest.manifest │ ├── mkdir.c │ ├── mkdir.manifest │ ├── mmap.c │ ├── mmap.manifest │ ├── netlink.c │ ├── netlink.manifest │ ├── netsock.c │ ├── netsock.manifest │ ├── nullpage.c │ ├── nullpage.manifest │ ├── paging.c │ ├── paging.manifest │ ├── pipe.c │ ├── pipe.manifest │ ├── read_contents │ │ ├── hello │ │ ├── mapfile │ │ ├── testpath │ │ └── unmapme │ ├── readv.c │ ├── readv.manifest │ ├── rename.c │ ├── rename.manifest │ ├── resolv.conf │ ├── sandbox.c │ ├── sandbox.manifest │ ├── sendfile.c │ ├── sendfile.manifest │ ├── shmem.c │ ├── shmem.manifest │ ├── signal.c │ ├── signal.manifest │ ├── sigoverflow.c │ ├── sigoverflow.manifest │ ├── socketpair.c │ ├── socketpair.manifest │ ├── symlink.c │ ├── symlink.manifest │ ├── syslog.c │ ├── syslog.manifest │ ├── thread_test.c │ ├── thread_test.manifest │ ├── time.c │ ├── time.manifest │ ├── tlbshootdown.c │ ├── tlbshootdown.manifest │ ├── tun.c │ ├── tun.manifest │ ├── udploop.c │ ├── udploop.manifest │ ├── umcg.c │ ├── umcg.manifest │ ├── unixsocket.c │ ├── unixsocket.manifest │ ├── unlink.c │ ├── unlink.manifest │ ├── vsyscall.c │ ├── vsyscall.manifest │ ├── web.c │ ├── web.manifest │ ├── webg.go │ ├── webg.manifest │ ├── webs-poll.manifest │ ├── webs-select.manifest │ ├── webs.manifest │ ├── write.c │ ├── write.manifest │ ├── write_contents │ │ ├── hello │ │ ├── infile │ │ └── outfile │ ├── writev.c │ └── writev.manifest ├── test_utils.h └── unit │ ├── Makefile │ ├── bitmap_test.c │ ├── buffer_test.c │ ├── closure_test.c │ ├── id_heap_test.c │ ├── memops_test.c │ ├── network_test.c │ ├── objcache_test.c │ ├── pageheap_test.c │ ├── parser_test.c │ ├── pqueue_test.c │ ├── queue_test.c │ ├── random_test.c │ ├── range_test.c │ ├── rbtree_test.c │ ├── table_test.c │ ├── tuple_test.c │ ├── udp_test.c │ └── vector_test.c ├── tools ├── Makefile ├── contgen.c ├── dump.c ├── lockstat.py ├── mkfs.c ├── nanos_gdb.py ├── tfs-fuse.c ├── trace-utilities │ ├── parse-trace-fg.py │ ├── parse-trace.py │ ├── readme.md │ ├── runtime-breakdown.py │ ├── summarize-trace.awk │ ├── trace-all.png │ └── trace-no-sleep-or-ftrace.png └── vdsogen.c └── vars.mk /.gdbinit: -------------------------------------------------------------------------------- 1 | macro define offsetof(t, f) (size_t)&((t *)0)->f 2 | macro define container_of(p, t, f) (t *)((void *)p - offsetof(t, f)) 3 | 4 | source tools/nanos_gdb.py 5 | 6 | -------------------------------------------------------------------------------- /.gdbinit-aarch64: -------------------------------------------------------------------------------- 1 | set architecture aarch64 2 | file ./output/platform/virt/bin/kernel.elf -o 0xffffffff3fc00000 3 | target remote :1234 4 | 5 | -------------------------------------------------------------------------------- /.gdbinit-riscv64: -------------------------------------------------------------------------------- 1 | set architecture riscv:rv64 2 | file ./output/platform/riscv-virt/bin/kernel.elf -o 0xfffffffeffe00000 3 | target remote :1234 4 | 5 | -------------------------------------------------------------------------------- /.gdbinit-x86-64: -------------------------------------------------------------------------------- 1 | set architecture i386:x86-64 2 | file ./output/platform/pc/bin/kernel.elf -o 0xffffffff7fe00000 3 | target remote :1234 4 | 5 | -------------------------------------------------------------------------------- /.github/workflows/main.yml: -------------------------------------------------------------------------------- 1 | name: Build 2 | on: 3 | push: 4 | branches: 5 | - 'feature/**' 6 | - 'fix/**' 7 | pull_request: 8 | jobs: 9 | mac-build: 10 | name: Mac Build 11 | runs-on: macos-latest 12 | steps: 13 | - name: Check out repository 14 | uses: actions/checkout@v4 15 | - name: Install tools 16 | run: brew install nasm x86_64-elf-binutils aarch64-elf-binutils 17 | - name: x86 build 18 | run: make -j`sysctl -n hw.ncpu` kernel PLATFORM=pc 19 | - name: ARM build 20 | run: make -j`sysctl -n hw.ncpu` kernel PLATFORM=virt 21 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | html/ 2 | latex/ 3 | 4 | target-root/ 5 | 6 | Makefile.local 7 | /tags 8 | /TAGS 9 | /GTAGS 10 | /GPATH 11 | /GRTAGS 12 | 13 | # test artifacts 14 | /test/go/go.sum 15 | /test/go/instance.img 16 | /test/go/image* 17 | /test/go/.staging/* 18 | /test/go/image 19 | /test/runtime/soop.data 20 | .ruby 21 | test/e2e/*/main 22 | 23 | # Default build directory 24 | /output 25 | 26 | # release 27 | /release 28 | latest.txt 29 | *.md5 30 | 31 | # Vendored libaries 32 | /vendor 33 | 34 | # Editor stuff 35 | *~ 36 | .vscode 37 | *.swo 38 | *.swp 39 | -------------------------------------------------------------------------------- /CHARTER.md: -------------------------------------------------------------------------------- 1 | # Nano Charter 2 | 3 | ## Mission 4 | 5 | ## Tenets (unless you know better ones) 6 | 7 | These tenets guide Nanos' development: 8 | 9 | 1. **Security**: 10 | 11 | Nanos aims to be a much more secure system than Linux. It does this 12 | through several thrusts. Not having the notion of users, running a 13 | single process per vm, and limiting the amount of code that is 14 | incorporated into each vm. 15 | 16 | 2. **Minimalist**: 17 | 18 | KISS. As Nanos is not intended to be ran on bare metal we strive to keep 19 | the core as simple as possible. 20 | 21 | 3. **Performance**: 22 | 23 | ## Contributions & Project Roles 24 | 25 | All contributions must align with this charter. 26 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | __STYLE GUIDE__ 2 | 3 | __LICENSE__ 4 | -------------------------------------------------------------------------------- /FAQ.md: -------------------------------------------------------------------------------- 1 | __FAQ__ 2 | 3 | Q: Is 32 bit supported? 4 | 5 | A: No and no intention. 6 | 7 | Q: Do you support multiple processes? 8 | 9 | A: No and no intention. 10 | 11 | Q: Do you support multiple threads? 12 | 13 | A: Yes. 14 | 15 | Q: Do you support ARM? 16 | 17 | A: We do somewhat. Today Nanos can run on the RPI4. 18 | 19 | [https://nanovms.com/dev/tutorials/nanos-on-64-bit-arm](https://nanovms.com/dev/tutorials/nanos-on-64-bit-arm) 20 | 21 | Q: Do you run in kubernetes? 22 | 23 | A: You can but you'll want to have access to virtualization as 24 | kubernetes is maily used for containers not vms. For more information 25 | check out [https://nanovms.gitbook.io/ops/k8s](https://nanovms.gitbook.io/ops/k8s) . 26 | 27 | Have other questions? Check out the [FAQ](https://nanos.org/faq) on the official Nanos website. 28 | -------------------------------------------------------------------------------- /ROADMAP.md: -------------------------------------------------------------------------------- 1 | __Roadmap__ 2 | 3 | This document is intended to track large features that are on the 4 | engineering roadmap. This is not an authoritative document - we 5 | obviously have internal project management/roadmaps. It's mainly here 6 | just to reduce questions. 7 | 8 | It should not be assumed that the architecture is 'set' based on this 9 | roadmap. We have many other features that might appear down the road. 10 | 11 | - [ ] AWS C series support 12 | - [ ] SMP 13 | - [ ] ESX 14 | - [ ] Hyper-V 15 | -------------------------------------------------------------------------------- /SECURITY.md: -------------------------------------------------------------------------------- 1 | ## Security 2 | 3 | Security is not binary. Software is not 'secure' or 'insecure'. It's 4 | more of a spectrum. 5 | 6 | This document contains any pro-active measures we've enabled. 7 | 8 | __ASLR__: 9 | 10 | * Stack Randomization 11 | 12 | * Heap Randomization 13 | 14 | * Library Randomization 15 | 16 | * Binary Randomization 17 | 18 | __KASLR__: 19 | 20 | * Kernel Load Address Randomization 21 | 22 | * Klib Load Address Randomization 23 | 24 | __Page Protections__: 25 | 26 | * Stack Execution off by Default 27 | 28 | * Heap Execution off by Default 29 | 30 | * Null Page is Not Mapped 31 | 32 | * Stack Cookies/Canaries 33 | 34 | * Rodata no execute 35 | 36 | * Text no write 37 | 38 | * Guard gap between process stack and adjacent mapping 39 | 40 | __Random Number Generation__: 41 | 42 | * virtio-rng driver 43 | 44 | * rdseed and rdrand CPU instructions on x86 platforms 45 | 46 | By default neither the user application nor the interpreter is allowed to be overwritten. 47 | 48 | Optional 'exec_protection' may also be turned on where one needs to 49 | explicitly mark files as executable. When this is turned on the 50 | application can not modify the executable and cannot create new 51 | executable files. 52 | 53 | Nanos also supports the pledge and unveil syscalls from OpenBSD for more 54 | restricted operating modes. 55 | 56 | ## Other Considerations 57 | 58 | * Single Process 59 | 60 | * No Users 61 | 62 | * No Shell 63 | 64 | To report security issues email security @ . We don't do PGP. 65 | (https://gist.github.com/rjhansen/67ab921ffb4084c865b3618d6955275f) 66 | -------------------------------------------------------------------------------- /doc/demo.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nanovms/nanos/478b8825bd6edc382080a772b228a49d26d2644b/doc/demo.gif -------------------------------------------------------------------------------- /klib/aws.h: -------------------------------------------------------------------------------- 1 | #define AWS_ERR_TOKEN_EXPIRED "ExpiredTokenException" 2 | 3 | boolean aws_metadata_available(void); 4 | void aws_metadata_get(heap h, sstring uri, buffer_handler handler); 5 | 6 | static inline void aws_region_get(heap h, buffer_handler handler) 7 | { 8 | aws_metadata_get(h, ss("/latest/meta-data/placement/region"), handler); 9 | } 10 | 11 | static inline void aws_hostname_get(heap h, buffer_handler handler) 12 | { 13 | aws_metadata_get(h, ss("/latest/meta-data/hostname"), handler); 14 | } 15 | 16 | typedef struct aws_cred { 17 | buffer access_key; 18 | buffer secret; 19 | buffer token; 20 | } *aws_cred; 21 | closure_type(aws_cred_handler, void, aws_cred cred); 22 | void aws_cred_get(heap h, aws_cred_handler handler); 23 | 24 | void aws_req_set_date(tuple req, buffer b); 25 | 26 | buffer aws_req_sign(heap h, sstring region, sstring service, sstring method, 27 | tuple req, buffer body, sstring access_key, sstring secret); 28 | -------------------------------------------------------------------------------- /klib/azure.h: -------------------------------------------------------------------------------- 1 | #ifndef AZURE_H_ 2 | #define AZURE_H_ 3 | 4 | typedef struct azure_ext { 5 | sstring name; 6 | sstring version; 7 | status s; 8 | u64 cfg_seconds; 9 | u64 cfg_seqno; 10 | } *azure_ext; 11 | 12 | closure_type(az_instance_md_handler, void, tuple md); 13 | 14 | boolean azure_register_ext(azure_ext ext); 15 | 16 | int azure_diag_init(tuple cfg); 17 | 18 | void azure_instance_md_get(az_instance_md_handler complete); 19 | 20 | void iso8601_write_interval(timestamp interval, buffer out); 21 | 22 | #endif 23 | -------------------------------------------------------------------------------- /klib/cloud_init.h: -------------------------------------------------------------------------------- 1 | boolean azure_cloud_init(heap h); 2 | -------------------------------------------------------------------------------- /klib/crc.h: -------------------------------------------------------------------------------- 1 | #ifndef _CRC_H_ 2 | #define _CRC_H_ 3 | 4 | u32 crc32c(const u8 *data, bytes len); 5 | 6 | #endif 7 | -------------------------------------------------------------------------------- /klib/klib.h: -------------------------------------------------------------------------------- 1 | enum { 2 | KLIB_INIT_OK = 0, 3 | KLIB_LOAD_FAILED, 4 | KLIB_MISSING_DEP, 5 | KLIB_INIT_IN_PROGRESS, 6 | KLIB_INIT_FAILED 7 | }; 8 | -------------------------------------------------------------------------------- /klib/mbedtls_conf.h: -------------------------------------------------------------------------------- 1 | #ifndef _RUNTIME_H_ 2 | #include 3 | #endif 4 | #include 5 | 6 | #define NULL ((void *)0) 7 | 8 | #define CHAR_BIT 8 9 | 10 | #define INT_MAX 0x7fffffff 11 | #define UINT_MAX 0xffffffff 12 | #define SIZE_MAX 0x7fffffffffffffffll 13 | 14 | typedef signed char int8_t; 15 | typedef unsigned char uint8_t; 16 | typedef short int16_t; 17 | typedef unsigned short uint16_t; 18 | typedef int int32_t; 19 | typedef unsigned int uint32_t; 20 | typedef long int64_t; 21 | typedef unsigned long uint64_t; 22 | 23 | typedef unsigned long size_t; 24 | typedef unsigned long uintptr_t; 25 | 26 | #define MBEDTLS_PLATFORM_CALLOC_MACRO mbedtls_calloc 27 | #define MBEDTLS_PLATFORM_FREE_MACRO mbedtls_free 28 | #define MBEDTLS_PLATFORM_TIME_MACRO rtime 29 | #define MBEDTLS_PLATFORM_TIME_TYPE_MACRO long 30 | #define MBEDTLS_PLATFORM_SNPRINTF_MACRO rsnprintf 31 | 32 | void *mbedtls_calloc(size_t n, size_t s); 33 | void mbedtls_free(void *ptr); 34 | 35 | #ifndef memset 36 | #define memset(block, c, size) runtime_memset((void *)(block), c, size) 37 | #endif 38 | #ifndef memcpy 39 | #define memcpy runtime_memcpy 40 | #endif 41 | #ifndef memmove 42 | #define memmove runtime_memcpy 43 | #endif 44 | #ifndef memcmp 45 | #define memcmp runtime_memcmp 46 | #endif 47 | #ifndef strcmp 48 | #define strcmp runtime_strcmp 49 | #endif 50 | #ifndef strchr 51 | #define strchr runtime_strchr 52 | #endif 53 | #ifndef strstr 54 | #define strstr runtime_strstr 55 | #endif 56 | -------------------------------------------------------------------------------- /klib/net_utils.h: -------------------------------------------------------------------------------- 1 | #ifndef NET_UTILS_H_ 2 | #define NET_UTILS_H_ 3 | 4 | #include 5 | 6 | typedef struct net_http_req_params { 7 | sstring host; 8 | tuple req; 9 | buffer body; 10 | value_handler resp_handler; 11 | http_method method; 12 | u16 port; 13 | boolean tls; 14 | } *net_http_req_params; 15 | 16 | void net_resolve(sstring host, void (*cb)(sstring host, const ip_addr_t *addr, void *cb_arg), 17 | void *cb_arg); 18 | 19 | status net_http_req(net_http_req_params params); 20 | 21 | #endif 22 | -------------------------------------------------------------------------------- /klib/sandbox.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include "sandbox.h" 4 | 5 | static struct sb_syscall sb_syscalls[SYS_MAX]; 6 | 7 | static sysreturn sb_handler(u64 arg0, u64 arg1, u64 arg2, u64 arg3, u64 arg4, u64 arg5) 8 | { 9 | syscall_context sc = (syscall_context)get_current_context(current_cpu()); 10 | sb_syscall sbsc = &sb_syscalls[sc->call]; 11 | sb_syscall_handler h; 12 | sysreturn rv; 13 | vector_foreach(&sbsc->sb_handlers, h) { 14 | if (h(arg0, arg1, arg2, arg3, arg4, arg5, &rv)) 15 | return rv; 16 | } 17 | if (sbsc->default_handler) 18 | return sbsc->default_handler(arg0, arg1, arg2, arg3, arg4, arg5); 19 | else 20 | return -ENOSYS; 21 | } 22 | 23 | int init(status_handler complete) 24 | { 25 | tuple root = get_root_tuple(); 26 | if (!root) 27 | return KLIB_INIT_FAILED; 28 | tuple sb_config = get_tuple(root, sym(sandbox)); 29 | if (!sb_config) 30 | return KLIB_INIT_OK; 31 | heap h = heap_locked(get_kernel_heaps()); 32 | for (int i = 0; i < SYS_MAX; i++) { 33 | bytes handler_memsize = 2 * sizeof(sb_syscall_handler); 34 | void *handlers_mem = allocate(h, handler_memsize); 35 | assert(handlers_mem != INVALID_ADDRESS); 36 | init_buffer(&sb_syscalls[i].sb_handlers, handler_memsize, false, h, handlers_mem); 37 | } 38 | tuple pledge_cfg = get_tuple(sb_config, sym(pledge)); 39 | if (pledge_cfg && !pledge_init(sb_syscalls, pledge_cfg)) 40 | return KLIB_INIT_FAILED; 41 | tuple unveil_cfg = get_tuple(sb_config, sym(unveil)); 42 | if (unveil_cfg && !unveil_init(sb_syscalls, unveil_cfg)) 43 | return KLIB_INIT_FAILED; 44 | for (int i = 0; i < SYS_MAX; i++) { 45 | sb_syscall sbsc = &sb_syscalls[i]; 46 | if (buffer_length(&sbsc->sb_handlers) != 0) 47 | sbsc->default_handler = swap_syscall_handler(linux_syscalls, i, sb_handler); 48 | } 49 | return KLIB_INIT_OK; 50 | } 51 | -------------------------------------------------------------------------------- /klib/sandbox.h: -------------------------------------------------------------------------------- 1 | typedef boolean (*sb_syscall_handler)(u64 arg0, u64 arg1, u64 arg2, u64 arg3, u64 arg4, u64 arg5, 2 | sysreturn *rv); 3 | 4 | typedef struct sb_syscall { 5 | struct buffer sb_handlers; 6 | sysreturn (*default_handler)(u64 arg0, u64 arg1, u64 arg2, u64 arg3, u64 arg4, u64 arg5); 7 | } *sb_syscall; 8 | 9 | /* OpenBSD syscalls, mapped to unused syscall numbers in Linux */ 10 | #define SYS_pledge 335 11 | #define SYS_unveil 336 12 | 13 | boolean pledge_init(sb_syscall syscalls, tuple cfg); 14 | boolean unveil_init(sb_syscall syscalls, tuple cfg); 15 | -------------------------------------------------------------------------------- /klib/shmem.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #define MEMFD_KNOWN_FLAGS \ 6 | (MFD_CLOEXEC | MFD_ALLOW_SEALING) 7 | 8 | static struct { 9 | filesystem fs; 10 | } shmem; 11 | 12 | sysreturn memfd_create(const char *name, unsigned int flags) 13 | { 14 | if (flags & ~MEMFD_KNOWN_FLAGS) 15 | return -EINVAL; 16 | filesystem fs = shmem.fs; 17 | fsfile fsf; 18 | filesystem_lock(fs); 19 | int fss = filesystem_creat_unnamed(fs, &fsf); 20 | if (fss == 0) { 21 | if (!(flags & MFD_ALLOW_SEALING)) 22 | fss = fs->set_seals(fs, fsf, F_SEAL_SEAL); 23 | } else { 24 | fsf = 0; 25 | } 26 | sysreturn rv; 27 | if (fss == 0) 28 | rv = unix_file_new(fs, fs->root, FDESC_TYPE_REGULAR, O_RDWR | O_TMPFILE, fsf); 29 | else 30 | rv = fss; 31 | filesystem_unlock(fs); 32 | if ((rv < 0) && fsf) 33 | fsfile_release(fsf); 34 | return rv; 35 | } 36 | 37 | int init(status_handler complete) 38 | { 39 | shmem.fs = tmpfs_new(); 40 | if (shmem.fs == INVALID_ADDRESS) { 41 | msg_err("shmem: failed to create tmpfs"); 42 | return KLIB_INIT_FAILED; 43 | } 44 | swap_syscall_handler(linux_syscalls, SYS_memfd_create, memfd_create); 45 | return KLIB_INIT_OK; 46 | } 47 | -------------------------------------------------------------------------------- /klib/test/klib.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #define Z_LEN 1024 4 | 5 | int y = 123; 6 | unsigned long z[Z_LEN]; 7 | 8 | int foo(int x) 9 | { 10 | z[0] = x; /* bss write */ 11 | return z[0] + y; /* test data */ 12 | } 13 | 14 | int init(status_handler complete) 15 | { 16 | /* test that bss is clear */ 17 | for (int i = 0; i < Z_LEN; i++) 18 | if (z[i] != 0) 19 | return KLIB_INIT_FAILED; 20 | 21 | int r = foo(1); 22 | if (r != 124) 23 | return KLIB_INIT_FAILED; 24 | 25 | unsigned long a = -1ull; 26 | runtime_memset((void *)&a, 0, sizeof(unsigned long)); 27 | return a == 0 ? KLIB_INIT_OK : KLIB_INIT_FAILED; 28 | } 29 | -------------------------------------------------------------------------------- /klib/test/lock.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | static boolean klib_test_rw_spinlock(void) 4 | { 5 | struct rw_spinlock l; 6 | spin_rw_lock_init(&l); 7 | if (!spin_tryrlock(&l)) { 8 | msg_err("%s: couldn't rlock unlocked spinlock", func_ss); 9 | return false; 10 | } 11 | if (spin_trywlock(&l)) { 12 | msg_err("%s: could wlock rlocked spinlock", func_ss); 13 | return false; 14 | } 15 | #if defined(SMP_ENABLE) 16 | if (!spin_tryrlock(&l)) { 17 | msg_err("%s: couldn't rlock rlocked spinlock", func_ss); 18 | return false; 19 | } 20 | spin_runlock(&l); 21 | #endif 22 | spin_runlock(&l); 23 | if (!spin_trywlock(&l)) { 24 | msg_err("%s: couldn't wlock unlocked spinlock", func_ss); 25 | return false; 26 | } 27 | if (spin_tryrlock(&l)) { 28 | msg_err("%s: could rlock wlocked spinlock", func_ss); 29 | return false; 30 | } 31 | if (spin_trywlock(&l)) { 32 | msg_err("%s: could wlock wlocked spinlock", func_ss); 33 | return false; 34 | } 35 | spin_wunlock(&l); 36 | return true; 37 | } 38 | 39 | int init(status_handler complete) 40 | { 41 | if (!klib_test_rw_spinlock()) 42 | return KLIB_INIT_FAILED; 43 | rprintf("Lock test OK\n"); 44 | return KLIB_INIT_OK; 45 | } 46 | -------------------------------------------------------------------------------- /klib/tls.h: -------------------------------------------------------------------------------- 1 | int tls_set_cacert(void *cert, u64 len); 2 | int tls_connect(ip_addr_t *addr, u16 port, connection_handler ch); 3 | -------------------------------------------------------------------------------- /klib/tmpfs.h: -------------------------------------------------------------------------------- 1 | #ifndef _TMPFS_H_ 2 | #define _TMPFS_H_ 3 | 4 | typedef struct tmpfs { 5 | struct filesystem fs; 6 | table files; 7 | int page_order; 8 | } *tmpfs; 9 | 10 | filesystem tmpfs_new(void); 11 | 12 | #endif 13 | -------------------------------------------------------------------------------- /klib/xml.h: -------------------------------------------------------------------------------- 1 | #ifndef XML_H_ 2 | #define XML_H_ 3 | 4 | typedef struct xml_elem { 5 | bytes start, len; 6 | bytes data_start, data_len; 7 | } *xml_elem; 8 | 9 | boolean xml_get_elem(buffer b, sstring name, xml_elem elem); 10 | boolean xml_elem_get_attr(buffer b, xml_elem elem, sstring name, bytes *start, bytes *len); 11 | 12 | #endif 13 | -------------------------------------------------------------------------------- /networking_setup: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # find the first ethernet adapter name 4 | ETH0="$(ip link | awk -F: '$0 !~ "lo|vir|wl|^[^0-9]"{print $2;getline}')" 5 | ##Setup 6 | # create bridge named br0. 7 | ip link add br0 type bridge 8 | # bring up the bridge. 9 | ip link set br0 up 10 | # add the ethernet adapter eth0 to bridge. 11 | ip link set $(ETH0) master br0 12 | # create a tap device named tap0. 13 | ip tuntap add tap0 mode tap user `whoami` 14 | # bring up the tap. 15 | ip link set tap0 up 16 | # add tap0 to bridge. 17 | ip link set tap0 master br0 18 | # assign ip to bridge. 19 | dhclient -v br0 20 | 21 | ##Cleanup 22 | # remove eth0 from br0. 23 | ip link set $(ETH0) nomaster 24 | # remove tap0 from br0. 25 | ip link set tap0 nomaster 26 | # take down tap0. 27 | ip link set tap0 down 28 | # delete the bridge. 29 | ip link delete br0 type bridge 30 | # delete tap0 31 | ip link delete tap0. 32 | # you might have to renew your IP 33 | dhclient -v $(ETH0) 34 | -------------------------------------------------------------------------------- /platform/pc/.gdb: -------------------------------------------------------------------------------- 1 | display/i $pc 2 | target remote :1234 3 | b *0x00080a6 4 | c 5 | disconnect 6 | set architecture i386:x86-64:intel 7 | target remote :1234 8 | -------------------------------------------------------------------------------- /platform/pc/boot/csum.inc: -------------------------------------------------------------------------------- 1 | csum: 2 | xor eax, eax 3 | .loop: 4 | add eax, [si] 5 | add si, 4 6 | sub cx, 4 7 | jnz .loop 8 | ret 9 | -------------------------------------------------------------------------------- /platform/pc/boot/linker_script: -------------------------------------------------------------------------------- 1 | OUTPUT_FORMAT("elf32-i386", "elf32-i386", "elf32-i386") 2 | OUTPUT_ARCH(i386) 3 | 4 | ENTRY(_start) 5 | 6 | PHDRS 7 | { 8 | text PT_LOAD FLAGS(5); /* R E */ 9 | rodata PT_LOAD FLAGS(4); /* R */ 10 | data PT_LOAD FLAGS(6); /* RW */ 11 | } 12 | 13 | SECTIONS 14 | { 15 | . = 0x8000; 16 | .start : { *(.start)} :text 17 | .text : { *(.text) *(.text.*) } :text 18 | .rodata : { *(.rodata) *(.rodata.*) } :rodata 19 | .data : { *(.data) *(.data.*) } :data 20 | .bss ALIGN(32): { *(.bss) *(.bss.*) } :data 21 | } 22 | -------------------------------------------------------------------------------- /platform/pc/boot/longmode.inc: -------------------------------------------------------------------------------- 1 | %define CR0_PE (1<<0) 2 | %define CR0_MP (1<<1) 3 | %define CR0_EM (1<<2) 4 | %define CR0_PG (1<<31) 5 | 6 | %define CR4_PAE (1<<5) 7 | %define CR4_PGE (1<<7) 8 | %define CR4_OSFXSR (1<<9) 9 | %define CR4_OSXMMEXCPT (1<<10) 10 | %define CR4_OSXSAVE (1<<18) 11 | 12 | %define MSR_EFER 0xC0000080 13 | %define EFER_LME (1<<8) 14 | %define EFER_NXE (1<<11) 15 | 16 | %macro PREPARE_LONG_MODE 1 17 | mov %1, CR4_PAE 18 | mov cr4, %1 19 | 20 | mov ecx, MSR_EFER ; Read from the EFER MSR. 21 | rdmsr 22 | or %1, EFER_LME | EFER_NXE ; Set the LME bit and nxe 23 | wrmsr 24 | %endmacro 25 | 26 | %macro ENTER_LONG_MODE 1 27 | mov %1, cr0 ; Activate long mode - 28 | or %1, CR0_PG | CR0_PE ; - by enabling paging and protection simultaneously. 29 | mov cr0, %1 30 | %endmacro 31 | 32 | -------------------------------------------------------------------------------- /platform/pc/test-libs: -------------------------------------------------------------------------------- 1 | lib:(children:(x86_64-linux-gnu:(children:(libc.so.6:(contents:(host:/lib/x86_64-linux-gnu/libc.so.6)) libpthread.so.0:(contents:(host:/lib/x86_64-linux-gnu/libpthread.so.0)) libresolv.so.2:(contents:(host:/lib/x86_64-linux-gnu/libresolv.so.2)))))) lib64:(children:(ld-linux-x86-64.so.2:(contents:(host:/lib64/ld-linux-x86-64.so.2)))) -------------------------------------------------------------------------------- /platform/riscv-virt/kernel_platform.h: -------------------------------------------------------------------------------- 1 | #define PHYSMEM_BASE 0x80000000 2 | #define BIOS_SIZE (256*KB) 3 | #define DTB_SIZE (16*KB) 4 | #define INIT_PAGEMEM (PHYSMEM_BASE+BIOS_SIZE+DTB_SIZE) 5 | #define INIT_IDENTITY_SIZE 0x00800000 6 | 7 | #define DEVICETREE_BLOB_BASE (KERNEL_BASE-DTB_SIZE) 8 | 9 | #define DEV_MAP_SIZE 0x80000000 10 | #define DEV_BASE_UART 0x10000000 11 | #define DEV_BASE_CLINT 0x02000000 12 | #define DEV_BASE_PLIC 0x0c000000 13 | #define DEV_BASE_RTC 0x00101000 14 | #define DEV_BASE_SYSCON 0x00100000 15 | #define DEV_BASE_PCIE_ECAM 0x30000000 16 | #define DEV_BASE_PCIE_MMIO 0x40000000 17 | #define DEV_BASE_PCIE_PIO 0x03000000 18 | 19 | #define SYSCON_POWEROFF 0x5555 20 | #define SYSCON_POWEROFF_FAIL 0x3333 21 | #define SYSCON_REBOOT 0x7777 22 | 23 | #ifndef __ASSEMBLY__ 24 | #define DEVICETREE pointer_from_u64(DEVICETREE_BLOB_BASE) 25 | 26 | #define mmio_base_addr(x) ((u64)(DEVICE_BASE + DEV_BASE_ ##x)) 27 | 28 | #include "sbi_ecall_interface.h" 29 | #endif 30 | -------------------------------------------------------------------------------- /platform/riscv-virt/test-libs: -------------------------------------------------------------------------------- 1 | lib:(children:(riscv64-linux-gnu:(children:(libc.so.6:(contents:(host:/lib/riscv64-linux-gnu/libc.so.6)) libpthread.so.0:(contents:(host:/lib/riscv64-linux-gnu/libpthread.so.0)) libresolv.so.2:(contents:(host:/lib/riscv64-linux-gnu/libresolv.so.2)))) ld-linux-riscv64-lp64d.so.1:(contents:(host:/lib/ld-linux-riscv64-lp64d.so.1)))) 2 | -------------------------------------------------------------------------------- /platform/virt/kernel_platform.h: -------------------------------------------------------------------------------- 1 | #define PHYSMEM_BASE 0x40000000 2 | #define PHYSMEM_BASE_MASK 0x3fffffff 3 | #define INIT_PAGEMEM 0x40200000 4 | #define INIT_IDENTITY_SIZE 0x00600000 5 | 6 | #define DEVICETREE_BLOB_BASE 0x40000000 7 | 8 | #define DEV_MAP_SIZE 0x40000000 9 | #define DEV_BASE_CPUPERIPHS 0x08000000 10 | #define DEV_BASE_GIC_DIST 0x08000000 11 | #define DEV_BASE_GIC_CPU 0x08010000 12 | #define DEV_BASE_GIC_V2M 0x08020000 13 | #define DEV_BASE_GIC_HYP 0x08030000 14 | #define DEV_BASE_GIC_VCPU 0x08040000 15 | #define DEV_BASE_GIC_ITS 0x08080000 16 | #define DEV_BASE_GIC_REDIST 0x080A0000 17 | #define DEV_BASE_UART 0x09000000 18 | #define DEV_BASE_RTC 0x09010000 19 | #define DEV_BASE_FW_CFG 0x09020000 20 | #define DEV_BASE_GPIO 0x09030000 21 | #define DEV_BASE_SECURE_UART 0x09040000 22 | #define DEV_BASE_SMMU 0x09050000 23 | #define DEV_BASE_PCDIMM_ACPI 0x09070000 24 | #define DEV_BASE_ACPI_GED 0x09080000 25 | #define DEV_BASE_NVDIMM_ACPI 0x09090000 26 | #define DEV_BASE_MMIO 0x0a000000 27 | #define DEV_BASE_PLATFORM_BUS 0x0c000000 28 | #define DEV_BASE_SECURE_MEM 0x0e000000 29 | #define DEV_BASE_PCIE_MMIO 0x10000000 30 | #define DEV_BASE_PCIE_PIO 0x3eff0000 31 | #define DEV_BASE_PCIE_ECAM 0x3f000000 32 | 33 | #define VIRT_PCIE_IRQ_BASE 3 34 | #define VIRT_PCIE_IRQ_NUM 4 35 | #define VIRT_GPIO_IRQ 7 36 | #define VIRT_MMIO_IRQ_BASE 16 37 | #define VIRT_MMIO_IRQ_NUM 32 38 | 39 | #ifndef __ASSEMBLY__ 40 | #define mmio_base_addr(x) ((u64)(DEVICE_BASE + DEV_BASE_ ##x)) 41 | 42 | #endif 43 | -------------------------------------------------------------------------------- /platform/virt/test-libs: -------------------------------------------------------------------------------- 1 | lib:(children:(aarch64-linux-gnu:(children:(libc.so.6:(contents:(host:/lib/aarch64-linux-gnu/libc.so.6)) libpthread.so.0:(contents:(host:/lib/aarch64-linux-gnu/libpthread.so.0)) libresolv.so.2:(contents:(host:/lib/aarch64-linux-gnu/libresolv.so.2)))) ld-linux-aarch64.so.1:(contents:(host:/lib/ld-linux-aarch64.so.1)))) -------------------------------------------------------------------------------- /release.md: -------------------------------------------------------------------------------- 1 | # Release Process 2 | 3 | ## Nanos 4 | Create a [github release](https://github.com/nanovms/nanos/releases) and build the source on 5 | Linux and Mac. Update the below. 6 | 7 | example: 8 | ``` 9 | ./release.sh 10 | ``` 11 | 12 | ## Ops 13 | 14 | See [OPS release.sh](https://github.com/nanovms/ops/blob/master/release.sh) 15 | 16 | ## Packages 17 | Follow the (PACKAGES.md)[PACKAGES.md] to update the packages. 18 | 19 | ## How end-user gets updates? 20 | Right now we dont push updates to user, but user need to request for update. 21 | 22 | 1. **Updating ops**: 23 | ``` 24 | ops update 25 | ``` 26 | 2. **Updating nanos**: 27 | ``` 28 | Use the -f flag with ops commands. 29 | ops run/load -f 30 | ``` 31 | -------------------------------------------------------------------------------- /scripts/readme.md: -------------------------------------------------------------------------------- 1 | First install apply-format package 2 | apt-get install apply-format or brew install apply-format 3 | 4 | Now run 5 | ``` 6 | scripts/apply-format 7 | ``` 8 | 9 | By default, apply-format reformats only the code which 10 | git diff would show, and prints the diff to the terminal.If you want to apply 11 | the changes, add it to you commit. 12 | 13 | See [here](https://github.com/barisione/clang-format-hooks) for more options. 14 | -------------------------------------------------------------------------------- /src/aarch64/acpi.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | void acpi_register_irq_handler(int irq, thunk t, sstring name) 7 | { 8 | irq_register_handler(irq, t, name, irange(0, 0)); 9 | } 10 | 11 | /* OS services layer */ 12 | 13 | ACPI_PHYSICAL_ADDRESS AcpiOsGetRootPointer(void) 14 | { 15 | return boot_params.acpi_rsdp; 16 | } 17 | 18 | ACPI_STATUS AcpiOsReadPort(ACPI_IO_ADDRESS address, UINT32 *value, UINT32 width) 19 | { 20 | switch (width) { 21 | case 8: 22 | *value = mmio_read_8(address); 23 | break; 24 | case 16: 25 | *value = mmio_read_16(address); 26 | break; 27 | case 32: 28 | *value = mmio_read_32(address); 29 | break; 30 | default: 31 | return AE_BAD_PARAMETER; 32 | } 33 | return AE_OK; 34 | } 35 | 36 | ACPI_STATUS AcpiOsWritePort(ACPI_IO_ADDRESS address, UINT32 value, UINT32 width) 37 | { 38 | switch (width) { 39 | case 8: 40 | mmio_write_8(address, value); 41 | break; 42 | case 16: 43 | mmio_write_16(address, value); 44 | break; 45 | case 32: 46 | mmio_write_32(address, value); 47 | break; 48 | default: 49 | return AE_BAD_PARAMETER; 50 | } 51 | return AE_OK; 52 | } 53 | -------------------------------------------------------------------------------- /src/aarch64/clock.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #define __vdso_dat (&(VVAR_REF(vdso_dat))) 5 | 6 | BSS_RO_AFTER_INIT clock_now platform_monotonic_now; 7 | BSS_RO_AFTER_INIT clock_timer platform_timer; 8 | 9 | static inline u64 cntfrq(void) 10 | { 11 | return read_psr(CNTFRQ_EL0); 12 | } 13 | 14 | closure_function(0, 0, timestamp, arm_clock_now) 15 | { 16 | u64 t = rdtsc(); 17 | u64 f = cntfrq(); 18 | u64 secs = t / f; 19 | u64 frac = t - secs * f; 20 | return seconds(secs) | ((frac << 32) / f); 21 | } 22 | 23 | closure_func_basic(clock_timer, void, arm_deadline_timer, 24 | timestamp interval) 25 | { 26 | write_psr(CNTV_TVAL_EL0, (cntfrq() * interval) >> 32); 27 | write_psr(CNTV_CTL_EL0, CNTV_CTL_EL0_ENABLE /* and clear imask */); 28 | } 29 | 30 | closure_function(0, 0, void, arm_timer_percpu_init) 31 | { 32 | } 33 | 34 | BSS_RO_AFTER_INIT closure_struct(arm_clock_now, _clock_now); 35 | BSS_RO_AFTER_INIT closure_struct(clock_timer, _deadline_timer); 36 | BSS_RO_AFTER_INIT closure_struct(arm_timer_percpu_init, _timer_percpu_init); 37 | 38 | void init_clock(void) 39 | { 40 | register_platform_clock_now(init_closure(&_clock_now, arm_clock_now), VDSO_CLOCK_SYSCALL, 0); 41 | register_platform_clock_timer(init_closure_func(&_deadline_timer, clock_timer, 42 | arm_deadline_timer), 43 | init_closure(&_timer_percpu_init, arm_timer_percpu_init)); 44 | } 45 | -------------------------------------------------------------------------------- /src/aarch64/def64.h: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nanovms/nanos/478b8825bd6edc382080a772b228a49d26d2644b/src/aarch64/def64.h -------------------------------------------------------------------------------- /src/aarch64/elf64.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #define R_AARCH64_GLOB_DAT 1025 5 | #define R_AARCH64_JUMP_SLOT 1026 6 | #define R_AARCH64_RELATIVE 1027 7 | 8 | void elf_apply_relocate_add(buffer elf, Elf64_Shdr *s, u64 offset) 9 | { 10 | Elf64_Rela *rel = buffer_ref(elf, s->sh_addr); 11 | for (int i = 0; i < s->sh_size / sizeof(*rel); i++) { 12 | void *loc = buffer_ref(elf, rel[i].r_offset); 13 | switch (ELF64_R_TYPE(rel[i].r_info)) { 14 | case R_AARCH64_RELATIVE: 15 | *(u64 *)loc += offset; 16 | break; 17 | } 18 | } 19 | } 20 | 21 | boolean elf_apply_relocate_syms(buffer elf, Elf64_Rela *rel, int relcount, 22 | elf_sym_relocator relocator) 23 | { 24 | for (int i = 0; i < relcount; i++) { 25 | switch (ELF64_R_TYPE(rel[i].r_info)) { 26 | case R_AARCH64_GLOB_DAT: 27 | case R_AARCH64_JUMP_SLOT: 28 | if (!apply(relocator, &rel[i])) 29 | return false; 30 | break; 31 | } 32 | } 33 | return true; 34 | } 35 | 36 | void arch_elf_relocate(Elf64_Rela *rel, u64 relsz, Elf64_Sym *syms, u64 base, u64 offset) 37 | { 38 | u64 *loc; 39 | u64 value; 40 | while (relsz > 0) { 41 | switch (ELF64_R_TYPE (rel->r_info)) { 42 | case R_AARCH64_RELATIVE: 43 | value = 0; 44 | break; 45 | default: 46 | goto next; 47 | } 48 | loc = pointer_from_u64(base + rel->r_offset); 49 | *loc = value + rel->r_addend + offset; 50 | next: 51 | rel++; 52 | relsz -= sizeof(*rel); 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /src/aarch64/gdb_machine.h: -------------------------------------------------------------------------------- 1 | 2 | static inline int computeSignal (context_frame c) 3 | { 4 | return 0; 5 | } 6 | 7 | static inline int get_register(u64 num, void *buf, context_frame c) 8 | { 9 | return -1; 10 | } 11 | 12 | static boolean set_thread_register(thread t, int regno, u64 val) 13 | { 14 | return false; 15 | } 16 | 17 | static inline void set_thread_pc(thread t, u64 addr) 18 | { 19 | } 20 | 21 | static inline void read_registers(buffer b, thread t) 22 | { 23 | } 24 | 25 | static inline void write_registers(buffer b, thread t) 26 | { 27 | } 28 | 29 | static inline void set_write_protect(boolean enable) 30 | { 31 | } 32 | 33 | boolean breakpoint_insert(heap h, u64 a, u8 type, u8 log_length, thunk completion) 34 | { 35 | return false; 36 | } 37 | 38 | boolean breakpoint_remove(heap h, u32 a, thunk completion) 39 | { 40 | return false; 41 | } 42 | -------------------------------------------------------------------------------- /src/aarch64/gpio.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #define PL061_GPIOIEV 0x40c 5 | #define PL061_GPIOIE 0x410 6 | #define PL061_GPIOIC 0x41c 7 | 8 | void gpio_irq_enable(u64 mask) 9 | { 10 | mmio_write_32(mmio_base_addr(GPIO) + PL061_GPIOIEV, mask); 11 | mmio_write_32(mmio_base_addr(GPIO) + PL061_GPIOIE, mask); 12 | } 13 | 14 | void gpio_irq_clear(u64 mask) 15 | { 16 | mmio_write_32(mmio_base_addr(GPIO) + PL061_GPIOIC, mask); 17 | } 18 | -------------------------------------------------------------------------------- /src/aarch64/gpio.h: -------------------------------------------------------------------------------- 1 | void gpio_irq_enable(u64 mask); 2 | void gpio_irq_clear(u64 mask); 3 | -------------------------------------------------------------------------------- /src/aarch64/hyperv.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #define HV_SMCCC_FUNC_NO 1 6 | 7 | #define HV_FUNC_ID (0x46000000 | HV_SMCCC_FUNC_NO) 8 | 9 | #define HVCALL_SET_VP_REGISTERS 0x0051 10 | #define HVCALL_GET_VP_REGISTERS 0x0050 11 | #define HV_HYPERCALL_FAST_BIT U64_FROM_BIT(16) 12 | #define HV_HYPERCALL_REP_COMP_1 U64_FROM_BIT(32) 13 | 14 | #define HV_PARTITION_ID_SELF (-1ull) 15 | 16 | #define HV_VP_INDEX_SELF (-2u) 17 | 18 | boolean hyperv_arch_detect(kernel_heaps kh) { 19 | u64 hv_id = acpi_get_hv_id(); 20 | if (runtime_memcmp(&hv_id, "MsHyperV", sizeof(hv_id))) 21 | return false; 22 | return true; 23 | } 24 | 25 | u64 aarch64_hv_get_vreg(u32 msr) 26 | { 27 | struct arm_hvc_full_ret ret = arm_hvc_full(HV_FUNC_ID, 28 | HVCALL_GET_VP_REGISTERS | HV_HYPERCALL_FAST_BIT | 29 | HV_HYPERCALL_REP_COMP_1, 30 | HV_PARTITION_ID_SELF, HV_VP_INDEX_SELF, msr); 31 | return ret.x6; 32 | } 33 | 34 | void aarch64_hv_set_vreg(u32 msr, u64 val) 35 | { 36 | arm_hvc(HV_FUNC_ID, HVCALL_SET_VP_REGISTERS | HV_HYPERCALL_FAST_BIT | HV_HYPERCALL_REP_COMP_1, 37 | HV_PARTITION_ID_SELF, HV_VP_INDEX_SELF, msr, 0, val, 0); 38 | } 39 | 40 | void hypercall_create(struct hypercall_ctx *hctx) 41 | { 42 | } 43 | 44 | u64 hypercall_md(volatile void *hc_addr, u64 in_val, u64 in_paddr, u64 out_paddr) 45 | { 46 | struct arm_hvc_ret ret = arm_hvc(HV_FUNC_ID, in_val, in_paddr, out_paddr, 0, 0, 0, 0); 47 | return ret.x0; 48 | } 49 | -------------------------------------------------------------------------------- /src/aarch64/klib.lds: -------------------------------------------------------------------------------- 1 | OUTPUT_FORMAT("elf64-littleaarch64") 2 | 3 | ENTRY(init) 4 | 5 | PHDRS 6 | { 7 | text PT_LOAD FLAGS(5); /* R E */ 8 | rodata PT_LOAD FLAGS(4); /* R */ 9 | data PT_LOAD FLAGS(6); /* RW */ 10 | } 11 | 12 | SECTIONS 13 | { 14 | . = SIZEOF_HEADERS; 15 | .text : { *(.text) *(.text.*) } :text 16 | . = ALIGN(4096); 17 | .rodata : { *(.rodata) *(.rodata.*) } :rodata 18 | 19 | . = ALIGN(4096); 20 | .data : { *(.data) *(.data.*) } :data 21 | .bss : { *(.bss) *(.bss.*) } :data 22 | 23 | /DISCARD/ : { *(.interp) } 24 | } 25 | -------------------------------------------------------------------------------- /src/aarch64/serial.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "serial.h" 4 | 5 | typedef struct pl011_console { 6 | struct console_driver driver; 7 | u32 *addr; 8 | } *pl011_console; 9 | 10 | RO_AFTER_INIT volatile u32 *UART0_DR = (volatile u32 *)DEV_BASE_UART; 11 | RO_AFTER_INIT volatile u32 *UART0_FR = (volatile u32 *)(DEV_BASE_UART + 0x18); 12 | 13 | #define UART_FR_TXFF (1 << 5) /* TX FIFO full */ 14 | 15 | static inline boolean tx_full(void) { 16 | return ((*UART0_FR) & UART_FR_TXFF) != 0; 17 | } 18 | 19 | /* This floods the ftrace buffers when user is outputting lots of data */ 20 | NOTRACE 21 | void serial_putchar(char c) 22 | { 23 | while (tx_full()); 24 | *UART0_DR = c; 25 | } 26 | 27 | void serial_set_devbase(u64 devbase) 28 | { 29 | UART0_DR = ((void*)UART0_DR) + devbase; 30 | UART0_FR = ((void*)UART0_FR) + devbase; 31 | } 32 | 33 | static void pl011_write(void *d, const char *s, bytes count) 34 | { 35 | pl011_console console = d; 36 | for (; count--; s++) { 37 | while (console->addr[6] & UART_FR_TXFF) 38 | ; 39 | console->addr[0] = *s; 40 | } 41 | } 42 | 43 | struct console_driver *pl011_console_init(kernel_heaps kh, void *base) 44 | { 45 | pl011_console console = allocate(heap_general(kh), sizeof(*console)); 46 | console->addr = base; 47 | zero(&console->driver, sizeof(console->driver)); 48 | console->driver.name = ss("pl011"); 49 | console->driver.write = pl011_write; 50 | return &console->driver; 51 | } 52 | -------------------------------------------------------------------------------- /src/aarch64/serial.h: -------------------------------------------------------------------------------- 1 | void serial_putchar(char c); 2 | void serial_set_devbase(u64 devbase); 3 | 4 | struct console_driver *pl011_console_init(kernel_heaps kh, void *base); 5 | -------------------------------------------------------------------------------- /src/aarch64/uefi.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | void uefi_arch_setup(heap general, heap aligned, uefi_arch_options options) 6 | { 7 | options->load_to_physical = true; 8 | } 9 | 10 | void uefi_start_kernel(void *image_handle, efi_system_table system_table, buffer kern_elf, 11 | void *kern_entry) 12 | { 13 | struct uefi_boot_params boot_params = {0}; 14 | for (int i = 0; i < system_table->number_of_table_entries; i++) { 15 | efi_configuration_table table = &system_table->configuration_table[i]; 16 | if (!runtime_memcmp(&table->guid, &uefi_acpi20_table, sizeof(table->guid))) { 17 | boot_params.acpi_rsdp = u64_from_pointer(table->table); 18 | } else if (!runtime_memcmp(&table->guid, &uefi_smbios_table, sizeof(table->guid))) { 19 | boot_params.smbios = u64_from_pointer(table->table); 20 | } 21 | } 22 | boot_params.efi_rt_svc = system_table->runtime_services; 23 | uefi_exit_bs(&boot_params.mem_map); 24 | 25 | /* disable MMU */ 26 | u64 sctlr = 0; 27 | asm volatile ("msr SCTLR_EL1, %0;" 28 | "isb":: "r" (sctlr)); 29 | 30 | void (*start)(u64 x0, u64 x1) = kern_entry; 31 | start(0, u64_from_pointer(&boot_params)); 32 | } 33 | 34 | physical map_with_complete(u64 v, physical p, u64 length, pageflags flags, status_handler complete) 35 | { 36 | /* Mapping is not needed, since the MMU is disabled before starting the kernel. */ 37 | if (complete) 38 | apply(complete, STATUS_OK); 39 | return p; 40 | } 41 | -------------------------------------------------------------------------------- /src/aarch64/uefi.lds: -------------------------------------------------------------------------------- 1 | OUTPUT_FORMAT("elf64-littleaarch64", "elf64-littleaarch64", "elf64-littleaarch64") 2 | OUTPUT_ARCH(aarch64) 3 | ENTRY(_start) 4 | SECTIONS 5 | { 6 | . = 0; 7 | .text : { 8 | *(.text.head) 9 | *(.text) 10 | *(.text.*) 11 | *(.gnu.linkonce.t.*) 12 | } 13 | 14 | . = ALIGN(4096); 15 | .reloc : { 16 | *(.reloc) 17 | } 18 | 19 | . = ALIGN(4096); 20 | .data : { 21 | _data = .; 22 | *(.rodata*) 23 | *(.got.plt) 24 | *(.got) 25 | *(.data*) 26 | *(.sdata) 27 | *(.sbss) 28 | *(.scommon) 29 | *(.dynbss) 30 | *(.bss) 31 | *(COMMON) 32 | *(.rel.local) 33 | } 34 | .note.gnu.build-id : { *(.note.gnu.build-id) } 35 | 36 | . = ALIGN(4096); 37 | .dynamic : { *(.dynamic) } 38 | 39 | _edata = .; 40 | _data_size = . - _data; 41 | 42 | . = ALIGN(4096); 43 | .dynsym : { *(.dynsym) } 44 | 45 | . = ALIGN(4096); 46 | .dynstr : { *(.dynstr) } 47 | 48 | . = ALIGN(4096); 49 | .ignored.reloc : { 50 | *(.rela.reloc) 51 | *(.eh_frame) 52 | *(.note.GNU-stack) 53 | } 54 | .comment 0 : { *(.comment) } 55 | } 56 | -------------------------------------------------------------------------------- /src/aws/aws.h: -------------------------------------------------------------------------------- 1 | void init_aws_ena(kernel_heaps kh); 2 | -------------------------------------------------------------------------------- /src/aws/ena/ena_com/ena_defs/ena_includes.h: -------------------------------------------------------------------------------- 1 | #include "ena_common_defs.h" 2 | #include "ena_regs_defs.h" 3 | #include "ena_admin_defs.h" 4 | #include "ena_eth_io_defs.h" 5 | -------------------------------------------------------------------------------- /src/aws/ena/ena_datapath.h: -------------------------------------------------------------------------------- 1 | /*- 2 | * SPDX-License-Identifier: BSD-2-Clause 3 | * 4 | * Copyright (c) 2015-2020 Amazon.com, Inc. or its affiliates. 5 | * All rights reserved. 6 | * 7 | * Redistribution and use in source and binary forms, with or without 8 | * modification, are permitted provided that the following conditions 9 | * are met: 10 | * 11 | * 1. Redistributions of source code must retain the above copyright 12 | * notice, this list of conditions and the following disclaimer. 13 | * 14 | * 2. Redistributions in binary form must reproduce the above copyright 15 | * notice, this list of conditions and the following disclaimer in the 16 | * documentation and/or other materials provided with the distribution. 17 | * 18 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 19 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 20 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 21 | * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 22 | * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 23 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 24 | * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 25 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 26 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 27 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 28 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 | */ 30 | 31 | #ifndef ENA_TXRX_H 32 | #define ENA_TXRX_H 33 | 34 | void ena_cleanup(void *arg, int pending); 35 | err_t ena_linkoutput(struct netif *netif, struct pbuf *p); 36 | void ena_deferred_mq_start(void *arg, int pending); 37 | 38 | #endif /* ENA_TXRX_H */ 39 | -------------------------------------------------------------------------------- /src/boot/boot.h: -------------------------------------------------------------------------------- 1 | #define physical_from_virtual(__x) u64_from_pointer(__x) 2 | 3 | typedef struct tagged_allocator { 4 | struct heap h; 5 | u8 tag; 6 | heap parent; 7 | } *tagged_allocator; 8 | 9 | static inline u64 tagged_allocate(heap h, bytes length) 10 | { 11 | tagged_allocator ta = (void *)h; 12 | u64 base = allocate_u64(ta->parent, length + 8); /* 8 bytes to preserve 64-bit alignment */ 13 | if (base == INVALID_PHYSICAL) 14 | return base; 15 | *(u8 *)pointer_from_u64(base + 7) = ta->tag; 16 | return base + 8; 17 | } 18 | 19 | static inline void tagged_deallocate(heap h, u64 a, bytes length) 20 | { 21 | tagged_allocator ta = (void *)h; 22 | deallocate_u64(ta->parent, a - 8, length + 8); 23 | } 24 | 25 | static inline heap allocate_tagged_region(heap h, u64 tag) 26 | { 27 | tagged_allocator ta = allocate(h, sizeof(struct tagged_allocator)); 28 | ta->h.alloc = tagged_allocate; 29 | ta->h.dealloc = tagged_deallocate; 30 | ta->tag = tag; 31 | ta->parent = h; 32 | return (heap)ta; 33 | } 34 | 35 | static inline __attribute__((always_inline)) u8 is_immediate(value v) 36 | { 37 | return ((word)v & 1) != 0; 38 | } 39 | 40 | static inline __attribute__((always_inline)) u8 is_immediate_integer(value v) 41 | { 42 | return ((word)v & 0x3) == 1; 43 | } 44 | 45 | static inline value_tag tagof(value v) 46 | { 47 | if (is_immediate_integer(v)) 48 | return tag_integer; 49 | return *((u8 *)v-1); 50 | } 51 | 52 | extern heap boot_buffer_heap; 53 | void *load_kernel_elf(buffer b, heap bss_heap); 54 | -------------------------------------------------------------------------------- /src/debug_all.h: -------------------------------------------------------------------------------- 1 | #define BLOCKQ_DEBUG 2 | #define CLOCK_DEBUG 3 | #define CONTEXT_DEBUG 4 | #define ELF_DEBUG 5 | #define EPOLL_DEBUG 6 | #define EXEC_DEBUG 7 | #define GDB_DEBUG 8 | #define INT_DEBUG 9 | #define IOUR_DEBUG 10 | #define KLIB_DEBUG 11 | #define KVM_DEBUG 12 | #define MGMT_DEBUG 13 | #define MUTEX_DEBUG 14 | #define NETLINK_DEBUG 15 | #define PAGECACHE_DEBUG 16 | #define PAGE_DEBUG 17 | #define PF_DEBUG 18 | #define PIPE_DEBUG 19 | #define SCHED_DEBUG 20 | #define SIGNAL_DEBUG 21 | #define STORAGE_DEBUG 22 | #define TFS_DEBUG 23 | #define TLOG_DEBUG 24 | #define UNIX_TIMER_DEBUG 25 | #define VIRTIO_BALLOON_DEBUG 26 | #define VIRTIO_BLK_DEBUG 27 | #define VIRTIO_MMIO_DEBUG 28 | #define VIRTIO_NET_DEBUG 29 | #define VIRTIO_PCI_DEBUG 30 | #define VIRTIO_SCSI_DEBUG 31 | #define VIRTQUEUE_DEBUG 32 | #define XEN_DEBUG 33 | #define XEN_INT_DEBUG 34 | #define XENNET_DEBUG 35 | #define XENSTORE_DEBUG 36 | -------------------------------------------------------------------------------- /src/drivers/ata-pci.h: -------------------------------------------------------------------------------- 1 | void init_ata_pci(kernel_heaps kh, storage_attach a); 2 | -------------------------------------------------------------------------------- /src/drivers/console.h: -------------------------------------------------------------------------------- 1 | struct console_driver { 2 | struct list l; 3 | void (*write)(void *d, const char *s, bytes count); 4 | void (*config)(void *d, tuple r); 5 | sstring name; 6 | boolean disabled; 7 | }; 8 | 9 | closure_type(console_attach, void, struct console_driver *driver); 10 | 11 | void init_console(kernel_heaps kh); 12 | void config_console(tuple root); 13 | void attach_console_driver(struct console_driver *driver); 14 | void console_force_unlock(void); 15 | 16 | void serial_console_write(void *d, const char *s, bytes count); 17 | -------------------------------------------------------------------------------- /src/drivers/dmi.h: -------------------------------------------------------------------------------- 1 | /* SMBIOS entry point structure size */ 2 | #define SMBIOS_EP_SIZE 32 3 | 4 | enum dmi_field { 5 | DMI_CHASSIS_ASSET_TAG, 6 | }; 7 | 8 | extern u64 smbios_entry_point; 9 | 10 | sstring dmi_get_string(enum dmi_field field); 11 | -------------------------------------------------------------------------------- /src/drivers/gve.h: -------------------------------------------------------------------------------- 1 | /* Google Virtual Ethernet (also known as gVNIC) driver */ 2 | void init_gve(kernel_heaps kh); 3 | -------------------------------------------------------------------------------- /src/drivers/netconsole.h: -------------------------------------------------------------------------------- 1 | void netconsole_register(kernel_heaps h, console_attach a); 2 | -------------------------------------------------------------------------------- /src/drivers/ns16550.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include "console.h" 3 | 4 | typedef struct ns16550_console { 5 | struct console_driver driver; 6 | u8 *addr; 7 | } *ns16550_console; 8 | 9 | static boolean tx_empty(volatile u8 *addr) { 10 | return *(addr + 5) & 0x20; 11 | } 12 | 13 | static void ns16550_write(void *d, const char *s, bytes count) 14 | { 15 | ns16550_console console = d; 16 | for (; count--; s++) { 17 | while (!tx_empty(console->addr)) 18 | ; 19 | *console->addr = *s; 20 | } 21 | } 22 | 23 | struct console_driver *ns16550_console_init(kernel_heaps kh, void *base) 24 | { 25 | ns16550_console console = allocate(heap_general(kh), sizeof(*console)); 26 | console->addr = base; 27 | zero(&console->driver, sizeof(console->driver)); 28 | console->driver.name = ss("16550"); 29 | console->driver.write = ns16550_write; 30 | return &console->driver; 31 | } 32 | -------------------------------------------------------------------------------- /src/drivers/ns16550.h: -------------------------------------------------------------------------------- 1 | struct console_driver *ns16550_console_init(kernel_heaps kh, void *base); 2 | -------------------------------------------------------------------------------- /src/drivers/nvme.h: -------------------------------------------------------------------------------- 1 | void init_nvme(kernel_heaps kh, storage_attach a); 2 | -------------------------------------------------------------------------------- /src/drivers/vga.h: -------------------------------------------------------------------------------- 1 | void vga_pci_register(kernel_heaps kh); 2 | -------------------------------------------------------------------------------- /src/fs/tfs.h: -------------------------------------------------------------------------------- 1 | #include "fs.h" 2 | 3 | typedef struct tfs *tfs; 4 | typedef struct tfsfile *tfsfile; 5 | 6 | extern io_status_handler ignore_io_status; 7 | 8 | #define MIN_EXTENT_SIZE PAGESIZE 9 | #define MAX_EXTENT_SIZE (PAGECACHE_MAX_SG_ENTRIES * PAGESIZE) 10 | #define MIN_EXTENT_ALLOC_SIZE (1 * MB) 11 | 12 | status filesystem_probe(u8 *first_sector, u8 *uuid, char *label); 13 | sstring filesystem_get_label(filesystem fs); 14 | void filesystem_get_uuid(filesystem fs, u8 *uuid); 15 | 16 | void create_filesystem(heap h, 17 | u64 blocksize, 18 | u64 size, 19 | storage_req_handler req_handler, 20 | boolean ro, 21 | sstring label, 22 | filesystem_complete complete); 23 | void destroy_filesystem(filesystem fs); 24 | 25 | fsfile fsfile_from_node(filesystem fs, tuple n); 26 | tfsfile allocate_fsfile(tfs fs, tuple md); 27 | 28 | int filesystem_write_tuple(tfs fs, tuple t); 29 | int filesystem_write_eav(tfs fs, tuple t, symbol a, value v, boolean cleanup); 30 | 31 | int filesystem_mkentry(filesystem fs, tuple cwd, sstring fp, tuple entry, 32 | boolean persistent, boolean recursive); 33 | int filesystem_mkdirpath(filesystem fs, tuple cwd, sstring fp, 34 | boolean persistent); 35 | -------------------------------------------------------------------------------- /src/gdb/gdb.h: -------------------------------------------------------------------------------- 1 | #define GDB 1 2 | 3 | // thunk service? 4 | void init_tcp_gdb(heap h, process p, u16 port); 5 | void gdb_check_fault_handler(thread t); 6 | -------------------------------------------------------------------------------- /src/gdb/gdb_internal.h: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | typedef struct gdb { 5 | struct spinlock send_lock; 6 | string output; 7 | string send_buffer; 8 | string out; 9 | string in; 10 | heap h; 11 | u8 checksum, sent_checksum; 12 | buffer_handler output_handler; 13 | thread t; // we can really get several 14 | process p; 15 | fault_handler fault_handler; 16 | boolean multiprocess; 17 | boolean sending; 18 | int ctid; // thread id for vcont/continues 19 | } *gdb; 20 | 21 | typedef struct handler { 22 | char *name; 23 | // reply 24 | boolean (*body)(gdb, buffer, string); 25 | } *handler; 26 | 27 | static inline char get_char(buffer b) 28 | { 29 | if (buffer_length(b)) { 30 | char r = peek_char(b); 31 | buffer_consume(b, 1); 32 | return(r); 33 | } 34 | return(0); 35 | } 36 | 37 | static inline boolean check(buffer b, char c) 38 | { 39 | if (peek_char(b) == c) { 40 | get_char(b); 41 | return(true); 42 | } 43 | return(false); 44 | } 45 | 46 | static inline void reset_buffer(string b) 47 | { 48 | b->start = 0; 49 | b->end = 0; 50 | } 51 | 52 | boolean parse_hex_pair(buffer in, u64 *first, u64 *second); 53 | boolean mem2hex (string b, void *mem, int count); 54 | boolean hex2mem (buffer b, void *mem, int count); 55 | void putpacket(gdb, string b); 56 | void putpacket_deferred(gdb, string b); 57 | boolean handle_query(gdb g, buffer b, string out, handler h); 58 | 59 | buffer_handler init_gdb(heap h, 60 | process p, 61 | buffer_handler outh); 62 | 63 | -------------------------------------------------------------------------------- /src/gdb/gdbtcp.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | typedef struct tcpgdb{ 4 | buffer_handler input; 5 | struct tcp_pcb *p; 6 | } *tcpgdb; 7 | 8 | closure_function(1, 1, status, gdb_send, 9 | tcpgdb, g, 10 | buffer b) 11 | { 12 | /* invoked exclusively by gdbserver_input with lwIP lock held */ 13 | err_t err = tcp_write(bound(g)->p, buffer_ref(b, 0), buffer_length(b), TCP_WRITE_FLAG_COPY); 14 | if (err != ERR_OK) 15 | return timm("result", "%s: tcp_write returned with error %d", func_ss, err); 16 | return STATUS_OK; 17 | } 18 | 19 | err_t gdb_input(void *z, struct tcp_pcb *pcb, struct pbuf *p, err_t err) 20 | { 21 | tcpgdb g = z; 22 | g->p = pcb; 23 | // i guess this is a close? 24 | if (p) { 25 | apply(g->input, alloca_wrap_buffer(p->payload, p->len)); 26 | // not necessarily 27 | tcp_recved(pcb, p->len); 28 | } 29 | return ERR_OK; 30 | } 31 | 32 | static err_t gdb_accept(void *z, struct tcp_pcb *pcb, err_t b) 33 | { 34 | tcpgdb g = z; 35 | tcp_arg(pcb, g); 36 | tcp_recv(pcb, gdb_input); 37 | return ERR_OK; 38 | } 39 | 40 | // should use unix api? 41 | void init_tcp_gdb(heap h, process p, u16 port) 42 | { 43 | tcpgdb g = (tcpgdb) allocate(h, sizeof(struct tcpgdb)); 44 | assert(g != INVALID_ADDRESS); 45 | g->p = tcp_new_ip_type(IPADDR_TYPE_ANY); 46 | // XXX threads lock taken here...shouldn't be issue but validate 47 | g->input = init_gdb(h, p, closure(h, gdb_send, g)); 48 | tcp_bind(g->p, IP_ANY_TYPE, port); 49 | g->p = tcp_listen(g->p); 50 | tcp_arg(g->p, g); 51 | tcp_accept(g->p, gdb_accept); 52 | } 53 | -------------------------------------------------------------------------------- /src/http/http.h: -------------------------------------------------------------------------------- 1 | typedef enum { 2 | HTTP_REQUEST_METHOD_GET = 0, 3 | HTTP_REQUEST_METHOD_HEAD, 4 | HTTP_REQUEST_METHOD_POST, 5 | HTTP_REQUEST_METHOD_PUT, 6 | HTTP_REQUEST_METHOD_DELETE, 7 | HTTP_REQUEST_METHOD_TRACE, 8 | HTTP_REQUEST_METHOD_OPTIONS, 9 | HTTP_REQUEST_METHOD_CONNECT, 10 | HTTP_REQUEST_METHOD_PATCH, 11 | HTTP_REQUEST_METHODS 12 | } http_method; 13 | 14 | typedef struct http_responder *http_responder; 15 | 16 | buffer_handler allocate_http_parser(heap h, value_handler each); 17 | // just format the buffer? 18 | status http_request(heap h, buffer_handler bh, http_method method, 19 | tuple headers, buffer body); 20 | status send_http_response(http_responder out, 21 | tuple t, 22 | buffer c); 23 | status send_http_chunk(http_responder out, buffer c); 24 | status send_http_chunked_response(http_responder out, tuple t); 25 | status send_http_response(http_responder out, tuple t, buffer c); 26 | 27 | extern const sstring http_request_methods[]; 28 | 29 | typedef struct http_listener *http_listener; 30 | closure_type(http_request_handler, void, http_method method, http_responder out, value v); 31 | 32 | void http_register_uri_handler(http_listener hl, sstring uri, http_request_handler each); 33 | void http_register_default_handler(http_listener hl, http_request_handler each); 34 | connection_handler connection_handler_from_http_listener(http_listener hl); 35 | http_listener allocate_http_listener(heap h, u16 port); 36 | void deallocate_http_listener(heap h, http_listener hl); 37 | -------------------------------------------------------------------------------- /src/hyperv/include/ctassert.h: -------------------------------------------------------------------------------- 1 | #ifndef _CTASSERT_H_ 2 | #define _CTASSERT_H_ 3 | 4 | /* 5 | * Macro to test if we're using a specific version of gcc or later. 6 | */ 7 | #if defined(__GNUC__) 8 | #define __GNUC_PREREQ__(ma, mi) \ 9 | (__GNUC__ > (ma) || __GNUC__ == (ma) && __GNUC_MINOR__ >= (mi)) 10 | #else 11 | #define __GNUC_PREREQ__(ma, mi) 0 12 | #endif 13 | 14 | #ifndef __has_extension 15 | #define __has_extension(x) 0 16 | #endif 17 | 18 | #if !__has_extension(c_static_assert) 19 | #if (defined(__cplusplus) && __cplusplus >= 201103L) || \ 20 | __has_extension(cxx_static_assert) 21 | #define _Static_assert(x, y) static_assert(x, y) 22 | #elif __GNUC_PREREQ__(4,6) && !defined(__cplusplus) 23 | /* Nothing, gcc 4.6 and higher has _Static_assert built-in */ 24 | #elif defined(__COUNTER__) 25 | #define _Static_assert(x, y) __Static_assert(x, __COUNTER__) 26 | #define __Static_assert(x, y) ___Static_assert(x, y) 27 | #define ___Static_assert(x, y) typedef char __assert_ ## y[(x) ? 1 : -1] \ 28 | __unused 29 | #else 30 | #define _Static_assert(x, y) struct __hack 31 | #endif 32 | #endif 33 | 34 | #ifndef CTASSERT 35 | #define CTASSERT(x) _Static_assert(x, "compile-time assertion failed") 36 | #endif 37 | 38 | #endif //_CTASSERT_H_ 39 | -------------------------------------------------------------------------------- /src/hyperv/include/hyperv_busdma.h: -------------------------------------------------------------------------------- 1 | /*- 2 | * Copyright (c) 2016 Microsoft Corp. 3 | * All rights reserved. 4 | * 5 | * Redistribution and use in source and binary forms, with or without 6 | * modification, are permitted provided that the following conditions 7 | * are met: 8 | * 1. Redistributions of source code must retain the above copyright 9 | * notice unmodified, this list of conditions, and the following 10 | * disclaimer. 11 | * 2. Redistributions in binary form must reproduce the above copyright 12 | * notice, this list of conditions and the following disclaimer in the 13 | * documentation and/or other materials provided with the distribution. 14 | * 15 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 16 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 17 | * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 18 | * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 19 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 20 | * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 21 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 22 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 23 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 24 | * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 | * 26 | * $FreeBSD$ 27 | */ 28 | 29 | #ifndef _HYPERV_BUSDMA_H_ 30 | #define _HYPERV_BUSDMA_H_ 31 | 32 | struct hyperv_dma { 33 | bus_addr_t hv_paddr; 34 | }; 35 | 36 | #endif /* !_HYPERV_BUSDMA_H_ */ 37 | -------------------------------------------------------------------------------- /src/hyperv/include/hyperv_platform.h: -------------------------------------------------------------------------------- 1 | boolean hyperv_detect(kernel_heaps kh); 2 | boolean hyperv_detected(void); 3 | void init_vmbus(kernel_heaps kh); 4 | status hyperv_probe_devices(storage_attach a, boolean* storage_inited); 5 | -------------------------------------------------------------------------------- /src/hyperv/vmbus/hyperv_var.h: -------------------------------------------------------------------------------- 1 | /*- 2 | * Copyright (c) 2016 Microsoft Corp. 3 | * All rights reserved. 4 | * 5 | * Redistribution and use in source and binary forms, with or without 6 | * modification, are permitted provided that the following conditions 7 | * are met: 8 | * 1. Redistributions of source code must retain the above copyright 9 | * notice unmodified, this list of conditions, and the following 10 | * disclaimer. 11 | * 2. Redistributions in binary form must reproduce the above copyright 12 | * notice, this list of conditions and the following disclaimer in the 13 | * documentation and/or other materials provided with the distribution. 14 | * 15 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 16 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 17 | * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 18 | * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 19 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 20 | * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 21 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 22 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 23 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 24 | * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 | * 26 | * $FreeBSD$ 27 | */ 28 | 29 | #ifndef _HYPERV_VAR_H_ 30 | #define _HYPERV_VAR_H_ 31 | 32 | uint64_t hypercall_post_message(bus_addr_t msg_paddr); 33 | uint64_t hypercall_signal_event(bus_addr_t monprm_paddr); 34 | uint64_t hyperv_tc64_rdmsr(void); 35 | 36 | #define VMBUS_DRIVER_NAME_MAX 16 37 | typedef struct vmbus_driver { 38 | struct list l; 39 | const struct hyperv_guid *type; 40 | vmbus_device_probe probe; 41 | } *vmbus_driver; 42 | 43 | #endif /* !_HYPERV_VAR_H_ */ 44 | -------------------------------------------------------------------------------- /src/kernel/dma.h: -------------------------------------------------------------------------------- 1 | #ifndef DMA_H_ 2 | #define DMA_H_ 3 | 4 | heap heap_dma(void); 5 | 6 | #ifdef DMA_BUFFERING 7 | 8 | void dma_init(kernel_heaps kh); 9 | 10 | sg_io dma_new_reader(heap h, sg_io_func read, void *priv); 11 | sg_io dma_new_writer(heap h, sg_io_func write, void *priv); 12 | 13 | #else 14 | 15 | static inline void dma_init(void *arg) {} 16 | 17 | #endif 18 | 19 | #endif 20 | -------------------------------------------------------------------------------- /src/kernel/klib.h: -------------------------------------------------------------------------------- 1 | /* in-kernel loadable library interface */ 2 | #include "../klib/klib.h" 3 | 4 | typedef struct klib_mapping { 5 | struct rmnode n; /* virtual */ 6 | u64 phys; 7 | pageflags flags; 8 | } *klib_mapping; 9 | 10 | typedef int (*klib_init)(status_handler complete); 11 | 12 | typedef struct klib { 13 | buffer name; 14 | range load_range; 15 | rangemap mappings; 16 | buffer elf; 17 | klib_init ki; 18 | } *klib; 19 | 20 | closure_type(klib_handler, void, klib ks, int rv); 21 | 22 | void load_klib(buffer name, klib_handler complete, status_handler sh); 23 | 24 | /* The caller must assure no references to klib remain before unloading. */ 25 | void unload_klib(klib kl); 26 | 27 | void init_klib(kernel_heaps kh, void *fs, tuple root, status_handler complete); 28 | 29 | void print_loaded_klibs(void); 30 | -------------------------------------------------------------------------------- /src/kernel/kvm_platform.h: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | static inline void QEMU_HALT(u8 code) __attribute__((noreturn)); 4 | 5 | static inline void QEMU_HALT(u8 code) 6 | { 7 | /* special qemu debug exit; returns ((code << 1) | 1) to shell */ 8 | out8(0x501, code); 9 | 10 | /* fallback (when no QEMU) */ 11 | 12 | /* Issue a CPU reset via port 0x64 of the PS/2 controller. */ 13 | out8(0x64, 0xfe); 14 | 15 | __asm__("cli"); 16 | __asm__("hlt"); 17 | 18 | while (1); 19 | } 20 | 21 | boolean kvm_detect(kernel_heaps kh); 22 | -------------------------------------------------------------------------------- /src/kernel/lockstats_struct.h: -------------------------------------------------------------------------------- 1 | #define LOCK_TYPE_SPIN 0 2 | #define LOCK_TYPE_MUTEX 1 3 | 4 | typedef struct lockstats_lock { 5 | int type; 6 | u64 acq_time; 7 | u64 trace_hash; 8 | } *lockstats_lock; 9 | -------------------------------------------------------------------------------- /src/kernel/log.h: -------------------------------------------------------------------------------- 1 | #define TRACE_OTHER U64_FROM_BIT(0) 2 | #define TRACE_THREAD_RUN U64_FROM_BIT(1) 3 | #define TRACE_PAGE_FAULT U64_FROM_BIT(2) 4 | 5 | u64 trace_get_flags(value v); 6 | 7 | typedef struct klog_dump { 8 | u8 header[4]; 9 | u64 boot_id; 10 | s32 exit_code; 11 | char msgs[KLOG_DUMP_SIZE - 16]; /* total size of the struct must match KLOG_DUMP_SIZE */ 12 | } __attribute__((packed)) *klog_dump; 13 | 14 | #ifdef KERNEL 15 | 16 | void klog_write(const char *s, bytes count); 17 | 18 | void klog_disk_setup(u64 disk_offset, storage_req_handler req_handler); 19 | void klog_set_boot_id(u64 id); 20 | void klog_load(klog_dump dest, status_handler sh); 21 | void klog_save(int exit_code, status_handler sh); 22 | void klog_dump_clear(void); 23 | 24 | void klog_set_level(string level); 25 | boolean klog_level_enabled(enum log_level level); 26 | 27 | #endif 28 | -------------------------------------------------------------------------------- /src/kernel/ltrace.h: -------------------------------------------------------------------------------- 1 | #ifdef CONFIG_LTRACE 2 | 3 | void ltrace_init(value cfg, buffer exe, u64 load_offset); 4 | boolean ltrace_handle_trap(context_frame f); 5 | void ltrace_signal(u32 signo); 6 | 7 | #else 8 | 9 | static inline void ltrace_init(value cfg, buffer exe, u64 load_offset) {} 10 | static inline boolean ltrace_handle_trap(context_frame f) {return false;} 11 | static inline void ltrace_signal(u32 signo) {} 12 | 13 | #endif 14 | -------------------------------------------------------------------------------- /src/kernel/management_telnet.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | //#define MGMT_DEBUG 5 | #ifdef MGMT_DEBUG 6 | #define mgmt_debug(x, ...) do {tprintf(sym(mgmt), 0, ss(x), ##__VA_ARGS__);} while(0) 7 | #else 8 | #define mgmt_debug(x, ...) 9 | #endif 10 | 11 | closure_function(3, 1, status, telnet_recv, 12 | heap, h, buffer_handler, out, parser, p, 13 | buffer b) 14 | { 15 | buffer_handler out = bound(out); 16 | if (!b) { 17 | // XXX need tuple parser dealloc 18 | mgmt_debug("%s: remote closed\n", func_ss); 19 | return STATUS_OK; 20 | } 21 | mgmt_debug("%s: got request \"%b\"\n", func_ss, b); 22 | switch (*((u8*)buffer_ref(b, 0))) { 23 | case 0x04: /* EOT */ 24 | mgmt_debug(" remote sent quit\n"); 25 | management_reset(); 26 | apply(out, 0); 27 | break; 28 | default: 29 | parser_feed(bound(p), b); 30 | } 31 | return STATUS_OK; 32 | } 33 | 34 | closure_function(1, 1, buffer_handler, each_telnet_connection, 35 | heap, h, 36 | buffer_handler out) 37 | { 38 | heap h = bound(h); 39 | mgmt_debug("telnet: connection\n"); 40 | parser p = management_parser(out); 41 | return closure(h, telnet_recv, h, out, p); 42 | } 43 | 44 | void init_management_telnet(heap h, value meta) 45 | { 46 | // XXX config port 47 | listen_port(h, 9090, closure(h, each_telnet_connection, h)); 48 | msg_info("Debug telnet server started on port 9090"); 49 | } 50 | -------------------------------------------------------------------------------- /src/kernel/mutex.h: -------------------------------------------------------------------------------- 1 | typedef struct mutex { 2 | u64 spin_iterations; 3 | context turn; 4 | void *mcs_tail; /* cpuinfo */ 5 | struct spinlock waiters_lock; 6 | struct list waiters; 7 | u64 mcs_spinouts; /* stats */ 8 | u64 acquire_spinouts; 9 | #ifdef LOCK_STATS 10 | struct lockstats_lock s; 11 | #endif 12 | } *mutex; 13 | 14 | void mutex_init(mutex m, u64 spin_iterations); 15 | 16 | boolean mutex_try_lock(mutex ql); 17 | 18 | void mutex_lock(mutex ql); 19 | 20 | void mutex_unlock(mutex ql); 21 | 22 | #define mutex_is_locked(m) ((m)->turn != 0) 23 | #define mutex_is_acquired(m) ((m)->turn == get_current_context(current_cpu())) 24 | 25 | mutex allocate_mutex(heap h, u64 spin_iterations); 26 | -------------------------------------------------------------------------------- /src/kernel/pvclock.h: -------------------------------------------------------------------------------- 1 | struct pvclock_vcpu_time_info { 2 | u32 version; 3 | u32 pad0; 4 | u64 tsc_timestamp; 5 | u64 system_time; 6 | u32 tsc_to_system_mul; 7 | s8 tsc_shift; 8 | u8 flags; 9 | u8 pad[2]; 10 | } __attribute__((__packed__)); 11 | 12 | struct pvclock_wall_clock { 13 | u32 version; 14 | u32 sec; 15 | u32 nsec; 16 | } __attribute__((__packed__)); 17 | 18 | u64 pvclock_now_ns(void); 19 | boolean init_tsc_deadline_timer(clock_timer *ct, thunk *per_cpu_init); 20 | void init_pvclock(heap h, struct pvclock_vcpu_time_info *pvclock, struct pvclock_wall_clock *wc); 21 | physical pvclock_get_physaddr(void); 22 | -------------------------------------------------------------------------------- /src/kernel/symtab.h: -------------------------------------------------------------------------------- 1 | void init_symtab(kernel_heaps kh); 2 | boolean symtab_is_empty(void); 3 | void *symtab_get_addr(sstring sym_name); 4 | void symtab_remove_addrs(range r); 5 | void add_elf_syms(buffer b, u64 load_offset); 6 | sstring find_elf_sym(u64 a, u64 *offset, u64 *len); 7 | void print_u64_with_sym(u64 a); 8 | -------------------------------------------------------------------------------- /src/kernel/tracelog.h: -------------------------------------------------------------------------------- 1 | void tprintf(symbol tag, tuple attrs, sstring format, ...); 2 | void vtprintf(symbol tag, tuple attrs, sstring format, vlist *ap); 3 | void init_tracelog_config(tuple root); 4 | void init_tracelog(heap h); 5 | -------------------------------------------------------------------------------- /src/kernel/vdso.h: -------------------------------------------------------------------------------- 1 | #define VVAR_DEF(type, name) type name 2 | #define VVAR_REF(name) __vdso_ ## name 3 | #define VVAR_DECL(type, name) extern VVAR type __vdso_ ## name 4 | 5 | #define VDSO_NO_NOW (timestamp)-1 6 | 7 | /* An instance of this struct is shared between kernel and userspace 8 | * Make sure there are no pointers embedded in it 9 | */ 10 | struct vdso_dat_struct { 11 | vdso_clock_id clock_src; 12 | timestamp rtc_offset; 13 | u64 pvclock_offset; 14 | volatile word vdso_gen; 15 | timestamp last_raw; /* time at which last_drift has been calculated */ 16 | s64 base_freq; /* frequency error adjustment */ 17 | s64 slew_freq; /* slewing frequency */ 18 | timestamp slew_start; 19 | timestamp slew_end; 20 | struct arch_vdso_dat machine; 21 | }; 22 | 23 | /* VDSO accessible variables */ 24 | VVAR_DECL(struct vdso_dat_struct, vdso_dat); 25 | 26 | /* now() routines that are accessible from both the VDSO and the core kernel */ 27 | struct pvclock_vcpu_time_info; 28 | VDSO u64 vdso_pvclock_now_ns(volatile struct pvclock_vcpu_time_info *); 29 | VDSO timestamp vdso_now(clock_id id); 30 | VDSO int vdso_getcpu(unsigned *cpu, unsigned *node); 31 | -------------------------------------------------------------------------------- /src/kernel/xen_platform.h: -------------------------------------------------------------------------------- 1 | boolean xen_detect(kernel_heaps kh); 2 | boolean xen_detected(void); 3 | status xen_probe_devices(void); 4 | void init_xennet(kernel_heaps kh); 5 | void init_xenblk(kernel_heaps kh, storage_attach sa); 6 | -------------------------------------------------------------------------------- /src/net/arch/cc.h: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nanovms/nanos/478b8825bd6edc382080a772b228a49d26d2644b/src/net/arch/cc.h -------------------------------------------------------------------------------- /src/net/arch/sys_arch.h: -------------------------------------------------------------------------------- 1 | typedef void * sys_prot_t; 2 | -------------------------------------------------------------------------------- /src/net/lwip.h: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | 19 | status direct_connect(heap h, ip_addr_t *addr, u16 port, connection_handler ch); 20 | 21 | closure_type(netif_dev_setup, boolean, tuple config); 22 | 23 | typedef struct netif_dev { 24 | struct netif n; 25 | closure_struct(netif_dev_setup, setup); 26 | } *netif_dev; 27 | 28 | static inline void netif_dev_init(netif_dev dev) 29 | { 30 | dev->setup.__apply = 0; 31 | } 32 | 33 | u16 ifflags_from_netif(struct netif *netif); 34 | boolean ifflags_to_netif(struct netif *netif, u16 flags); /* do not call with lwIP lock held */ 35 | bytes netif_name_cpy(char *dest, struct netif *netif); 36 | 37 | #define netif_is_loopback(netif) (((netif)->name[0] == 'l') && ((netif)->name[1] == 'o')) 38 | 39 | #define netif_get_type(netif) (netif_is_loopback(netif) ? ARPHRD_LOOPBACK : \ 40 | netif_is_flag_set(netif, NETIF_FLAG_ETHARP) ? ARPHRD_ETHER : \ 41 | ARPHRD_VOID) 42 | 43 | extern int (*net_ip_input_filter)(struct pbuf *pbuf, struct netif *input_netif); 44 | -------------------------------------------------------------------------------- /src/net/net.h: -------------------------------------------------------------------------------- 1 | #define NET 1 2 | #define NET_SYSCALLS 1 3 | 4 | void init_net(kernel_heaps kh); 5 | void init_network_iface(tuple root, merge m); 6 | status listen_port(heap h, u16 port, connection_handler c); 7 | -------------------------------------------------------------------------------- /src/net/stdlib.h: -------------------------------------------------------------------------------- 1 | /* not a real stdlib.h. shim for lwip */ 2 | -------------------------------------------------------------------------------- /src/net/string.h: -------------------------------------------------------------------------------- 1 | /* not a real string.h. shim for lwip */ 2 | 3 | -------------------------------------------------------------------------------- /src/riscv64/elf64.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #define R_RISCV_64 2 5 | #define R_RISCV_RELATIVE 3 6 | #define R_RISCV_JUMP_SLOT 5 7 | 8 | void elf_apply_relocate_add(buffer elf, Elf64_Shdr *s, u64 offset) 9 | { 10 | Elf64_Rela *rel = buffer_ref(elf, s->sh_addr); 11 | for (int i = 0; i < s->sh_size / sizeof(*rel); i++) { 12 | void *loc = buffer_ref(elf, rel[i].r_offset); 13 | switch (ELF64_R_TYPE(rel[i].r_info)) { 14 | case R_RISCV_RELATIVE: 15 | *(u64 *)loc += offset + rel[i].r_addend; 16 | break; 17 | } 18 | } 19 | } 20 | 21 | boolean elf_apply_relocate_syms(buffer elf, Elf64_Rela *rel, int relcount, 22 | elf_sym_relocator relocator) 23 | { 24 | for (int i = 0; i < relcount; i++) { 25 | switch (ELF64_R_TYPE(rel[i].r_info)) { 26 | case R_RISCV_64: 27 | case R_RISCV_JUMP_SLOT: 28 | if (!apply(relocator, &rel[i])) 29 | return false; 30 | break; 31 | } 32 | } 33 | return true; 34 | } 35 | 36 | void arch_elf_relocate(Elf64_Rela *rel, u64 relsz, Elf64_Sym *syms, u64 base, u64 offset) 37 | { 38 | u64 *loc; 39 | u64 value; 40 | while (relsz > 0) { 41 | switch (ELF64_R_TYPE(rel->r_info)) { 42 | case R_RISCV_64: 43 | value = syms[ELF64_R_SYM(rel->r_info)].st_value; 44 | break; 45 | case R_RISCV_RELATIVE: 46 | value = 0; 47 | break; 48 | default: 49 | goto next; 50 | } 51 | loc = pointer_from_u64(base + rel->r_offset); 52 | *loc = value + rel->r_addend + offset; 53 | next: 54 | rel++; 55 | relsz -= sizeof(*rel); 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /src/riscv64/gdb_machine.h: -------------------------------------------------------------------------------- 1 | 2 | static inline int computeSignal (context_frame frame) 3 | { 4 | return 0; 5 | } 6 | 7 | static inline int get_register(u64 num, void *buf, context_frame c) 8 | { 9 | return -1; 10 | } 11 | 12 | static boolean set_thread_register(thread t, int regno, u64 val) 13 | { 14 | return false; 15 | } 16 | 17 | static inline void set_thread_pc(thread t, u64 addr) 18 | { 19 | } 20 | 21 | static inline void read_registers(buffer b, thread t) 22 | { 23 | } 24 | 25 | static inline void write_registers(buffer b, thread t) 26 | { 27 | } 28 | 29 | static inline void set_write_protect(boolean enable) 30 | { 31 | } 32 | 33 | boolean breakpoint_insert(heap h, u64 a, u8 type, u8 log_length, thunk completion) 34 | { 35 | return false; 36 | } 37 | 38 | boolean breakpoint_remove(heap h, u32 a, thunk completion) 39 | { 40 | return false; 41 | } 42 | -------------------------------------------------------------------------------- /src/riscv64/klib.lds: -------------------------------------------------------------------------------- 1 | OUTPUT_FORMAT("elf64-littleriscv") 2 | 3 | ENTRY(init) 4 | 5 | PHDRS 6 | { 7 | text PT_LOAD FLAGS(5); /* R E */ 8 | rodata PT_LOAD FLAGS(4); /* R */ 9 | data PT_LOAD FLAGS(6); /* RW */ 10 | } 11 | 12 | SECTIONS 13 | { 14 | . = SIZEOF_HEADERS; 15 | .text : { *(.text) *(.text.*) } :text 16 | . = ALIGN(4096); 17 | .rodata : { *(.rodata) *(.rodata.*) } :rodata 18 | 19 | . = ALIGN(4096); 20 | .data : { *(.data) *(.data.*) } :data 21 | .bss : { *(.bss) *(.bss.*) } :data 22 | 23 | /DISCARD/ : { *(.interp) } 24 | } 25 | -------------------------------------------------------------------------------- /src/riscv64/plic.h: -------------------------------------------------------------------------------- 1 | #define PLIC_MAX_INT 0x35 2 | #define PLIC_VIRTIO_INTS_START 1 3 | #define PLIC_VIRTIO_INTS_END 9 4 | #define PLIC_PCIE_INTS_START 0x20 5 | #define PLIC_PCIE_INTS_END 0x23 6 | 7 | #define PLIC_PRIORITY 0 8 | #define PLIC_PENDING 0x1000 9 | #define PLIC_ENABLE_BASE 0x2000 10 | #define PLIC_ENABLE_CTX_LEN 0x80 11 | #define PLIC_ENABLE(CTX) (PLIC_ENABLE_BASE + PLIC_ENABLE_CTX_LEN * (CTX)) 12 | #define PLIC_THRESH_BASE 0x200000 13 | #define PLIC_CLAIM_BASE 0x200004 14 | #define PLIC_THRESH_CTX_LEN 0x1000 15 | #define PLIC_CLAIM_CTX_LEN 0x1000 16 | #define PLIC_THRESH(CTX) (PLIC_THRESH_BASE + PLIC_THRESH_CTX_LEN * (CTX)) 17 | #define PLIC_CLAIM(CTX) (PLIC_CLAIM_BASE + PLIC_CLAIM_CTX_LEN * (CTX)) 18 | 19 | void plic_disable_int(int irq); 20 | void plic_enable_int(int irq, u32 target_cpu); 21 | void plic_set_int_priority(int irq, u32 pri); 22 | void plic_set_threshold(u64 hartid, u32 thresh); 23 | void plic_set_int_config(int irq, u32 cfg); 24 | boolean plic_int_is_pending(int irq); 25 | u64 plic_dispatch_int(void); 26 | void plic_eoi(int irq); 27 | void init_plic(); 28 | 29 | -------------------------------------------------------------------------------- /src/riscv64/serial.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include "serial.h" 3 | 4 | /* This is a NS16550A UART, i.e. PC style */ 5 | volatile u8 *UART0_BASE = (volatile u8 *)DEV_BASE_UART; 6 | 7 | static inline boolean tx_empty(void) { 8 | return *(UART0_BASE+5) & 0x20; 9 | } 10 | 11 | /* This floods the ftrace buffers when user is outputting lots of data */ 12 | NOTRACE 13 | void serial_putchar(char c) 14 | { 15 | while (!tx_empty()); 16 | *UART0_BASE = c; 17 | } 18 | 19 | void serial_set_devbase(u64 devbase) 20 | { 21 | UART0_BASE = pointer_from_u64(u64_from_pointer(UART0_BASE) + devbase); 22 | } 23 | 24 | -------------------------------------------------------------------------------- /src/riscv64/serial.h: -------------------------------------------------------------------------------- 1 | void serial_putchar(char c); 2 | void serial_set_devbase(u64 devbase); 3 | 4 | -------------------------------------------------------------------------------- /src/riscv64/vdso.lds: -------------------------------------------------------------------------------- 1 | OUTPUT_FORMAT("elf64-littleriscv") 2 | 3 | SECTIONS 4 | { 5 | . = SIZEOF_HEADERS; 6 | .hash : { *(.hash) } : text 7 | .gnu.hash : { *(.gnu.hash) } : text 8 | .dynsym : { *(.dynsym) } : text 9 | .dynstr : { *(.dynstr) } : text 10 | .dynamic : { *(.dynamic) } : dynamic : text 11 | 12 | .gnu.version : { *(.gnu.version) } : text 13 | .gnu.version_d : { *(.gnu.version_d) } : text 14 | .gnu.version_r : { *(.gnu.version_r) } : text 15 | 16 | .plt : { *(.plt) } : text 17 | .rela.dyn : { *(.rela.dyn) } : text 18 | .got : { *(.got) } : text 19 | .got.plt : { *(.got.plt) } : text 20 | 21 | .eh_frame_hdr : { *(.eh_frame_hdr) } : eh_frame_hdr : text 22 | .eh_frame : { *(.eh_frame) } : text 23 | .text : { *(.text*) } : text 24 | 25 | /* 2 vvar pages follow the text: 26 | * i. 1 for variables in the vva 27 | * ii. 1 for the pvclock page 28 | */ 29 | vvar_page = ALIGN(4096); 30 | __vdso_vdso_dat = vvar_page + 128; 31 | pvclock_page = vvar_page + 4096; 32 | } 33 | 34 | /* 35 | * We specify the program headers to ensure that there is only a single 36 | * PT_LOAD segment 37 | * - put ELF header + program headers in text 38 | */ 39 | PHDRS 40 | { 41 | text PT_LOAD FILEHDR PHDRS FLAGS(5); /*rd+exec*/ 42 | dynamic PT_DYNAMIC FLAGS(4); /*rdonly*/ 43 | /*note PT_NOTE FLAGS(4);*/ 44 | eh_frame_hdr PT_GNU_EH_FRAME FLAGS(4); 45 | } 46 | 47 | /* Pretend like we are Linux 2.6 */ 48 | VERSION 49 | { 50 | LINUX_2.6 { 51 | global: 52 | rt_sigreturn; 53 | __vdso_rt_sigreturn; 54 | gettimeofday; 55 | __vdso_gettimeofday; 56 | clock_gettime; 57 | __vdso_clock_gettime; 58 | getcpu; 59 | __vdso_getcpu; 60 | time; 61 | __vdso_time; 62 | local: 63 | *; 64 | }; 65 | } 66 | 67 | VDSO_sigtramp = __vdso_rt_sigreturn; 68 | 69 | -------------------------------------------------------------------------------- /src/runtime/attributes.h: -------------------------------------------------------------------------------- 1 | /* attributes for compiling+linking */ 2 | 3 | #define NOTRACE __attribute__((no_instrument_function)) 4 | #define HIDDEN __attribute__((visibility("hidden"))) 5 | #define VDSO HIDDEN 6 | #define VVAR HIDDEN 7 | #define VSYSCALL NOTRACE __attribute__((section(".vsyscall"))) 8 | #ifdef KERNEL 9 | #define RO_AFTER_INIT __attribute__((section(".ro_after_init"))) 10 | #define BSS_RO_AFTER_INIT __attribute__((section(".bss.ro_after_init"))) 11 | #else 12 | #define RO_AFTER_INIT 13 | #define BSS_RO_AFTER_INIT 14 | #endif 15 | -------------------------------------------------------------------------------- /src/runtime/context.h: -------------------------------------------------------------------------------- 1 | typedef u64 *context_frame; 2 | closure_type(fault_handler, context, context ctx); 3 | 4 | #define CONTEXT_TYPE_UNDEFINED 0 5 | #define CONTEXT_TYPE_KERNEL 1 6 | #define CONTEXT_TYPE_SYSCALL 2 7 | #define CONTEXT_TYPE_THREAD 3 8 | #define CONTEXT_TYPE_PROCESS 4 9 | #define CONTEXT_TYPE_MAX 5 10 | 11 | struct context { 12 | u64 frame[FRAME_SIZE]; /* must be first */ 13 | struct refcount refcount; 14 | void (*pause)(struct context *); 15 | void (*resume)(struct context *); 16 | void (*pre_suspend)(struct context *); 17 | void (*schedule_return)(struct context *); 18 | fault_handler fault_handler; 19 | heap transient_heap; 20 | void *waiting_on; /* should use tag types here */ 21 | struct list mutex_l; /* mutex waiters */ 22 | u32 active_cpu; 23 | u8 type; 24 | }; 25 | -------------------------------------------------------------------------------- /src/runtime/crypto/chacha.h: -------------------------------------------------------------------------------- 1 | /* $OpenBSD: chacha.h,v 1.4 2016/08/27 04:04:56 guenther Exp $ */ 2 | 3 | /* 4 | chacha-merged.c version 20080118 5 | D. J. Bernstein 6 | Public domain. 7 | 8 | $FreeBSD$ 9 | */ 10 | 11 | #ifndef CHACHA_H 12 | #define CHACHA_H 13 | 14 | struct chacha_ctx { 15 | u32 input[16]; 16 | }; 17 | 18 | #define CHACHA_MINKEYLEN 16 19 | #define CHACHA_NONCELEN 8 20 | #define CHACHA_CTRLEN 8 21 | #define CHACHA_STATELEN (CHACHA_NONCELEN+CHACHA_CTRLEN) 22 | #define CHACHA_BLOCKLEN 64 23 | 24 | #ifdef CHACHA_EMBED 25 | #define LOCAL static 26 | #else 27 | #define LOCAL 28 | #endif 29 | 30 | #ifdef CHACHA_NONCE0_CTR128 31 | #define CHACHA_UNUSED __unused 32 | #else 33 | #define CHACHA_UNUSED 34 | #endif 35 | 36 | LOCAL void chacha_keysetup(struct chacha_ctx *x, const u8 *k, u32 kbits); 37 | LOCAL void chacha_ivsetup(struct chacha_ctx *x, const u8 *iv CHACHA_UNUSED, 38 | const u8 *ctr); 39 | LOCAL void chacha_encrypt_bytes(struct chacha_ctx *x, const u8 *m, 40 | u8 *c, u32 bytes); 41 | 42 | #undef CHACHA_UNUSED 43 | 44 | #endif /* CHACHA_H */ 45 | 46 | -------------------------------------------------------------------------------- /src/runtime/files.mk: -------------------------------------------------------------------------------- 1 | RUNTIME=$(SRCDIR)/runtime/bitmap.c \ 2 | $(SRCDIR)/runtime/buffer.c \ 3 | $(SRCDIR)/runtime/crypto/chacha.c \ 4 | $(SRCDIR)/runtime/extra_prints.c \ 5 | $(SRCDIR)/runtime/format.c \ 6 | $(SRCDIR)/runtime/heap/mem_debug.c \ 7 | $(SRCDIR)/runtime/heap/freelist.c \ 8 | $(SRCDIR)/runtime/heap/id.c \ 9 | $(SRCDIR)/runtime/heap/mcache.c \ 10 | $(SRCDIR)/runtime/heap/page.c \ 11 | $(SRCDIR)/runtime/heap/reserve.c \ 12 | $(SRCDIR)/runtime/heap/objcache.c \ 13 | $(SRCDIR)/runtime/json.c \ 14 | $(SRCDIR)/runtime/management.c \ 15 | $(SRCDIR)/runtime/memops.c \ 16 | $(SRCDIR)/runtime/merge.c \ 17 | $(SRCDIR)/runtime/pqueue.c \ 18 | $(SRCDIR)/runtime/queue.c \ 19 | $(SRCDIR)/runtime/random.c \ 20 | $(SRCDIR)/runtime/range.c \ 21 | $(SRCDIR)/runtime/rbtree.c \ 22 | $(SRCDIR)/runtime/ringbuf.c \ 23 | $(SRCDIR)/runtime/runtime_init.c \ 24 | $(SRCDIR)/runtime/sg.c \ 25 | $(SRCDIR)/runtime/sha256.c \ 26 | $(SRCDIR)/runtime/string.c \ 27 | $(SRCDIR)/runtime/symbol.c \ 28 | $(SRCDIR)/runtime/table.c \ 29 | $(SRCDIR)/runtime/timer.c \ 30 | $(SRCDIR)/runtime/tuple.c \ 31 | $(SRCDIR)/runtime/tuple_parser.c \ 32 | $(SRCDIR)/runtime/vector.c 33 | -------------------------------------------------------------------------------- /src/runtime/format.h: -------------------------------------------------------------------------------- 1 | extern void vbprintf(buffer s, sstring fmt, vlist *ap); 2 | 3 | struct formatter_state { 4 | int state; 5 | int format; // format character ('s', 'd', ...) 6 | int modifier; // format modifier ('l') 7 | int width; // format width 8 | int align; // format align ('-') 9 | int fill; // format fill 10 | int precision; // format precision 11 | }; 12 | 13 | // make sure its safe to read more than one format char ala %02x 14 | // if we parameterize newline we can do some nicer formatting tricks 15 | typedef void (*formatter)(buffer dest, struct formatter_state *s, vlist *ap); 16 | void register_format(character c, formatter f, int accepts_long); 17 | void init_extra_prints(void); 18 | 19 | buffer aprintf_sstring(heap h, sstring fmt, ...); 20 | #define aprintf(h, fmt, ...) aprintf_sstring(h, ss(fmt), ##__VA_ARGS__) 21 | 22 | void bprintf_sstring(buffer b, sstring fmt, ...); 23 | #define bprintf(b, fmt, ...) bprintf_sstring(b, ss(fmt), ##__VA_ARGS__) 24 | 25 | int rsnprintf_sstring(char *str, u64 size, sstring fmt, ...); 26 | #define rsnprintf(str, size, fmt, ...) rsnprintf_sstring(str, size, ss(fmt), ##__VA_ARGS__) 27 | 28 | void rprintf_sstring(sstring format, ...); 29 | #define rprintf(fmt, ...) rprintf_sstring(ss(fmt), ##__VA_ARGS__) 30 | -------------------------------------------------------------------------------- /src/runtime/heap/debug_heap.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | typedef struct dheap { 4 | struct heap h; 5 | heap parent; 6 | } *dheap; 7 | 8 | static u64 debug_alloc(heap h, bytes size) 9 | { 10 | dheap d = (dheap)h; 11 | u64 result = allocate_u64(d->parent, size); 12 | if (result != INVALID_PHYSICAL) 13 | rprintf("alloc %p %p -> %p %p (%p)\n", d->parent, size, result, 14 | physical_from_virtual(pointer_from_u64(result)), 15 | d->parent->alloc); 16 | return result; 17 | } 18 | 19 | static void debug_dealloc(heap h, u64 x, bytes size) 20 | { 21 | } 22 | 23 | heap debug_heap(heap meta, heap target) 24 | { 25 | dheap n = allocate(meta, sizeof(struct dheap)); 26 | assert(n != INVALID_ADDRESS); 27 | n->h.alloc = debug_alloc; 28 | n->h.dealloc = debug_dealloc; 29 | n->parent = target; 30 | return (heap)n; 31 | } 32 | 33 | -------------------------------------------------------------------------------- /src/runtime/heap/id.h: -------------------------------------------------------------------------------- 1 | typedef struct id_heap { 2 | struct heap h; 3 | boolean (*add_range)(struct id_heap *i, u64 base, u64 length); 4 | boolean (*set_area)(struct id_heap *i, u64 base, u64 length, boolean validate, boolean allocate); 5 | void (*set_randomize)(struct id_heap *i, boolean randomize); 6 | u64 (*alloc_subrange)(struct id_heap *i, bytes count, u64 start, u64 end); 7 | void (*set_next)(struct id_heap *i, bytes count, u64 next); 8 | /* private */ 9 | u64 page_order; 10 | u64 allocated; 11 | u64 total; 12 | u64 flags; 13 | heap meta; 14 | heap map; 15 | heap parent; 16 | rangemap ranges; 17 | tuple mgmt; 18 | /* additional private data may extend past this definition */ 19 | } *id_heap; 20 | 21 | id_heap create_id_heap(heap meta, heap map, u64 base, u64 length, bytes pagesize, boolean locking); 22 | id_heap create_id_heap_backed(heap meta, heap map, heap parent, bytes pagesize, boolean locking); 23 | id_heap allocate_id_heap(heap meta, heap map, bytes pagesize, boolean locking); /* id heap with no ranges */ 24 | id_heap clone_id_heap(id_heap source); 25 | boolean id_heap_range_foreach(id_heap i, range_handler rh); 26 | #define destroy_id_heap(__h) destroy_heap(&(__h)->h) 27 | #define id_heap_add_range(__h, __b, __l) ((__h)->add_range(__h, __b, __l)) 28 | #define id_heap_set_area(__h, __b, __l, __v, __a) ((__h)->set_area(__h, __b, __l, __v, __a)) 29 | #define id_heap_set_randomize(__h, __r) ((__h)->set_randomize(__h, __r)) 30 | #define id_heap_alloc_subrange(__h, __c, __s, __e) ((__h)->alloc_subrange(__h, __c, __s, __e)) 31 | #define id_heap_set_next(__h, __c, __n) ((__h)->set_next(__h, __c, __n)) 32 | 33 | /* If count == 1, the return value is guaranteed to be the lowest-numbered 34 | * non-allocated id starting from min. */ 35 | static inline u64 id_heap_alloc_gte(id_heap i, bytes count, u64 min) 36 | { 37 | id_heap_set_next(i, count, min); 38 | return id_heap_alloc_subrange(i, count, min, infinity); 39 | } 40 | 41 | boolean id_heap_prealloc(id_heap i); 42 | -------------------------------------------------------------------------------- /src/runtime/heap/page.h: -------------------------------------------------------------------------------- 1 | #ifndef _PAGE_HEAP_H_ 2 | #define _PAGE_HEAP_H_ 3 | 4 | heap pageheap_init(heap meta); 5 | boolean pageheap_add_range(u64 base, u64 length); 6 | void pageheap_init_done(void *virt_base, u64 max_page_size); 7 | bytes pageheap_max_pagesize(void); 8 | void pageheap_range_foreach(range_handler rh); 9 | 10 | #endif 11 | -------------------------------------------------------------------------------- /src/runtime/ip.h: -------------------------------------------------------------------------------- 1 | static boolean parse_v4_address(buffer b, u32 *u) 2 | { 3 | u64 a; 4 | *u = 0; 5 | parse_int(b, 10, &a); *u = (*u<<8)|a; 6 | if (pop_u8(b) != '.') return false; 7 | parse_int(b, 10, &a); *u = (*u<<8)|a; 8 | if (pop_u8(b) != '.') return false; 9 | parse_int(b, 10, &a); *u = (*u<<8)|a; 10 | if (pop_u8(b) != '.') return false; 11 | parse_int(b, 10, &a); *u = (*u<<8)|a; 12 | return true; 13 | } 14 | 15 | static boolean parse_v4_address_and_port(buffer b, u32 *u, u16 *port) 16 | { 17 | u64 a; 18 | if (!parse_v4_address(b, u)) return false; 19 | if (pop_u8(b) != ':') return false; 20 | parse_int(b, 10, &a); 21 | *port = (u16)a; 22 | return true; 23 | } 24 | -------------------------------------------------------------------------------- /src/runtime/management.h: -------------------------------------------------------------------------------- 1 | #ifndef _MANAGEMENT_H_ 2 | #define _MANAGEMENT_H_ 3 | 4 | void init_management(heap function_tuple_heap, heap general); 5 | void init_management_root(tuple root); 6 | tuple allocate_function_tuple(tuple_get g, tuple_set s, tuple_iterate i); 7 | void management_reset(void); 8 | parser management_parser(buffer_handler out); 9 | 10 | struct tuple_notifier; 11 | typedef struct tuple_notifier *tuple_notifier; 12 | closure_type(set_value_notify, boolean, value new_v); 13 | closure_type(get_value_notify, value); 14 | 15 | tuple_notifier tuple_notifier_wrap(value parent, boolean copy_on_write); 16 | void tuple_notifier_unwrap(tuple_notifier tn); 17 | void tuple_notifier_register_get_notify(tuple_notifier tn, symbol s, get_value_notify n); 18 | void tuple_notifier_register_set_notify(tuple_notifier tn, symbol s, set_value_notify n); 19 | 20 | #endif 21 | -------------------------------------------------------------------------------- /src/runtime/merge.c: -------------------------------------------------------------------------------- 1 | #ifdef KERNEL 2 | #include 3 | #else 4 | #include 5 | #endif 6 | 7 | closure_type(merge_apply, status_handler); 8 | 9 | struct merge { 10 | heap h; 11 | word count; 12 | merge_apply apply; 13 | status_handler completion; 14 | status last_status; 15 | }; 16 | 17 | closure_function(1, 1, void, merge_join, 18 | merge, m, 19 | status s) 20 | { 21 | merge m = bound(m); 22 | if (s != STATUS_OK) 23 | m->last_status = s; // last failed status 24 | 25 | word n = fetch_and_add(&m->count, (word)-1); 26 | if (n == 1) { 27 | #if KERNEL 28 | async_apply_status_handler(m->completion, m->last_status); 29 | #else 30 | apply(m->completion, m->last_status); 31 | #endif 32 | deallocate_closure(m->apply); 33 | deallocate(m->h, m, sizeof(struct merge)); 34 | closure_finish(); 35 | } 36 | } 37 | 38 | closure_function(2, 0, status_handler, merge_add, 39 | merge, m, status_handler, sh) 40 | { 41 | fetch_and_add(&bound(m)->count, 1); 42 | return bound(sh); 43 | } 44 | 45 | merge allocate_merge(heap h, status_handler completion) 46 | { 47 | merge m = allocate_zero(h, sizeof(struct merge)); 48 | assert(m != INVALID_ADDRESS); 49 | m->h = h; 50 | status_handler sh = closure(h, merge_join, m); 51 | m->apply = closure(h, merge_add, m, sh); 52 | m->completion = completion; 53 | m->last_status = STATUS_OK; 54 | return m; 55 | } 56 | 57 | status_handler apply_merge(merge m) 58 | { 59 | return apply(m->apply); 60 | } 61 | -------------------------------------------------------------------------------- /src/runtime/metadata.h: -------------------------------------------------------------------------------- 1 | static inline tuple resolve_path(tuple n, vector v) 2 | { 3 | buffer i; 4 | vector_foreach(v, i) { 5 | /* null entries ("//") are skipped in path */ 6 | if (buffer_length(i) == 0) 7 | continue; 8 | tuple c = get_tuple(n, sym(children)); 9 | if (!c) 10 | return c; 11 | n = get_tuple(c, intern(i)); 12 | if (!n) 13 | return n; 14 | } 15 | return n; 16 | } 17 | 18 | static inline tuple children(tuple x) 19 | { 20 | return get_tuple(x, sym(children)); 21 | } 22 | 23 | static inline string contents(tuple x) 24 | { 25 | return get_string(x, sym(contents)); 26 | } 27 | 28 | static inline tuple lookup(tuple t, symbol a) 29 | { 30 | if (a == sym_this("..")) 31 | return get_tuple(t, a); 32 | if (a == sym_this(".")) 33 | return t; 34 | tuple c = children(t); 35 | if (!c) 36 | return c; 37 | return get_tuple(c, a); 38 | } 39 | -------------------------------------------------------------------------------- /src/runtime/pqueue.h: -------------------------------------------------------------------------------- 1 | typedef struct pqueue *pqueue; 2 | pqueue allocate_pqueue(heap h, boolean(*)(void *, void *)); 3 | void deallocate_pqueue(pqueue q); 4 | void pqueue_insert(pqueue q, void *v); 5 | boolean pqueue_remove(pqueue q, void *v); 6 | void pqueue_remove_at(pqueue q, u32 index); 7 | void *pqueue_peek(pqueue q); 8 | void *pqueue_peek_at(pqueue q, u32 index); 9 | void *pqueue_pop(pqueue q); 10 | u64 pqueue_length(pqueue q); 11 | void pqueue_reorder(pqueue q); 12 | closure_type(pqueue_element_handler, boolean, void *elem); 13 | boolean pqueue_walk(pqueue q, pqueue_element_handler h); 14 | -------------------------------------------------------------------------------- /src/runtime/predef.h: -------------------------------------------------------------------------------- 1 | typedef struct buffer *buffer; 2 | typedef struct heap *heap; 3 | 4 | #define varg __builtin_va_arg 5 | #define vlist __builtin_va_list 6 | #define vstart __builtin_va_start 7 | #define vend __builtin_va_end 8 | 9 | -------------------------------------------------------------------------------- /src/runtime/queue.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #define _queue_buf_offset pad(sizeof(struct queue), DEFAULT_CACHELINE_SIZE) 4 | #define _queue_alloc_size(o) (_queue_buf_offset + queue_data_size(o)) 5 | 6 | /* will round up size to next power-of-2 */ 7 | queue allocate_queue(heap h, u64 size) 8 | { 9 | if (size == 0) 10 | return INVALID_ADDRESS; 11 | int order = find_order(size); 12 | queue q = allocate(h, _queue_alloc_size(order)); 13 | if (q == INVALID_ADDRESS) 14 | return q; 15 | void *buf = ((void *)q) + _queue_buf_offset; 16 | queue_init(q, order, buf); 17 | q->h = h; 18 | return q; 19 | } 20 | 21 | void deallocate_queue(queue q) 22 | { 23 | if (q->h) 24 | deallocate(q->h, q, _queue_alloc_size(q->order)); 25 | } 26 | -------------------------------------------------------------------------------- /src/runtime/rbtree.h: -------------------------------------------------------------------------------- 1 | typedef struct rbnode *rbnode; 2 | struct rbnode { 3 | word parent_color; /* parent used for verification */ 4 | rbnode c[2]; 5 | }; 6 | 7 | closure_type(rbnode_handler, boolean, rbnode n); 8 | closure_type(rb_key_compare, int, rbnode a, rbnode b); 9 | 10 | typedef struct rbtree { 11 | rbnode root; 12 | u64 count; 13 | rb_key_compare key_compare; 14 | rbnode_handler print_key; 15 | heap h; 16 | } *rbtree; 17 | 18 | boolean rbtree_insert_node(rbtree t, rbnode n); 19 | 20 | boolean rbtree_remove_by_key(rbtree t, rbnode k); 21 | 22 | /* Delete by node is really delete by key, because we need to perform 23 | transformations while descending the tree in order to do a safe 24 | removal - but we'll keep the call as part of the interface in case 25 | a more optimal solution arises later. */ 26 | static inline void rbtree_remove_node(rbtree t, rbnode n) 27 | { 28 | assert(rbtree_remove_by_key(t, n)); 29 | } 30 | 31 | rbnode rbtree_lookup(rbtree t, rbnode k); 32 | 33 | void init_rbtree(rbtree t, rb_key_compare key_compare, rbnode_handler print_key); 34 | 35 | rbtree allocate_rbtree(heap h, rb_key_compare key_compare, rbnode_handler print_key); 36 | 37 | void destruct_rbtree(rbtree t, rbnode_handler destructor); 38 | 39 | void deallocate_rbtree(rbtree rb, rbnode_handler destructor); 40 | 41 | #define RB_INORDER 0 42 | #define RB_PREORDER 1 43 | #define RB_POSTORDER 2 44 | 45 | void rbtree_dump(rbtree t, int order); 46 | 47 | boolean rbtree_traverse(rbtree t, int order, rbnode_handler rh); 48 | 49 | status rbtree_validate(rbtree t); 50 | 51 | static inline u64 rbtree_get_count(rbtree t) 52 | { 53 | return t->count; 54 | } 55 | 56 | static inline void init_rbnode(rbnode n) 57 | { 58 | n->parent_color = 0; 59 | n->c[0] = n->c[1] = 0; 60 | } 61 | 62 | /* not for key nodes! */ 63 | rbnode rbnode_get_prev(rbnode h); 64 | rbnode rbnode_get_next(rbnode h); 65 | 66 | rbnode rbtree_lookup_max_lte(rbtree t, rbnode k); 67 | rbnode rbtree_find_first(rbtree t); 68 | -------------------------------------------------------------------------------- /src/runtime/refcount.h: -------------------------------------------------------------------------------- 1 | /* a lightweight, inline version of merge without status handling */ 2 | typedef struct refcount { 3 | word c; 4 | thunk completion; 5 | } *refcount; 6 | 7 | static inline void init_refcount(refcount r, int c, thunk completion) 8 | { 9 | r->c = c; 10 | r->completion = completion; 11 | } 12 | 13 | static inline void refcount_reserve(refcount r) 14 | { 15 | fetch_and_add(&r->c, 1); 16 | } 17 | 18 | static inline boolean refcount_release(refcount r) 19 | { 20 | word n = fetch_and_add(&r->c, (word)-1); 21 | assert(n > 0); 22 | if (n == 1) { 23 | if (r->completion) 24 | apply(r->completion); 25 | return true; 26 | } 27 | return false; 28 | } 29 | 30 | static inline void refcount_set_count(refcount r, int c) 31 | { 32 | r->c = c; 33 | } 34 | -------------------------------------------------------------------------------- /src/runtime/ringbuf.h: -------------------------------------------------------------------------------- 1 | typedef buffer ringbuf; 2 | 3 | static inline ringbuf allocate_ringbuf(heap h, bytes len) 4 | { 5 | /* ensure that length is a power of 2 */ 6 | return allocate_buffer(h, U64_FROM_BIT(find_order(len))); 7 | } 8 | 9 | #define ringbuf_length buffer_length 10 | #define ringbuf_ref buffer_ref 11 | #define deallocate_ringbuf deallocate_buffer 12 | 13 | boolean ringbuf_read(ringbuf b, void *dest, bytes len); 14 | boolean ringbuf_peek(ringbuf b, void *dest, bytes len); 15 | boolean ringbuf_write(ringbuf b, const void *src, bytes len); 16 | boolean ringbuf_memset(ringbuf b, u8 c, bytes len); 17 | 18 | void ringbuf_overwrite(ringbuf b, bytes offset, const void *src, bytes len); 19 | 20 | static inline void ringbuf_produce(ringbuf b, bytes len) 21 | { 22 | b->end += len; 23 | } 24 | 25 | static inline void ringbuf_consume(ringbuf b, bytes len) 26 | { 27 | b->start += len; 28 | } 29 | 30 | static inline void ringbuf_unconsume(ringbuf b, bytes len) 31 | { 32 | b->start -= len; 33 | } 34 | 35 | static inline bytes ringbuf_space(ringbuf b) 36 | { 37 | return b->length - buffer_length(b); 38 | } 39 | 40 | boolean ringbuf_extend(ringbuf b, bytes len); 41 | bytes ringbuf_set_capacity(ringbuf b, bytes len); 42 | -------------------------------------------------------------------------------- /src/runtime/runtime_string.h: -------------------------------------------------------------------------------- 1 | char *runtime_strchr(sstring s, int c); 2 | char *runtime_strrchr(sstring s, int c); 3 | char *runtime_strstr(sstring haystack, sstring needle); 4 | sstring runtime_strtok_r(sstring *str, sstring delim, sstring *saveptr); 5 | int runtime_strcmp(sstring string1, sstring string2); 6 | 7 | string wrap_string(void *body, bytes length); 8 | string allocate_string(bytes size); 9 | void init_strings(heap h, heap init); 10 | 11 | #define deallocate_string deallocate_buffer 12 | 13 | static inline string string_from_buf(void *x, bytes len) 14 | { 15 | string s = allocate_string(len); 16 | buffer_assert(s != INVALID_ADDRESS); 17 | buffer_assert(buffer_append(s, x, len)); 18 | return s; 19 | } 20 | 21 | static inline string wrap_string_sstring(sstring s) 22 | { 23 | return string_from_buf(s.ptr, s.len); 24 | } 25 | 26 | #define wrap_string_cstring(x) wrap_string_sstring(ss(x)) 27 | -------------------------------------------------------------------------------- /src/runtime/signature.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | void buffer_signature(buffer b, signature dest) 4 | { 5 | buffer s = alloca_wrap_buffer(dest, sizeof(signature)); 6 | sha256(s, b); 7 | } 8 | 9 | void signature_xor(signature sdest, signature source) 10 | { 11 | sdest->s[0] ^= source->s[0]; 12 | sdest->s[1] ^= source->s[1]; 13 | sdest->s[2] ^= source->s[2]; 14 | sdest->s[3] ^= source->s[3]; 15 | } 16 | 17 | void tuple_signature(tuple t, signature dest); 18 | 19 | closure_function(2, 2, boolean, tuple_signature_each, 20 | signature, dest, u64, slen, 21 | value, n, value, v) 22 | { 23 | u64 slen = bound(slen); 24 | buffer b = little_stack_buffer(2*slen); 25 | buffer nv = little_stack_buffer(slen); 26 | 27 | assert(is_symbol(n)); 28 | buffer_signature(symbol_string(n), buffer_ref(b, 0)); 29 | if (is_tuple(v)) { 30 | tuple_signature(v, buffer_ref(b, slen)); 31 | } else { 32 | // XXX type 33 | buffer_signature(v, buffer_ref(b, slen)); 34 | } 35 | sha256(nv, b); 36 | signature_xor(bound(dest), buffer_ref(nv, 0)); 37 | return true; 38 | } 39 | 40 | void tuple_signature(tuple t, signature dest) 41 | { 42 | u64 slen = sizeof(struct signature); 43 | zero(dest, slen); 44 | iterate(t, stack_closure(tuple_signature_each, dest, slen)); 45 | } 46 | 47 | static inline boolean signature_equal(void *a, void* b) 48 | { 49 | return runtime_memcmp(a, b, sizeof(struct signature)) == 0; 50 | } 51 | 52 | static inline key signature_key(void *z) 53 | { 54 | u64 *s = (u64 *)z; 55 | return s[0] ^ s[1] ^ s[2] ^ s[3]; 56 | } 57 | 58 | table allocate_signature_table(heap h) 59 | { 60 | return allocate_table(h, signature_key, signature_equal); 61 | } 62 | 63 | -------------------------------------------------------------------------------- /src/runtime/sstring.h: -------------------------------------------------------------------------------- 1 | /* Simple string structure that does not use NULL string terminators. */ 2 | typedef struct sstring { 3 | bytes len; 4 | char *ptr; 5 | } sstring; 6 | 7 | #define ss(x) ({ \ 8 | assert_string_literal(x); \ 9 | sstring s = { \ 10 | .len = sizeof(x) - 1, \ 11 | .ptr = x, \ 12 | }; \ 13 | s; \ 14 | }) 15 | 16 | /* Should only be used for initialization of static variables. 17 | * For all other uses, ss() is more efficient. */ 18 | #define ss_static_init(x) { \ 19 | .len = sizeof(x) - 1, \ 20 | .ptr = string_literal(x), \ 21 | } 22 | 23 | #define sstring_foreach(__i, __c, __s) \ 24 | for (bytes __i = 0, __c, __limit = (__s).len; \ 25 | (__c = (__s).ptr[__i]), (__i) < __limit; \ 26 | (__i)++) 27 | 28 | #define file_ss isstring((char *)__FILE__, sizeof(__FILE__) - 1) 29 | #define func_ss isstring((char *)__func__, sizeof(__func__) - 1) 30 | 31 | static inline sstring isstring(char *ptr, bytes len) 32 | { 33 | sstring s = { 34 | .len = len, 35 | .ptr = ptr, 36 | }; 37 | return s; 38 | } 39 | 40 | static inline sstring sstring_null(void) 41 | { 42 | sstring s = { 43 | .ptr = 0, 44 | }; 45 | return s; 46 | } 47 | 48 | static inline sstring sstring_empty(void) 49 | { 50 | sstring s = { 51 | .len = 0, 52 | .ptr = "", 53 | }; 54 | return s; 55 | } 56 | 57 | static inline sstring sstring_from_cstring(const char *cstring, bytes maxlen) 58 | { 59 | sstring s = { 60 | .ptr = (char *)cstring, 61 | }; 62 | bytes len; 63 | for (len = 0; len < maxlen; len++) 64 | if (cstring[len] == '\0') 65 | break; 66 | s.len = len; 67 | return s; 68 | } 69 | 70 | static inline boolean sstring_is_null(sstring s) 71 | { 72 | return (s.ptr == 0); 73 | } 74 | 75 | static inline boolean sstring_is_empty(sstring s) 76 | { 77 | return (s.len == 0); 78 | } 79 | -------------------------------------------------------------------------------- /src/runtime/status.h: -------------------------------------------------------------------------------- 1 | #define STATUS_OK ((tuple)0) 2 | 3 | typedef tuple status; 4 | closure_type(status_handler, void, status s); 5 | 6 | extern tuple timm_oom; 7 | 8 | static inline void timm_term(tuple t, sstring n, sstring f, ...) 9 | { 10 | vlist a; 11 | vstart(a, f); 12 | symbol k = sym_sstring(n); 13 | string s = allocate_string(100); 14 | vbprintf(s, f, &a); 15 | vend(a); 16 | set(t, k, s); 17 | } 18 | 19 | tuple timm_clone(tuple t); 20 | 21 | void timm_dealloc(tuple t); 22 | 23 | #define timm(n, f, ...) ({ \ 24 | tuple s = allocate_tuple(); \ 25 | if (s != INVALID_ADDRESS) \ 26 | timm_term(s, ss(n), ss(f), ## __VA_ARGS__); \ 27 | else \ 28 | s = timm_oom; \ 29 | s; \ 30 | }) 31 | 32 | #define timm_sstring(n, f, ...) ({ \ 33 | tuple s = allocate_tuple(); \ 34 | if (s != INVALID_ADDRESS) \ 35 | timm_term(s, n, f, ## __VA_ARGS__); \ 36 | else \ 37 | s = timm_oom; \ 38 | s; \ 39 | }) 40 | 41 | #define timm_append(s, n, f, ...) ({ \ 42 | if (s != timm_oom) \ 43 | timm_term(s, ss(n), ss(f), ## __VA_ARGS__); \ 44 | s; \ 45 | }) 46 | 47 | // build up status chain 48 | #define timm_up(sd, first, ...) \ 49 | ({ \ 50 | tuple __up = timm(first, __VA_ARGS__); \ 51 | set(__up, sym(down), sd); \ 52 | __up; \ 53 | }) 54 | 55 | static inline boolean is_ok(status s) 56 | { 57 | return (s == STATUS_OK); 58 | } 59 | -------------------------------------------------------------------------------- /src/runtime/symbol.h: -------------------------------------------------------------------------------- 1 | extern void init_symbols(heap h, heap init); 2 | typedef struct symbol *symbol; 3 | symbol intern(buffer); 4 | symbol intern_u64(u64); 5 | 6 | string symbol_string(symbol s); 7 | 8 | #define sym(name) \ 9 | ({static symbol __s = 0;\ 10 | if (!__s){char x[] = #name; __s = intern(alloca_wrap_buffer(x, sizeof(x)-1));} \ 11 | __s;}) 12 | 13 | #define sym_this(name) ({ \ 14 | assert_string_literal(name); \ 15 | intern(alloca_wrap_buffer(name, sizeof(name) - 1)); \ 16 | }) 17 | 18 | #define sym_sstring(name) ({ \ 19 | sstring __n = name; \ 20 | intern(alloca_wrap_buffer(__n.ptr, __n.len)); \ 21 | }) 22 | 23 | table symbol_table(); 24 | key key_from_symbol(void *z); 25 | -------------------------------------------------------------------------------- /src/runtime/table.h: -------------------------------------------------------------------------------- 1 | typedef struct table *table; 2 | 3 | typedef u64 key; 4 | 5 | typedef struct entry { 6 | void *v; 7 | key k; 8 | void *c; 9 | struct entry *next; 10 | } *entry; 11 | 12 | struct table { 13 | heap h; 14 | heap eh; 15 | int buckets; 16 | int count; 17 | entry *entries; 18 | key (*key_function)(void *x); 19 | boolean (*equals_function)(void *x, void *y); 20 | }; 21 | 22 | table allocate_table(heap h, key (*key_function)(void *x), boolean (*equal_function)(void *x, void *y)); 23 | table allocate_table_preallocated(heap h, heap entry_parent, key (*key_function)(void *x), boolean (*equal_function)(void *x, void *y), u64 prealloc_count); 24 | void deallocate_table(table t); 25 | void table_validate(table t, sstring n); 26 | int table_elements(table t); 27 | void *table_find(table t, void *c); 28 | //void *table_find_key (table t, void *c, void **kr); 29 | void table_set(table t, void *c, void *v); 30 | boolean table_set_noreplace(table t, void *c, void *v); 31 | void table_clear(table t); 32 | 33 | /* Returns the value being removed if found, 0 otherwise. */ 34 | void *table_remove(table t, void *c); 35 | 36 | #define eZ(x,y) ((entry) x)->y 37 | 38 | #define table_foreach(__t, __k, __v)\ 39 | for (int __i = 0 ; __i< (__t)->buckets; __i++) \ 40 | for (void *__k, *__v, *__j = ((__t)->entries[__i]), *__next; \ 41 | __j && (__next = eZ((__j), next) , __k = eZ(__j, c), __v = eZ(__j, v)); \ 42 | __j = __next) 43 | 44 | boolean pointer_equal(void *a, void* b); 45 | key identity_key(void *a); 46 | -------------------------------------------------------------------------------- /src/runtime/vector.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | BSS_RO_AFTER_INIT static heap vheap; 4 | 5 | vector allocate_tagged_vector(int length) 6 | { 7 | return allocate_vector(vheap, length); 8 | } 9 | 10 | void init_vectors(heap h, heap init) 11 | { 12 | vheap = h; 13 | } 14 | -------------------------------------------------------------------------------- /src/unix/mktime.h: -------------------------------------------------------------------------------- 1 | struct tm { 2 | int tm_year; 3 | u8 tm_mon; 4 | u8 tm_mday; 5 | u8 tm_hour; 6 | u8 tm_min; 7 | u8 tm_sec; 8 | }; 9 | 10 | extern int mktime(struct tm *tm); 11 | extern struct tm *gmtime_r(u64 *timep, struct tm *result); 12 | -------------------------------------------------------------------------------- /src/unix/notify.h: -------------------------------------------------------------------------------- 1 | typedef struct notify_set *notify_set; 2 | typedef struct notify_entry *notify_entry; 3 | 4 | /* Notify handlers receive event changes, including falling edges; 5 | if the last argument is a non-zero thread pointer, event changes 6 | are relevant only for waiters on that thread. */ 7 | closure_type(event_handler, u64, u64 events, void *arg); 8 | 9 | #define NOTIFY_FLAGS_EXCLUSIVE U64_FROM_BIT(0) 10 | 11 | #define NOTIFY_RESULT_CONSUMED U64_FROM_BIT(0) 12 | #define NOTIFY_RESULT_RELEASE U64_FROM_BIT(1) 13 | 14 | /* NOTIFY_EVENTS_RELEASE is a special value of events to signal to the 15 | event_handler that a notify_set is being deallocated. 16 | event_handlers should detect this special case and release 17 | resources (e.g. epollfd) accordingly. */ 18 | #define NOTIFY_EVENTS_RELEASE (-1ull) 19 | 20 | notify_set allocate_notify_set(heap h); 21 | 22 | void deallocate_notify_set(notify_set s); 23 | 24 | notify_entry notify_add_with_flags(notify_set s, u64 eventmask, u64 flags, event_handler eh); 25 | 26 | #define notify_add(s, e, h) notify_add_with_flags(s, e, 0, h) 27 | 28 | void notify_remove(notify_set s, notify_entry e, boolean release); 29 | 30 | u64 notify_entry_get_eventmask(notify_entry n); 31 | void notify_entry_update_eventmask(notify_entry n, u64 eventmask); 32 | 33 | u64 notify_get_eventmask_union(notify_set s); 34 | 35 | void notify_dispatch(notify_set s, u64 events); 36 | 37 | boolean notify_dispatch_with_arg(notify_set s, u64 events, void *arg); 38 | 39 | #define notify_dispatch_for_thread notify_dispatch_with_arg 40 | 41 | void notify_release(notify_set s); 42 | -------------------------------------------------------------------------------- /src/unix/unix.h: -------------------------------------------------------------------------------- 1 | typedef struct kernel_heaps *kernel_heaps; 2 | typedef struct unix_heaps *unix_heaps; 3 | typedef struct process *process; 4 | typedef struct thread *thread; 5 | 6 | process init_unix(kernel_heaps kh, tuple root, filesystem fs); 7 | process create_process(unix_heaps uh, tuple root, filesystem fs); 8 | void process_get_cwd(process p, filesystem *cwd_fs, inode *cwd); 9 | thread create_thread(process p, u64 tid); 10 | void exec_elf(process kp, string program_path, status_handler complete); 11 | void unix_shutdown(void); 12 | 13 | void program_set_perms(tuple root, tuple prog); 14 | 15 | void dump_mem_stats(buffer b); 16 | 17 | void coredump_set_limit(u64 s); 18 | u64 coredump_get_limit(void); 19 | 20 | timestamp proc_utime(process p); 21 | timestamp proc_stime(process p); 22 | 23 | timestamp thread_utime(thread t); 24 | timestamp thread_stime(thread t); 25 | -------------------------------------------------------------------------------- /src/unix/vdso.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | /* see linker_script */ 5 | extern void * vvar_page; 6 | 7 | /* auto-generated into vdso-image.c 8 | * contains the raw binary image of the VDSO ELF 9 | */ 10 | extern unsigned char vdso_raw[]; 11 | 12 | #define __vdso_dat (&(VVAR_REF(vdso_dat))) 13 | 14 | void init_vdso(process p) 15 | { 16 | physical paddr; 17 | u64 vaddr, size; 18 | pageflags flags = pageflags_default_user(); 19 | 20 | /* sanity checks */ 21 | assert(((unsigned long)&vvar_page & MASK(PAGELOG)) == 0); 22 | assert(((unsigned long)vdso_raw & MASK(PAGELOG)) == 0); 23 | 24 | /* map single VDSO PT_LOAD segment, which contains the raw ELF binary */ 25 | { 26 | vaddr = p->vdso_base; 27 | assert((vdso_raw_length & PAGEMASK) == 0); 28 | size = vdso_raw_length; 29 | paddr = physical_from_virtual(vdso_raw); 30 | assert(paddr != INVALID_PHYSICAL); 31 | map(vaddr, paddr, size, pageflags_exec(flags)); 32 | } 33 | 34 | /* map first vvar page, which contains various kernel data */ 35 | { 36 | vaddr = vaddr + size; 37 | size = PAGESIZE; 38 | paddr = physical_from_virtual((void *)&vvar_page); 39 | assert(paddr != INVALID_PHYSICAL); 40 | map(vaddr, paddr, size, pageflags_noexec(flags)); 41 | } 42 | 43 | /* map pvclock page */ 44 | { 45 | vaddr = vaddr + size; 46 | size = PAGESIZE; 47 | #ifdef __x86_64__ 48 | paddr = pvclock_get_physaddr(); 49 | #else 50 | paddr = INVALID_PHYSICAL; // XXX 51 | #endif 52 | if (paddr != INVALID_PHYSICAL) { 53 | __vdso_dat->pvclock_offset = paddr & PAGEMASK; 54 | map(vaddr, paddr & ~PAGEMASK, size, 55 | pageflags_user(pageflags_readonly(pageflags_dma()))); 56 | } 57 | } 58 | 59 | #ifdef __x86_64__ 60 | /* init legacy vsyscall mappings */ 61 | init_vsyscall(); 62 | #endif 63 | } 64 | -------------------------------------------------------------------------------- /src/unix/vsock.h: -------------------------------------------------------------------------------- 1 | #define VSOCK_SHUTDOWN_TX U64_FROM_BIT(0) 2 | #define VSOCK_SHUTDOWN_RX U64_FROM_BIT(1) 3 | 4 | typedef struct vsock_connection { 5 | struct vsock_conn_id { 6 | u32 local_port; 7 | u32 peer_cid; 8 | u32 peer_port; 9 | } id; 10 | void *vsock; 11 | void *bound; 12 | struct refcount refc; 13 | struct spinlock lock; 14 | } *vsock_connection; 15 | 16 | static inline void vsock_conn_init(vsock_connection conn, u32 local_port, 17 | u32 peer_cid, u32 peer_port, thunk free) 18 | { 19 | conn->id.local_port = local_port; 20 | conn->id.peer_cid = peer_cid; 21 | conn->id.peer_port = peer_port; 22 | conn->bound = 0; 23 | init_refcount(&conn->refc, 1 , free); 24 | spin_lock_init(&conn->lock); 25 | } 26 | 27 | #define vsock_conn_lock(c) spin_lock(&(c)->lock) 28 | #define vsock_conn_unlock(c) spin_unlock(&(c)->lock) 29 | 30 | #define vsock_conn_release(c) refcount_release(&(c)->refc) 31 | 32 | void vsock_set_transport(void *transport); 33 | 34 | u32 vsock_get_buf_size(void); 35 | 36 | /* Functions returning a vsock_connection must return with the connection locked. */ 37 | boolean vsock_connect_request(vsock_connection conn); 38 | vsock_connection vsock_connect_complete(struct vsock_conn_id *conn_id, boolean success); 39 | vsock_connection vsock_get_conn(struct vsock_conn_id *conn_id); 40 | vsock_connection vsock_rx(struct vsock_conn_id *conn_id, void *data, u64 len); 41 | void vsock_buf_space_notify(vsock_connection conn, u64 buf_space); 42 | vsock_connection vsock_shutdown_request(struct vsock_conn_id *conn_id, int flags, 43 | boolean *conn_close); 44 | void vsock_conn_reset(struct vsock_conn_id *conn_id); 45 | -------------------------------------------------------------------------------- /src/unix_process/mmap_heap.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | void mmapheap_dealloc(heap h, u64 x, bytes size) 7 | { 8 | if (munmap((void *)x, size)) 9 | halt("munmap failed %s\n", errno_sstring()); 10 | } 11 | 12 | u64 mmapheap_alloc(heap h, bytes size) 13 | { 14 | void * rv = mmap(0, size + h->pagesize, PROT_READ | PROT_WRITE, 15 | MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); 16 | if (rv == MAP_FAILED) { 17 | msg_err("mmap() failed: errno %s", errno_sstring()); 18 | return INVALID_PHYSICAL; 19 | } else { 20 | return (u64_from_pointer(rv) + h->pagesize - 1) & ~(h->pagesize - 1); 21 | } 22 | } 23 | 24 | heap allocate_mmapheap(heap meta, bytes size) 25 | { 26 | heap h = allocate_zero(meta, sizeof(struct heap)); 27 | assert(h != INVALID_ADDRESS); 28 | h->alloc = mmapheap_alloc; 29 | h->dealloc = mmapheap_dealloc; 30 | h->pagesize = pad(size, 4096); 31 | return h; 32 | } 33 | -------------------------------------------------------------------------------- /src/unix_process/socket_user.h: -------------------------------------------------------------------------------- 1 | typedef struct notifier { 2 | heap h; 3 | boolean (*_register)(struct notifier *n, descriptor f, u32 events, thunk a); 4 | void (*reset_fd)(struct notifier *n, descriptor f); 5 | void (*spin)(struct notifier *n); 6 | } *notifier; 7 | 8 | #define notifier_register(n, f, e, a) ((n)->_register(n, f, e, a)) 9 | #define notifier_reset_fd(n, f) ((n)->reset_fd(n, f)) 10 | #define notifier_spin(n) ((n)->spin(n)); 11 | 12 | void connection(heap h, 13 | notifier n, 14 | buffer target, 15 | connection_handler c, 16 | status_handler failure); 17 | void listen_port(heap h, notifier n, u16 port, connection_handler); 18 | notifier create_select_notifier(heap h); 19 | notifier create_poll_notifier(heap h); 20 | notifier create_epoll_notifier(heap h); 21 | -------------------------------------------------------------------------------- /src/unix_process/ssp.c: -------------------------------------------------------------------------------- 1 | unsigned long __attribute__((weak)) __stack_chk_guard = 0x595e9fbd94fda766; 2 | -------------------------------------------------------------------------------- /src/unix_process/tiny_heap.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | typedef struct tiny { 4 | struct heap h; 5 | void *next; 6 | u64 offset; 7 | void *base; 8 | heap parent; 9 | }*tiny; 10 | 11 | static u64 alloc(heap h, u64 size) 12 | { 13 | tiny t = (tiny)h; 14 | 15 | if ((t->offset +size) > t->parent->pagesize) { 16 | void *new = allocate(t->parent, t->parent->pagesize); 17 | if (new == INVALID_ADDRESS) 18 | return INVALID_PHYSICAL; 19 | t->base = new; 20 | t->offset = sizeof(void *); 21 | return alloc(h, size); 22 | } 23 | u64 res = u64_from_pointer(t->base) + t->offset; 24 | t->offset += size; 25 | return res; 26 | } 27 | 28 | 29 | static void destroy(heap h) 30 | { 31 | tiny t = (tiny)h; 32 | heap p = t->parent; 33 | void * x=t->base; 34 | while(x) { 35 | void *next = *(void **)x; 36 | deallocate(p, next, p->pagesize); 37 | x = next; 38 | } 39 | } 40 | 41 | heap make_tiny_heap(heap parent) 42 | { 43 | void *x = allocate(parent, parent->pagesize); 44 | assert(x != INVALID_ADDRESS); 45 | tiny t = (tiny)x; 46 | t->h.alloc = alloc; 47 | t->h.dealloc = leak; 48 | t->h.destroy = destroy; 49 | t->base = x; 50 | t->parent = parent; 51 | t->offset = sizeof(struct tiny); 52 | return x; 53 | } 54 | -------------------------------------------------------------------------------- /src/unix_process/unix_process_runtime.h: -------------------------------------------------------------------------------- 1 | typedef int descriptor; 2 | heap init_process_runtime(); 3 | sstring errno_sstring(void); 4 | heap allocate_mmapheap(heap meta, bytes size); 5 | heap make_tiny_heap(heap parent); 6 | tuple parse_arguments(heap h, int argc, char **argv); 7 | -------------------------------------------------------------------------------- /src/virtio/scsi.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | int scsi_data_len(u8 cmd) 5 | { 6 | switch (cmd) { 7 | case SCSI_CMD_INQUIRY: 8 | return sizeof(struct scsi_res_inquiry); 9 | case SCSI_CMD_SERVICE_ACTION: 10 | return sizeof(struct scsi_res_read_capacity_16); 11 | case SCSI_CMD_REPORT_LUNS: 12 | return sizeof(struct scsi_res_report_luns); 13 | default: 14 | return 0; 15 | } 16 | } 17 | 18 | static void scsi_bdump_sense(buffer b, const u8 *sense, int length) 19 | { 20 | assert(length >= sizeof(struct scsi_sense_data)); 21 | for (int i = 0; i < sizeof(struct scsi_sense_data); i++) { 22 | if (i > 0) 23 | push_u8(b, ' '); 24 | bprintf(b, "%02x", sense[i]); 25 | } 26 | struct scsi_sense_data *ssd = (struct scsi_sense_data *) sense; 27 | bprintf(b, ": KEY %x, ASC/ASCQ %02x/%02x", 28 | (ssd->flags & SSD_KEY), ssd->asc, ssd->ascq); 29 | } 30 | 31 | void scsi_dump_sense(const u8 *sense, int length) 32 | { 33 | buffer b = little_stack_buffer(1024); 34 | scsi_bdump_sense(b, sense, length); 35 | rprintf("SCSI SENSE %b\n", b); 36 | } 37 | -------------------------------------------------------------------------------- /src/virtio/virtio.h: -------------------------------------------------------------------------------- 1 | void init_virtio_9p(kernel_heaps kh); 2 | void init_virtio_balloon(kernel_heaps kh); 3 | void init_virtio_blk(kernel_heaps kh, storage_attach a); 4 | void init_virtio_network(kernel_heaps kh); 5 | void init_virtio_rng(kernel_heaps kh); 6 | void init_virtio_scsi(kernel_heaps kh, storage_attach a); 7 | void init_virtio_socket(kernel_heaps kh); 8 | 9 | void virtio_mmio_enum_devs(kernel_heaps kh); 10 | -------------------------------------------------------------------------------- /src/virtio/virtio_9p.h: -------------------------------------------------------------------------------- 1 | void *v9p_get_iobuf(void *priv, u64 size); 2 | void v9p_put_iobuf(void *priv, void *buf, u64 size); 3 | 4 | int v9p_statfs(void *priv, u32 fid, struct p9_statfs_resp *resp); 5 | int v9p_lopen(void *priv, u32 fid, u32 flags, u64 *qid, u32 *iounit); 6 | int v9p_lcreate(void *priv, u32 fid, string name, u32 flags, u32 mode, u64 *qid, u32 *iounit); 7 | int v9p_symlink(void *priv, u32 dfid, string name, string target, u64 *qid); 8 | int v9p_mknod(void *priv, u32 dfid, string name, u32 mode, u32 major, u32 minor, u64 *qid); 9 | int v9p_readlink(void *priv, u32 fid, buffer target); 10 | int v9p_getattr(void *priv, u32 fid, u64 req_mask, struct p9_getattr_resp *resp); 11 | int v9p_setattr(void *priv, u32 fid, u32 valid, u32 mode, u32 uid, u32 gid, u64 size, 12 | timestamp atime, timestamp mtime); 13 | int v9p_readdir(void *priv, u32 fid, u64 offset, void *buf, u32 count, u32 *ret_count); 14 | int v9p_fsync(void *priv, u32 fid, u32 datasync); 15 | int v9p_mkdir(void *priv, u32 dfid, string name, u32 mode, u64 *qid); 16 | int v9p_renameat(void *priv, u32 old_dfid, string old_name, u32 new_dfid, string new_name); 17 | int v9p_unlinkat(void *priv, u32 dfid, string name, u32 flags); 18 | int v9p_version(void *priv, u32 msize, sstring version, u32 *ret_msize); 19 | int v9p_attach(void *priv, u32 root_fid, u64 *root_qid); 20 | int v9p_walk(void *priv, u32 fid, u32 newfid, string wname, struct p9_qid *qid); 21 | int v9p_clunk(void *priv, u32 fid); 22 | 23 | void v9p_read(void *priv, u32 fid, u64 offset, u32 count, void *dest, status_handler complete); 24 | void v9p_write(void *priv, u32 fid, u64 offset, u32 count, void *src, status_handler complete); 25 | -------------------------------------------------------------------------------- /src/virtio/virtio_endian.h: -------------------------------------------------------------------------------- 1 | /* 2 | * virtio legacy host: guest-endian 3 | * virtio v1 (modern) host: little-endian 4 | */ 5 | #define virtio_htog16(modern, val) ((modern) ? le16toh(val) : (val)) 6 | #define virtio_htog32(modern, val) ((modern) ? le32toh(val) : (val)) 7 | #define virtio_htog64(modern, val) ((modern) ? le64toh(val) : (val)) 8 | -------------------------------------------------------------------------------- /src/virtio/virtio_socket.h: -------------------------------------------------------------------------------- 1 | u32 virtio_sock_get_guest_cid(void *priv); 2 | vsock_connection virtio_sock_conn_new(void *priv, u32 local_port, u32 peer_cid, u32 peer_port, 3 | u32 buf_size); 4 | boolean virtio_sock_connect(vsock_connection conn); 5 | boolean virtio_sock_connect_abort(vsock_connection conn); 6 | void *virtio_sock_alloc_txbuf(void *priv, u64 size); 7 | void virtio_sock_free_txbuf(void *priv, void *buf); 8 | void virtio_sock_free_rxbuf(void *priv, void *buf); 9 | u64 virtio_sock_get_buf_space(vsock_connection conn); 10 | boolean virtio_sock_tx(vsock_connection conn, void *data); 11 | void virtio_sock_recved(vsock_connection conn, u64 length); 12 | boolean virtio_sock_shutdown(vsock_connection conn, int flags); 13 | -------------------------------------------------------------------------------- /src/vmware/vmware.h: -------------------------------------------------------------------------------- 1 | void init_pvscsi(kernel_heaps kh, storage_attach a); 2 | void init_vmxnet3_network(kernel_heaps kh); 3 | -------------------------------------------------------------------------------- /src/x86_64/def64.h: -------------------------------------------------------------------------------- 1 | typedef unsigned char u8; 2 | typedef char s8; 3 | typedef unsigned short u16; 4 | typedef short s16; 5 | typedef unsigned int u32; 6 | typedef int s32; 7 | typedef unsigned long long u64; 8 | typedef long long s64; 9 | typedef __uint128_t u128; 10 | 11 | typedef u64 word; 12 | typedef s64 sword; 13 | typedef u64 bytes; 14 | 15 | #define U16_MAX 0xFFFF 16 | #define S16_MAX ((s16)(U16_MAX >> 1)) 17 | #define S16_MIN (-S16_MAX - 1) 18 | 19 | #define U32_MAX (~0u) 20 | #define S32_MAX ((s32)(U32_MAX >> 1)) 21 | #define S32_MIN (-S32_MAX - 1) 22 | 23 | #define U64_MAX (~0ull) 24 | #define S64_MAX ((s64)(U64_MAX >> 1)) 25 | #define S64_MIN (-S64_MAX - 1) 26 | 27 | #define IMM_UINT_MAX (1ull << (64 - 2 /* encoding */ - 1 /* no sign */)) 28 | #define IMM_UINT_MIN (0) 29 | #define IMM_SINT_MAX ((s64)IMM_UINT_MAX) 30 | #define IMM_SINT_MIN (((s64)(1ull << 63)) >> 2) /* sign extend */ 31 | 32 | typedef void *value; 33 | typedef u8 value_tag; 34 | 35 | #define pointer_from_u64(__a) ((void *)(__a)) 36 | #define u64_from_pointer(__a) ((u64)(__a)) 37 | 38 | #define field_from_u64(u, f) (((u) >> f ## _SHIFT) & MASK(f ## _BITS)) 39 | 40 | #define DIV(__x, __by, __q, __r){ \ 41 | register u64 a asm("rax");\ 42 | register u64 d asm("rdx");\ 43 | register u64 c asm("rcx");\ 44 | a = __x;\ 45 | c = __by;\ 46 | d = 0;\ 47 | asm("divq %%rcx":"=r"(a), "=r"(d): "r"(a),"r"(d),"r"(c));\ 48 | __q = a;\ 49 | __r = d;\ 50 | } 51 | 52 | #define ROL(__x, __b)\ 53 | ({\ 54 | __asm__("rolq %1, %0": "=g"(__x): "i" (__b));\ 55 | __x;\ 56 | }) 57 | 58 | /* returns -1 if x == 0, caller must check */ 59 | static inline u64 msb(u64 x) 60 | { 61 | return x ? 63 - __builtin_clzll(x) : -1ull; 62 | } 63 | 64 | static inline u64 lsb(u64 x) 65 | { 66 | return ((s64)__builtin_ffsll(x)) - 1; 67 | } 68 | -------------------------------------------------------------------------------- /src/x86_64/elf64.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #define R_X86_64_NONE 0 5 | #define R_X86_64_64 1 6 | #define R_X86_64_PC32 2 7 | #define R_X86_64_GOT32 3 8 | #define R_X86_64_PLT32 4 9 | #define R_X86_64_COPY 5 10 | #define R_X86_64_GLOB_DAT 6 11 | #define R_X86_64_JUMP_SLOT 7 12 | #define R_X86_64_RELATIVE 8 13 | 14 | void elf_apply_relocate_add(buffer elf, Elf64_Shdr *s, u64 offset) 15 | { 16 | Elf64_Rela *rel = buffer_ref(elf, s->sh_addr); 17 | for (int i = 0; i < s->sh_size / sizeof(*rel); i++) { 18 | void *loc = buffer_ref(elf, rel[i].r_offset); 19 | switch (ELF64_R_TYPE(rel[i].r_info)) { 20 | case R_X86_64_RELATIVE: 21 | *(u64 *)loc += offset; 22 | break; 23 | } 24 | } 25 | } 26 | 27 | boolean elf_apply_relocate_syms(buffer elf, Elf64_Rela *rel, int relcount, 28 | elf_sym_relocator relocator) 29 | { 30 | for (int i = 0; i < relcount; i++) { 31 | switch (ELF64_R_TYPE(rel[i].r_info)) { 32 | case R_X86_64_GLOB_DAT: 33 | case R_X86_64_JUMP_SLOT: 34 | if (!apply(relocator, &rel[i])) 35 | return false; 36 | break; 37 | } 38 | } 39 | return true; 40 | } 41 | 42 | void arch_elf_relocate(Elf64_Rela *rel, u64 relsz, Elf64_Sym *syms, u64 base, u64 offset) 43 | { 44 | u64 *loc; 45 | u64 value; 46 | while (relsz > 0) { 47 | switch (ELF64_R_TYPE (rel->r_info)) { 48 | case R_X86_64_RELATIVE: 49 | value = 0; 50 | break; 51 | default: 52 | goto next; 53 | } 54 | loc = pointer_from_u64(base + rel->r_offset); 55 | *loc = value + rel->r_addend + offset; 56 | next: 57 | rel++; 58 | relsz -= sizeof(*rel); 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /src/x86_64/frame.h: -------------------------------------------------------------------------------- 1 | #define FRAME_RAX 0 2 | #define FRAME_RBX 1 3 | #define FRAME_RCX 2 4 | #define FRAME_RDX 3 5 | #define FRAME_RSI 4 6 | #define FRAME_RDI 5 7 | #define FRAME_RBP 6 8 | #define FRAME_RSP 7 9 | #define FRAME_R8 8 10 | #define FRAME_R9 9 11 | #define FRAME_R10 10 12 | #define FRAME_R11 11 13 | #define FRAME_R12 12 14 | #define FRAME_R13 13 15 | #define FRAME_R14 14 16 | #define FRAME_R15 15 17 | 18 | #define FRAME_RIP 16 19 | #define FRAME_EFLAGS 17 20 | #define FRAME_CS 18 21 | #define FRAME_SS 19 22 | #define FRAME_DS 20 23 | #define FRAME_ES 21 24 | #define FRAME_FSBASE 22 25 | #define FRAME_GSBASE 23 26 | 27 | #define FRAME_N_PSTATE 24 28 | 29 | #define FRAME_VECTOR 24 30 | 31 | #define FRAME_ERROR_PF_P 0x01 /* prot violation */ 32 | #define FRAME_ERROR_PF_RW 0x02 /* write access */ 33 | #define FRAME_ERROR_PF_US 0x04 /* user access */ 34 | #define FRAME_ERROR_PF_RSV 0x08 /* pte reserved set */ 35 | #define FRAME_ERROR_PF_ID 0x10 /* instruction fetch */ 36 | 37 | #define FRAME_ERROR_CODE 25 38 | #define FRAME_STACK_TOP 26 39 | 40 | #define FRAME_CR2 27 41 | #define FRAME_FULL 28 42 | #define FRAME_SAVED_RAX 29 43 | #define FRAME_EXTENDED 30 44 | #define FRAME_SIZE 31 45 | 46 | #define ERR_FRAME_RBX 0 47 | #define ERR_FRAME_RBP 1 48 | #define ERR_FRAME_R12 2 49 | #define ERR_FRAME_R13 3 50 | #define ERR_FRAME_R14 4 51 | #define ERR_FRAME_R15 5 52 | #define ERR_FRAME_RSP 6 53 | #define ERR_FRAME_RIP 7 54 | #define ERR_FRAME_SIZE 8 55 | 56 | #define ERR_FRAME_FULL ERR_FRAME_RIP 57 | -------------------------------------------------------------------------------- /src/x86_64/gdb_machine.h: -------------------------------------------------------------------------------- 1 | const int signalmap[]={8, 5, 0, 5, 8, 10, 4, 8, 7, 10, 11, 11, 11, 11, 0, 0, 8, 10, 10, 8, 10}; 2 | static inline int computeSignal (context_frame frame) 3 | { 4 | u64 exceptionVector = frame[FRAME_VECTOR]; 5 | if (exceptionVector > (sizeof(signalmap)/sizeof(int))) 6 | return(7); 7 | return(signalmap[exceptionVector]); 8 | } 9 | 10 | /* XXX This is a hack. The numbering of the registers is based on 11 | * xml files describing the registers. For reference, see 12 | * https://github.com/bminor/binutils-gdb/tree/master/gdb/features/i386 13 | * The register numbers can change based on which register groups 14 | * gdb is using. I think the qSupported xmlRegisters option can allow 15 | * the stub to define which registers are which number, which is the 16 | * real solution. */ 17 | static inline int get_register(u64 num, void *buf, context_frame f) 18 | { 19 | /* gp registers plus rip */ 20 | if (num < 17) { 21 | *(u64 *)buf = f[num]; 22 | return sizeof(u64); 23 | } else if (num >= 17 && num < 24) { 24 | *(u32 *)buf = (u32)f[num]; 25 | return sizeof(u32); 26 | } else if (num == 57 || num == 58) { 27 | *(u64 *)buf = f[num-35]; 28 | return sizeof(u64); 29 | } else 30 | return -1; 31 | } 32 | 33 | static boolean set_thread_register(thread t, int regno, u64 val) 34 | { 35 | if (regno < 22) { 36 | thread_frame(t)[regno] = val; 37 | return true; 38 | } 39 | return false; 40 | } 41 | 42 | static inline void set_thread_pc(thread t, u64 addr) 43 | { 44 | set_thread_register(t, FRAME_RIP, addr); 45 | } 46 | 47 | static inline void read_registers(buffer b, thread t) 48 | { 49 | mem2hex (b, thread_frame(t), sizeof(u64)*17); 50 | } 51 | 52 | static inline void write_registers(buffer b, thread t) 53 | { 54 | hex2mem (b, thread_frame(t), sizeof(u64)*17); 55 | } 56 | 57 | static inline void set_write_protect(boolean enable) 58 | { 59 | set_page_write_protect(enable); 60 | } 61 | -------------------------------------------------------------------------------- /src/x86_64/io.h: -------------------------------------------------------------------------------- 1 | static inline void out8(u32 port, u8 data) 2 | { 3 | __asm __volatile("outb %0, %w1" : : "a" (data), "Nd" (port)); 4 | } 5 | 6 | static inline void out16(u32 port, u16 data) 7 | { 8 | __asm __volatile("outw %0, %w1" : : "a" (data), "Nd" (port)); 9 | } 10 | 11 | static inline void out32(u32 port, u32 data) 12 | { 13 | __asm __volatile("outl %0, %w1" : : "a" (data), "Nd" (port)); 14 | } 15 | 16 | static inline void outs32(u32 port, const void *addr, u32 count) 17 | { 18 | __asm __volatile("cld; rep; outsl" 19 | : "+S" (addr), "+c" (count) 20 | : "d" (port)); 21 | } 22 | 23 | static inline void out64(u32 port, u64 data) 24 | { 25 | u32 datal = data, datah = data >> 32; 26 | __asm __volatile("outl %0, %w1" : : "a" (datal), "Nd" (port)); 27 | __asm __volatile("outl %0, %w1" : : "a" (datah), "Nd" (port + 4)); 28 | } 29 | 30 | static inline u8 in8(u32 port) 31 | { 32 | unsigned char ret; 33 | asm volatile ("inb %%dx,%%al":"=a" (ret):"d" (port)); 34 | return ret; 35 | } 36 | 37 | static inline u16 in16(u32 port) 38 | { 39 | u16 data; 40 | 41 | __asm __volatile("inw %w1, %0" : "=a" (data) : "Nd" (port)); 42 | return (data); 43 | } 44 | 45 | static inline u32 in32(u32 port) 46 | { 47 | u32 data; 48 | __asm __volatile("inl %w1, %0" : "=a" (data) : "Nd" (port)); 49 | return (data); 50 | } 51 | 52 | static inline void ins32(u32 port, void *addr, u32 count) 53 | { 54 | __asm __volatile("cld; rep; insl" 55 | : "+D" (addr), "+c" (count) 56 | : "d" (port) 57 | : "memory"); 58 | } 59 | 60 | static inline u64 in64(u32 port) 61 | { 62 | u32 datal, datah; 63 | __asm __volatile("inl %w1, %0" : "=a" (datal) : "Nd" (port)); 64 | __asm __volatile("inl %w1, %0" : "=a" (datah) : "Nd" (port + 4)); 65 | return (((u64)datah) << 32) | datal; 66 | } 67 | -------------------------------------------------------------------------------- /src/x86_64/klib.lds: -------------------------------------------------------------------------------- 1 | OUTPUT_FORMAT("elf64-x86-64") 2 | 3 | ENTRY(init) 4 | 5 | PHDRS 6 | { 7 | text PT_LOAD FLAGS(5); /* R E */ 8 | rodata PT_LOAD FLAGS(4); /* R */ 9 | data PT_LOAD FLAGS(6); /* RW */ 10 | } 11 | 12 | SECTIONS 13 | { 14 | . = SIZEOF_HEADERS; 15 | .text : { *(.text) *(.text.*) } :text 16 | . = ALIGN(4096); 17 | .rodata : { *(.rodata) *(.rodata.*) } :rodata 18 | 19 | . = ALIGN(4096); 20 | .data : { *(.data) *(.data.*) } :data 21 | .bss : { *(.bss) *(.bss.*) } :data 22 | 23 | /DISCARD/ : { *(.interp) } 24 | } 25 | -------------------------------------------------------------------------------- /src/x86_64/pvm.h: -------------------------------------------------------------------------------- 1 | /* Pagetable-based Virtual Machine hypervisor */ 2 | 3 | #ifndef PVM_H_ 4 | #define PVM_H_ 5 | 6 | struct pvm_vcpu { 7 | u64 event_flags; 8 | u32 event_errcode; 9 | u32 event_vector; 10 | u64 cr2; 11 | u64 reserved0[5]; 12 | u16 user_cs, user_ss; 13 | u32 reserved1; 14 | u64 reserved2; 15 | u64 user_gsbase; 16 | u32 eflags; 17 | u32 pkru; 18 | u64 rip; 19 | u64 rsp; 20 | u64 rcx; 21 | u64 r11; 22 | }; 23 | 24 | boolean pvm_detect(void); 25 | range pvm_get_addr_range(void); 26 | void pvm_setup(kernel_heaps kh); 27 | 28 | void pvm_cpuid(u32 leaf, u32 subleaf, u32 *v); 29 | void pvm_syscall_entry(void); 30 | void pvm_frame_return(context_frame f) __attribute__((noreturn)); 31 | void pvm_event_return(context_frame f) __attribute__((noreturn)); 32 | 33 | extern boolean pvm_detected; 34 | 35 | #endif 36 | -------------------------------------------------------------------------------- /src/x86_64/segment.inc: -------------------------------------------------------------------------------- 1 | %define SEG_DESC_G (1 << 23) ; Granularity 2 | %define SEG_DESC_DB (1 << 22) ; Code: default size, Data: big 3 | %define SEG_DESC_L (1 << 21) ; Code: Long (64-bit) 4 | %define SEG_DESC_AVL (1 << 20) ; Available 5 | %define SEG_DESC_P (1 << 15) ; Present 6 | %define SEG_DESC_DPL_SHIFT 13 7 | %define SEG_DESC_S (1 << 12) ; Code/data (vs sys) 8 | %define SEG_DESC_CODE (1 << 11) ; Code descriptor type (vs data) 9 | %define SEG_DESC_C (1 << 10) ; Conforming 10 | %define SEG_DESC_RW (1 << 9) ; Code: readable, Data: writeable 11 | %define SEG_DESC_A (1 << 8) ; Accessed 12 | 13 | %define KERN_CODE_SEG_DESC (SEG_DESC_L | SEG_DESC_P | SEG_DESC_S | SEG_DESC_CODE | SEG_DESC_RW) 14 | %define KERN_DATA_SEG_DESC (SEG_DESC_P | SEG_DESC_S | SEG_DESC_RW) 15 | %define USER_CODE_SEG_DESC (SEG_DESC_L | SEG_DESC_P | (3 << SEG_DESC_DPL_SHIFT) | SEG_DESC_S | SEG_DESC_CODE | SEG_DESC_RW) 16 | %define USER_DATA_SEG_DESC (SEG_DESC_S | (3 << SEG_DESC_DPL_SHIFT) | SEG_DESC_P | SEG_DESC_RW) 17 | -------------------------------------------------------------------------------- /src/x86_64/serial.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "serial.h" 4 | 5 | #define BASE 0x3f8 6 | 7 | void serial_init() 8 | { 9 | out8(BASE+3, 0x80); // dlab 10 | out8(BASE+0, 0x0c); // 9600 11 | out8(BASE+1, 0x0); // divisor latch 12 | out8(BASE+3, 0x3); // 8n1 13 | out8(BASE+2, 0xc7); // fifo control 14 | out8(BASE+5, 0xc7); // dtr, rts, out2 15 | } 16 | 17 | static boolean is_transmit_empty() { 18 | return in8(BASE + 5) & 0x20; 19 | } 20 | 21 | /* This floods the ftrace buffers when user is outputting lots of data */ 22 | NOTRACE 23 | void serial_putchar(char c) 24 | { 25 | while (!is_transmit_empty()) 26 | ; 27 | out8(BASE, c); 28 | } 29 | -------------------------------------------------------------------------------- /src/x86_64/serial.h: -------------------------------------------------------------------------------- 1 | void serial_init(); 2 | void serial_putchar(char c); 3 | -------------------------------------------------------------------------------- /src/x86_64/synth.h: -------------------------------------------------------------------------------- 1 | typedef u8 reg; 2 | 3 | void mov_64_imm(buffer b, reg r, u64 imm); 4 | void mov_32_imm(buffer b, reg r, u32 imm); 5 | void jump_indirect(buffer b, reg r); 6 | void indirect_displacement(buffer b, reg dest, reg source, u32 d); 7 | void indirect_scale(buffer b, reg dest, u32 scale, reg index, reg base); 8 | void debug_trap(buffer b); 9 | void indirect(buffer b, reg dest, reg source); 10 | void jump_indirect(buffer b, reg r); 11 | 12 | // definitions in tuple space 13 | // is callee save argo 14 | #if 0 15 | REGISTER_A false 16 | REGISTER_B true 17 | REGISTER_C false syscall_number 3(user) 18 | REGISTER_D false 2 19 | REGISTER_DI false 0 20 | REGISTER_SI false 1 21 | REGISTER_8 false 4 22 | REGISTER_9 false 5 23 | REGISTER_10 false 3(syscall) 24 | REGISTER_11 false syscall_flags 25 | REGISTER_12 true 26 | REGISTER_13 true 27 | REGISTER_14 true 28 | REGISTER_15 true 29 | #endif 30 | 31 | #define REGISTER_A 0 32 | #define REGISTER_B 3 33 | #define REGISTER_C 1 34 | #define REGISTER_D 2 35 | #define REGISTER_DI 7 36 | #define REGISTER_SI 6 37 | #define REGISTER_BP 5 38 | #define REGISTER_SP 4 39 | #define REGISTER_8 8 40 | #define REGISTER_9 9 41 | #define REGISTER_10 10 42 | #define REGISTER_11 11 43 | #define REGISTER_12 12 44 | #define REGISTER_13 13 45 | #define REGISTER_14 14 46 | #define REGISTER_15 15 47 | 48 | 49 | 50 | 51 | 52 | -------------------------------------------------------------------------------- /src/x86_64/uefi-crt0.s: -------------------------------------------------------------------------------- 1 | bits 64 2 | 3 | %include "longmode.inc" 4 | 5 | extern IMAGE_BASE 6 | extern _DYNAMIC ; linker symbol with the start address of the .dynamic section 7 | extern elf_dyn_relocate 8 | extern efi_main 9 | 10 | section .text 11 | 12 | global _start 13 | _start: 14 | sub rsp, 8 15 | push rcx ; image handle 16 | push rdx ; system table 17 | 18 | lea rdi, [rel IMAGE_BASE] 19 | mov rsi, rdi 20 | lea rdx, [rel _DYNAMIC] 21 | call elf_dyn_relocate 22 | 23 | mov ecx, MSR_EFER 24 | rdmsr 25 | or eax, EFER_NXE 26 | wrmsr 27 | 28 | pop rsi ; system table 29 | pop rdi ; image handle 30 | call efi_main 31 | 32 | add rsp, 8 33 | ret 34 | 35 | global read_msr 36 | read_msr: 37 | mov rcx, rdi 38 | mov rax, 0 39 | rdmsr 40 | shl rdx, 0x20 41 | or rax, rdx 42 | ret 43 | 44 | global write_msr 45 | write_msr: 46 | mov rcx, rdi 47 | mov rax, rsi 48 | mov rdx, rsi 49 | shr rdx, 0x20 50 | wrmsr 51 | ret 52 | 53 | ;; The .reloc section contains the fixup table; it must be present and non-emtpy 54 | ;; even if there are no fixups to be applied 55 | section .reloc 56 | 57 | align 4 58 | ;; Dummy fixup block, with no fixups 59 | dd 0 ; page RVA (dummy) 60 | dd 8 ; block size 61 | -------------------------------------------------------------------------------- /src/x86_64/uefi.lds: -------------------------------------------------------------------------------- 1 | OUTPUT_FORMAT("elf64-x86-64", "elf64-x86-64", "elf64-x86-64") 2 | OUTPUT_ARCH(i386:x86-64) 3 | ENTRY(_start) 4 | SECTIONS 5 | { 6 | . = 0; 7 | IMAGE_BASE = .; 8 | .hash : { *(.hash) } 9 | .gnu.hash : { *(.gnu.hash) } 10 | 11 | . = ALIGN(4096); 12 | .eh_frame : { 13 | *(.eh_frame) 14 | } 15 | 16 | . = ALIGN(4096); 17 | .text : { 18 | *(.text) 19 | *(.text.*) 20 | *(.gnu.linkonce.t.*) 21 | } 22 | 23 | . = ALIGN(4096); 24 | .reloc : { 25 | *(.reloc) 26 | } 27 | 28 | . = ALIGN(4096); 29 | .data : { 30 | *(.rodata*) 31 | *(.got.plt) 32 | *(.got) 33 | *(.data*) 34 | *(.sdata) 35 | *(.sbss) 36 | *(.scommon) 37 | *(.dynbss) 38 | *(.bss) 39 | *(COMMON) 40 | *(.rel.local) 41 | } 42 | .note.gnu.build-id : { *(.note.gnu.build-id) } 43 | 44 | . = ALIGN(4096); 45 | .dynamic : { *(.dynamic) } 46 | 47 | . = ALIGN(4096); 48 | .rela : { 49 | *(.rela.data*) 50 | *(.rela.got) 51 | *(.rela.stab) 52 | } 53 | 54 | . = ALIGN(4096); 55 | .dynsym : { *(.dynsym) } 56 | 57 | . = ALIGN(4096); 58 | .dynstr : { *(.dynstr) } 59 | 60 | . = ALIGN(4096); 61 | .ignored.reloc : { 62 | *(.rela.reloc) 63 | *(.eh_frame) 64 | *(.note.GNU-stack) 65 | } 66 | .comment 0 : { *(.comment) } 67 | } 68 | -------------------------------------------------------------------------------- /src/x86_64/vdso.lds: -------------------------------------------------------------------------------- 1 | OUTPUT_FORMAT("elf64-x86-64") 2 | 3 | SECTIONS 4 | { 5 | . = SIZEOF_HEADERS; 6 | .hash : { *(.hash) } : text 7 | .gnu.hash : { *(.gnu.hash) } : text 8 | .dynsym : { *(.dynsym) } : text 9 | .dynstr : { *(.dynstr) } : text 10 | .dynamic : { *(.dynamic) } : dynamic : text 11 | 12 | .gnu.version : { *(.gnu.version) } : text 13 | .gnu.version_d : { *(.gnu.version_d) } : text 14 | .gnu.version_r : { *(.gnu.version_r) } : text 15 | 16 | .eh_frame_hdr : { *(.eh_frame_hdr) } : eh_frame_hdr : text 17 | .eh_frame : { *(.eh_frame) } : text 18 | .text : { *(.text*) } : text 19 | 20 | /* 2 vvar pages follow the text: 21 | * i. 1 for variables in the vva 22 | * ii. 1 for the pvclock page 23 | */ 24 | vvar_page = ALIGN(4096); 25 | __vdso_vdso_dat = vvar_page + 128; 26 | pvclock_page = vvar_page + 4096; 27 | } 28 | 29 | /* 30 | * We specify the program headers to ensure that there is only a single 31 | * PT_LOAD segment 32 | * - put ELF header + program headers in text 33 | */ 34 | PHDRS 35 | { 36 | text PT_LOAD FILEHDR PHDRS FLAGS(5); /*rd+exec*/ 37 | dynamic PT_DYNAMIC FLAGS(4); /*rdonly*/ 38 | /*note PT_NOTE FLAGS(4);*/ 39 | eh_frame_hdr PT_GNU_EH_FRAME FLAGS(4); 40 | } 41 | 42 | /* Pretend like we are Linux 2.6 */ 43 | VERSION 44 | { 45 | LINUX_2.6 { 46 | global: 47 | clock_gettime; 48 | __vdso_clock_gettime; 49 | gettimeofday; 50 | __vdso_gettimeofday; 51 | getcpu; 52 | __vdso_getcpu; 53 | time; 54 | __vdso_time; 55 | local: 56 | *; 57 | }; 58 | } 59 | -------------------------------------------------------------------------------- /src/x86_64/x86.h: -------------------------------------------------------------------------------- 1 | #ifndef X86_H_ 2 | #define X86_H_ 3 | 4 | #define INTERRUPT_VECTOR_START 32 /* end of exceptions */ 5 | 6 | #ifdef KERNEL 7 | extern struct x86_pv_ops { 8 | void (*cpuid)(u32 leaf, u32 subleaf, u32 *v); 9 | void (*frame_return)(u64 *f) __attribute__((noreturn)); 10 | } pv_ops; 11 | 12 | static inline void cpuid(u32 leaf, u32 subleaf, u32 *v) 13 | { 14 | pv_ops.cpuid(leaf, subleaf, v); 15 | } 16 | #else 17 | #define cpuid x86_cpuid 18 | #endif 19 | 20 | static inline void x86_cpuid(u32 leaf, u32 subleaf, u32 *v) 21 | { 22 | asm volatile("cpuid" : "=a" (v[0]), "=b" (v[1]), "=c" (v[2]), "=d" (v[3]) : 23 | "0" (leaf), "2" (subleaf)); 24 | } 25 | 26 | void x86_frame_return(u64 *f) __attribute__((noreturn)); 27 | 28 | void common_handler(void); 29 | 30 | #endif 31 | -------------------------------------------------------------------------------- /src/x86_64/x86.inc: -------------------------------------------------------------------------------- 1 | default rel 2 | 3 | %include "frame.inc" 4 | 5 | %define FS_MSR 0xc0000100 6 | %define KERNEL_GS_MSR 0xc0000102 7 | 8 | %macro global_func 1 9 | global %1:function (%1.end - %1) 10 | %endmacro 11 | %macro global_data 1 12 | global %1:data (%1.end - %1) 13 | %endmacro 14 | 15 | extern use_xsave 16 | 17 | %macro load_extended_registers 1 18 | mov rcx, [%1+FRAME_EXTENDED*8] 19 | mov al, [use_xsave] 20 | test al, al 21 | jnz %%xs 22 | fxrstor [rcx] 23 | jmp %%out 24 | %%xs: 25 | mov edx, 0xffffffff 26 | mov eax, edx 27 | xrstor [rcx] 28 | %%out: 29 | %endmacro 30 | 31 | %macro save_extended_registers 1 32 | mov rcx, [%1+FRAME_EXTENDED*8] 33 | mov al, [use_xsave] 34 | test al, al 35 | jnz %%xs 36 | fxsave [rcx] ; we wouldn't have to do this if we could guarantee no other user thread ran before us 37 | jmp %%out 38 | %%xs: 39 | mov edx, 0xffffffff 40 | mov eax, edx 41 | xsave [rcx] 42 | %%out: 43 | %endmacro 44 | -------------------------------------------------------------------------------- /src/xen/public/io/protocols.h: -------------------------------------------------------------------------------- 1 | /****************************************************************************** 2 | * protocols.h 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a copy 5 | * of this software and associated documentation files (the "Software"), to 6 | * deal in the Software without restriction, including without limitation the 7 | * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 8 | * sell copies of the Software, and to permit persons to whom the Software is 9 | * furnished to do so, subject to the following conditions: 10 | * 11 | * The above copyright notice and this permission notice shall be included in 12 | * all copies or substantial portions of the Software. 13 | * 14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 19 | * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 20 | * DEALINGS IN THE SOFTWARE. 21 | * 22 | * Copyright (c) 2008, Keir Fraser 23 | */ 24 | 25 | #ifndef __XEN_PROTOCOLS_H__ 26 | #define __XEN_PROTOCOLS_H__ 27 | 28 | #define XEN_IO_PROTO_ABI_X86_32 "x86_32-abi" 29 | #define XEN_IO_PROTO_ABI_X86_64 "x86_64-abi" 30 | #define XEN_IO_PROTO_ABI_ARM "arm-abi" 31 | 32 | #if defined(__i386__) 33 | # define XEN_IO_PROTO_ABI_NATIVE XEN_IO_PROTO_ABI_X86_32 34 | #elif defined(__x86_64__) 35 | # define XEN_IO_PROTO_ABI_NATIVE XEN_IO_PROTO_ABI_X86_64 36 | #elif defined(__arm__) || defined(__aarch64__) 37 | # define XEN_IO_PROTO_ABI_NATIVE XEN_IO_PROTO_ABI_ARM 38 | #else 39 | # error arch fixup needed here 40 | #endif 41 | 42 | #endif 43 | -------------------------------------------------------------------------------- /test/Makefile: -------------------------------------------------------------------------------- 1 | include ../vars.mk 2 | 3 | SUBDIR= unit runtime go e2e 4 | 5 | # can't do runtime until image build is common... 6 | SUBDIR_SKIP-test= runtime 7 | 8 | all test: 9 | $(foreach d,$(filter-out $(SUBDIR_SKIP-$@),$(SUBDIR)),$(call execute_command,$(Q) $(MAKE) -C $d $@ PLATFORM=$(PLATFORM))) 10 | 11 | test: all 12 | 13 | include ../rules.mk 14 | -------------------------------------------------------------------------------- /test/e2e/Makefile: -------------------------------------------------------------------------------- 1 | # Go parameters 2 | GOBUILD= $(GO) build 3 | GOCLEAN= $(GO) clean 4 | GOTEST= $(GO) test 5 | GOGET= $(GO) get 6 | BINARY_NAME= ops 7 | 8 | include ../../vars.mk 9 | 10 | test: 11 | $(Q) $(MKDIR) $(OBJDIR) 12 | $(Q) $(LN) -sf $(PLATFORMOBJDIR)/bin/kernel.img $(OBJDIR)/kernel.img 13 | $(Q) $(LN) -sf $(PLATFORMOBJDIR)/boot/boot.img $(OBJDIR)/boot.img 14 | $(GOTEST) -v 15 | 16 | CLEANFILES+= $(OBJDIR)/kernel.img $(OBJDIR)/boot.img 17 | 18 | .PHONY: test 19 | 20 | include ../../rules.mk 21 | -------------------------------------------------------------------------------- /test/e2e/cloud_init/config.json: -------------------------------------------------------------------------------- 1 | { 2 | "Boot": "../../../output/test/e2e/boot.img", 3 | "Kernel": "../../../output/test/e2e/kernel.img", 4 | "KlibDir": "../../../output/klib/bin", 5 | "BaseVolumeSz": "20m", 6 | "Klibs": [ 7 | "cloud_init", 8 | "tls" 9 | ], 10 | "ManifestPassthrough": { 11 | "cloud_init": { 12 | "download_env": [ 13 | { 14 | "src": "http://10.0.2.2:8080" 15 | } 16 | ] 17 | }, 18 | "debug_exit":"t" 19 | } 20 | } 21 | 22 | -------------------------------------------------------------------------------- /test/e2e/cloud_init/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "os" 6 | ) 7 | 8 | func main() { 9 | b, ok := os.LookupEnv("VAR1") 10 | if ok { 11 | fmt.Println(b) 12 | } 13 | } 14 | 15 | -------------------------------------------------------------------------------- /test/e2e/e2e_test.go: -------------------------------------------------------------------------------- 1 | package e2e 2 | 3 | import "testing" 4 | 5 | func TestE2E(t *testing.T) { 6 | RunE2ETests(t) 7 | } 8 | -------------------------------------------------------------------------------- /test/e2e/go.mod: -------------------------------------------------------------------------------- 1 | module e2e 2 | 3 | go 1.13 4 | -------------------------------------------------------------------------------- /test/e2e/go/config.json: -------------------------------------------------------------------------------- 1 | { 2 | "Args": ["main"], 3 | "RunConfig": { 4 | "Ports": ["8080"] 5 | }, 6 | "Boot": "../../../output/test/e2e/boot.img", 7 | "Kernel": "../../../output/test/e2e/kernel.img" 8 | } 9 | -------------------------------------------------------------------------------- /test/e2e/go/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "net/http" 6 | ) 7 | 8 | func main() { 9 | http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) { 10 | fmt.Fprintf(w, "Hello, you've requested: %s\n", r.URL.Path) 11 | }) 12 | 13 | http.ListenAndServe(":8080", nil) 14 | } 15 | -------------------------------------------------------------------------------- /test/e2e/nginx_1.15.6/config.json: -------------------------------------------------------------------------------- 1 | { 2 | "Files": ["index.html"], 3 | "Dirs": ["usr"], 4 | "RunConfig": { 5 | "Ports": ["8084"] 6 | }, 7 | "Boot": "../../../output/test/e2e/boot.img", 8 | "Kernel": "../../../output/test/e2e/kernel.img", 9 | "BaseVolumeSz": "30m" 10 | } 11 | -------------------------------------------------------------------------------- /test/e2e/nginx_1.15.6/index.html: -------------------------------------------------------------------------------- 1 | test 2 | -------------------------------------------------------------------------------- /test/e2e/nginx_1.15.6/usr/local/nginx/conf/nginx.conf: -------------------------------------------------------------------------------- 1 | worker_processes 1; 2 | daemon off; 3 | master_process off; 4 | 5 | pid bob.pid; 6 | 7 | error_log stderr crit; 8 | 9 | 10 | events { 11 | worker_connections 1024; 12 | } 13 | 14 | http { 15 | 16 | access_log off; 17 | error_log off; 18 | 19 | 20 | server { 21 | listen 8084; 22 | 23 | location / { 24 | root /; 25 | } 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /test/e2e/node_alloc/alloc.js: -------------------------------------------------------------------------------- 1 | let array = []; 2 | let start = Date.now(); 3 | var i = setInterval(function() { 4 | if (Date.now() - start > 10000) 5 | clearInterval(i); 6 | array.push(new Array(1000000).join("x")); 7 | }, 1000); 8 | -------------------------------------------------------------------------------- /test/e2e/node_alloc/config.json: -------------------------------------------------------------------------------- 1 | { 2 | "Args": ["alloc.js"], 3 | "Boot": "../../../output/test/e2e/boot.img", 4 | "Kernel": "../../../output/test/e2e/kernel.img", 5 | "ManifestPassthrough": { 6 | "debug_exit":"t" 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /test/e2e/node_v11.5.0/config.json: -------------------------------------------------------------------------------- 1 | { 2 | "Args": ["hi.js"], 3 | "RunConfig": { 4 | "Ports": ["8083"] 5 | }, 6 | "Boot": "../../../output/test/e2e/boot.img", 7 | "Kernel": "../../../output/test/e2e/kernel.img" 8 | } 9 | -------------------------------------------------------------------------------- /test/e2e/node_v11.5.0/hi.js: -------------------------------------------------------------------------------- 1 | var http = require('http'); 2 | http.createServer(function (req, res) { 3 | res.writeHead(200, {'Content-Type': 'text/plain'}); 4 | res.end('Hello World\n'); 5 | }).listen(8083, "0.0.0.0"); 6 | console.log('Server running at http://127.0.0.1:8083/'); 7 | -------------------------------------------------------------------------------- /test/e2e/php_7.3.5/b.php: -------------------------------------------------------------------------------- 1 | on("start", function ($server) { 4 | echo "Swoole http server is started at http://127.0.0.1:9501\n"; 5 | }); 6 | $http->on("request", function ($request, $response) { 7 | $response->header("Content-Type", "text/plain"); 8 | $response->end("Hello World\n"); 9 | }); 10 | $http->start(); 11 | ?> 12 | -------------------------------------------------------------------------------- /test/e2e/php_7.3.5/config.json: -------------------------------------------------------------------------------- 1 | { 2 | "Args": ["b.php"], 3 | "RunConfig": { 4 | "Ports": ["9501"] 5 | }, 6 | "Boot": "../../../output/test/e2e/boot.img", 7 | "Kernel": "../../../output/test/e2e/kernel.img" 8 | } 9 | -------------------------------------------------------------------------------- /test/e2e/python_3.6.7/config.json: -------------------------------------------------------------------------------- 1 | { 2 | "Args":["-m", "http.server"], 3 | "RunConfig": { 4 | "Ports": ["8000"] 5 | }, 6 | "Boot": "../../../output/test/e2e/boot.img", 7 | "Kernel": "../../../output/test/e2e/kernel.img" 8 | } 9 | -------------------------------------------------------------------------------- /test/e2e/python_alloc/alloc.py: -------------------------------------------------------------------------------- 1 | def allocate_memory(): 2 | try: 3 | memory_list = [] 4 | while True: 5 | memory_list.append(" " * 1024 * 1024) 6 | except MemoryError: 7 | exit(0) 8 | 9 | if __name__ == "__main__": 10 | allocate_memory() 11 | -------------------------------------------------------------------------------- /test/e2e/python_alloc/config.json: -------------------------------------------------------------------------------- 1 | { 2 | "Args":["alloc.py"], 3 | "Boot": "../../../output/test/e2e/boot.img", 4 | "Kernel": "../../../output/test/e2e/kernel.img", 5 | "ManifestPassthrough": { 6 | "expected_exit_code": ["7","9"], 7 | "debug_exit":"t" 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /test/e2e/ruby_3.1.2/config.json: -------------------------------------------------------------------------------- 1 | { 2 | "Args": ["myapp.rb"], 3 | "RunConfig": { 4 | "Ports": ["4567"] 5 | }, 6 | "Boot": "../../../output/test/e2e/boot.img", 7 | "Kernel": "../../../output/test/e2e/kernel.img" 8 | } 9 | -------------------------------------------------------------------------------- /test/e2e/ruby_3.1.2/myapp.rb: -------------------------------------------------------------------------------- 1 | require 'sinatra' 2 | 3 | set :bind, '0.0.0.0' 4 | 5 | get '/' do 6 | 'Hello World!' 7 | end 8 | -------------------------------------------------------------------------------- /test/e2e/ruby_alloc/config.json: -------------------------------------------------------------------------------- 1 | { 2 | "Args": ["myapp.rb", "-o", "0.0.0.0"], 3 | "ENV": { 4 | "GEM_HOME": ".ruby" 5 | }, 6 | "Boot": "../../../output/test/e2e/boot.img", 7 | "Kernel": "../../../output/test/e2e/kernel.img", 8 | "ManifestPassthrough": { 9 | "debug_exit":"t", 10 | "expected_exit_code":["9", "11"] 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /test/e2e/ruby_alloc/myapp.rb: -------------------------------------------------------------------------------- 1 | begin 2 | array = [] 3 | start = Time.now 4 | while (Time.now - start) < 5 5 | array << "x" * (1024 * 1024) 6 | end 7 | rescue => e 8 | puts "Memory exhausted: #{e}" 9 | end 10 | -------------------------------------------------------------------------------- /test/e2e/rust/config.json: -------------------------------------------------------------------------------- 1 | { 2 | "Args": ["main"], 3 | "RunConfig": { 4 | "Ports": ["8080"] 5 | }, 6 | "Boot": "../../../output/test/e2e/boot.img", 7 | "Kernel": "../../../output/test/e2e/kernel.img" 8 | } 9 | -------------------------------------------------------------------------------- /test/e2e/rust/http_server.rs: -------------------------------------------------------------------------------- 1 | // Updated example from http://rosettacode.org/wiki/Hello_world/Web_server#Rust 2 | // to work with Rust 1.0 beta 3 | 4 | use std::net::{TcpStream, TcpListener}; 5 | use std::io::{Read, Write}; 6 | use std::thread; 7 | 8 | 9 | fn handle_read(mut stream: &TcpStream) { 10 | let mut buf = [0u8 ;4096]; 11 | match stream.read(&mut buf) { 12 | Ok(_) => { 13 | let req_str = String::from_utf8_lossy(&buf); 14 | println!("{}", req_str); 15 | }, 16 | Err(e) => println!("Unable to read stream: {}", e), 17 | } 18 | } 19 | 20 | fn handle_write(mut stream: TcpStream) { 21 | let response = b"HTTP/1.1 200 OK\r\nContent-Type: text/html; charset=UTF-8\r\n\r\nHello world\r\n"; 22 | match stream.write(response) { 23 | Ok(_) => println!("Response sent"), 24 | Err(e) => println!("Failed sending response: {}", e), 25 | } 26 | } 27 | 28 | fn handle_client(stream: TcpStream) { 29 | handle_read(&stream); 30 | handle_write(stream); 31 | } 32 | 33 | fn main() { 34 | let listener = TcpListener::bind("0.0.0.0:8080").unwrap(); 35 | println!("Listening for connections on port {}", 8080); 36 | 37 | for stream in listener.incoming() { 38 | match stream { 39 | Ok(stream) => { 40 | thread::spawn(|| { 41 | handle_client(stream) 42 | }); 43 | } 44 | Err(e) => { 45 | println!("Unable to connect: {}", e); 46 | } 47 | } 48 | } 49 | } 50 | 51 | -------------------------------------------------------------------------------- /test/e2e/stressdisk/config.json: -------------------------------------------------------------------------------- 1 | { 2 | "BaseVolumeSz": "32m", 3 | "Args": [ 4 | "-f=1", 5 | "-s=3", 6 | "-t=0", 7 | "-d=/tfs_mnt" 8 | ], 9 | "Mounts": { 10 | "stressdisk": "tfs_mnt" 11 | }, 12 | "RunConfig": { 13 | "Memory": "512M" 14 | }, 15 | "ManifestPassthrough": { 16 | "debug_exit":"t" 17 | }, 18 | "Boot": "../../../output/test/e2e/boot.img", 19 | "Kernel": "../../../output/test/e2e/kernel.img" 20 | } 21 | -------------------------------------------------------------------------------- /test/functional.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | cd .. && make run-nokvm & 4 | 5 | sleep 2 6 | 7 | curl -i -f -XGET http://127.0.0.1:8080 | grep '200 OK' || exit 1 8 | -------------------------------------------------------------------------------- /test/go/Makefile: -------------------------------------------------------------------------------- 1 | # Go parameters 2 | GOBUILD= $(GO) build 3 | GOCLEAN= $(GO) clean 4 | GOTEST= $(GO) test 5 | GOGET= $(GO) get 6 | GOMOD= $(GO) mod 7 | BINARY_NAME= ops 8 | 9 | include ../../vars.mk 10 | 11 | all: build 12 | 13 | build: deps 14 | $(GOBUILD) 15 | 16 | test: build 17 | $(Q) $(MKDIR) $(OBJDIR) 18 | $(Q) $(LN) -sf $(PLATFORMOBJDIR)/bin/kernel.img $(OBJDIR)/kernel.img 19 | $(Q) $(LN) -sf $(PLATFORMOBJDIR)/boot/boot.img $(OBJDIR)/boot.img 20 | $(GOTEST) -v 21 | 22 | CLEANFILES+= $(OBJDIR)/kernel.img $(OBJDIR)/boot.img 23 | 24 | post-clean: 25 | $(Q) $(GOMOD) tidy 26 | $(Q) $(GOCLEAN) 27 | $(Q) $(RM) -rf .staging 28 | $(Q) $(RM) -f $(BINARY_NAME) image ../runtime/soop.data 29 | 30 | deps: 31 | GO111MODULE=on $(GOGET) github.com/nanovms/ops/lepton 32 | $(GOMOD) tidy 33 | 34 | .PHONY: build test clean deps 35 | 36 | include ../../rules.mk 37 | -------------------------------------------------------------------------------- /test/go/go.mod: -------------------------------------------------------------------------------- 1 | module github.com/nanovms/nanos/test/go 2 | 3 | go 1.20 4 | 5 | require github.com/nanovms/ops v0.0.0-20230718011213-a3de0c53ef21 6 | 7 | require ( 8 | github.com/go-errors/errors v1.0.1 // indirect 9 | github.com/mattn/go-runewidth v0.0.10 // indirect 10 | github.com/mitchellh/colorstring v0.0.0-20190213212951-d06e56a500db // indirect 11 | github.com/olekukonko/tablewriter v0.0.4 // indirect 12 | github.com/rivo/uniseg v0.2.0 // indirect 13 | github.com/schollz/progressbar/v3 v3.7.3 // indirect 14 | golang.org/x/crypto v0.35.0 // indirect 15 | golang.org/x/sys v0.30.0 // indirect 16 | golang.org/x/term v0.29.0 // indirect 17 | ) 18 | -------------------------------------------------------------------------------- /test/go/js/hello.js: -------------------------------------------------------------------------------- 1 | console.log("hello from nodejs") 2 | -------------------------------------------------------------------------------- /test/runtime/README.md: -------------------------------------------------------------------------------- 1 | # Examples 2 | 3 | Set ```TARGET``` to run a specific example: 4 | ``` 5 | make TARGET= run 6 | ``` 7 | 8 | Certain examples require ```go``` to be built. 9 | 10 | More examples can be found in [docs/examples#examples](https://docs.opsity/ops/examples#examples). 11 | 12 | Example | Language | Description 13 | -|-|- 14 | aio | c | 15 | aslr | c | 16 | creat | c | 17 | dup | c | 18 | epoll | c | 19 | eventfd | c | 20 | fadvise | c | 21 | fallocate | c | 22 | fcntl | c | 23 | fst | go | 24 | fs_full | c | 25 | ftrace | c | 26 | futex | c | 27 | futexrobust | c | 28 | getdents | c | 29 | getrandom | c | 30 | hw | c | hello world (dynamic linking) 31 | hws | c | hello world (static linking) 32 | hwg | go | hello world 33 | inotify | c | 34 | io_uring | c | 35 | ktest | c | 36 | mkdir | c | 37 | mmap | c | 38 | netlink | c | 39 | netsock | c | 40 | nullpage | c | 41 | paging | c | 42 | pipe | c | 43 | readv | c | 44 | rename | c | 45 | sandbox | c | 46 | sendfile | c | 47 | shmem | c | 48 | signal | c | 49 | sigoverflow | c | 50 | socketpair | c | 51 | symlink | c | 52 | syslog | c | 53 | thread_test | c | 54 | time | c | 55 | tlbshootdown | c | 56 | tun | c | 57 | udploop | c | 58 | umcg | c | 59 | unixsocket | c | 60 | unlink | c | 61 | vsyscall | c | 62 | web | c | webserver on localhost:8080 (dynamic linking) 63 | webs | c | webserver on localhost:8080 (static linking) 64 | webg | go | webserver on localhost:8080 65 | write | c | 66 | writev | c | 67 | -------------------------------------------------------------------------------- /test/runtime/aio.manifest: -------------------------------------------------------------------------------- 1 | ( 2 | children:( 3 | #user program 4 | aio:(contents:(host:output/test/runtime/bin/aio)) 5 | ) 6 | # filesystem path to elf for kernel to run 7 | program:/aio 8 | # trace:t 9 | # debugsyscalls:t 10 | fault:t 11 | arguments:[aio] 12 | environment:() 13 | ) 14 | -------------------------------------------------------------------------------- /test/runtime/aslr.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | int main(int argc, char **argv) 5 | { 6 | volatile int stack_variable; 7 | void *heap_pointer = malloc(64); 8 | printf("{ 'main':%p, 'library':%p, 'heap':%p, 'stack':%p }\n", main, malloc, heap_pointer, &stack_variable); 9 | return 0; 10 | } 11 | -------------------------------------------------------------------------------- /test/runtime/aslr.manifest: -------------------------------------------------------------------------------- 1 | ( 2 | children:( 3 | #user program 4 | aslr:(contents:(host:output/test/runtime/bin/aslr)) 5 | TEST-LIBS) 6 | # filesystem path to elf for kernel to run 7 | program:/aslr 8 | # trace:t 9 | # debugsyscalls:t 10 | # noaslr:t 11 | fault:t 12 | arguments:[aslr] 13 | environment:(USER:bobby PWD:/) 14 | ) 15 | -------------------------------------------------------------------------------- /test/runtime/creat.manifest: -------------------------------------------------------------------------------- 1 | ( 2 | children:( 3 | #user program 4 | creat:(contents:(host:output/test/runtime/bin/creat)) 5 | ) 6 | # filesystem path to elf for kernel to run 7 | program:/creat 8 | # trace:t 9 | # debugsyscalls:t 10 | fault:t 11 | arguments:[webg poppy] 12 | environment:(USER:bobby PWD:/) 13 | ) 14 | -------------------------------------------------------------------------------- /test/runtime/dummy.manifest: -------------------------------------------------------------------------------- 1 | ( 2 | program:/dummy 3 | fault:t 4 | arguments:[webg poppy] 5 | environment:(USER:bobby PWD:/) 6 | ) 7 | -------------------------------------------------------------------------------- /test/runtime/dup.c: -------------------------------------------------------------------------------- 1 | #define _GNU_SOURCE 2 | #include 3 | #include 4 | #include 5 | 6 | #include "../test_utils.h" 7 | 8 | #define DUP_FD_COUNT 60000 9 | 10 | static void test_dup(void) 11 | { 12 | test_assert((dup(-1) < 0) && (errno == EBADF)); 13 | for (int i = 0; i < DUP_FD_COUNT; i++) { 14 | test_assert(dup(2) == (3 + i)); 15 | } 16 | for (int i = 0; i < DUP_FD_COUNT; i++) { 17 | test_assert(close(3 + i) == 0); 18 | } 19 | } 20 | 21 | static void test_dup2(void) 22 | { 23 | test_assert((dup2(-1, 2) < 0) && (errno == EBADF)); 24 | test_assert(dup2(1, 2) == 2); /* closing and then re-opening fd 2 */ 25 | test_assert(dup2(2, 2) == 2); 26 | for (int i = DUP_FD_COUNT; i > 2; i--) { 27 | test_assert(dup2(2, i) == i); 28 | } 29 | for (int i = DUP_FD_COUNT; i > 2; i--) { 30 | test_assert(close(i) == 0); 31 | } 32 | } 33 | 34 | static void test_dup3(void) 35 | { 36 | test_assert((dup3(2, 2, 0) < 0) && (errno == EINVAL)); 37 | test_assert((dup3(2, 3, ~O_CLOEXEC) < 0) && (errno == EINVAL)); 38 | test_assert(dup3(2, 3, 0) == 3); 39 | test_assert(close(3) == 0); 40 | } 41 | 42 | int main(int argc, char **argv) 43 | { 44 | test_dup(); 45 | test_dup2(); 46 | test_dup3(); 47 | printf("Test passed\n"); 48 | return EXIT_SUCCESS; 49 | } 50 | -------------------------------------------------------------------------------- /test/runtime/dup.manifest: -------------------------------------------------------------------------------- 1 | ( 2 | children:( 3 | #user program 4 | dup:(contents:(host:output/test/runtime/bin/dup)) 5 | ) 6 | # filesystem path to elf for kernel to run 7 | program:/dup 8 | # trace:t 9 | # debugsyscalls:t 10 | fault:t 11 | arguments:[dup] 12 | environment:() 13 | ) 14 | -------------------------------------------------------------------------------- /test/runtime/epoll.manifest: -------------------------------------------------------------------------------- 1 | ( 2 | children:( 3 | #user program 4 | epoll:(contents:(host:output/test/runtime/bin/epoll)) 5 | ) 6 | # filesystem path to elf for kernel to run 7 | program:/epoll 8 | # trace:t 9 | # debugsyscalls:t 10 | fault:t 11 | arguments:[webg poppy] 12 | environment:(USER:bobby PWD:/) 13 | ) 14 | -------------------------------------------------------------------------------- /test/runtime/eventfd.manifest: -------------------------------------------------------------------------------- 1 | ( 2 | children:( 3 | #user program 4 | eventfd:(contents:(host:output/test/runtime/bin/eventfd)) 5 | ) 6 | # filesystem path to elf for kernel to run 7 | program:/eventfd 8 | # trace:t 9 | # debugsyscalls:t 10 | # fault:t 11 | arguments:[test] 12 | environment:(USER:bobby PWD:/) 13 | ) 14 | -------------------------------------------------------------------------------- /test/runtime/fadvise.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | #include "../test_utils.h" 7 | 8 | /* fadvise stub test for parameters only */ 9 | 10 | void test_fadvise(int fd, int64_t off, uint64_t len, int adv, int exp, char *name) 11 | { 12 | int r = posix_fadvise(fd, off, len, adv); 13 | if (r != exp) { 14 | test_perror("fadvise test '%s' did not get expected result: %d != %d", 15 | name, r, exp); 16 | } 17 | } 18 | 19 | int main(int argc, char **argv) 20 | { 21 | int fd = open("test_fadvise", O_CREAT|O_RDWR, 0644); 22 | if (fd < 0) { 23 | test_perror("open"); 24 | } 25 | test_fadvise(fd, 0, 128, POSIX_FADV_SEQUENTIAL, 0, "set sequential"); 26 | test_fadvise(fd, 0, 128, POSIX_FADV_RANDOM, 0, "set random"); 27 | test_fadvise(fd, 0, 128, POSIX_FADV_NOREUSE, 0, "set noreuse"); 28 | test_fadvise(fd, 0, 128, POSIX_FADV_WILLNEED, 0, "set willneed"); 29 | test_fadvise(fd, 0, 128, POSIX_FADV_DONTNEED, 0, "set dontneed"); 30 | test_fadvise(fd, 0, 128, POSIX_FADV_NORMAL, 0, "set normal"); 31 | test_fadvise(fd, 0, 128, 9999, EINVAL, "use bad advice"); 32 | close(fd); 33 | test_fadvise(fd, 0, 128, 9999, EBADF, "use bad fd"); 34 | printf("fadvise test passed\n"); 35 | exit(EXIT_SUCCESS); 36 | } 37 | -------------------------------------------------------------------------------- /test/runtime/fadvise.manifest: -------------------------------------------------------------------------------- 1 | ( 2 | children:( 3 | #user program 4 | fadvise:(contents:(host:output/test/runtime/bin/fadvise)) 5 | ) 6 | # filesystem path to elf for kernel to run 7 | program:/fadvise 8 | # trace:t 9 | # debugsyscalls:t 10 | fault:t 11 | arguments:[fadvise] 12 | environment:() 13 | ) 14 | -------------------------------------------------------------------------------- /test/runtime/fallocate.manifest: -------------------------------------------------------------------------------- 1 | ( 2 | children:( 3 | #user program 4 | fallocate:(contents:(host:output/test/runtime/bin/fallocate)) 5 | ) 6 | # filesystem path to elf for kernel to run 7 | program:/fallocate 8 | # trace:t 9 | # debugsyscalls:t 10 | fault:t 11 | arguments:[fallocate] 12 | environment:() 13 | ) 14 | -------------------------------------------------------------------------------- /test/runtime/fcntl.manifest: -------------------------------------------------------------------------------- 1 | ( 2 | boot:( 3 | children:( 4 | klib:(children:( 5 | tmpfs:(contents:(host:ARCH_DIR/bin/tmpfs)) 6 | shmem:(contents:(host:ARCH_DIR/bin/shmem)) 7 | )) 8 | ) 9 | ) 10 | children:( 11 | #user program 12 | fcntl:(contents:(host:output/test/runtime/bin/fcntl)) 13 | ) 14 | # filesystem path to elf for kernel to run 15 | program:/fcntl 16 | klibs:bootfs 17 | # trace:t 18 | # debugsyscalls:t 19 | fault:t 20 | arguments:[webg poppy] 21 | environment:(USER:bobby PWD:/) 22 | ) 23 | -------------------------------------------------------------------------------- /test/runtime/fs_full.manifest: -------------------------------------------------------------------------------- 1 | ( 2 | children:( 3 | fs_full:(contents:(host:output/test/runtime/bin/fs_full)) 4 | ) 5 | # filesystem path to elf for kernel to run 6 | program:/fs_full 7 | # trace:t 8 | # debugsyscalls:t 9 | fault:t 10 | arguments:[fs_full] 11 | environment:(USER:bobby PWD:/) 12 | imagesize:128M 13 | ) 14 | -------------------------------------------------------------------------------- /test/runtime/fst.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "io/ioutil" 6 | "log" 7 | "os" 8 | ) 9 | 10 | func main() { 11 | d1 := []byte("hello\ngo\n") 12 | err := ioutil.WriteFile("zig", d1, 0644) 13 | if err != nil { 14 | log.Fatal(err) 15 | } 16 | 17 | fileInfo, err := os.Stat("zig") 18 | if err != nil { 19 | log.Fatal(err) 20 | } 21 | fmt.Println(fileInfo); 22 | files, err := ioutil.ReadDir("/") 23 | if err != nil { 24 | log.Fatal(err) 25 | } 26 | 27 | for _, f := range files { 28 | fmt.Println(f.Name(), f.Size(), f.IsDir()) 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /test/runtime/fst.manifest: -------------------------------------------------------------------------------- 1 | ( 2 | children:( 3 | #user program 4 | fst:(contents:(host:output/test/runtime/bin/fst)) 5 | a:(children:(hello:(contents:(host:test/runtime/getdents_contents/a/hello)))) 6 | b:(children:(stuff:(contents:(host:test/runtime/getdents_contents/b/stuff)))) 7 | c:(children:(stuff:(contents:(host:test/runtime/getdents_contents/b/stuff)))) 8 | d:(children:(stuff:(contents:(host:test/runtime/getdents_contents/b/stuff)))) 9 | e:(children:(stuff:(contents:(host:test/runtime/getdents_contents/b/stuff)))) 10 | f:(children:(stuff:(contents:(host:test/runtime/getdents_contents/b/stuff)))) 11 | g:(children:(stuff:(contents:(host:test/runtime/getdents_contents/b/stuff)))) 12 | ) 13 | # filesystem path to elf for kernel to run 14 | program:/fst 15 | #trace:t 16 | #debugsyscalls:t 17 | fault:t 18 | arguments:[webg poppy] 19 | environment:(USER:bobby PWD:/) 20 | ) 21 | -------------------------------------------------------------------------------- /test/runtime/ftrace.manifest: -------------------------------------------------------------------------------- 1 | ( 2 | children:( 3 | ftrace:(contents:(host:output/test/runtime/bin/ftrace)) 4 | infile:(contents:(host:test/runtime/read_contents/hello)) 5 | ) 6 | # filesystem path to elf for kernel to run 7 | program:/ftrace 8 | fault:t 9 | arguments:[/ftrace] 10 | environment:(USER:bobby PWD:/) 11 | ) 12 | -------------------------------------------------------------------------------- /test/runtime/futex.manifest: -------------------------------------------------------------------------------- 1 | ( 2 | children:( 3 | futex:(contents:(host:output/test/runtime/bin/futex)) 4 | ) 5 | # filesystem path to elf for kernel to run 6 | program:/futex 7 | arguments:[/futex] 8 | environment:(USER:bobby PWD:/) 9 | ) -------------------------------------------------------------------------------- /test/runtime/futexrobust.manifest: -------------------------------------------------------------------------------- 1 | ( 2 | children:( 3 | #user program 4 | futexrobust:(contents:(host:output/test/runtime/bin/futexrobust)) 5 | ) 6 | # filesystem path to elf for kernel to run 7 | program:/futexrobust 8 | # trace:t 9 | # debugsyscalls:t 10 | fault:t 11 | arguments:[futexrobust] 12 | environment:() 13 | ) 14 | -------------------------------------------------------------------------------- /test/runtime/getdents_contents/a/hello: -------------------------------------------------------------------------------- 1 | Hello, World! 2 | -------------------------------------------------------------------------------- /test/runtime/getdents_contents/b/stuff: -------------------------------------------------------------------------------- 1 | How's it going. 2 | -------------------------------------------------------------------------------- /test/runtime/getrandom.c: -------------------------------------------------------------------------------- 1 | #define _GNU_SOURCE 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | #define BUF_LEN (4ull << 20) 11 | 12 | static int hash[256]; 13 | 14 | void *malloc(size_t size); 15 | void free(void *ptr); 16 | 17 | int 18 | __getrandom(void *buf, int i, int f) 19 | { 20 | return syscall(SYS_getrandom, buf, i, f); 21 | } 22 | 23 | int main(int argc, char **argvp) 24 | { 25 | int r, i; 26 | char *buffer = malloc(BUF_LEN); 27 | if (!buffer) { 28 | printf("failed to allocate a buffer\n"); 29 | return 1; 30 | } 31 | 32 | r = __getrandom(buffer, BUF_LEN, 0); 33 | if (r != BUF_LEN) { 34 | printf("didn't get enough bytes: r = %d, errno = %d\n", r, errno); 35 | return 2; 36 | } 37 | 38 | /* Estimate Shannon entropy by: 39 | * 40 | * 1) calculate probabilities for each value 41 | * 2) calculate the log2 of each probability 42 | * 3) negative sum them up 43 | */ 44 | for (i = 0; i < BUF_LEN; i ++) 45 | hash[(unsigned char) buffer[i]] ++; 46 | 47 | /* now P(i) = hash[i] / BUF_LEN */ 48 | 49 | double entropy = 0; 50 | for (i = 0; i < 256; i ++) { 51 | double pi = ((double) hash[i]) / BUF_LEN; 52 | if (pi < (double) 0.000001) { 53 | pi = (double) 0.000001; 54 | } 55 | 56 | double log2pi = (double)log(pi) / (double)log(2); 57 | entropy += (double)pi * (double)log2pi; 58 | } 59 | 60 | entropy *= (double) -1; 61 | printf("Shannon Entropy of getrandom(2) is %f bits per byte\n", entropy); 62 | return EXIT_SUCCESS; 63 | } 64 | -------------------------------------------------------------------------------- /test/runtime/getrandom.manifest: -------------------------------------------------------------------------------- 1 | ( 2 | children:( 3 | #user program 4 | getrandom:(contents:(host:output/test/runtime/bin/getrandom)) 5 | ) 6 | # filesystem path to elf for kernel to run 7 | program:/getrandom 8 | # trace:t 9 | # debugsyscalls:t 10 | # fault:t 11 | arguments:[webg poppy] 12 | environment:(USER:bobby PWD:/) 13 | ) 14 | -------------------------------------------------------------------------------- /test/runtime/hw.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | int main(int argc, char **argv) 6 | { 7 | printf("hello world!\n"); 8 | printf("args:\n"); 9 | for (int i = 0; i < argc; i++) printf (" %s\n", argv[i]); 10 | return EXIT_SUCCESS; 11 | } 12 | 13 | -------------------------------------------------------------------------------- /test/runtime/hw.manifest: -------------------------------------------------------------------------------- 1 | ( 2 | children:( 3 | #user program 4 | hw:(contents:(host:output/test/runtime/bin/hw)) 5 | etc:(children:(ld.so.cache:(contents:(host:/etc/ld.so.cache)))) 6 | TEST-LIBS) 7 | # filesystem path to elf for kernel to run 8 | program:/hw 9 | # trace:t 10 | # debugsyscalls:t 11 | fault:t 12 | arguments:[hw poppy] 13 | environment:(USER:bobby PWD:/) 14 | ) 15 | -------------------------------------------------------------------------------- /test/runtime/hwg.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ("fmt") 4 | 5 | func main() { 6 | fmt.Println("hello world"); 7 | } 8 | -------------------------------------------------------------------------------- /test/runtime/hwg.manifest: -------------------------------------------------------------------------------- 1 | ( 2 | children:( 3 | #user program 4 | hwg:(contents:(host:output/test/runtime/bin/hwg)) 5 | etc:(children:(ld.so.cache:(contents:(host:/etc/ld.so.cache)))) 6 | TEST-LIBS) 7 | # filesystem path to elf for kernel to run 8 | program:/hwg 9 | # trace:t 10 | # debugsyscalls:t 11 | fault:t 12 | arguments:[hwg poppy] 13 | environment:(USER:bobby PWD:/) 14 | ) 15 | -------------------------------------------------------------------------------- /test/runtime/hws.manifest: -------------------------------------------------------------------------------- 1 | ( 2 | boot:( 3 | children:( 4 | klib:(children:( 5 | strace:(contents:(host:ARCH_DIR/bin/strace)) 6 | )) 7 | ) 8 | ) 9 | klibs:bootfs 10 | children:( 11 | #user program 12 | hws:(contents:(host:output/test/runtime/bin/hws))) 13 | # filesystem path to elf for kernel to run 14 | program:/hws 15 | # trace:t 16 | # debugsyscalls:t 17 | # fault:t 18 | arguments:[webg poppy] 19 | environment:(USER:bobby PWD:/) 20 | ) 21 | -------------------------------------------------------------------------------- /test/runtime/inotify.manifest: -------------------------------------------------------------------------------- 1 | ( 2 | children:( 3 | inotify:(contents:(host:output/test/runtime/bin/inotify)) 4 | ) 5 | program:/inotify 6 | environment:() 7 | ) 8 | -------------------------------------------------------------------------------- /test/runtime/io_uring.manifest: -------------------------------------------------------------------------------- 1 | ( 2 | children:( 3 | io_uring:(contents:(host:output/test/runtime/bin/io_uring)) 4 | etc:(children:(ld.so.cache:(contents:(host:/etc/ld.so.cache)) passwd:(contents:(host:/etc/passwd)) group:(contents:(host:/etc/group)))) 5 | ) 6 | program:/io_uring 7 | # trace:t 8 | # debugsyscalls:t 9 | fault:t 10 | environment:() 11 | imagesize:30M 12 | ) 13 | -------------------------------------------------------------------------------- /test/runtime/ktest.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | int main(int argc, char **argv) 4 | { 5 | /* nothing to do: if this program is started, in-kernel tests have already run successfully */ 6 | return EXIT_SUCCESS; 7 | } 8 | 9 | -------------------------------------------------------------------------------- /test/runtime/ktest.manifest: -------------------------------------------------------------------------------- 1 | ( 2 | boot:( 3 | children:( 4 | klib:(children:( 5 | test:(children:( 6 | klib:(contents:(host:ARCH_DIR/bin/test/klib)) 7 | lock:(contents:(host:ARCH_DIR/bin/test/lock)) 8 | page_table:(contents:(host:ARCH_DIR/bin/test/page_table)) 9 | )) 10 | )) 11 | ) 12 | ) 13 | children:( 14 | #user program 15 | ktest:(contents:(host:output/test/runtime/bin/ktest)) 16 | etc:(children:(ld.so.cache:(contents:(host:/etc/ld.so.cache))))) 17 | # filesystem path to elf for kernel to run 18 | program:/ktest 19 | klibs:bootfs 20 | klib_test:t 21 | arguments:[ktest] 22 | environment:() 23 | ) 24 | -------------------------------------------------------------------------------- /test/runtime/mkdir.manifest: -------------------------------------------------------------------------------- 1 | ( 2 | children:( 3 | #user program 4 | mkdir:(contents:(host:output/test/runtime/bin/mkdir)) 5 | tmp:(children:(mkdir_test:(children:()))) 6 | ) 7 | # filesystem path to elf for kernel to run 8 | program:/mkdir 9 | # trace:t 10 | # debugsyscalls:t 11 | # fault:t 12 | arguments:[mkdir /tmp/mkdir_test] 13 | environment:(USER:bobby PWD:/) 14 | cwd:/tmp/mkdir_test 15 | ) 16 | -------------------------------------------------------------------------------- /test/runtime/mmap.manifest: -------------------------------------------------------------------------------- 1 | ( 2 | children:( 3 | mmap:(contents:(host:output/test/runtime/bin/mmap)) 4 | infile:(contents:(host:test/runtime/read_contents/hello)) 5 | mapfile:(contents:(host:test/runtime/read_contents/mapfile)) 6 | mapfile2:(contents:(host:test/runtime/read_contents/mapfile)) 7 | stattest:(contents:(host:test/runtime/read_contents/mapfile)) 8 | unmapme:(contents:(host:test/runtime/read_contents/unmapme)) 9 | testpath:(contents:(host:test/runtime/read_contents/testpath)) 10 | ) 11 | # filesystem path to elf for kernel to run 12 | program:/mmap 13 | # trace:t 14 | # debugsyscalls:t 15 | # mmap_min_addr:0 16 | fault:t 17 | arguments:[/mmap] # intensive, zeropage, exec 18 | environment:(USER:bobby PWD:/) 19 | exec_protection:t 20 | imagesize:30M 21 | ) 22 | -------------------------------------------------------------------------------- /test/runtime/netlink.manifest: -------------------------------------------------------------------------------- 1 | ( 2 | children:( 3 | netlink:(contents:(host:output/test/runtime/bin/netlink)) 4 | ) 5 | program:/netlink 6 | environment:() 7 | ) 8 | -------------------------------------------------------------------------------- /test/runtime/netsock.manifest: -------------------------------------------------------------------------------- 1 | ( 2 | children:( 3 | netsock:(contents:(host:output/test/runtime/bin/netsock)) 4 | ) 5 | program:/netsock 6 | fault:t 7 | environment:() 8 | ) 9 | -------------------------------------------------------------------------------- /test/runtime/nullpage.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | int 5 | main() 6 | { 7 | printf("started\n"); 8 | 9 | char *p = 0; 10 | memcpy(p, "\xcd\x03", 2); 11 | 12 | printf("before\n"); 13 | ((void(*)())p)(); 14 | printf("after\n"); 15 | 16 | return 0; 17 | } 18 | -------------------------------------------------------------------------------- /test/runtime/nullpage.manifest: -------------------------------------------------------------------------------- 1 | ( 2 | children:( 3 | nullpage:(contents:(host:output/test/runtime/bin/nullpage)) 4 | ) 5 | program:/nullpage 6 | # trace:t 7 | # debugsyscalls:t 8 | fault:t 9 | arguments:[nullpage] 10 | environment:(USER:bobby PWD:/) 11 | ) 12 | -------------------------------------------------------------------------------- /test/runtime/paging.manifest: -------------------------------------------------------------------------------- 1 | ( 2 | children:( 3 | paging:(contents:(host:output/test/runtime/bin/paging)) 4 | ) 5 | program:/paging 6 | # trace:t 7 | # debugsyscalls:t 8 | fault:t 9 | # available tests: { write-exec, write-ro, exec-mmap, exec-heap, exec-stack } 10 | arguments:[paging write-exec] 11 | environment:(USER:bobby PWD:/) 12 | ) 13 | -------------------------------------------------------------------------------- /test/runtime/pipe.manifest: -------------------------------------------------------------------------------- 1 | ( 2 | children:( 3 | #user program 4 | pipe:(contents:(host:output/test/runtime/bin/pipe)) 5 | ) 6 | # filesystem path to elf for kernel to run 7 | program:/pipe 8 | # trace:t 9 | # debugsyscalls:t 10 | # fault:t 11 | arguments:[test] 12 | environment:(USER:bobby PWD:/) 13 | ) 14 | -------------------------------------------------------------------------------- /test/runtime/read_contents/hello: -------------------------------------------------------------------------------- 1 | pad one six four 2 | -------------------------------------------------------------------------------- /test/runtime/read_contents/mapfile: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nanovms/nanos/478b8825bd6edc382080a772b228a49d26d2644b/test/runtime/read_contents/mapfile -------------------------------------------------------------------------------- /test/runtime/read_contents/testpath: -------------------------------------------------------------------------------- 1 | /infile -------------------------------------------------------------------------------- /test/runtime/read_contents/unmapme: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nanovms/nanos/478b8825bd6edc382080a772b228a49d26d2644b/test/runtime/read_contents/unmapme -------------------------------------------------------------------------------- /test/runtime/readv.manifest: -------------------------------------------------------------------------------- 1 | ( 2 | children:( 3 | readv:(contents:(host:output/test/runtime/bin/readv)) 4 | hello:(contents:(host:test/runtime/read_contents/hello)) 5 | ) 6 | program:/readv 7 | # trace:t 8 | # debugsyscalls:t 9 | fault:t 10 | arguments:[/] 11 | environment:(USER:bobby PWD:/) 12 | ) 13 | -------------------------------------------------------------------------------- /test/runtime/rename.manifest: -------------------------------------------------------------------------------- 1 | ( 2 | children:( 3 | #user program 4 | rename:(contents:(host:output/test/runtime/bin/rename)) 5 | ) 6 | # filesystem path to elf for kernel to run 7 | program:/rename 8 | # trace:t 9 | # debugsyscalls:t 10 | fault:t 11 | arguments:[rename] 12 | environment:() 13 | ) 14 | -------------------------------------------------------------------------------- /test/runtime/resolv.conf: -------------------------------------------------------------------------------- 1 | nameserver 8.8.8.8 2 | -------------------------------------------------------------------------------- /test/runtime/sandbox.manifest: -------------------------------------------------------------------------------- 1 | ( 2 | boot:( 3 | children:( 4 | klib:(children:( 5 | sandbox:(contents:(host:ARCH_DIR/bin/sandbox)) 6 | )) 7 | ) 8 | ) 9 | children:( 10 | sandbox:(contents:(host:output/test/runtime/bin/sandbox)) 11 | ) 12 | program:/sandbox 13 | klibs:bootfs 14 | environment:() 15 | sandbox:(pledge:() unveil:()) 16 | ) 17 | -------------------------------------------------------------------------------- /test/runtime/sendfile.manifest: -------------------------------------------------------------------------------- 1 | ( 2 | children:( 3 | # files 4 | infile:(contents:(host:test/runtime/write_contents/infile)) 5 | outfile:(contents:(host:test/runtime/write_contents/outfile)) 6 | 7 | #user program 8 | sendfile:(contents:(host:output/test/runtime/bin/sendfile)) 9 | etc:(children:(ld.so.cache:(contents:(host:/etc/ld.so.cache))))) 10 | # filesystem path to elf for kernel to run 11 | program:/sendfile 12 | # put all the tracing arguments in subtree 13 | #trace: 14 | #debugsyscalls:t 15 | fault:t 16 | arguments:[sendfile longargument] 17 | environment:(USER:bobby PWD:password) 18 | ) 19 | -------------------------------------------------------------------------------- /test/runtime/shmem.manifest: -------------------------------------------------------------------------------- 1 | ( 2 | boot:( 3 | children:( 4 | klib:(children:( 5 | tmpfs:(contents:(host:ARCH_DIR/bin/tmpfs)) 6 | shmem:(contents:(host:ARCH_DIR/bin/shmem)) 7 | )) 8 | ) 9 | ) 10 | children:( 11 | shmem:(contents:(host:output/test/runtime/bin/shmem)) 12 | ) 13 | klibs:bootfs 14 | program:/shmem 15 | environment:() 16 | ) 17 | -------------------------------------------------------------------------------- /test/runtime/signal.manifest: -------------------------------------------------------------------------------- 1 | ( 2 | children:( 3 | #user program 4 | signal:(contents:(host:output/test/runtime/bin/signal)) 5 | ) 6 | # filesystem path to elf for kernel to run 7 | program:/signal 8 | # trace:t 9 | # debugsyscalls:t 10 | # fault:t 11 | arguments:[test] 12 | environment:(USER:bobby PWD:/) 13 | ) 14 | -------------------------------------------------------------------------------- /test/runtime/sigoverflow.c: -------------------------------------------------------------------------------- 1 | #define _GNU_SOURCE 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | void handler(int signo) 10 | { 11 | switch (signo) { 12 | case SIGUSR1: 13 | break; 14 | case SIGABRT: 15 | break; 16 | default: 17 | break; 18 | } 19 | abort(); 20 | } 21 | 22 | void *thread(void *a) 23 | { 24 | usleep(1000*1000); 25 | return 0; 26 | } 27 | 28 | int main(int argc, char **argv) 29 | { 30 | pthread_t pt; 31 | 32 | printf("expecting signal stack overflow to segfault...\n"); 33 | pid_t pid = getpid(); 34 | pthread_create(&pt, NULL, thread, 0); 35 | assert(signal(SIGUSR1, handler) != SIG_ERR); 36 | assert(signal(SIGABRT, handler) != SIG_ERR); 37 | kill(pid, SIGUSR1); 38 | pthread_join(pt, 0); 39 | return 0; 40 | } 41 | 42 | -------------------------------------------------------------------------------- /test/runtime/sigoverflow.manifest: -------------------------------------------------------------------------------- 1 | ( 2 | children:( 3 | #user program 4 | sigoverflow:(contents:(host:output/test/runtime/bin/sigoverflow)) 5 | ) 6 | # filesystem path to elf for kernel to run 7 | program:/sigoverflow 8 | # trace:t 9 | # debugsyscalls:t 10 | # fault:t 11 | arguments:[test] 12 | environment:(USER:bobby PWD:/) 13 | # expect to segfault 14 | expected_exit_code:11 15 | ) 16 | -------------------------------------------------------------------------------- /test/runtime/socketpair.manifest: -------------------------------------------------------------------------------- 1 | ( 2 | children:( 3 | #user program 4 | socketpair:(contents:(host:output/test/runtime/bin/socketpair)) 5 | ) 6 | # filesystem path to elf for kernel to run 7 | program:/socketpair 8 | # trace:t 9 | # debugsyscalls:t 10 | # fault:t 11 | arguments:[socketpair] 12 | environment:(USER:bobby PWD:/) 13 | ) 14 | -------------------------------------------------------------------------------- /test/runtime/symlink.manifest: -------------------------------------------------------------------------------- 1 | ( 2 | children:( 3 | #user program 4 | symlink:(contents:(host:output/test/runtime/bin/symlink)) 5 | ) 6 | # filesystem path to elf for kernel to run 7 | program:/symlink 8 | # trace:t 9 | # debugsyscalls:t 10 | fault:t 11 | arguments:[symlink] 12 | environment:() 13 | ) 14 | -------------------------------------------------------------------------------- /test/runtime/syslog.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | #include 9 | 10 | #include "../test_utils.h" 11 | 12 | #define SYSLOG_FILE_PATH "var/log/syslog" 13 | 14 | static void syslog_test_basic(void) 15 | { 16 | const int total = 64 * KB; 17 | struct stat s; 18 | int fd; 19 | char buf[64]; 20 | 21 | do { 22 | printf("01234567890123456789012345678901234567890123456789012345678901234567890123456789"); 23 | test_assert(stat(SYSLOG_FILE_PATH, &s) == 0); 24 | } while (s.st_size < total); 25 | 26 | /* Look for the pattern output via printf() in the syslog file (which will contain kernel trace 27 | * messages interspersed with the printf output). */ 28 | fd = open(SYSLOG_FILE_PATH, O_RDONLY); 29 | test_assert(fd > 0); 30 | buf[sizeof(buf) - 1] = '\0'; 31 | while (1) { 32 | test_assert(read(fd, buf, sizeof(buf) - 1) == sizeof(buf) - 1); 33 | if (strstr(buf, "0123456789")) 34 | break; 35 | } 36 | } 37 | 38 | int main(int argc, char **argv) 39 | { 40 | syslog_test_basic(); 41 | return EXIT_SUCCESS; 42 | } 43 | -------------------------------------------------------------------------------- /test/runtime/syslog.manifest: -------------------------------------------------------------------------------- 1 | ( 2 | boot:( 3 | children:( 4 | klib:(children:( 5 | strace:(contents:(host:ARCH_DIR/bin/strace)) 6 | syslog:(contents:(host:ARCH_DIR/bin/syslog)) 7 | )) 8 | ) 9 | ) 10 | children:( 11 | syslog:(contents:(host:output/test/runtime/bin/syslog)) 12 | ) 13 | klibs:bootfs 14 | syslog:( 15 | file:var/log/syslog 16 | ) 17 | consoles:[-serial -vga] 18 | trace:t 19 | debugsyscalls:t 20 | environment:() 21 | program:syslog 22 | ) 23 | -------------------------------------------------------------------------------- /test/runtime/thread_test.manifest: -------------------------------------------------------------------------------- 1 | ( 2 | children:( 3 | tt:(contents:(host:output/test/runtime/bin/thread_test))) 4 | program:/tt 5 | arguments:[thread_test] 6 | environment:(USER:bobby PWD:/) 7 | # trace:t 8 | # debugsyscalls:t 9 | ) 10 | -------------------------------------------------------------------------------- /test/runtime/time.manifest: -------------------------------------------------------------------------------- 1 | ( 2 | children:( 3 | #user program 4 | time:(contents:(host:output/test/runtime/bin/time)) 5 | ) 6 | # filesystem path to elf for kernel to run 7 | program:/time 8 | # trace:t 9 | # debugsyscalls:t 10 | # fault:t 11 | arguments:[time -s] 12 | environment:(USER:bobby PWD:/) 13 | ) 14 | -------------------------------------------------------------------------------- /test/runtime/tlbshootdown.manifest: -------------------------------------------------------------------------------- 1 | ( 2 | children:( 3 | tlbshootdown:(contents:(host:output/test/runtime/bin/tlbshootdown)) 4 | ) 5 | # filesystem path to elf for kernel to run 6 | program:/tlbshootdown 7 | # trace:t 8 | # debugsyscalls:t 9 | fault:t 10 | arguments:[tlbshootdown] 11 | environment:(USER:bobby PWD:/) 12 | exec_protection:t 13 | imagesize:30M 14 | ) 15 | -------------------------------------------------------------------------------- /test/runtime/tun.manifest: -------------------------------------------------------------------------------- 1 | ( 2 | boot:( 3 | children:( 4 | klib:(children:(tun:(contents:(host:ARCH_DIR/bin/tun)))) 5 | ) 6 | ) 7 | children:( 8 | tun:(contents:(host:output/test/runtime/bin/tun)) 9 | ) 10 | klibs:bootfs 11 | environment:() 12 | program:/tun 13 | ) 14 | -------------------------------------------------------------------------------- /test/runtime/udploop.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | #include "../test_utils.h" 9 | 10 | #define DEFAULT_PORT 5309 11 | #define BUFLEN 1500 12 | 13 | int main(int argc, char ** argv) 14 | { 15 | heap h = init_process_runtime(); 16 | tuple t = parse_arguments(h, argc, argv); 17 | u16 lport = DEFAULT_PORT; 18 | char buf[BUFLEN]; 19 | u64 result; 20 | 21 | if (get_u64(t, sym(port), &result)) 22 | lport = result; 23 | rprintf("using local port %d\n", lport); 24 | 25 | int fd = socket(AF_INET, SOCK_DGRAM, 0); 26 | if (fd < 0) 27 | test_perror("socket"); 28 | 29 | struct sockaddr_in lsin; 30 | lsin.sin_family = AF_INET; 31 | lsin.sin_port = htons(lport); 32 | lsin.sin_addr.s_addr = htonl(INADDR_ANY); 33 | 34 | if (bind(fd, (struct sockaddr *)&lsin, sizeof(lsin)) < 0) 35 | test_perror("bind"); 36 | 37 | struct sockaddr_in rsin; 38 | socklen_t rsin_len = sizeof(rsin); 39 | const char * tstr = "terminate"; 40 | do { 41 | int rlen = recvfrom(fd, buf, BUFLEN, 0, (struct sockaddr *)&rsin, &rsin_len); 42 | if (rlen < 0) 43 | test_perror("recvfrom"); 44 | if (rlen == 0) 45 | continue; 46 | 47 | int slen = sendto(fd, buf, rlen, 0, (struct sockaddr *)&rsin, rsin_len); 48 | // XXX retry on EINTR / EAGAIN 49 | if (slen < 0) 50 | test_perror("sendto"); 51 | 52 | int tlen = strlen(tstr); 53 | if (rlen >= tlen && strncmp(tstr, buf, tlen) == 0) { 54 | rprintf("success\n"); 55 | close(fd); 56 | exit(EXIT_SUCCESS); 57 | } 58 | } while(1); 59 | 60 | return 0; 61 | } 62 | -------------------------------------------------------------------------------- /test/runtime/udploop.manifest: -------------------------------------------------------------------------------- 1 | ( 2 | children:( 3 | #user program 4 | udploop:(contents:(host:output/test/runtime/bin/udploop))) 5 | # filesystem path to elf for kernel to run 6 | program:/udploop 7 | fault:t 8 | arguments:[udploop] 9 | environment:(USER:bobby PWD:/) 10 | ) 11 | -------------------------------------------------------------------------------- /test/runtime/umcg.manifest: -------------------------------------------------------------------------------- 1 | ( 2 | boot:( 3 | children:( 4 | klib:(children:(umcg:(contents:(host:ARCH_DIR/bin/umcg)))) 5 | ) 6 | ) 7 | children:( 8 | umcg:(contents:(host:output/test/runtime/bin/umcg)) 9 | TEST-LIBS 10 | ) 11 | klibs:bootfs 12 | program:/umcg 13 | environment:() 14 | arguments:[umcg] 15 | ) 16 | -------------------------------------------------------------------------------- /test/runtime/unixsocket.manifest: -------------------------------------------------------------------------------- 1 | ( 2 | children:( 3 | #user program 4 | unixsocket:(contents:(host:output/test/runtime/bin/unixsocket)) 5 | ) 6 | # filesystem path to elf for kernel to run 7 | program:/unixsocket 8 | # trace:t 9 | # debugsyscalls:t 10 | fault:t 11 | arguments:[unixsocket] 12 | environment:() 13 | ) 14 | -------------------------------------------------------------------------------- /test/runtime/unlink.manifest: -------------------------------------------------------------------------------- 1 | ( 2 | children:( 3 | #user program 4 | unlink:(contents:(host:output/test/runtime/bin/unlink)) 5 | ) 6 | # filesystem path to elf for kernel to run 7 | program:/unlink 8 | # trace:t 9 | # debugsyscalls:t 10 | fault:t 11 | arguments:[unlink] 12 | environment:() 13 | ) 14 | -------------------------------------------------------------------------------- /test/runtime/vsyscall.c: -------------------------------------------------------------------------------- 1 | /* vsyscall test */ 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | #include "../test_utils.h" 10 | 11 | #define VSYSCALL_BASE 0xffffffffff600000ull 12 | #define VSYSCALL_OFFSET_VGETTIMEOFDAY 0x000 13 | #define VSYSCALL_OFFSET_VTIME 0x400 14 | #define VSYSCALL_OFFSET_VGETCPU 0x800 15 | 16 | typedef long (*gettimeofday_fn)(struct timeval *tv, struct timezone *tz); 17 | typedef long (*time_fn)(time_t *); 18 | typedef long (*getcpu_fn)(unsigned *, unsigned *, void *); 19 | 20 | static gettimeofday_fn vgettimeofday = (gettimeofday_fn)(VSYSCALL_BASE + VSYSCALL_OFFSET_VGETTIMEOFDAY); 21 | static time_fn vtime = (time_fn)(VSYSCALL_BASE + VSYSCALL_OFFSET_VTIME); 22 | static getcpu_fn vgetcpu = (getcpu_fn)(VSYSCALL_BASE + VSYSCALL_OFFSET_VGETCPU); 23 | 24 | int main(int argc, char * argv[]) 25 | { 26 | unsigned cpu = 0, node = 0; 27 | if (vgetcpu(&cpu, &node, NULL) != 0) { 28 | test_perror("vgetcpu"); 29 | } 30 | printf("vgetcpu: cpu %d, node %d\n", cpu, node); 31 | 32 | for (int i = 0; i < 3; i++) { 33 | struct timeval tv; 34 | time_t t1, t2; 35 | 36 | vgettimeofday(&tv, NULL); 37 | printf("vgettimeofday: tv_sec = %lu, tv_usec = %lu\n", tv.tv_sec, tv.tv_usec); 38 | 39 | t1 = vtime(NULL); 40 | if (t1 == -1) { 41 | test_perror("vtime #1"); 42 | } 43 | printf("vtime with null arg: returned %lu\n", t1); 44 | 45 | t1 = vtime(&t2); 46 | if (t1 == -1) { 47 | test_perror("vtime #2"); 48 | } 49 | printf("vtime with arg: returned %lu, stored %lu\n", t1, t2); 50 | if (t1 != t2) { 51 | test_error("return val and stored time mismatch"); 52 | } 53 | 54 | sleep(1); 55 | } 56 | 57 | return EXIT_SUCCESS; 58 | } 59 | -------------------------------------------------------------------------------- /test/runtime/vsyscall.manifest: -------------------------------------------------------------------------------- 1 | ( 2 | children:( 3 | #user program 4 | vsyscall:(contents:(host:output/test/runtime/bin/vsyscall)) 5 | ) 6 | # filesystem path to elf for kernel to run 7 | program:/vsyscall 8 | # trace:t 9 | # debugsyscalls:t 10 | # fault:t 11 | arguments:[vsyscall] 12 | environment:(USER:bobby PWD:/) 13 | ) 14 | -------------------------------------------------------------------------------- /test/runtime/web.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | closure_function(1, 3, void, each_request, 7 | heap, h, 8 | http_method m, http_responder out, value v) 9 | { 10 | send_http_response(out, 11 | timm("ContentType", "text/html"), 12 | aprintf(bound(h), "unibooty!")); 13 | } 14 | 15 | int main(int argc, char **argv) 16 | { 17 | heap h = init_process_runtime(); 18 | tuple t = parse_arguments(h, argc, argv); 19 | notifier n = get(t, sym(select)) ? create_select_notifier(h) : 20 | get(t, sym(poll)) ? create_poll_notifier(h) : 21 | create_epoll_notifier(h); 22 | u16 port = 8080; 23 | http_listener hl = allocate_http_listener(h, port); 24 | http_register_default_handler(hl, closure(h, each_request, h)); 25 | listen_port(h, n, port, connection_handler_from_http_listener(hl)); 26 | rprintf("Server started on port %d\n", port); 27 | notifier_spin(n); 28 | return 0; 29 | } 30 | -------------------------------------------------------------------------------- /test/runtime/web.manifest: -------------------------------------------------------------------------------- 1 | ( 2 | children:( 3 | web:(contents:(host:output/test/runtime/bin/web)) 4 | etc:(children:( 5 | ld.so.cache:(contents:(host:/etc/ld.so.cache)) 6 | )) 7 | TEST-LIBS) 8 | program:/web 9 | # trace:t 10 | # debugsyscalls:t 11 | fault:t 12 | arguments:[web] 13 | environment:(USER:bobby PWD:/) 14 | ) 15 | -------------------------------------------------------------------------------- /test/runtime/webg.manifest: -------------------------------------------------------------------------------- 1 | ( 2 | children:( 3 | #user program 4 | webg:(contents:(host:output/test/runtime/bin/webg)) 5 | etc:(children:(ld.so.cache:(contents:(host:/etc/ld.so.cache)) resolv.conf:(contents:(host:test/runtime/resolv.conf)))) 6 | TEST-LIBS) 7 | # filesystem path to elf for kernel to run 8 | program:/webg 9 | # put all the tracing arguments in subtree 10 | # trace:t 11 | # debugsyscalls:t 12 | # telnet:t 13 | # http:t 14 | # fault:t 15 | # reboot_on_exit:t 16 | arguments:[webg longargument] 17 | environment:(USER:bobby PWD:password) 18 | ) 19 | -------------------------------------------------------------------------------- /test/runtime/webs-poll.manifest: -------------------------------------------------------------------------------- 1 | ( 2 | children:( 3 | #user program 4 | webs:(contents:(host:output/test/runtime/bin/webs))) 5 | # filesystem path to elf for kernel to run 6 | program:/webs 7 | fault:t 8 | arguments:[webs -poll 1] 9 | environment:(USER:bobby PWD:/) 10 | ) 11 | -------------------------------------------------------------------------------- /test/runtime/webs-select.manifest: -------------------------------------------------------------------------------- 1 | ( 2 | children:( 3 | #user program 4 | webs:(contents:(host:output/test/runtime/bin/webs))) 5 | # filesystem path to elf for kernel to run 6 | program:/webs 7 | fault:t 8 | arguments:[webs -select 1] 9 | environment:(USER:bobby PWD:/) 10 | ) 11 | -------------------------------------------------------------------------------- /test/runtime/webs.manifest: -------------------------------------------------------------------------------- 1 | ( 2 | children:( 3 | #user program 4 | webs:(contents:(host:output/test/runtime/bin/webs))) 5 | # filesystem path to elf for kernel to run 6 | program:/webs 7 | fault:t 8 | arguments:[webs] 9 | environment:(USER:bobby PWD:/) 10 | ) 11 | -------------------------------------------------------------------------------- /test/runtime/write.manifest: -------------------------------------------------------------------------------- 1 | ( 2 | children:( 3 | write:(contents:(host:output/test/runtime/bin/write)) 4 | hello:(contents:(host:test/runtime/write_contents/hello)) 5 | ) 6 | program:/write 7 | # trace:t 8 | # debugsyscalls:t 9 | fault:t 10 | # arguments:[write -p] 11 | environment:(USER:bobby PWD:/) 12 | imagesize:64M 13 | ) 14 | -------------------------------------------------------------------------------- /test/runtime/write_contents/hello: -------------------------------------------------------------------------------- 1 | The ringer cannot look empty. -------------------------------------------------------------------------------- /test/runtime/write_contents/infile: -------------------------------------------------------------------------------- 1 | Some example Text 2 | Some example Text 3 | Some example Text 4 | Some example Text 5 | Some example Text 6 | Some example Text 7 | Some example Text 8 | Some example Text 9 | Some example Text 10 | Some example Text 11 | Some example Text 12 | Some example Text 13 | Some example Text 14 | -------------------------------------------------------------------------------- /test/runtime/write_contents/outfile: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /test/runtime/writev.manifest: -------------------------------------------------------------------------------- 1 | ( 2 | children:( 3 | writev:(contents:(host:output/test/runtime/bin/writev)) 4 | hello:(contents:(host:test/runtime/write_contents/hello)) 5 | ) 6 | program:/writev 7 | # trace:t 8 | # debugsyscalls:t 9 | fault:t 10 | arguments:[/] 11 | environment:(USER:bobby PWD:/) 12 | ) 13 | -------------------------------------------------------------------------------- /test/test_utils.h: -------------------------------------------------------------------------------- 1 | #ifndef _TEST_UTILS_H_ 2 | #define _TEST_UTILS_H_ 3 | 4 | #include 5 | #include 6 | 7 | #define FAULT_ADDR ((void *)0xBADF0000) 8 | 9 | #define test_assert(expr) do { \ 10 | if (!(expr)) { \ 11 | fprintf(stderr, "Error: %s -- failed at %s:%d\n", #expr, __FILE__, __LINE__); \ 12 | exit(EXIT_FAILURE); \ 13 | } \ 14 | } while (0) 15 | 16 | #define test_error(msg, ...) do { \ 17 | fprintf(stderr, "Error at %s:%d: " msg "\n", __FILE__, __LINE__, ##__VA_ARGS__); \ 18 | exit(EXIT_FAILURE); \ 19 | } while (0) 20 | 21 | #define test_perror(msg, ...) do { \ 22 | fprintf(stderr, "Error at %s:%d: " msg ": " , __FILE__, __LINE__, ##__VA_ARGS__); \ 23 | perror(NULL); \ 24 | exit(EXIT_FAILURE); \ 25 | } while (0) 26 | 27 | #endif 28 | -------------------------------------------------------------------------------- /test/unit/closure_test.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include "../test_utils.h" 4 | 5 | #define TEST_L -1ull 6 | #define TEST_R -5ull 7 | #define TEST_RV 3 8 | 9 | closure_function(1, 1, u64, test0, 10 | u64, l, 11 | u64 r) 12 | { 13 | if (bound(l) != TEST_L || r != TEST_R) { 14 | test_error("argument mismatch"); 15 | } 16 | closure_finish(); 17 | return TEST_RV; 18 | } 19 | 20 | static boolean terminate_reached; 21 | 22 | closure_function(1, 2, void, test1, 23 | int, count, 24 | void *self, boolean terminate) 25 | { 26 | if (terminate) { 27 | if (bound(count) != 1) { 28 | test_error("bound variable value mismatch"); 29 | } 30 | terminate_reached = true; 31 | return; 32 | } 33 | if (closure_self() != self) { 34 | test_error("self mismatch: %p, %p, terminate %d", closure_self(), self, terminate); 35 | } 36 | bound(count)++; 37 | apply(closure_self(), self, true); 38 | } 39 | 40 | closure_type(test0_type, u64, u64 r); 41 | closure_type(test1_type, void, void *self, boolean terminate); 42 | 43 | int main(int argc, char **argv) 44 | { 45 | heap h = init_process_runtime(); 46 | u64 heap_occupancy = heap_allocated(h); 47 | test0_type f = closure(h, test0, TEST_L); 48 | if (apply(f, TEST_R) != TEST_RV) { 49 | test_error("return value mismatch"); 50 | } 51 | if (heap_allocated(h) > heap_occupancy) { 52 | test_error("leak after closure_finish(): prev %lld, now %lld", 53 | heap_occupancy, heap_allocated(h)); 54 | } 55 | heap_occupancy = heap_allocated(h); 56 | test1_type t = closure(h, test1, 0); 57 | apply(t, t, false); 58 | deallocate_closure(t); 59 | if (heap_allocated(h) > heap_occupancy) { 60 | test_error("leak after deallocate_closure(): prev %lld, now %lld", 61 | heap_occupancy, heap_allocated(h)); 62 | } 63 | return EXIT_SUCCESS; 64 | } 65 | -------------------------------------------------------------------------------- /tools/Makefile: -------------------------------------------------------------------------------- 1 | include ../vars.mk 2 | 3 | override ARCH=$(HOST_ARCH) 4 | override CROSS_COMPILE= 5 | ifeq ($(shell uname -s),Darwin) 6 | override CC=cc 7 | endif 8 | CONTGEN=$(OBJDIR)/bin/contgen 9 | PROGRAMS=dump mkfs vdsogen 10 | ADDITIONAL_PROGRAMS=tfs-fuse 11 | 12 | SRCS-dump= \ 13 | $(CURDIR)/dump.c \ 14 | $(RUNTIME) \ 15 | $(SRCDIR)/fs/fs.c \ 16 | $(SRCDIR)/fs/tfs.c \ 17 | $(SRCDIR)/fs/tlog.c \ 18 | $(SRCDIR)/unix_process/unix_process_runtime.c 19 | 20 | SRCS-tfs-fuse= \ 21 | $(CURDIR)/tfs-fuse.c \ 22 | $(RUNTIME) \ 23 | $(SRCDIR)/fs/fs.c \ 24 | $(SRCDIR)/fs/tfs.c \ 25 | $(SRCDIR)/fs/tlog.c \ 26 | $(SRCDIR)/unix_process/unix_process_runtime.c 27 | LIBS-tfs-fuse= -lfuse -lpthread 28 | 29 | SRCS-mkfs= \ 30 | $(CURDIR)/mkfs.c \ 31 | $(RUNTIME) \ 32 | $(SRCDIR)/fs/fs.c \ 33 | $(SRCDIR)/fs/tfs.c \ 34 | $(SRCDIR)/fs/tlog.c \ 35 | $(SRCDIR)/unix_process/unix_process_runtime.c 36 | 37 | SRCS-vdsogen= $(CURDIR)/vdsogen.c 38 | 39 | CFLAGS+=-O3 \ 40 | -I$(ARCHDIR) \ 41 | -I$(SRCDIR) \ 42 | -I$(SRCDIR)/runtime \ 43 | -I$(SRCDIR)/fs \ 44 | -I$(SRCDIR)/unix_process 45 | 46 | all: $(PROGRAMS) 47 | 48 | include ../rules.mk 49 | 50 | contgen: $(CONTGEN) 51 | 52 | $(CONTGEN): $(CURDIR)/contgen.c 53 | @$(MKDIR) $(dir $@) 54 | $(CC) $(DEPFLAGS) -std=gnu11 -O3 $< -o $@ 55 | 56 | CLEANFILES+= $(CONTGEN) $(TOOLDIR)/contgen.d 57 | -------------------------------------------------------------------------------- /tools/trace-utilities/runtime-breakdown.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | import os 4 | import sys 5 | import pandas as pd 6 | import plotly.graph_objs as go 7 | 8 | def main(argv): 9 | argc = len(argv) 10 | if argc != 2: 11 | print >> sys.stderr, "Usage: %s " % argv[0] 12 | return -1 13 | 14 | df = pd.read_csv(argv[1]) 15 | tids = sorted(set(df['tid'])) 16 | functions = sorted(set(df['function']), reverse=True) 17 | 18 | fig = go.Figure( 19 | data=[ 20 | go.Bar( 21 | name=fn, 22 | x=tids, 23 | y = [ 24 | sum(df[(df['function'] == fn) & (df['tid'] == tid)]['latency_us_self']) 25 | for tid in tids 26 | ] 27 | ) 28 | for fn in functions 29 | ] 30 | ) 31 | fig.update_layout( 32 | title = "Sum of Per-Function Self Latencies", 33 | xaxis_title = "Thread Idx", 34 | yaxis_title = "Latency (us)", 35 | barmode='stack', 36 | yaxis={'categoryorder' : 'total ascending'} 37 | ) 38 | fig.show() 39 | 40 | if __name__ == "__main__": 41 | argv = sys.argv 42 | sys.exit(main(argv)) 43 | -------------------------------------------------------------------------------- /tools/trace-utilities/summarize-trace.awk: -------------------------------------------------------------------------------- 1 | #!/usr/bin/awk -f 2 | 3 | BEGIN { 4 | FS="," 5 | format_string="%s,%s,%s,%s\n" 6 | if (ARGV[1] == "-t") { 7 | format_string="%-30s\t%s\t%13s\t%13s\n" 8 | delete ARGV[1] 9 | } 10 | printf format_string, "function", "count", "tot lat", "self lat" 11 | } 12 | { 13 | if (NR==0) { next } 14 | names[$1] = $1 15 | counts[$1] += 1 16 | fnlat[$1] += $3 / 1000 17 | selflat[$1] += $4 / 1000 18 | } 19 | END { 20 | for (n in names) { 21 | f = fnlat[n] 22 | s = selflat[n] 23 | printf format_string, n, counts[n], f, s 24 | } 25 | } 26 | 27 | -------------------------------------------------------------------------------- /tools/trace-utilities/trace-all.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nanovms/nanos/478b8825bd6edc382080a772b228a49d26d2644b/tools/trace-utilities/trace-all.png -------------------------------------------------------------------------------- /tools/trace-utilities/trace-no-sleep-or-ftrace.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nanovms/nanos/478b8825bd6edc382080a772b228a49d26d2644b/tools/trace-utilities/trace-no-sleep-or-ftrace.png -------------------------------------------------------------------------------- /vars.mk: -------------------------------------------------------------------------------- 1 | # paths 2 | makefile_dir= $(patsubst %/,%,$(dir $(abspath $(firstword $(filter $1, $(MAKEFILE_LIST)))))) 3 | CURDIR= $(call makefile_dir, Makefile) 4 | ROOTDIR= $(call makefile_dir, %vars.mk) 5 | SRCDIR= $(ROOTDIR)/src 6 | OUTDIR= $(ROOTDIR)/output 7 | OBJDIR= $(subst $(ROOTDIR),$(OUTDIR),$(CURDIR)) 8 | VENDORDIR= $(ROOTDIR)/vendor 9 | TOOLDIR= $(OUTDIR)/tools/bin 10 | PATCHDIR= $(ROOTDIR)/patches 11 | UNAME_s= $(shell uname -s) 12 | UNAME_m= $(shell uname -m) 13 | 14 | HOST_ARCH= $(UNAME_m) 15 | ifeq ($(HOST_ARCH),arm64) 16 | override HOST_ARCH:= aarch64 17 | endif 18 | 19 | # If no platform is specified, try to guess it from the host architecture. 20 | ifeq ($(PLATFORM),) 21 | ARCH?= $(HOST_ARCH) 22 | ifeq ($(ARCH),aarch64) 23 | PLATFORM?= virt 24 | endif 25 | ifeq ($(ARCH),x86_64) 26 | PLATFORM?= pc 27 | endif 28 | ifeq ($(ARCH),riscv64) 29 | PLATFORM?= riscv-virt 30 | endif 31 | else 32 | # Otherwise, assume we're cross-compiling, and derive the arch from the platform. 33 | ifeq ($(PLATFORM),virt) 34 | ARCH?= aarch64 35 | endif 36 | ifeq ($(PLATFORM),pc) 37 | ARCH?= x86_64 38 | endif 39 | ifeq ($(PLATFORM),riscv-virt) 40 | ARCH?= riscv64 41 | endif 42 | ifneq ($(ARCH),$(HOST_ARCH)) 43 | CROSS_COMPILE?= $(ARCH)-linux-gnu- 44 | endif 45 | endif 46 | 47 | ifeq ($(UNAME_s),Darwin) 48 | CROSS_COMPILE=$(ARCH)-elf- 49 | endif 50 | 51 | PLATFORMDIR= $(ROOTDIR)/platform/$(PLATFORM) 52 | PLATFORMOBJDIR= $(subst $(ROOTDIR),$(OUTDIR),$(PLATFORMDIR)) 53 | ARCHDIR= $(SRCDIR)/$(ARCH) 54 | --------------------------------------------------------------------------------