├── .gitignore ├── 0-blinky ├── .gitignore ├── Makefile ├── phase3 │ ├── Makefile │ ├── blinky.c │ ├── crt0.S │ └── layout.ld └── phase4 │ ├── .vscode │ └── settings.json │ ├── Cargo.toml │ ├── Makefile │ ├── Xargo.toml │ ├── aarch64-none-elf.json │ ├── build.rs │ ├── ext │ ├── crt0.S │ └── layout.ld │ └── src │ ├── lang_items.rs │ └── lib.rs ├── 1-shell ├── .gitignore ├── Makefile ├── ferris-wheel │ ├── compile-fail │ │ ├── modules-1.rs │ │ └── move.rs │ ├── compile-pass │ │ ├── borrow-1.rs │ │ ├── const.rs │ │ ├── derive.rs │ │ ├── feature-1.rs │ │ ├── io-read-write.rs │ │ ├── lifetimes-1.rs │ │ ├── lifetimes-2.rs │ │ ├── lifetimes-3.rs │ │ ├── lifetimes-4.rs │ │ ├── mutability-1.rs │ │ ├── mutability-2.rs │ │ ├── mutability-3.rs │ │ ├── mutability-4.rs │ │ ├── pattern-match-1.rs │ │ ├── privacy.rs │ │ ├── semi.rs │ │ ├── trait-namespace.rs │ │ └── try.rs │ ├── questions │ │ ├── borrow-1 │ │ ├── borrow-2 │ │ ├── builder │ │ ├── const │ │ ├── derive │ │ ├── expressions │ │ ├── feature-1 │ │ ├── io-read-write │ │ ├── lifetimes-1 │ │ ├── lifetimes-2 │ │ ├── lifetimes-3 │ │ ├── lifetimes-4 │ │ ├── modules-1 │ │ ├── move │ │ ├── mutability-1 │ │ ├── mutability-2 │ │ ├── mutability-3 │ │ ├── mutability-4 │ │ ├── pattern-match-1 │ │ ├── privacy │ │ ├── semi │ │ ├── trait-impl │ │ ├── trait-namespace │ │ ├── try │ │ └── ufcs │ ├── run-pass │ │ ├── borrow-2.rs │ │ ├── builder.rs │ │ ├── expressions.rs │ │ ├── trait-impl.rs │ │ └── ufcs.rs │ └── test.sh ├── getting-started │ └── questions │ │ └── assignment0 ├── questions │ ├── blinky-states │ ├── bootloader-timeout │ ├── drop-container │ ├── fake-states │ ├── led-pattern │ ├── restricted-reads │ ├── shell-lookback │ ├── small-kernels │ └── write-fmt ├── stack-vec │ ├── Cargo.toml │ ├── questions │ │ ├── clone-for-pop │ │ ├── deref-in-tests │ │ ├── lifetime │ │ └── push-fails │ └── src │ │ ├── lib.rs │ │ └── tests.rs ├── ttywrite │ ├── Cargo.toml │ ├── questions │ │ ├── bad-tests │ │ └── invalid │ ├── src │ │ ├── main.rs │ │ └── parsers.rs │ └── test.sh ├── volatile │ ├── Cargo.toml │ ├── questions │ │ ├── enforcing │ │ ├── macros │ │ ├── pub-constructor │ │ ├── safety │ │ ├── traits │ │ └── unique-volatile │ └── src │ │ └── lib.rs └── xmodem │ ├── Cargo.toml │ └── src │ ├── lib.rs │ ├── progress.rs │ ├── read_ext.rs │ └── tests.rs ├── 2-fs ├── .gitignore ├── Makefile ├── fat32-fuzz │ ├── .gitignore │ ├── Cargo.toml │ └── src │ │ └── main.rs ├── fat32 │ ├── Cargo.toml │ └── src │ │ ├── lib.rs │ │ ├── mbr.rs │ │ ├── tests.rs │ │ ├── traits │ │ ├── block_device.rs │ │ ├── dummy.rs │ │ ├── fs.rs │ │ ├── metadata.rs │ │ └── mod.rs │ │ ├── util.rs │ │ └── vfat │ │ ├── cache.rs │ │ ├── cluster.rs │ │ ├── dir.rs │ │ ├── ebpb.rs │ │ ├── entry.rs │ │ ├── error.rs │ │ ├── fat.rs │ │ ├── file.rs │ │ ├── metadata.rs │ │ ├── mod.rs │ │ ├── shared.rs │ │ └── vfat.rs └── questions │ ├── atag-cmdline │ ├── atag-mem │ ├── bin-about │ ├── bin-frag │ ├── bump-chain │ ├── enduser-unsafe │ ├── foreign-safety │ ├── foreign-sync │ ├── lfn-identity │ ├── libc-align │ ├── ll-alloc │ ├── mangling │ ├── manual-lookup │ ├── max-clusters │ ├── max-file-size │ ├── mbr-magic │ └── onus ├── 3-spawn ├── .gitignore ├── Makefile └── questions │ ├── arm-aarch32 │ ├── arm-el │ ├── arm-int │ ├── arm-mask │ ├── arm-pc │ ├── arm-sp-el │ ├── arm-svc │ ├── arm-x30 │ ├── asm-cbz │ ├── asm-init │ ├── asm-memcpy │ ├── asm-movk │ ├── isolated-stacks │ ├── kernel-distrust │ ├── lazy-float │ ├── lazy-stacks │ ├── new-state │ ├── reentrant-irq │ ├── sleep-elapsed │ ├── stack-drop │ ├── stack-size │ ├── syscall-error │ ├── wait-queue │ └── wfi ├── README.md ├── os ├── .gitignore ├── Makefile ├── bootloader │ ├── .vscode │ │ └── settings.json │ ├── Cargo.toml │ ├── Makefile │ ├── Xargo.toml │ ├── aarch64-none-elf.json │ ├── build.rs │ ├── ext │ │ ├── config.txt │ │ ├── init.S │ │ └── layout.ld │ └── src │ │ ├── allocator │ │ ├── console.rs │ │ ├── kmain.rs │ │ ├── lang_items.rs │ │ └── mutex.rs ├── kernel │ ├── .gdbinit │ ├── .vscode │ │ └── settings.json │ ├── Cargo.toml │ ├── Makefile │ ├── aarch64-none-elf.json │ ├── build.rs │ ├── ext │ │ ├── init.S │ │ └── layout.ld │ └── src │ │ ├── aarch64.rs │ │ ├── allocator │ │ ├── bin.rs │ │ ├── bump.rs │ │ ├── linked_list.rs │ │ ├── mod.rs │ │ ├── tests.rs │ │ └── util.rs │ │ ├── console.rs │ │ ├── dwarf.rs │ │ ├── fs │ │ ├── mod.rs │ │ └── sd.rs │ │ ├── kmain.rs │ │ ├── lang_items.rs │ │ ├── mutex.rs │ │ ├── process │ │ ├── mod.rs │ │ ├── process.rs │ │ ├── scheduler.rs │ │ ├── stack.rs │ │ └── state.rs │ │ ├── shell.rs │ │ ├── traps │ │ ├── irq.rs │ │ ├── mod.rs │ │ ├── syndrome.rs │ │ ├── syscall.rs │ │ └── trap_frame.rs │ │ ├── user │ │ ├── mod.rs │ │ ├── shell.rs │ │ └── syscall.rs │ │ └── vm │ │ ├── address.rs │ │ └── mod.rs ├── pi │ ├── Cargo.toml │ └── src │ │ ├── atags │ │ ├── atag.rs │ │ ├── mod.rs │ │ └── raw.rs │ │ ├── common.rs │ │ ├── gpio.rs │ │ ├── interrupt.rs │ │ ├── lib.rs │ │ ├── timer │ │ ├── generic_timer.rs │ │ ├── mod.rs │ │ └── system_timer.rs │ │ └── uart.rs ├── std │ ├── Cargo.toml │ └── src │ │ ├── ascii.rs │ │ ├── build.rs │ │ ├── collections │ │ ├── hash │ │ │ ├── bench.rs │ │ │ ├── map.rs │ │ │ ├── mod.rs │ │ │ ├── set.rs │ │ │ └── table.rs │ │ └── mod.rs │ │ ├── env.rs │ │ ├── error.rs │ │ ├── f32.rs │ │ ├── f64.rs │ │ ├── ffi │ │ ├── c_str.rs │ │ ├── mod.rs │ │ └── os_str.rs │ │ ├── fs.rs │ │ ├── heap.rs │ │ ├── io │ │ ├── buffered.rs │ │ ├── cursor.rs │ │ ├── error.rs │ │ ├── impls.rs │ │ ├── lazy.rs │ │ ├── mod.rs │ │ ├── prelude.rs │ │ ├── stdio.rs │ │ └── util.rs │ │ ├── lib.rs │ │ ├── macros.rs │ │ ├── memchr.rs │ │ ├── net │ │ ├── addr.rs │ │ ├── ip.rs │ │ ├── mod.rs │ │ ├── parser.rs │ │ ├── tcp.rs │ │ ├── test.rs │ │ └── udp.rs │ │ ├── num.rs │ │ ├── os │ │ ├── mod.rs │ │ └── raw.rs │ │ ├── panic.rs │ │ ├── panicking.rs │ │ ├── path.rs │ │ ├── prelude │ │ ├── mod.rs │ │ └── v1.rs │ │ ├── primitive_docs.rs │ │ ├── process.rs │ │ ├── rt.rs │ │ ├── sync │ │ ├── barrier.rs │ │ ├── condvar.rs │ │ ├── mod.rs │ │ ├── mpsc │ │ │ ├── blocking.rs │ │ │ ├── cache_aligned.rs │ │ │ ├── mod.rs │ │ │ ├── mpsc_queue.rs │ │ │ ├── oneshot.rs │ │ │ ├── select.rs │ │ │ ├── shared.rs │ │ │ ├── spsc_queue.rs │ │ │ ├── stream.rs │ │ │ └── sync.rs │ │ ├── mutex.rs │ │ ├── once.rs │ │ └── rwlock.rs │ │ ├── sys │ │ ├── mod.rs │ │ ├── redox │ │ │ ├── args.rs │ │ │ ├── backtrace │ │ │ │ ├── mod.rs │ │ │ │ ├── printing.rs │ │ │ │ └── tracing.rs │ │ │ ├── cmath.rs │ │ │ ├── condvar.rs │ │ │ ├── env.rs │ │ │ ├── ext │ │ │ │ ├── ffi.rs │ │ │ │ ├── fs.rs │ │ │ │ ├── io.rs │ │ │ │ ├── mod.rs │ │ │ │ ├── process.rs │ │ │ │ └── thread.rs │ │ │ ├── fast_thread_local.rs │ │ │ ├── fd.rs │ │ │ ├── fs.rs │ │ │ ├── memchr.rs │ │ │ ├── mod.rs │ │ │ ├── mutex.rs │ │ │ ├── net │ │ │ │ ├── dns │ │ │ │ │ ├── answer.rs │ │ │ │ │ ├── mod.rs │ │ │ │ │ └── query.rs │ │ │ │ ├── mod.rs │ │ │ │ ├── netc.rs │ │ │ │ ├── tcp.rs │ │ │ │ └── udp.rs │ │ │ ├── os.rs │ │ │ ├── os_str.rs │ │ │ ├── path.rs │ │ │ ├── pipe.rs │ │ │ ├── process.rs │ │ │ ├── rand.rs │ │ │ ├── rwlock.rs │ │ │ ├── stack_overflow.rs │ │ │ ├── stdio.rs │ │ │ ├── syscall │ │ │ │ ├── arch │ │ │ │ │ ├── arm.rs │ │ │ │ │ ├── x86.rs │ │ │ │ │ └── x86_64.rs │ │ │ │ ├── call.rs │ │ │ │ ├── data.rs │ │ │ │ ├── error.rs │ │ │ │ ├── flag.rs │ │ │ │ ├── mod.rs │ │ │ │ └── number.rs │ │ │ ├── thread.rs │ │ │ ├── thread_local.rs │ │ │ └── time.rs │ │ └── ros │ │ │ └── mod.rs │ │ ├── sys_common │ │ ├── at_exit_imp.rs │ │ ├── backtrace.rs │ │ ├── bytestring.rs │ │ ├── condvar.rs │ │ ├── gnu │ │ │ ├── libbacktrace.rs │ │ │ └── mod.rs │ │ ├── io.rs │ │ ├── mod.rs │ │ ├── mutex.rs │ │ ├── net.rs │ │ ├── poison.rs │ │ ├── process.rs │ │ ├── remutex.rs │ │ ├── rwlock.rs │ │ ├── thread.rs │ │ ├── thread_info.rs │ │ ├── thread_local.rs │ │ ├── util.rs │ │ └── wtf8.rs │ │ ├── termination.rs │ │ ├── thread │ │ ├── local.rs │ │ └── mod.rs │ │ └── time │ │ ├── duration.rs │ │ └── mod.rs └── volatile │ ├── Cargo.toml │ └── src │ ├── lib.rs │ ├── macros.rs │ └── traits.rs └── rust-toolchain /.gitignore: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jiegec/cs140e/e0e469a5e6055948a37d9fccd75f5ae8fed18dbc/.gitignore -------------------------------------------------------------------------------- /0-blinky/.gitignore: -------------------------------------------------------------------------------- 1 | # Prerequisites 2 | *.d 3 | 4 | # Object files 5 | *.o 6 | *.ko 7 | *.obj 8 | *.elf 9 | 10 | # Linker output 11 | *.ilk 12 | *.map 13 | *.exp 14 | 15 | # Precompiled Headers 16 | *.gch 17 | *.pch 18 | 19 | # Libraries 20 | *.lib 21 | *.a 22 | *.la 23 | *.lo 24 | 25 | # Shared objects (inc. Windows DLLs) 26 | *.dll 27 | *.so 28 | *.so.* 29 | *.dylib 30 | 31 | # Executables 32 | *.exe 33 | *.out 34 | *.app 35 | *.i*86 36 | *.x86_64 37 | *.hex 38 | *.bin 39 | *.img 40 | 41 | # Debug files 42 | *.dSYM/ 43 | *.su 44 | *.idb 45 | *.pdb 46 | 47 | # Kernel Module Compile Results 48 | *.mod* 49 | *.cmd 50 | .tmp_versions/ 51 | modules.order 52 | Module.symvers 53 | Mkfile.old 54 | dkms.conf 55 | 56 | # Generated by Cargo 57 | # will have compiled files and executables 58 | /target/ 59 | 60 | # Remove Cargo.lock from gitignore if creating an executable, leave it for libraries 61 | # More information here http://doc.crates.io/guide.html#cargotoml-vs-cargolock 62 | Cargo.lock 63 | 64 | # These are backup files generated by rustfmt 65 | **/*.rs.bk 66 | 67 | # Windows thumbnail cache files 68 | Thumbs.db 69 | ehthumbs.db 70 | ehthumbs_vista.db 71 | 72 | # Dump file 73 | *.stackdump 74 | 75 | # Folder config file 76 | [Dd]esktop.ini 77 | 78 | # Recycle Bin used on file shares 79 | $RECYCLE.BIN/ 80 | 81 | # Windows Installer files 82 | *.cab 83 | *.msi 84 | *.msm 85 | *.msp 86 | 87 | # Windows shortcuts 88 | *.lnk 89 | 90 | # General 91 | .DS_Store 92 | .AppleDouble 93 | .LSOverride 94 | 95 | # Thumbnails 96 | ._* 97 | 98 | # Files that might appear in the root of a volume 99 | .DocumentRevisions-V100 100 | .fseventsd 101 | .Spotlight-V100 102 | .TemporaryItems 103 | .Trashes 104 | .VolumeIcon.icns 105 | .com.apple.timemachine.donotpresent 106 | 107 | # Directories potentially created on remote AFP share 108 | .AppleDB 109 | .AppleDesktop 110 | Network Trash Folder 111 | Temporary Items 112 | .apdisk 113 | 114 | # Submission files 115 | *.tar.gz 116 | 117 | # Assignment 0 specific 118 | phase4/build 119 | phase4/target 120 | files/ 121 | -------------------------------------------------------------------------------- /0-blinky/Makefile: -------------------------------------------------------------------------------- 1 | ASSIGNMENT_NAME := assignment0 2 | BASE_URL := https://web.stanford.edu/class/cs140e 3 | SUBMISSION_SITE := $(BASE_URL)/assignments/submission/ 4 | SUBMIT_TAR := $(ASSIGNMENT_NAME).tar.gz 5 | 6 | FILES_DIR := files 7 | FIRMWARE_DIR := $(FILES_DIR)/firmware 8 | FIRMWARE_TAR := $(FIRMWARE_DIR).tar.gz 9 | ASSIGNMENT_FILES := $(FIRMWARE_TAR) $(addprefix $(FILES_DIR)/, activity-led-blink.bin gpio16-blink.bin) 10 | 11 | .PHONY: all submission fetch 12 | 13 | all: 14 | @echo "usage: make [target]" 15 | @echo "fetch download assignment files" 16 | @echo "submission create submission tarball" 17 | @echo "clean clean products from all targets" 18 | 19 | submission: $(SUBMIT_TAR) 20 | @echo "Your submission file "$^" was successfully created." 21 | @echo "Submit it at $(SUBMISSION_SITE)" 22 | 23 | fetch: $(FIRMWARE_DIR) $(ASSIGNMENT_FILES) 24 | 25 | $(SUBMIT_TAR): 26 | @if ! [ -z "$$(git status --porcelain)" ]; then \ 27 | echo "There are uncommited changes! Aborting."; \ 28 | exit 1; \ 29 | fi 30 | git archive --format=tar.gz -o $@ HEAD 31 | 32 | $(FILES_DIR): 33 | @mkdir -p $@ 34 | 35 | $(ASSIGNMENT_FILES): | $(FILES_DIR) 36 | wget $(BASE_URL)/assignments/0-blinky/data/$(@:$(FILES_DIR)/%=%) -O $@ 37 | 38 | $(FIRMWARE_DIR): $(FIRMWARE_TAR) | $(FILES_DIR) 39 | tar -xzvf $^ -C $(FILES_DIR) 40 | @touch $(FIRMWARE_DIR) 41 | 42 | clean: 43 | rm -rf $(SUBMIT_TAR) $(FILES_DIR) 44 | make clean -C phase3 45 | make clean -C phase4 46 | -------------------------------------------------------------------------------- /0-blinky/phase3/Makefile: -------------------------------------------------------------------------------- 1 | CROSS=aarch64-none-elf 2 | CC=$(CROSS)-gcc 3 | CFLAGS=-Wall -O -ffreestanding 4 | 5 | BLINKY_OBJS=crt0.o blinky.o 6 | 7 | all: blinky.bin 8 | 9 | %.o: %.S 10 | $(CROSS)-gcc -c $< -o $@ 11 | 12 | %.o: %.c 13 | $(CROSS)-gcc -c $< -o $@ 14 | 15 | blinky.bin: blinky.elf 16 | $(CROSS)-objcopy -O binary $< $@ 17 | 18 | blinky.elf: $(BLINKY_OBJS) layout.ld 19 | $(CROSS)-ld $(BLINKY_OBJS) -o $@ -Tlayout.ld 20 | 21 | clean: 22 | rm -f $(BLINKY_OBJS) *.bin *.elf 23 | -------------------------------------------------------------------------------- /0-blinky/phase3/blinky.c: -------------------------------------------------------------------------------- 1 | #define GPIO_BASE (0x3F000000 + 0x200000) 2 | 3 | volatile unsigned *GPIO_FSEL1 = (volatile unsigned *)(GPIO_BASE + 0x04); 4 | volatile unsigned *GPIO_SET0 = (volatile unsigned *)(GPIO_BASE + 0x1C); 5 | volatile unsigned *GPIO_CLR0 = (volatile unsigned *)(GPIO_BASE + 0x28); 6 | 7 | static void spin_sleep_us(unsigned int us) { 8 | for (unsigned int i = 0; i < us * 6; i++) { 9 | asm volatile("nop"); 10 | } 11 | } 12 | 13 | static void spin_sleep_ms(unsigned int ms) { 14 | spin_sleep_us(ms * 1000); 15 | } 16 | 17 | int main(void) { 18 | // STEP 1: Set GPIO Pin 16 as output. 19 | *GPIO_FSEL1 = 0b001 << 18; 20 | // STEP 2: Continuously set and clear GPIO 16. 21 | while (1) { 22 | *GPIO_SET0 = 1 << 16; 23 | spin_sleep_ms(1000); 24 | *GPIO_CLR0 = 1 << 16; 25 | spin_sleep_ms(1000); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /0-blinky/phase3/crt0.S: -------------------------------------------------------------------------------- 1 | .section .traps, "ax" 2 | .global __start 3 | __start: 4 | b __start_ram 5 | 6 | .text 7 | .type __start_ram, %function 8 | __start_ram: 9 | # read processor number, move slave processors to an infinite loop 10 | mrs x7, mpidr_el1 11 | and x7, x7, #3 12 | cbz x7, __start_master 13 | b __hang 14 | 15 | __start_master: 16 | # load stack pointer (on 32bit) 17 | adrp x2, __cpu0_stack_end 18 | add x2, x2, #:lo12:__cpu0_stack_end 19 | mov sp, x2 20 | 21 | __clear_bss: 22 | ldr w0, _bss_segment + 0 23 | ldr w1, _bss_segment + 4 24 | __clear: 25 | cbz x1, __go_main 26 | str xzr, [x0], #8 27 | sub x1, x1, #1 28 | cbnz x1, __clear 29 | __go_main: 30 | bl main 31 | __hang: 32 | # wait forever in case of exit 33 | wfe 34 | b __hang 35 | 36 | # add section debug inf 37 | .size __start_ram, . - __start_ram 38 | 39 | _bss_segment: 40 | .word __bss_start 41 | .word __bss_dwords 42 | -------------------------------------------------------------------------------- /0-blinky/phase3/layout.ld: -------------------------------------------------------------------------------- 1 | MEMORY { 2 | SRAM (rwx) : ORIGIN = 0, LENGTH = 32M 3 | } 4 | 5 | SECTIONS { 6 | .text : { 7 | KEEP (*(.traps)) 8 | . = 0x8000; /* Space for command line. */ 9 | *(.text .text.* .gnu.linkonce.t*) 10 | } 11 | 12 | .rodata : { 13 | *(.rodata .rodata.* .gnu.linkonce.r*) 14 | } 15 | 16 | .data : { 17 | *(.data .data.* .gnu.linkonce.d*) 18 | } 19 | 20 | .bss (NOLOAD) : { 21 | __bss_start = ALIGN(0x10); 22 | *(.bss .bss.*) 23 | *(COMMON) 24 | 25 | __bss_end = ALIGN(0x10); 26 | 27 | . = ALIGN(0x10); 28 | . += 0x1000; 29 | __cpu0_stack_end = .; 30 | 31 | _end = .; 32 | } 33 | 34 | __bss_dwords = (__bss_end - __bss_start) >> 3; 35 | 36 | /** 37 | * DWARF debug sections. 38 | * 39 | * Symbols in the DWARF debugging sections are relative to the beginning of 40 | * the section so we begin them at 0. 41 | **/ 42 | 43 | /* DWARF 1.1 and DWARF 2 */ 44 | .debug_aranges 0 : { *(.debug_aranges) } 45 | .debug_pubnames 0 : { *(.debug_pubnames) } 46 | 47 | /* DWARF 2 */ 48 | .debug_info 0 : { *(.debug_info .gnu.linkonce.wi.*) } 49 | .debug_abbrev 0 : { *(.debug_abbrev) } 50 | .debug_line 0 : { *(.debug_line) } 51 | .debug_frame 0 : { *(.debug_frame) } 52 | .debug_str 0 : { *(.debug_str) } 53 | .debug_loc 0 : { *(.debug_loc) } 54 | .debug_macinfo 0 : { *(.debug_macinfo) } 55 | 56 | /* DWARF 3 */ 57 | .debug_pubtypes 0 : { *(.debug_pubtypes) } 58 | .debug_ranges 0 : { *(.debug_ranges) } 59 | 60 | .ARM.attributes 0 : { KEEP (*(.ARM.attributes)) KEEP (*(.gnu.attributes)) } 61 | .note.gnu.arm.ident 0 : { KEEP (*(.note.gnu.arm.ident)) } 62 | 63 | .ARM.extab : { *(.ARM.extab* .gnu.linkonce.armextab.*) } 64 | PROVIDE_HIDDEN (__exidx_start = .); 65 | .ARM.exidx : { *(.ARM.exidx* .gnu.linkonce.armexidx.*) } 66 | PROVIDE_HIDDEN (__exidx_end = .); 67 | 68 | /DISCARD/ : { *(.note.GNU-stack) *(.gnu_debuglink) *(.gnu.lto_*) } 69 | } 70 | -------------------------------------------------------------------------------- /0-blinky/phase4/.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "rust.target": "aarch64-none-elf", 3 | "rust.sysroot": "/Users/macbookair/.xargo" 4 | } -------------------------------------------------------------------------------- /0-blinky/phase4/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "blinky" 3 | version = "0.1.0" 4 | 5 | [lib] 6 | crate-type = ["staticlib"] 7 | 8 | [profile.dev] 9 | panic = "abort" 10 | lto = true 11 | debug = true 12 | 13 | [profile.test] 14 | panic = "abort" 15 | lto = true 16 | debug = true 17 | 18 | [profile.release] 19 | panic = "abort" 20 | lto = true 21 | debug = true 22 | 23 | [dependencies] 24 | rlibc = "*" 25 | -------------------------------------------------------------------------------- /0-blinky/phase4/Makefile: -------------------------------------------------------------------------------- 1 | TARGET ?= aarch64-none-elf 2 | CROSS ?= $(TARGET) 3 | 4 | CC := $(CROSS)-gcc 5 | XARGO := CARGO_INCREMENTAL=0 RUST_TARGET_PATH="$(shell pwd)" xargo 6 | 7 | LD_LAYOUT := ext/layout.ld 8 | 9 | RUST_BINARY := $(shell cat Cargo.toml | grep name | cut -d\" -f 2 | tr - _) 10 | RUST_BUILD_DIR := target/$(TARGET) 11 | RUST_DEBUG_LIB := $(RUST_BUILD_DIR)/debug/lib$(RUST_BINARY).a 12 | RUST_RELEASE_LIB := $(RUST_BUILD_DIR)/release/lib$(RUST_BINARY).a 13 | 14 | RUST_DEPS = Xargo.toml Cargo.toml build.rs $(LD_LAYOUT) src/* 15 | EXT_DEPS = $(BUILD_DIR)/crt0.o 16 | 17 | BUILD_DIR := build 18 | KERNEL := $(BUILD_DIR)/$(RUST_BINARY) 19 | RUST_LIB := $(BUILD_DIR)/$(RUST_BINARY).a 20 | 21 | .PHONY: all clean check 22 | 23 | VPATH = ext 24 | 25 | all: $(KERNEL).hex $(KERNEL).bin 26 | 27 | check: 28 | @$(XARGO) check --target=$(TARGET) 29 | 30 | $(RUST_DEBUG_LIB): $(RUST_DEPS) 31 | @echo "+ Building $@ [xargo]" 32 | @$(XARGO) build --target=$(TARGET) 33 | 34 | $(RUST_RELEASE_LIB): $(RUST_DEPS) 35 | @echo "+ Building $@ [xargo --release]" 36 | @$(XARGO) build --release --target=$(TARGET) 37 | 38 | ifeq ($(DEBUG),1) 39 | $(RUST_LIB): $(RUST_DEBUG_LIB) | $(BUILD_DIR) 40 | @cp $< $@ 41 | else 42 | $(RUST_LIB): $(RUST_RELEASE_LIB) | $(BUILD_DIR) 43 | @cp $< $@ 44 | endif 45 | 46 | $(BUILD_DIR): 47 | @mkdir -p $@ 48 | 49 | $(BUILD_DIR)/%.o: %.c | $(BUILD_DIR) 50 | @echo "+ Building $@ [cc $<]" 51 | @$(CC) $(CCFLAGS) -c $< -o $@ 52 | 53 | $(BUILD_DIR)/%.o: %.S | $(BUILD_DIR) 54 | @echo "+ Building $@ [as $<]" 55 | @$(CC) $(CCFLAGS) -c $< -o $@ 56 | 57 | $(KERNEL).elf: $(EXT_DEPS) $(RUST_LIB) | $(BUILD_DIR) 58 | @echo "+ Building $@ [ld $^]" 59 | @$(CROSS)-ld --gc-sections -o $@ $^ -T$(LD_LAYOUT) 60 | 61 | $(KERNEL).hex: $(KERNEL).elf | $(BUILD_DIR) 62 | @echo "+ Building $@ [objcopy $<]" 63 | @$(CROSS)-objcopy $< -O ihex $@ 64 | 65 | $(KERNEL).bin: $(KERNEL).elf | $(BUILD_DIR) 66 | @echo "+ Building $@ [objcopy $<]" 67 | @$(CROSS)-objcopy $< -O binary $@ 68 | 69 | clean: 70 | $(XARGO) clean 71 | rm -rf $(BUILD_DIR) 72 | -------------------------------------------------------------------------------- /0-blinky/phase4/Xargo.toml: -------------------------------------------------------------------------------- 1 | [dependencies] 2 | core = {} 3 | 4 | [dependencies.compiler_builtins] 5 | stage = 1 6 | -------------------------------------------------------------------------------- /0-blinky/phase4/aarch64-none-elf.json: -------------------------------------------------------------------------------- 1 | { 2 | "abi-blacklist": [ 3 | "stdcall", 4 | "fastcall", 5 | "vectorcall", 6 | "thiscall", 7 | "win64", 8 | "sysv64" 9 | ], 10 | "arch": "aarch64", 11 | "data-layout": "e-m:e-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128", 12 | "executables": true, 13 | "linker": "aarch64-none-elf-ld", 14 | "linker-flavor": "ld", 15 | "linker-is-gnu": true, 16 | "llvm-target": "aarch64-unknown-none", 17 | "no-compiler-rt": true, 18 | "features": "+a53,+strict-align", 19 | "max-atomic-width": 128, 20 | "os": "none", 21 | "panic": "abort", 22 | "panic-strategy": "abort", 23 | "position-independent-executables": true, 24 | "target-c-int-width": "32", 25 | "target-endian": "little", 26 | "target-pointer-width": "64", 27 | "disable-redzone": true 28 | } 29 | -------------------------------------------------------------------------------- /0-blinky/phase4/build.rs: -------------------------------------------------------------------------------- 1 | pub fn main() { 2 | println!("cargo:rerun-if-changed=ext/layout.ld"); 3 | println!("cargo:rerun-if-changed=ext/crt0.S"); 4 | } 5 | -------------------------------------------------------------------------------- /0-blinky/phase4/ext/crt0.S: -------------------------------------------------------------------------------- 1 | .section .traps, "ax" 2 | .global __start 3 | __start: 4 | b __start_ram 5 | 6 | .text 7 | .type __start_ram, %function 8 | __start_ram: 9 | # read processor number, move slave processors to an infinite loop 10 | mrs x7, mpidr_el1 11 | and x7, x7, #3 12 | cbz x7, __start_master 13 | b __hang 14 | 15 | __start_master: 16 | # load stack pointer (on 32bit) 17 | adrp x2, __cpu0_stack_end 18 | add x2, x2, #:lo12:__cpu0_stack_end 19 | mov sp, x2 20 | 21 | __clear_bss: 22 | ldr w0, _bss_segment + 0 23 | ldr w1, _bss_segment + 4 24 | __clear: 25 | cbz x1, __go_main 26 | str xzr, [x0], #8 27 | sub x1, x1, #1 28 | cbnz x1, __clear 29 | __go_main: 30 | bl kmain 31 | __hang: 32 | # wait forever in case of exit 33 | wfe 34 | b __hang 35 | 36 | # add section debug inf 37 | .size __start_ram, . - __start_ram 38 | 39 | _bss_segment: 40 | .word __bss_start 41 | .word __bss_dwords 42 | -------------------------------------------------------------------------------- /0-blinky/phase4/ext/layout.ld: -------------------------------------------------------------------------------- 1 | MEMORY { 2 | SRAM (rwx) : ORIGIN = 0, LENGTH = 32M 3 | } 4 | 5 | SECTIONS { 6 | .text : { 7 | KEEP (*(.traps)) 8 | . = 0x8000; /* Space for command line. */ 9 | *(.text .text.* .gnu.linkonce.t*) 10 | } 11 | 12 | .rodata : { 13 | *(.rodata .rodata.* .gnu.linkonce.r*) 14 | } 15 | 16 | .data : { 17 | *(.data .data.* .gnu.linkonce.d*) 18 | } 19 | 20 | .bss (NOLOAD) : { 21 | __bss_start = ALIGN(0x10); 22 | *(.bss .bss.*) 23 | *(COMMON) 24 | 25 | __bss_end = ALIGN(0x10); 26 | 27 | . = ALIGN(0x10); 28 | . += 0x1000; 29 | __cpu0_stack_end = .; 30 | 31 | _end = .; 32 | } 33 | 34 | __bss_dwords = (__bss_end - __bss_start) >> 3; 35 | 36 | /** 37 | * DWARF debug sections. 38 | * 39 | * Symbols in the DWARF debugging sections are relative to the beginning of 40 | * the section so we begin them at 0. 41 | **/ 42 | 43 | /* DWARF 1.1 and DWARF 2 */ 44 | .debug_aranges 0 : { *(.debug_aranges) } 45 | .debug_pubnames 0 : { *(.debug_pubnames) } 46 | 47 | /* DWARF 2 */ 48 | .debug_info 0 : { *(.debug_info .gnu.linkonce.wi.*) } 49 | .debug_abbrev 0 : { *(.debug_abbrev) } 50 | .debug_line 0 : { *(.debug_line) } 51 | .debug_frame 0 : { *(.debug_frame) } 52 | .debug_str 0 : { *(.debug_str) } 53 | .debug_loc 0 : { *(.debug_loc) } 54 | .debug_macinfo 0 : { *(.debug_macinfo) } 55 | 56 | /* DWARF 3 */ 57 | .debug_pubtypes 0 : { *(.debug_pubtypes) } 58 | .debug_ranges 0 : { *(.debug_ranges) } 59 | 60 | .ARM.attributes 0 : { KEEP (*(.ARM.attributes)) KEEP (*(.gnu.attributes)) } 61 | .note.gnu.arm.ident 0 : { KEEP (*(.note.gnu.arm.ident)) } 62 | 63 | .ARM.extab : { *(.ARM.extab* .gnu.linkonce.armextab.*) } 64 | PROVIDE_HIDDEN (__exidx_start = .); 65 | .ARM.exidx : { *(.ARM.exidx* .gnu.linkonce.armexidx.*) } 66 | PROVIDE_HIDDEN (__exidx_end = .); 67 | 68 | /DISCARD/ : { *(.note.GNU-stack) *(.gnu_debuglink) *(.gnu.lto_*) } 69 | } 70 | -------------------------------------------------------------------------------- /0-blinky/phase4/src/lang_items.rs: -------------------------------------------------------------------------------- 1 | #[lang = "eh_personality"] pub extern fn eh_personality() {} 2 | 3 | #[lang = "panic_fmt"] #[no_mangle] pub extern fn panic_fmt() -> ! { loop{} } 4 | 5 | #[no_mangle] 6 | pub unsafe extern fn memcpy(dest: *mut u8, src: *const u8, 7 | n: usize) -> *mut u8 { 8 | let mut i = 0; 9 | while i < n { 10 | *dest.offset(i as isize) = *src.offset(i as isize); 11 | i += 1; 12 | } 13 | return dest; 14 | } 15 | 16 | #[no_mangle] 17 | pub unsafe extern fn memmove(dest: *mut u8, src: *const u8, 18 | n: usize) -> *mut u8 { 19 | if src < dest as *const u8 { // copy from end 20 | let mut i = n; 21 | while i != 0 { 22 | i -= 1; 23 | *dest.offset(i as isize) = *src.offset(i as isize); 24 | } 25 | } else { // copy from beginning 26 | let mut i = 0; 27 | while i < n { 28 | *dest.offset(i as isize) = *src.offset(i as isize); 29 | i += 1; 30 | } 31 | } 32 | return dest; 33 | } 34 | 35 | #[no_mangle] 36 | pub unsafe extern fn memset(s: *mut u8, c: i32, n: usize) -> *mut u8 { 37 | let mut i = 0; 38 | while i < n { 39 | *s.offset(i as isize) = c as u8; 40 | i += 1; 41 | } 42 | return s; 43 | } 44 | 45 | #[no_mangle] 46 | pub unsafe extern fn memcmp(s1: *const u8, s2: *const u8, n: usize) -> i32 { 47 | let mut i = 0; 48 | while i < n { 49 | let a = *s1.offset(i as isize); 50 | let b = *s2.offset(i as isize); 51 | if a != b { 52 | return a as i32 - b as i32 53 | } 54 | i += 1; 55 | } 56 | return 0; 57 | } 58 | -------------------------------------------------------------------------------- /0-blinky/phase4/src/lib.rs: -------------------------------------------------------------------------------- 1 | #![feature(compiler_builtins_lib, lang_items, asm, pointer_methods)] 2 | #![no_builtins] 3 | #![no_std] 4 | 5 | extern crate compiler_builtins; 6 | 7 | pub mod lang_items; 8 | 9 | const GPIO_BASE: usize = 0x3F000000 + 0x200000; 10 | 11 | const GPIO_FSEL1: *mut u32 = (GPIO_BASE + 0x04) as *mut u32; 12 | const GPIO_SET0: *mut u32 = (GPIO_BASE + 0x1C) as *mut u32; 13 | const GPIO_CLR0: *mut u32 = (GPIO_BASE + 0x28) as *mut u32; 14 | 15 | #[inline(never)] 16 | fn spin_sleep_ms(ms: usize) { 17 | for _ in 0..(ms * 600) { 18 | unsafe { asm!("nop" :::: "volatile"); } 19 | } 20 | } 21 | 22 | #[no_mangle] 23 | pub unsafe extern "C" fn kmain() { 24 | // STEP 1: Set GPIO Pin 16 as output. 25 | GPIO_FSEL1.write_volatile(1 << 18); 26 | // STEP 2: Continuously set and clear GPIO 16. 27 | loop { 28 | GPIO_SET0.write_volatile(1 << 16); 29 | spin_sleep_ms(1000); 30 | GPIO_CLR0.write_volatile(1 << 16); 31 | spin_sleep_ms(1000); 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /1-shell/.gitignore: -------------------------------------------------------------------------------- 1 | # Swap 2 | [._]*.s[a-v][a-z] 3 | [._]*.sw[a-p] 4 | [._]s[a-v][a-z] 5 | [._]sw[a-p] 6 | 7 | # Session 8 | Session.vim 9 | 10 | # Temporary 11 | .netrwhist 12 | *~ 13 | 14 | # Org-mode 15 | .org-id-locations 16 | *_archive 17 | 18 | # flymake-mode 19 | *_flymake.* 20 | 21 | # reftex files 22 | *.rel 23 | 24 | # cask packages 25 | .cask/ 26 | 27 | # Flycheck 28 | flycheck_*.el 29 | 30 | # projectiles files 31 | .projectile 32 | 33 | # directory configuration 34 | .dir-locals.el 35 | 36 | # Prerequisites 37 | *.d 38 | 39 | # Object files 40 | *.o 41 | *.ko 42 | *.obj 43 | *.elf 44 | 45 | # Linker output 46 | *.ilk 47 | *.map 48 | *.exp 49 | 50 | # Precompiled Headers 51 | *.gch 52 | *.pch 53 | 54 | # Libraries 55 | *.lib 56 | *.a 57 | *.la 58 | *.lo 59 | 60 | # Shared objects (inc. Windows DLLs) 61 | *.dll 62 | *.so 63 | *.so.* 64 | *.dylib 65 | 66 | # Executables 67 | *.exe 68 | *.out 69 | *.app 70 | *.i*86 71 | *.x86_64 72 | *.hex 73 | *.bin 74 | *.img 75 | 76 | # Debug files 77 | *.dSYM/ 78 | *.su 79 | *.idb 80 | *.pdb 81 | 82 | # Kernel Module Compile Results 83 | *.mod* 84 | *.cmd 85 | .tmp_versions/ 86 | modules.order 87 | Module.symvers 88 | Mkfile.old 89 | dkms.conf 90 | 91 | # Generated by Cargo 92 | # will have compiled files and executables 93 | target/ 94 | 95 | # Remove Cargo.lock from gitignore if creating an executable, leave it for libraries 96 | # More information here http://doc.crates.io/guide.html#cargotoml-vs-cargolock 97 | Cargo.lock 98 | 99 | # These are backup files generated by rustfmt 100 | **/*.rs.bk 101 | 102 | # Windows thumbnail cache files 103 | Thumbs.db 104 | ehthumbs.db 105 | ehthumbs_vista.db 106 | 107 | # Dump file 108 | *.stackdump 109 | 110 | # Folder config file 111 | [Dd]esktop.ini 112 | 113 | # Recycle Bin used on file shares 114 | $RECYCLE.BIN/ 115 | 116 | # Windows Installer files 117 | *.cab 118 | *.msi 119 | *.msm 120 | *.msp 121 | 122 | # Windows shortcuts 123 | *.lnk 124 | 125 | # General 126 | .DS_Store 127 | .AppleDouble 128 | .LSOverride 129 | 130 | # Thumbnails 131 | ._* 132 | 133 | # Files that might appear in the root of a volume 134 | .DocumentRevisions-V100 135 | .fseventsd 136 | .Spotlight-V100 137 | .TemporaryItems 138 | .Trashes 139 | .VolumeIcon.icns 140 | .com.apple.timemachine.donotpresent 141 | 142 | # Directories potentially created on remote AFP share 143 | .AppleDB 144 | .AppleDesktop 145 | Network Trash Folder 146 | Temporary Items 147 | .apdisk 148 | 149 | # Submission files 150 | *.tar.gz 151 | 152 | # Assignment 1 specific 153 | ttywrite/input 154 | ttywrite/output 155 | -------------------------------------------------------------------------------- /1-shell/Makefile: -------------------------------------------------------------------------------- 1 | ASSIGNMENT_NAME := assignment1 2 | BASE_URL := https://web.stanford.edu/class/cs140e 3 | SUBMISSION_SITE := $(BASE_URL)/assignments/submission/ 4 | SUBMIT_TAR := $(ASSIGNMENT_NAME).tar.gz 5 | 6 | CS140E_REL_ROOT := .. 7 | REPO_NAMES := 0-blinky 1-shell os 8 | QUESTIONS_DIRS := $(shell find . -type d -name "questions") 9 | 10 | .PHONY: all test check submission clean 11 | 12 | all: 13 | @echo "usage: make [target]" 14 | @echo 15 | @echo "available targets:" 16 | @echo "test run tests for all targets" 17 | @echo "check ensure every question is answered" 18 | @echo "submission create submission tarball" 19 | @echo "clean clean products from all targets" 20 | 21 | test: 22 | cd ttywrite && ./test.sh 23 | cd stack-vec && cargo test 24 | cd xmodem && cargo test 25 | 26 | check: 27 | @okay=true; \ 28 | for qdir in $(QUESTIONS_DIRS); do \ 29 | for file in "$${qdir}/"*; do \ 30 | if ! [ -s "$${file}" ]; then \ 31 | okay=false; \ 32 | echo "Question file '$${file}' is empty."; \ 33 | fi \ 34 | done \ 35 | done; \ 36 | if ! $$okay; then \ 37 | echo "Questions remain unanswered. Aborting."; \ 38 | exit 1; \ 39 | else \ 40 | echo "All questions appear to be answered."; \ 41 | fi 42 | 43 | submission: $(SUBMIT_TAR) 44 | @echo "Your submission file "$^" was successfully created." 45 | @echo "Submit it at $(SUBMISSION_SITE)" 46 | 47 | .FORCE: 48 | $(SUBMIT_TAR): .FORCE 49 | @rm -f $@ 50 | @cwd="$${PWD}"; \ 51 | for repo in $(REPO_NAMES); do \ 52 | repo_path="$${cwd}/$(CS140E_REL_ROOT)/$${repo}"; \ 53 | cd "$${repo_path}"; \ 54 | if ! [ -z "$$(git status --porcelain)" ]; then \ 55 | echo "There are uncommited changes in $${repo}! Aborting."; \ 56 | rm -f $@; \ 57 | exit 1; \ 58 | else \ 59 | git_files=$$(git ls-files) ; \ 60 | cd "$${repo_path}/.." ; \ 61 | for file in $$git_files; do \ 62 | tar -rf "$${cwd}/$@" "$${repo}/$${file}"; \ 63 | done \ 64 | fi \ 65 | done 66 | @gzip -f $@ 67 | @mv $@.gz $@ 68 | 69 | clean: 70 | rm -f $(SUBMIT_TAR) 71 | cd ttywrite && cargo clean 72 | cd stack-vec && cargo clean 73 | cd xmodem && cargo clean 74 | -------------------------------------------------------------------------------- /1-shell/ferris-wheel/compile-fail/modules-1.rs: -------------------------------------------------------------------------------- 1 | // FIXME: Prevent this file from compiling! Diff budget: 1 line. 2 | 3 | mod a { 4 | fn f() { } 5 | } 6 | 7 | // Do not modify this function. 8 | fn main() { 9 | a::f(); 10 | } 11 | -------------------------------------------------------------------------------- /1-shell/ferris-wheel/compile-fail/move.rs: -------------------------------------------------------------------------------- 1 | // FIXME: Prevent this file from compiling! Diff budget: 1 line. 2 | struct MyType(usize); 3 | 4 | // Note: do not modify this function. 5 | fn main() { 6 | let x = MyType(10); 7 | let y = x; 8 | let z = x; 9 | } 10 | -------------------------------------------------------------------------------- /1-shell/ferris-wheel/compile-pass/borrow-1.rs: -------------------------------------------------------------------------------- 1 | // FIXME: Make me compile! Diff budget: 1 line. 2 | 3 | #[derive(Clone, Copy)] 4 | struct MyType(usize); 5 | 6 | // Do not modify this function. 7 | pub fn main() { 8 | let x = MyType(1); 9 | let y = &x; 10 | let z = *y; 11 | } 12 | -------------------------------------------------------------------------------- /1-shell/ferris-wheel/compile-pass/const.rs: -------------------------------------------------------------------------------- 1 | // FIXME: Make me compile! Diff budget: 3 lines. 2 | #![feature(const_fn)] 3 | 4 | const VAR: i32 = add(34, 10); 5 | 6 | const fn add(a: i32, b: i32) -> i32 { 7 | a + b 8 | } 9 | 10 | fn main() { } 11 | -------------------------------------------------------------------------------- /1-shell/ferris-wheel/compile-pass/derive.rs: -------------------------------------------------------------------------------- 1 | // FIXME: Make me compile! Diff budget: 1 line. 2 | #[derive(Debug, Clone, Copy)] 3 | enum Duration { 4 | MilliSeconds(u64), 5 | Seconds(u32), 6 | Minutes(u16) 7 | } 8 | 9 | pub fn main() { 10 | println!("Duration: {:?}", Duration::MilliSeconds(1200)); 11 | 12 | let x = Duration::Minutes(10); 13 | let y = x; 14 | let z = x; 15 | } 16 | -------------------------------------------------------------------------------- /1-shell/ferris-wheel/compile-pass/feature-1.rs: -------------------------------------------------------------------------------- 1 | // FIXME: Make me compile! Diff budget: 2 lines. 2 | #![feature(i128_type)] 3 | // Do not modify this definition. 4 | enum Duration { 5 | MicroSeconds(u128), 6 | MilliSeconds(u64), 7 | Seconds(u32), 8 | Minutes(u16) 9 | } 10 | 11 | fn main() { } 12 | -------------------------------------------------------------------------------- /1-shell/ferris-wheel/compile-pass/io-read-write.rs: -------------------------------------------------------------------------------- 1 | // FIXME: Make me compile! Diff budget: 2 lines. 2 | use std::io; 3 | 4 | struct ReadWrapper { 5 | inner: T 6 | } 7 | 8 | impl io::Read for ReadWrapper { 9 | fn read(&mut self, buf: &mut [u8]) -> Result { 10 | self.inner.read(buf) 11 | } 12 | } 13 | 14 | fn main() { } 15 | -------------------------------------------------------------------------------- /1-shell/ferris-wheel/compile-pass/lifetimes-1.rs: -------------------------------------------------------------------------------- 1 | // FIXME: Make me compile! Diff budget: 1 line. 2 | 3 | struct StrWrapper<'a>(&'a str); 4 | 5 | impl<'a> StrWrapper<'a> { 6 | fn inner(&self) -> &'a str { 7 | self.0 8 | } 9 | } 10 | 11 | // Do not modify this function. 12 | pub fn main() { 13 | let string = "Hello!"; 14 | let wrapper = StrWrapper(&string); 15 | let _: &'static str = wrapper.inner(); 16 | } 17 | -------------------------------------------------------------------------------- /1-shell/ferris-wheel/compile-pass/lifetimes-2.rs: -------------------------------------------------------------------------------- 1 | // FIXME: Make me compile! Diff budget: 3 lines. 2 | 3 | // Do not modify the inner type &'a T. 4 | struct RefWrapper<'a, T: 'a>(&'a T); 5 | 6 | impl<'a, T> RefWrapper<'a, T> { 7 | fn inner(&self) -> &'a T { 8 | self.0 9 | } 10 | } 11 | 12 | // Do not modify this function. 13 | pub fn main() { 14 | let x = 1; 15 | let mut r = &x; 16 | r = RefWrapper(r).inner(); 17 | } 18 | -------------------------------------------------------------------------------- /1-shell/ferris-wheel/compile-pass/lifetimes-3.rs: -------------------------------------------------------------------------------- 1 | // FIXME: Make me compile! Diff budget: 2 lines. 2 | 3 | // Do not modify the inner type &'a T. 4 | struct RefWrapper<'a, T: 'a>(&'a T); 5 | 6 | // Do not modify the inner type &'b RefWrapper<'a, T>. 7 | struct RefWrapperWrapper<'b, 'a : 'b, T: 'a>(&'b RefWrapper<'a, T>); 8 | 9 | pub fn main() { } 10 | -------------------------------------------------------------------------------- /1-shell/ferris-wheel/compile-pass/lifetimes-4.rs: -------------------------------------------------------------------------------- 1 | // FIXME: Make me compile! Diff budget: 3 lines. 2 | 3 | // Do not modify the inner type &'a T. 4 | struct RefWrapper<'a, T: 'a>(&'a T); 5 | 6 | // Do not modify the inner type &'b RefWrapper<'a, T>. 7 | struct RefWrapperWrapper<'b, 'a: 'b, T: 'a>(&'b RefWrapper<'a, T>); 8 | 9 | impl<'b, 'a, T> RefWrapperWrapper<'b, 'a, T> { 10 | fn inner(&self) -> &'a T { 11 | (self.0).0 12 | } 13 | } 14 | 15 | pub fn main() { } 16 | -------------------------------------------------------------------------------- /1-shell/ferris-wheel/compile-pass/mutability-1.rs: -------------------------------------------------------------------------------- 1 | // FIXME: Make me compile! Diff budget: 1 line. 2 | fn make_1(v: &mut u32) { 3 | *v = 1; 4 | } 5 | 6 | pub fn main() { } 7 | -------------------------------------------------------------------------------- /1-shell/ferris-wheel/compile-pass/mutability-2.rs: -------------------------------------------------------------------------------- 1 | // FIXME: Make me compile! Diff budget: 1 line. 2 | 3 | pub fn main() { 4 | let x : &mut i32 = &mut 10; 5 | *x = 20; 6 | } 7 | -------------------------------------------------------------------------------- /1-shell/ferris-wheel/compile-pass/mutability-3.rs: -------------------------------------------------------------------------------- 1 | // FIXME: Make me compile! Diff budget: 1 line. 2 | 3 | pub fn main() { 4 | let mut x = 10; 5 | x = 20; 6 | } 7 | -------------------------------------------------------------------------------- /1-shell/ferris-wheel/compile-pass/mutability-4.rs: -------------------------------------------------------------------------------- 1 | // FIXME: Make me compile! Diff budget: 2 lines. 2 | 3 | struct MyStruct(usize); 4 | 5 | impl MyStruct { 6 | fn make_1(&mut self) { 7 | self.0 = 1; 8 | } 9 | } 10 | 11 | pub fn main() { 12 | let mut x = MyStruct(10); 13 | x.make_1(); 14 | } 15 | -------------------------------------------------------------------------------- /1-shell/ferris-wheel/compile-pass/pattern-match-1.rs: -------------------------------------------------------------------------------- 1 | // FIXME: Make me compile! Diff budget: 2 lines. 2 | 3 | // Do not change this definition. 4 | enum MyEnum { 5 | A(String), 6 | B(String) 7 | } 8 | 9 | fn matcher(val: &MyEnum) -> &str { 10 | match *val { 11 | MyEnum::A(ref string) => string.as_str(), 12 | MyEnum::B(ref string) => string.as_str() 13 | } 14 | } 15 | 16 | fn main() { } 17 | -------------------------------------------------------------------------------- /1-shell/ferris-wheel/compile-pass/privacy.rs: -------------------------------------------------------------------------------- 1 | // FIXME: Make me compile! Diff budget: 1 line. 2 | 3 | mod a { 4 | pub fn f() { } 5 | } 6 | 7 | // Do not modify this function. 8 | fn main() { 9 | a::f(); 10 | } 11 | -------------------------------------------------------------------------------- /1-shell/ferris-wheel/compile-pass/semi.rs: -------------------------------------------------------------------------------- 1 | // FIXME: Make me compile! Diff budget: 1 character. 2 | 3 | fn add(a: i32, b: i32) -> i32 { 4 | a + b 5 | } 6 | 7 | fn main() { } 8 | -------------------------------------------------------------------------------- /1-shell/ferris-wheel/compile-pass/trait-namespace.rs: -------------------------------------------------------------------------------- 1 | // FIXME: Make me compile! Diff budget: 2 lines. 2 | 3 | // Do not change this module. 4 | mod a { 5 | pub trait MyTrait { 6 | fn foo(&self) { } 7 | } 8 | 9 | pub struct MyType; 10 | 11 | impl MyTrait for MyType { } 12 | } 13 | 14 | use a::MyTrait; 15 | 16 | // Do not modify this function. 17 | fn main() { 18 | let x = a::MyType; 19 | x.foo(); 20 | } 21 | -------------------------------------------------------------------------------- /1-shell/ferris-wheel/compile-pass/try.rs: -------------------------------------------------------------------------------- 1 | // FIXME: Make me compile. Diff budget: 12 line additions and 2 characters. 2 | struct ErrorA; 3 | struct ErrorB; 4 | 5 | enum Error { 6 | A(ErrorA), 7 | B(ErrorB), 8 | } 9 | 10 | impl std::convert::From for Error { 11 | fn from(e: ErrorA) -> Self { 12 | Error::A(e) 13 | } 14 | } 15 | 16 | impl std::convert::From for Error { 17 | fn from(e: ErrorB) -> Self { 18 | Error::B(e) 19 | } 20 | } 21 | 22 | fn do_a() -> Result { 23 | Err(ErrorA) 24 | } 25 | 26 | fn do_b() -> Result { 27 | Err(ErrorB) 28 | } 29 | 30 | fn do_both() -> Result<(u16, u32), Error> { 31 | Ok((do_a()?, do_b()?)) 32 | } 33 | 34 | fn main() {} 35 | -------------------------------------------------------------------------------- /1-shell/ferris-wheel/questions/borrow-1: -------------------------------------------------------------------------------- 1 | Cannot move out of a borrowed content. Make it a ref. -------------------------------------------------------------------------------- /1-shell/ferris-wheel/questions/borrow-2: -------------------------------------------------------------------------------- 1 | Rust does not allow mutable borrowing after a immutable borrowing in the same scope. -------------------------------------------------------------------------------- /1-shell/ferris-wheel/questions/builder: -------------------------------------------------------------------------------- 1 | Implement the Builder design pattern for `Builder'. -------------------------------------------------------------------------------- /1-shell/ferris-wheel/questions/const: -------------------------------------------------------------------------------- 1 | Mark `add' as a const function (use feature to enable this unstable feature). -------------------------------------------------------------------------------- /1-shell/ferris-wheel/questions/derive: -------------------------------------------------------------------------------- 1 | Add #derive-s for `Duration'. `Debug' for output, `Copy' for multiple assignments and `Clone' for `Copy'. -------------------------------------------------------------------------------- /1-shell/ferris-wheel/questions/expressions: -------------------------------------------------------------------------------- 1 | Implement a generic `max' function that uses `PartialOrd' as a type constraint. -------------------------------------------------------------------------------- /1-shell/ferris-wheel/questions/feature-1: -------------------------------------------------------------------------------- 1 | Add `i128_type' feature for the use of i128. -------------------------------------------------------------------------------- /1-shell/ferris-wheel/questions/io-read-write: -------------------------------------------------------------------------------- 1 | Add missing T and its constraint for the impl. -------------------------------------------------------------------------------- /1-shell/ferris-wheel/questions/lifetimes-1: -------------------------------------------------------------------------------- 1 | Make the return value of `inner' have the same lifetime as the wrapper itself. Then the compiler can deduce that all variables have the `static' lifetime. -------------------------------------------------------------------------------- /1-shell/ferris-wheel/questions/lifetimes-2: -------------------------------------------------------------------------------- 1 | Add the corresponding generics for the `RefWrapper' and also the same lifetime for the type `T'. -------------------------------------------------------------------------------- /1-shell/ferris-wheel/questions/lifetimes-3: -------------------------------------------------------------------------------- 1 | Add the corresponding generics for lifetimes. Here, `T' has a longer lifetime than `a', and `a' has a longer lifetime than `b', thus adding the lifetimes for them. -------------------------------------------------------------------------------- /1-shell/ferris-wheel/questions/lifetimes-4: -------------------------------------------------------------------------------- 1 | Mostly the same as `lifetimes-3', just adding the generics for `RefWrapperWrapper'. -------------------------------------------------------------------------------- /1-shell/ferris-wheel/questions/modules-1: -------------------------------------------------------------------------------- 1 | Make `a::f' private prevents the program from compiling. -------------------------------------------------------------------------------- /1-shell/ferris-wheel/questions/move: -------------------------------------------------------------------------------- 1 | Remove the #derive-s of `MyType', so multiple moves make the program not compiling. -------------------------------------------------------------------------------- /1-shell/ferris-wheel/questions/mutability-1: -------------------------------------------------------------------------------- 1 | Marking `v' mutable does the trick. -------------------------------------------------------------------------------- /1-shell/ferris-wheel/questions/mutability-2: -------------------------------------------------------------------------------- 1 | Replace `let x' with `let ref mut x' to make `x' a reference to a mutable integer. Using `&mut i32' as the type explicitly also does the trick. -------------------------------------------------------------------------------- /1-shell/ferris-wheel/questions/mutability-3: -------------------------------------------------------------------------------- 1 | Replace `let x' with `let mut x' to make `x' a mutable integer. -------------------------------------------------------------------------------- /1-shell/ferris-wheel/questions/mutability-4: -------------------------------------------------------------------------------- 1 | `self.0' is mutated, so `&self' should be mutable. Also, `x' needs to be mutable. -------------------------------------------------------------------------------- /1-shell/ferris-wheel/questions/pattern-match-1: -------------------------------------------------------------------------------- 1 | Use `ref' in pattern matching to prevent move and fix the lifetime error. -------------------------------------------------------------------------------- /1-shell/ferris-wheel/questions/privacy: -------------------------------------------------------------------------------- 1 | `a::f' should be public for `main' to call. -------------------------------------------------------------------------------- /1-shell/ferris-wheel/questions/semi: -------------------------------------------------------------------------------- 1 | Remove the semicolon to make the result of the last expression to be the return value. -------------------------------------------------------------------------------- /1-shell/ferris-wheel/questions/trait-impl: -------------------------------------------------------------------------------- 1 | Implement trait `PartialEq' and `Debug' for `Duration'. -------------------------------------------------------------------------------- /1-shell/ferris-wheel/questions/trait-namespace: -------------------------------------------------------------------------------- 1 | `use a::MyTrait' to introduce the `foo' into the current scope. -------------------------------------------------------------------------------- /1-shell/ferris-wheel/questions/try: -------------------------------------------------------------------------------- 1 | Use `?' to propogate the error to the caller and get the result, then implementing `From' for automatically wrapping errors. -------------------------------------------------------------------------------- /1-shell/ferris-wheel/questions/ufcs: -------------------------------------------------------------------------------- 1 | Fix the name clashing by renaming one of the foo-s to foo2. -------------------------------------------------------------------------------- /1-shell/ferris-wheel/run-pass/borrow-2.rs: -------------------------------------------------------------------------------- 1 | // FIXME: Make me pass! Diff budget: 2 lines. 2 | 3 | #[derive(Debug, PartialEq)] 4 | struct MyType(usize); 5 | 6 | pub fn main() { 7 | let mut x = MyType(1); 8 | { 9 | let y = &x; 10 | assert_eq!(*y, MyType(1)); 11 | } 12 | 13 | // Do not modify this line. 14 | let x = &mut x; 15 | } 16 | -------------------------------------------------------------------------------- /1-shell/ferris-wheel/run-pass/builder.rs: -------------------------------------------------------------------------------- 1 | // FIXME: Make me pass! Diff budget: 30 lines. 2 | 3 | struct Builder { 4 | string: Option, 5 | number: Option, 6 | } 7 | 8 | impl Builder { 9 | fn default() -> Builder { 10 | Builder { 11 | string: None, 12 | number: None 13 | } 14 | } 15 | 16 | fn string>(&mut self, s: T) -> &mut Self { 17 | self.string = Some(s.into()); 18 | self 19 | } 20 | 21 | fn number(&mut self, n: usize) -> &mut Self { 22 | self.number = Some(n); 23 | self 24 | } 25 | } 26 | 27 | impl ToString for Builder { 28 | fn to_string(&self) -> String { 29 | [ 30 | &self.string, 31 | &self.number.map(|x| x.to_string()), 32 | ].iter() 33 | .filter(|x| x.is_some()) 34 | .map(|&x| x.clone().unwrap()) 35 | .collect::>() 36 | .join(" ") 37 | } 38 | } 39 | 40 | // Do not modify this function. 41 | fn main() { 42 | let empty = Builder::default().to_string(); 43 | assert_eq!(empty, ""); 44 | 45 | let just_str = Builder::default().string("hi").to_string(); 46 | assert_eq!(just_str, "hi"); 47 | 48 | let just_num = Builder::default().number(254).to_string(); 49 | assert_eq!(just_num, "254"); 50 | 51 | let a = Builder::default() 52 | .string("hello, world!") 53 | .number(200) 54 | .to_string(); 55 | 56 | assert_eq!(a, "hello, world! 200"); 57 | 58 | let b = Builder::default() 59 | .string("hello, world!") 60 | .number(200) 61 | .string("bye now!") 62 | .to_string(); 63 | 64 | assert_eq!(b, "bye now! 200"); 65 | 66 | let c = Builder::default().string("heap!".to_owned()).to_string(); 67 | 68 | assert_eq!(c, "heap!"); 69 | } 70 | -------------------------------------------------------------------------------- /1-shell/ferris-wheel/run-pass/expressions.rs: -------------------------------------------------------------------------------- 1 | // FIXME: Make me pass! Diff budget: 10 lines. 2 | // Do not `use` any items. 3 | 4 | // Do not change the following two lines. 5 | #[derive(Debug, PartialOrd, PartialEq, Clone, Copy)] 6 | struct IntWrapper(isize); 7 | 8 | fn max(a: T, b: T) -> T { 9 | if a > b { 10 | a 11 | } else { 12 | b 13 | } 14 | } 15 | 16 | pub fn main() { 17 | assert_eq!(max(1usize, 3), 3); 18 | assert_eq!(max(1u8, 3), 3); 19 | assert_eq!(max(1u8, 3), 3); 20 | assert_eq!(max(IntWrapper(120), IntWrapper(248)), IntWrapper(248)); 21 | } 22 | -------------------------------------------------------------------------------- /1-shell/ferris-wheel/run-pass/trait-impl.rs: -------------------------------------------------------------------------------- 1 | // FIXME: Make me pass! Diff budget: 25 lines. 2 | 3 | #[derive(Debug)] 4 | enum Duration { 5 | MilliSeconds(u64), 6 | Seconds(u32), 7 | Minutes(u16), 8 | } 9 | 10 | use Duration::MilliSeconds; 11 | use Duration::Seconds; 12 | use Duration::Minutes; 13 | 14 | impl PartialEq for Duration { 15 | fn eq(&self, other: &Duration) -> bool { 16 | let a: u64 = match self { 17 | &Duration::MilliSeconds(m) => m, 18 | &Duration::Seconds(s) => s as u64 * 1000, 19 | &Duration::Minutes(m) => m as u64 * 60000, 20 | }; 21 | let b: u64 = match other { 22 | &Duration::MilliSeconds(m) => m, 23 | &Duration::Seconds(s) => s as u64 * 1000, 24 | &Duration::Minutes(m) => m as u64 * 60000, 25 | }; 26 | a == b 27 | } 28 | } 29 | 30 | fn main() { 31 | assert_eq!(Seconds(120), Minutes(2)); 32 | assert_eq!(Seconds(420), Minutes(7)); 33 | assert_eq!(MilliSeconds(420000), Minutes(7)); 34 | assert_eq!(MilliSeconds(43000), Seconds(43)); 35 | } 36 | -------------------------------------------------------------------------------- /1-shell/ferris-wheel/run-pass/ufcs.rs: -------------------------------------------------------------------------------- 1 | // FIXME: Make me pass! Diff budget: 2 lines. 2 | 3 | struct Dummy; 4 | 5 | pub trait Foo { 6 | fn foo(&self) -> usize { 1 } 7 | } 8 | 9 | pub trait FooToo { 10 | fn foo(&self) -> usize { 2 } 11 | } 12 | 13 | impl Foo for Dummy { } 14 | 15 | impl FooToo for Dummy { } 16 | 17 | fn main() { 18 | let dummy = Dummy; 19 | 20 | let x = Foo::foo(&dummy); 21 | let y = FooToo::foo(&dummy); 22 | 23 | // Values for `x` and `y` must come from calling `foo()` methods. 24 | assert_eq!(x, 1); 25 | assert_eq!(y, 2); 26 | } 27 | -------------------------------------------------------------------------------- /1-shell/getting-started/questions/assignment0: -------------------------------------------------------------------------------- 1 | GPIO27: GPFSEL2, GPSET0, GPCLR0, Pin 13 on the left -------------------------------------------------------------------------------- /1-shell/questions/blinky-states: -------------------------------------------------------------------------------- 1 | START -> OUTPUT -> SET -> CLEAR -> SET -> CLEAR -> ... 2 | -------------------------------------------------------------------------------- /1-shell/questions/bootloader-timeout: -------------------------------------------------------------------------------- 1 | If timeout is not specified, the `NAK' sent from receiver may not arrive at the sender, so the sender has to wait for another `NAK' indefinitely, yet the bootloader will only send `NAK' again on timeout. 2 | -------------------------------------------------------------------------------- /1-shell/questions/drop-container: -------------------------------------------------------------------------------- 1 | If multiple mutable references to a singleton exists, data race safety can no longer be guaranteed. By using a mutex, only one thread at a time can acquire the mutable reference. 2 | -------------------------------------------------------------------------------- /1-shell/questions/fake-states: -------------------------------------------------------------------------------- 1 | If user faked a GPIO pin to state `Input', but the pin has not been initialized to allow input, it would disobey the hardware's spec. 2 | -------------------------------------------------------------------------------- /1-shell/questions/led-pattern: -------------------------------------------------------------------------------- 1 | Sorry, no idea ;) 2 | -------------------------------------------------------------------------------- /1-shell/questions/restricted-reads: -------------------------------------------------------------------------------- 1 | By using `ReadVolatile', writing to them is forbidden. 2 | -------------------------------------------------------------------------------- /1-shell/questions/shell-lookback: -------------------------------------------------------------------------------- 1 | `StackVec' is extensively used for arrays, `Gpio' is used in `Uart' and `Console', and `Console' is used for printing to console. 2 | -------------------------------------------------------------------------------- /1-shell/questions/small-kernels: -------------------------------------------------------------------------------- 1 | `/System/Library/Kernels/kernel' is just 13MB in size. So 63.5MiB is really big enough. 2 | -------------------------------------------------------------------------------- /1-shell/questions/write-fmt: -------------------------------------------------------------------------------- 1 | `write_fmt' comes from the default implementation in trait `alloc::fmt::Write', which calls`write_str' to print the result into UART. 2 | -------------------------------------------------------------------------------- /1-shell/stack-vec/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "stack-vec" 3 | version = "0.1.0" 4 | 5 | [dependencies] 6 | -------------------------------------------------------------------------------- /1-shell/stack-vec/questions/clone-for-pop: -------------------------------------------------------------------------------- 1 | Because items in the array cannot be moved out of the array. -------------------------------------------------------------------------------- /1-shell/stack-vec/questions/deref-in-tests: -------------------------------------------------------------------------------- 1 | The indexing and `iter()' methods requires `Deref' and sometimes `DerefMut' to convert a `StackVec' to a slice, which has the corresponding methods to call. It can be seen that `StackVec' act as a smart pointer to the underlying array. 2 | Because `DerefMut' relies on `Deref', without both, all indexing tests and iterator test fail to compile. 3 | With only `Deref', mutable indexing test will fail to compile. -------------------------------------------------------------------------------- /1-shell/stack-vec/questions/lifetime: -------------------------------------------------------------------------------- 1 | Because the type itself has its lifetime, too, and the type must outlive the objects of it. -------------------------------------------------------------------------------- /1-shell/stack-vec/questions/push-fails: -------------------------------------------------------------------------------- 1 | Because `StackVec' uses a fixed stack memory for storing its items, but `Vec' expands its allocated memory region when necessary. -------------------------------------------------------------------------------- /1-shell/ttywrite/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "ttywrite" 3 | version = "0.1.0" 4 | 5 | [dependencies] 6 | structopt = "0.1.0" 7 | structopt-derive = "0.1.0" 8 | serial = "0.4" 9 | xmodem = { path = "../xmodem" } 10 | -------------------------------------------------------------------------------- /1-shell/ttywrite/questions/bad-tests: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jiegec/cs140e/e0e469a5e6055948a37d9fccd75f5ae8fed18dbc/1-shell/ttywrite/questions/bad-tests -------------------------------------------------------------------------------- /1-shell/ttywrite/questions/invalid: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jiegec/cs140e/e0e469a5e6055948a37d9fccd75f5ae8fed18dbc/1-shell/ttywrite/questions/invalid -------------------------------------------------------------------------------- /1-shell/ttywrite/src/parsers.rs: -------------------------------------------------------------------------------- 1 | use serial::core::{CharSize, BaudRate, StopBits, FlowControl}; 2 | 3 | pub fn parse_width(s: &str) -> Result { 4 | match s { 5 | "5" => Ok(CharSize::Bits5), 6 | "6" => Ok(CharSize::Bits6), 7 | "7" => Ok(CharSize::Bits7), 8 | "8" => Ok(CharSize::Bits8), 9 | _ => Err("value must be >= 5 and <= 8") 10 | } 11 | } 12 | 13 | pub fn parse_stop_bits(s: &str) -> Result { 14 | match s { 15 | "1" => Ok(StopBits::Stop1), 16 | "2" => Ok(StopBits::Stop2), 17 | _ => Err("value must '1' or '2'") 18 | } 19 | } 20 | 21 | pub fn parse_flow_control(s: &str) -> Result { 22 | match s { 23 | "none" => Ok(FlowControl::FlowNone), 24 | "software" => Ok(FlowControl::FlowSoftware), 25 | "hardware" => Ok(FlowControl::FlowHardware), 26 | _ => Err("value must be 'none', 'software' (xon/xoff), or 'hardware' (rts/cts)") 27 | } 28 | } 29 | 30 | pub fn parse_baud_rate(s: &str) -> Result { 31 | Ok(BaudRate::from_speed(s.parse()?)) 32 | } 33 | -------------------------------------------------------------------------------- /1-shell/ttywrite/test.sh: -------------------------------------------------------------------------------- 1 | #! /bin/bash 2 | 3 | function cleanup_and_exit() { 4 | kill $! 5 | exit $1 6 | } 7 | 8 | # generates a random base64 encoded string between 1 and 512 bytes 9 | function rand_string() { 10 | base64 < /dev/urandom | head -c $((1 + RANDOM % 512)) 11 | } 12 | 13 | # Use color when outputting to the terminal. 14 | if [ -t 1 ]; then 15 | KNRM="\x1B[0m"; KRED="\x1B[31m"; KGRN="\x1B[32m"; KBLU="\x1B[34m" 16 | else 17 | KNRM=""; KRED=""; KGRN=""; KBLU="" 18 | fi 19 | 20 | if ! command -v socat > /dev/null 2>&1; then 21 | echo >&2 "error: the 'socat' command is required but not installed" 22 | echo >&2 "help: install the 'socat' package using your package manager" 23 | exit 1 24 | fi 25 | 26 | echo -e "${KBLU}Compiling project with 'cargo build'...${KNRM}" 27 | if ! cargo build; then 28 | echo -e "${KRED}ERROR: ttywrite compilation failed${KNRM}" >&2 29 | fi 30 | 31 | echo -e "${KBLU}Opening PTYs...${KNRM}" 32 | PARAMS="pty,echo=0,raw,ispeed=115200,ospeed=115200,parenb=0,cs8,cstopb=0" 33 | socat -u ${PARAMS},link=input ${PARAMS},link=output & 34 | sleep 1 35 | 36 | if [[ "$(uname)" = "Darwin" ]]; then 37 | # having GNU coreutils in my PATH 38 | stty -F input min 0 time 1 39 | stty -F output min 0 time 1 40 | else 41 | stty -F input min 0 time 1 42 | stty -F output min 0 time 1 43 | fi 44 | 45 | for i in {1..10}; do 46 | echo -e "${KBLU}Running test ${i}/10.${KNRM}" 47 | 48 | input=$(rand_string) 49 | echo -n "${input}" | ./target/debug/ttywrite -r input 50 | output=$(cat output) 51 | if [[ "${output}" != "${input}" ]]; then 52 | echo -e "${KRED}ERROR: input and output differ${KNRM}" >&2 53 | echo "${input} != ${output}" >&2 54 | cleanup_and_exit 1 55 | fi 56 | done 57 | 58 | echo -e "${KGRN}SUCCESS${KNRM}" 59 | cleanup_and_exit 0 60 | -------------------------------------------------------------------------------- /1-shell/volatile/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "volatile" 3 | version = "0.1.0" 4 | authors = ["Sergio Benitez "] 5 | 6 | [dependencies] 7 | -------------------------------------------------------------------------------- /1-shell/volatile/questions/enforcing: -------------------------------------------------------------------------------- 1 | The inner pointer field `self.0' is not public, thus can only be accessed indirectly by its public functions. `ReadVolatile' provides `read' and returns a const pointer to T for `inner'. `WriteVolatile' provides `write' but returns a mutable pointer to T for `inner', which might allow reading the pointer in fact. -------------------------------------------------------------------------------- /1-shell/volatile/questions/macros: -------------------------------------------------------------------------------- 1 | These macros are helpers to help implement those trait for `Volatile'-s. -------------------------------------------------------------------------------- /1-shell/volatile/questions/pub-constructor: -------------------------------------------------------------------------------- 1 | In this way, `self.0' can be accessed directly from the outside of the library, thus the safety implications can no longer hold. -------------------------------------------------------------------------------- /1-shell/volatile/questions/safety: -------------------------------------------------------------------------------- 1 | Because, `read' and `write' have no raw pointers in their function signature, yet `new' needs a raw pointer passed in. -------------------------------------------------------------------------------- /1-shell/volatile/questions/traits: -------------------------------------------------------------------------------- 1 | By using these traits, the default implementation included in these traits reuses much code and allow for cleaner implementation for `Volatile'-s. However, the `new' methods have to have different type signature for different semantics, so they cannot be put into a trait, but they still provide a similar interface. It eases using the library and prevents the library author from making errors. -------------------------------------------------------------------------------- /1-shell/volatile/questions/unique-volatile: -------------------------------------------------------------------------------- 1 | `UniqueVolatile' means no pointer aliasing i.e. only one `UniqueVolatile' corresponds to the underlying pointer, allowing it to be thread safe. On the other side, `Volatile' does not have this restriction. -------------------------------------------------------------------------------- /1-shell/xmodem/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "xmodem" 3 | version = "0.1.0" 4 | authors = ["Sergio Benitez "] 5 | 6 | [dependencies] 7 | -------------------------------------------------------------------------------- /1-shell/xmodem/src/progress.rs: -------------------------------------------------------------------------------- 1 | /// Enum representing how much progress has been made transmitting/receiving. 2 | /// 3 | /// A value of this type is passed in to the progress callback supplied to 4 | /// methods like [`Xmodem::transmit_with_progress()`], 5 | /// [`Xmodem::receive_with_progress()`], and [`Xmodem::new_with_progress()`]. It 6 | /// is intended to be used by progress indicators or for debugging purposes. 7 | #[derive(Debug, Copy, Clone)] 8 | pub enum Progress { 9 | /// Waiting for receiver to send NAK. 10 | Waiting, 11 | /// Download/upload has started. 12 | Started, 13 | /// Packet `.0` was transmitted/received. 14 | Packet(u8), 15 | } 16 | 17 | /// Type for progress callbacks. 18 | pub type ProgressFn = fn(Progress); 19 | 20 | /// Noop progress callback. 21 | pub fn noop(_: Progress) { } 22 | -------------------------------------------------------------------------------- /1-shell/xmodem/src/read_ext.rs: -------------------------------------------------------------------------------- 1 | use std::io; 2 | 3 | pub trait ReadExt: io::Read { 4 | fn read_max(&mut self, mut buf: &mut [u8]) -> io::Result { 5 | let start_len = buf.len(); 6 | while !buf.is_empty() { 7 | match self.read(buf) { 8 | Ok(0) => break, 9 | Ok(n) => { let tmp = buf; buf = &mut tmp[n..]; } 10 | Err(ref e) if e.kind() == io::ErrorKind::Interrupted => {} 11 | Err(e) => return Err(e), 12 | } 13 | } 14 | 15 | Ok(start_len - buf.len()) 16 | } 17 | } 18 | 19 | impl ReadExt for T { } 20 | -------------------------------------------------------------------------------- /2-fs/.gitignore: -------------------------------------------------------------------------------- 1 | # Swap 2 | [._]*.s[a-v][a-z] 3 | [._]*.sw[a-p] 4 | [._]s[a-v][a-z] 5 | [._]sw[a-p] 6 | 7 | # Session 8 | Session.vim 9 | 10 | # Temporary 11 | .netrwhist 12 | *~ 13 | 14 | # Org-mode 15 | .org-id-locations 16 | *_archive 17 | 18 | # flymake-mode 19 | *_flymake.* 20 | 21 | # reftex files 22 | *.rel 23 | 24 | # cask packages 25 | .cask/ 26 | 27 | # Flycheck 28 | flycheck_*.el 29 | 30 | # projectiles files 31 | .projectile 32 | 33 | # directory configuration 34 | .dir-locals.el 35 | 36 | # Prerequisites 37 | *.d 38 | 39 | # Object files 40 | *.o 41 | *.ko 42 | *.obj 43 | *.elf 44 | 45 | # Linker output 46 | *.ilk 47 | *.map 48 | *.exp 49 | 50 | # Precompiled Headers 51 | *.gch 52 | *.pch 53 | 54 | # Libraries 55 | *.lib 56 | *.a 57 | *.la 58 | *.lo 59 | 60 | # Shared objects (inc. Windows DLLs) 61 | *.dll 62 | *.so 63 | *.so.* 64 | *.dylib 65 | 66 | # Executables 67 | *.exe 68 | *.out 69 | *.app 70 | *.i*86 71 | *.x86_64 72 | *.hex 73 | *.bin 74 | *.img 75 | 76 | # Debug files 77 | *.dSYM/ 78 | *.su 79 | *.idb 80 | *.pdb 81 | 82 | # Kernel Module Compile Results 83 | *.mod* 84 | *.cmd 85 | .tmp_versions/ 86 | modules.order 87 | Module.symvers 88 | Mkfile.old 89 | dkms.conf 90 | 91 | # Generated by Cargo 92 | # will have compiled files and executables 93 | target/ 94 | 95 | # Remove Cargo.lock from gitignore if creating an executable, leave it for libraries 96 | # More information here http://doc.crates.io/guide.html#cargotoml-vs-cargolock 97 | Cargo.lock 98 | 99 | # These are backup files generated by rustfmt 100 | **/*.rs.bk 101 | 102 | # Windows thumbnail cache files 103 | Thumbs.db 104 | ehthumbs.db 105 | ehthumbs_vista.db 106 | 107 | # Dump file 108 | *.stackdump 109 | 110 | # Folder config file 111 | [Dd]esktop.ini 112 | 113 | # Recycle Bin used on file shares 114 | $RECYCLE.BIN/ 115 | 116 | # Windows Installer files 117 | *.cab 118 | *.msi 119 | *.msm 120 | *.msp 121 | 122 | # Windows shortcuts 123 | *.lnk 124 | 125 | # General 126 | .DS_Store 127 | .AppleDouble 128 | .LSOverride 129 | 130 | # Thumbnails 131 | ._* 132 | 133 | # Files that might appear in the root of a volume 134 | .DocumentRevisions-V100 135 | .fseventsd 136 | .Spotlight-V100 137 | .TemporaryItems 138 | .Trashes 139 | .VolumeIcon.icns 140 | .com.apple.timemachine.donotpresent 141 | 142 | # Directories potentially created on remote AFP share 143 | .AppleDB 144 | .AppleDesktop 145 | Network Trash Folder 146 | Temporary Items 147 | .apdisk 148 | 149 | # Submission files 150 | *.tar.gz 151 | 152 | # Assignment 2 specific 153 | resources/ 154 | files/ 155 | -------------------------------------------------------------------------------- /2-fs/fat32-fuzz/.gitignore: -------------------------------------------------------------------------------- 1 | output/ 2 | -------------------------------------------------------------------------------- /2-fs/fat32-fuzz/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "fat32-fuzz" 3 | version = "0.1.0" 4 | authors = ["Jiajie Chen "] 5 | edition = "2018" 6 | 7 | [dependencies] 8 | fat32 = { path = "../fat32/" } 9 | afl = "0.4.3" 10 | -------------------------------------------------------------------------------- /2-fs/fat32-fuzz/src/main.rs: -------------------------------------------------------------------------------- 1 | #[macro_use] 2 | extern crate afl; 3 | extern crate fat32; 4 | 5 | use fat32::traits::BlockDevice; 6 | use fat32::vfat::VFat; 7 | use std::io::Cursor; 8 | 9 | fn main() { 10 | fuzz!(|data: &[u8]| { 11 | let vec = Vec::from(data); 12 | if let Ok(vfat) = VFat::from(Cursor::new(vec)) { 13 | 14 | } 15 | }); 16 | } 17 | -------------------------------------------------------------------------------- /2-fs/fat32/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "fat32" 3 | version = "0.1.0" 4 | authors = ["Sergio Benitez "] 5 | 6 | [features] 7 | custom_std = ["std"] 8 | 9 | [dependencies] 10 | std = { path = "../../os/std" , optional = true} 11 | 12 | [dev-dependencies] 13 | rand = "0.4" -------------------------------------------------------------------------------- /2-fs/fat32/src/lib.rs: -------------------------------------------------------------------------------- 1 | #![feature(decl_macro)] 2 | #![allow(safe_packed_borrows)] 3 | 4 | #[cfg(not(target_endian="little"))] 5 | compile_error!("only little endian platforms supported"); 6 | 7 | #[cfg(test)] 8 | mod tests; 9 | mod mbr; 10 | mod util; 11 | 12 | pub mod vfat; 13 | pub mod traits; 14 | 15 | pub use mbr::*; 16 | -------------------------------------------------------------------------------- /2-fs/fat32/src/traits/dummy.rs: -------------------------------------------------------------------------------- 1 | use std::io; 2 | use traits::{File, Dir, Entry, Metadata, Timestamp}; 3 | 4 | /// A type that implements all of the file system traits. 5 | #[derive(Copy, Clone)] 6 | pub struct Dummy; 7 | 8 | impl io::Write for Dummy { 9 | fn write(&mut self, _buf: &[u8]) -> io::Result { panic!("Dummy") } 10 | fn flush(&mut self) -> io::Result<()> { panic!("Dummy") } 11 | } 12 | 13 | impl io::Read for Dummy { 14 | fn read(&mut self, _buf: &mut [u8]) -> io::Result { panic!("Dummy") } 15 | } 16 | 17 | impl io::Seek for Dummy { 18 | fn seek(&mut self, _pos: io::SeekFrom) -> io::Result { panic!("Dummy") } 19 | } 20 | 21 | impl File for Dummy { 22 | fn sync(&mut self) -> io::Result<()> { panic!("Dummy") } 23 | fn size(&self) -> u64 { panic!("Dummy") } 24 | } 25 | 26 | /// Trait implemented by directories in a file system. 27 | impl Dir for Dummy { 28 | /// The type of entry stored in this directory. 29 | type Entry = Dummy; 30 | type Iter = Dummy; 31 | 32 | /// Returns an interator over the entries in this directory. 33 | fn entries(&self) -> io::Result { panic!("Dummy") } 34 | } 35 | 36 | impl Iterator for Dummy { 37 | type Item = Dummy; 38 | fn next(&mut self) -> Option { panic!("Dummy") } 39 | } 40 | 41 | impl Entry for Dummy { 42 | type File = Dummy; 43 | type Dir = Dummy; 44 | type Metadata = Dummy; 45 | 46 | fn name(&self) -> &str { panic!("Dummy") } 47 | fn metadata(&self) -> &Self::Metadata { panic!("Dummy") } 48 | fn as_file(&self) -> Option<&Self::File> { panic!("Dummy") } 49 | fn as_dir(&self) -> Option<&Self::Dir> { panic!("Dummy") } 50 | fn into_file(self) -> Option { panic!("Dummy") } 51 | fn into_dir(self) -> Option { panic!("Dummy") } 52 | } 53 | 54 | impl Timestamp for Dummy { 55 | fn year(&self) -> usize { panic!("Dummy") } 56 | fn month(&self) -> u8 { panic!("Dummy") } 57 | fn day(&self) -> u8 { panic!("Dummy") } 58 | fn hour(&self) -> u8 { panic!("Dummy") } 59 | fn minute(&self) -> u8 { panic!("Dummy") } 60 | fn second(&self) -> u8 { panic!("Dummy") } 61 | } 62 | 63 | impl Metadata for Dummy { 64 | type Timestamp = Dummy; 65 | fn read_only(&self) -> bool { panic!("Dummy") } 66 | fn hidden(&self) -> bool { panic!("Dummy") } 67 | fn system(&self) -> bool { panic!("Dummy") } 68 | fn volume_id(&self) -> bool { panic!("Dummy") } 69 | fn archive(&self) -> bool { panic!("Dummy") } 70 | fn created(&self) -> Self::Timestamp { panic!("Dummy") } 71 | fn accessed(&self) -> Self::Timestamp { panic!("Dummy") } 72 | fn modified(&self) -> Self::Timestamp { panic!("Dummy") } 73 | } 74 | -------------------------------------------------------------------------------- /2-fs/fat32/src/traits/metadata.rs: -------------------------------------------------------------------------------- 1 | /// Trait for a timestamp (year, month, day, hour, minute, second). 2 | pub trait Timestamp: Copy + Clone + Sized { 3 | /// The calendar year. 4 | /// 5 | /// The year is not offset. 2009 is 2009. 6 | fn year(&self) -> usize; 7 | 8 | /// The calendar month, starting at 1 for January. Always in range [1, 12]. 9 | /// 10 | /// January is 1, Feburary is 2, ..., December is 12. 11 | fn month(&self) -> u8; 12 | 13 | /// The calendar day, starting at 1. Always in range [1, 31]. 14 | fn day(&self) -> u8; 15 | 16 | /// The 24-hour hour. Always in range [0, 24). 17 | fn hour(&self) -> u8; 18 | 19 | /// The minute. Always in range [0, 60). 20 | fn minute(&self) -> u8; 21 | 22 | /// The second. Always in range [0, 60). 23 | fn second(&self) -> u8; 24 | } 25 | 26 | /// Trait for directory entry metadata. 27 | pub trait Metadata: Sized { 28 | /// Type corresponding to a point in time. 29 | type Timestamp: Timestamp; 30 | 31 | /// Whether the associated entry is read only. 32 | fn read_only(&self) -> bool; 33 | 34 | /// Whether the entry should be "hidden" from directory traversals. 35 | fn hidden(&self) -> bool; 36 | 37 | fn system(&self) -> bool; 38 | fn volume_id(&self) -> bool; 39 | fn archive(&self) -> bool; 40 | 41 | /// The timestamp when the entry was created. 42 | fn created(&self) -> Self::Timestamp; 43 | 44 | /// The timestamp for the entry's last access. 45 | fn accessed(&self) -> Self::Timestamp; 46 | 47 | /// The timestamp for the entry's last modification. 48 | fn modified(&self) -> Self::Timestamp; 49 | } 50 | 51 | -------------------------------------------------------------------------------- /2-fs/fat32/src/traits/mod.rs: -------------------------------------------------------------------------------- 1 | mod fs; 2 | mod block_device; 3 | mod metadata; 4 | mod dummy; 5 | 6 | pub use self::fs::{Dir, Entry, File, FileSystem}; 7 | pub use self::metadata::{Metadata, Timestamp}; 8 | pub use self::block_device::BlockDevice; 9 | pub use self::dummy::Dummy; 10 | -------------------------------------------------------------------------------- /2-fs/fat32/src/vfat/cluster.rs: -------------------------------------------------------------------------------- 1 | #[derive(PartialEq, Eq, PartialOrd, Ord, Debug, Copy, Clone, Hash)] 2 | pub struct Cluster(u32); 3 | 4 | impl From for Cluster { 5 | fn from(raw_num: u32) -> Cluster { 6 | Cluster(raw_num & !(0xF << 28)) 7 | } 8 | } 9 | 10 | // TODO: Implement any useful helper methods on `Cluster`. 11 | impl Cluster { 12 | pub(super) fn cluster_num(&self) -> u32 { 13 | self.0 14 | } 15 | 16 | pub(super) fn cluster_index(&self) -> u32 { 17 | // Cluster start from 2 18 | self.0 - 2 19 | } 20 | 21 | pub(super) fn is_valid(&self) -> bool { 22 | self.0 >= 2 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /2-fs/fat32/src/vfat/entry.rs: -------------------------------------------------------------------------------- 1 | use traits; 2 | use vfat::{Dir, File, Metadata}; 3 | 4 | // TODO: You may need to change this definition. 5 | #[derive(Debug)] 6 | pub enum Entry { 7 | File(File), 8 | Dir(Dir), 9 | } 10 | 11 | // TODO: Implement any useful helper methods on `Entry`. 12 | 13 | // FIXME: Implement `traits::Entry` for `Entry`. 14 | impl traits::Entry for Entry { 15 | type File = File; 16 | type Dir = Dir; 17 | type Metadata = Metadata; 18 | 19 | fn name(&self) -> &str { 20 | match self { 21 | &Entry::File(ref file) => file.name(), 22 | &Entry::Dir(ref dir) => dir.name(), 23 | } 24 | } 25 | 26 | fn metadata(&self) -> &Self::Metadata { 27 | match self { 28 | &Entry::File(ref file) => &file.metadata, 29 | &Entry::Dir(ref dir) => &dir.metadata, 30 | } 31 | } 32 | 33 | fn as_file(&self) -> Option<&Self::File> { 34 | match self { 35 | &Entry::File(ref file) => Some(file), 36 | _ => None 37 | } 38 | } 39 | 40 | fn as_dir(&self) -> Option<&Self::Dir> { 41 | match self { 42 | &Entry::Dir(ref dir) => Some(dir), 43 | _ => None 44 | } 45 | } 46 | 47 | fn into_file(self) -> Option { 48 | match self { 49 | Entry::File(file) => Some(file), 50 | _ => None 51 | } 52 | } 53 | 54 | fn into_dir(self) -> Option { 55 | match self { 56 | Entry::Dir(dir) => Some(dir), 57 | _ => None 58 | } 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /2-fs/fat32/src/vfat/error.rs: -------------------------------------------------------------------------------- 1 | use std::io; 2 | 3 | use mbr; 4 | 5 | #[derive(Debug)] 6 | pub enum Error { 7 | Mbr(mbr::Error), 8 | Io(io::Error), 9 | BadSignature, 10 | NotFound 11 | } 12 | 13 | impl From for Error { 14 | fn from(error: mbr::Error) -> Error { 15 | Error::Mbr(error) 16 | } 17 | } 18 | 19 | impl From for Error { 20 | fn from(error: io::Error) -> Error { 21 | Error::Io(error) 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /2-fs/fat32/src/vfat/fat.rs: -------------------------------------------------------------------------------- 1 | use std::fmt; 2 | use vfat::*; 3 | 4 | use self::Status::*; 5 | 6 | #[derive(Debug, PartialEq)] 7 | pub enum Status { 8 | /// The FAT entry corresponds to an unused (free) cluster. 9 | Free, 10 | /// The FAT entry/cluster is reserved. 11 | Reserved, 12 | /// The FAT entry corresponds to a valid data cluster. The next cluster in 13 | /// the chain is `Cluster`. 14 | Data(Cluster), 15 | /// The FAT entry corresponds to a bad (disk failed) cluster. 16 | Bad, 17 | /// The FAT entry corresponds to a valid data cluster. The corresponding 18 | /// cluster is the last in its chain. 19 | Eoc(u32) 20 | } 21 | 22 | #[repr(C, packed)] 23 | pub struct FatEntry(u32); 24 | 25 | impl FatEntry { 26 | /// Returns the `Status` of the FAT entry `self`. 27 | pub(super) fn status(&self) -> Status { 28 | let bits = self.0 & (0x0FFF_FFFFu32); 29 | match bits { 30 | 0x0000_0000 => { 31 | Free 32 | } 33 | 0x0000_0001 => { 34 | Reserved 35 | } 36 | 0x0000_0002 ... 0x0FFF_FFEF => { 37 | Data(Cluster::from(self.0)) 38 | } 39 | 0x0FFF_FFF0 ... 0x0FFF_FFF6 => { 40 | Reserved 41 | } 42 | 0x0FFF_FFF7 => { 43 | Bad 44 | } 45 | 0x0FFF_FFF8 ... 0x0FFF_FFFF => { 46 | Eoc(self.0) 47 | } 48 | _ => unreachable!() 49 | } 50 | } 51 | } 52 | 53 | impl fmt::Debug for FatEntry { 54 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 55 | f.debug_struct("FatEntry") 56 | .field("value", &self.0) 57 | .field("status", &self.status()) 58 | .finish() 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /2-fs/fat32/src/vfat/mod.rs: -------------------------------------------------------------------------------- 1 | pub(crate) mod file; 2 | pub(crate) mod dir; 3 | pub(crate) mod vfat; 4 | pub(crate) mod ebpb; 5 | pub(crate) mod error; 6 | pub(crate) mod cluster; 7 | pub(crate) mod fat; 8 | pub(crate) mod entry; 9 | pub(crate) mod metadata; 10 | pub(crate) mod cache; 11 | pub(crate) mod shared; 12 | 13 | pub use self::ebpb::BiosParameterBlock; 14 | pub use self::file::File; 15 | pub use self::dir::Dir; 16 | pub use self::error::Error; 17 | pub use self::vfat::VFat; 18 | pub use self::entry::Entry; 19 | pub use self::metadata::{Metadata, Attributes, Date, Time, Timestamp}; 20 | pub use self::shared::Shared; 21 | 22 | pub(crate) use self::cache::{CachedDevice, Partition}; 23 | pub(crate) use self::fat::{Status, FatEntry}; 24 | pub(crate) use self::cluster::Cluster; 25 | -------------------------------------------------------------------------------- /2-fs/fat32/src/vfat/shared.rs: -------------------------------------------------------------------------------- 1 | use std::ops::{Deref, DerefMut}; 2 | 3 | /// A smart pointer to a shared instance of type `T`. 4 | /// 5 | /// The inner `T` can be borrowed immutably with `.borrow()` and mutably with 6 | /// `.borrow_mut()`. The implementation guarantees the usual reference 7 | /// guarantees. 8 | #[derive(Debug)] 9 | pub struct Shared(imp::Inner); 10 | 11 | #[cfg(target_os = "ros")] 12 | mod imp { 13 | use std::rc::Rc; 14 | use std::sync::Mutex; 15 | use super::Shared; 16 | 17 | pub type Inner = Rc>; 18 | 19 | pub fn new(val: T) -> Inner { 20 | Rc::new(Mutex::new(val)) 21 | } 22 | 23 | // Without an enabled MMU/cache, the processor faults on atomic accesses. 24 | // As such, use an `Rc` instead of an `Arc` when running on ROS until 25 | // multithreading, the MMU, and caches are enabled. 26 | unsafe impl Sync for Shared {} 27 | unsafe impl Send for Shared {} 28 | } 29 | 30 | #[cfg(not(target_os = "ros"))] 31 | mod imp { 32 | use std::sync::{Arc, Mutex}; 33 | 34 | pub type Inner = ::std::sync::Arc<::std::sync::Mutex>; 35 | 36 | pub fn new(val: T) -> Inner { 37 | Arc::new(Mutex::new(val)) 38 | } 39 | } 40 | 41 | impl Shared { 42 | /// Wraps `val` into a `Shared` and returns it. 43 | pub fn new(val: T) -> Shared { 44 | Shared(imp::new(val)) 45 | } 46 | 47 | /// Returns an immutable borrow to the inner value. 48 | /// 49 | /// If the inner value is presently mutably borrowed, this function blocks 50 | /// until that borrow is returned. 51 | pub fn borrow<'a>(&'a self) -> impl Deref + 'a { 52 | self.0.lock().expect("all okay") 53 | } 54 | 55 | /// Returns an mutable borrow to the inner value. 56 | /// 57 | /// If the inner value is presently borrowed, mutably or immutably, this 58 | /// function blocks until all borrows are returned. 59 | pub fn borrow_mut<'a>(&'a self) -> impl DerefMut + 'a { 60 | self.0.lock().expect("all okay") 61 | } 62 | } 63 | 64 | impl Clone for Shared { 65 | /// Returns a copy of the shared pointer. 66 | /// 67 | /// The value `T` itself is not copied; only the metadata associated with 68 | /// the smart pointer required for accurate book-keeping is copied. 69 | fn clone(&self) -> Shared { 70 | Shared(self.0.clone()) 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /2-fs/questions/atag-cmdline: -------------------------------------------------------------------------------- 1 | Content: 2 | bcm2708_fb.fbwidth=656 bcm2708_fb.fbheight=416 bcm2708_fb.fbswap=1 dma.dmachans=0x7f35 bcm2709.boardrev=0xa02082 bcm2709.serial=0xe5da193c bcm2709.uart_clock=48000000 smsc95xx.macaddr=B8:27:EB:DA:19:3C vc_mem.mem_base=0x3ec00000 vc_mem.mem_size=0x40000000 console=ttyS0,115200 kgdboc=ttyS0,115200 console=tty1 root=/dev/mmcblk0p2 rootfstype=ext4 rootwait 3 | -------------------------------------------------------------------------------- /2-fs/questions/atag-mem: -------------------------------------------------------------------------------- 1 | Memory: start=0, size=994050048 2 | 994050048=948MiB 3 | -------------------------------------------------------------------------------- /2-fs/questions/bin-about: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jiegec/cs140e/e0e469a5e6055948a37d9fccd75f5ae8fed18dbc/2-fs/questions/bin-about -------------------------------------------------------------------------------- /2-fs/questions/bin-frag: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jiegec/cs140e/e0e469a5e6055948a37d9fccd75f5ae8fed18dbc/2-fs/questions/bin-frag -------------------------------------------------------------------------------- /2-fs/questions/bump-chain: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jiegec/cs140e/e0e469a5e6055948a37d9fccd75f5ae8fed18dbc/2-fs/questions/bump-chain -------------------------------------------------------------------------------- /2-fs/questions/enduser-unsafe: -------------------------------------------------------------------------------- 1 | We can limit `unsafe' to only a small portion of code that we can easily check, leaving rest of the code safe Rust. It's hard to enforce the same constraint in C. 2 | -------------------------------------------------------------------------------- /2-fs/questions/foreign-safety: -------------------------------------------------------------------------------- 1 | The file system is wrapped in a Shared, so only one thread can use the filesystem at a time. 2 | -------------------------------------------------------------------------------- /2-fs/questions/foreign-sync: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jiegec/cs140e/e0e469a5e6055948a37d9fccd75f5ae8fed18dbc/2-fs/questions/foreign-sync -------------------------------------------------------------------------------- /2-fs/questions/lfn-identity: -------------------------------------------------------------------------------- 1 | The attribute field is shared among regular entry and lfn entry. But a latter one has 0x0F in this field, which is impossible for a former one. 2 | -------------------------------------------------------------------------------- /2-fs/questions/libc-align: -------------------------------------------------------------------------------- 1 | Because `malloc' returns a pointer that is aligned for any kind of type. It must return a pointer that is aligned to max alignment, which is 2*sizeof(int). 2 | -------------------------------------------------------------------------------- /2-fs/questions/ll-alloc: -------------------------------------------------------------------------------- 1 | It saves the list pointers in place. Because we are implementing the allocator, it's hard to dynamically allocate some space for storing the linked list. 2 | -------------------------------------------------------------------------------- /2-fs/questions/mangling: -------------------------------------------------------------------------------- 1 | In C++ and Rust, methods can be overloaded, so functions have to be identified by both its name and its argument types. 2 | -------------------------------------------------------------------------------- /2-fs/questions/manual-lookup: -------------------------------------------------------------------------------- 1 | To get /a/b/c.txt: 2 | Get root directory, from its entries, find one dir nameb a; 3 | Use /a, from its entries, find one dir named b; 4 | Use /a/b, from its entries, find one file named c.txt. 5 | -------------------------------------------------------------------------------- /2-fs/questions/max-clusters: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jiegec/cs140e/e0e469a5e6055948a37d9fccd75f5ae8fed18dbc/2-fs/questions/max-clusters -------------------------------------------------------------------------------- /2-fs/questions/max-file-size: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jiegec/cs140e/e0e469a5e6055948a37d9fccd75f5ae8fed18dbc/2-fs/questions/max-file-size -------------------------------------------------------------------------------- /2-fs/questions/mbr-magic: -------------------------------------------------------------------------------- 1 | Last two bytes should be 0x55, 0xAA. 2 | -------------------------------------------------------------------------------- /2-fs/questions/onus: -------------------------------------------------------------------------------- 1 | In C, the size is kept put before the memory address. In Rust, size and alignment is passed into `dealloc', so its implementation can be simplified, and size of the buffer is saved elsewhere e.g. len in String. 2 | -------------------------------------------------------------------------------- /3-spawn/.gitignore: -------------------------------------------------------------------------------- 1 | # Swap 2 | [._]*.s[a-v][a-z] 3 | [._]*.sw[a-p] 4 | [._]s[a-v][a-z] 5 | [._]sw[a-p] 6 | 7 | # Session 8 | Session.vim 9 | 10 | # Temporary 11 | .netrwhist 12 | *~ 13 | 14 | # Org-mode 15 | .org-id-locations 16 | *_archive 17 | 18 | # flymake-mode 19 | *_flymake.* 20 | 21 | # reftex files 22 | *.rel 23 | 24 | # cask packages 25 | .cask/ 26 | 27 | # Flycheck 28 | flycheck_*.el 29 | 30 | # projectiles files 31 | .projectile 32 | 33 | # directory configuration 34 | .dir-locals.el 35 | 36 | # Prerequisites 37 | *.d 38 | 39 | # Object files 40 | *.o 41 | *.ko 42 | *.obj 43 | *.elf 44 | 45 | # Linker output 46 | *.ilk 47 | *.map 48 | *.exp 49 | 50 | # Precompiled Headers 51 | *.gch 52 | *.pch 53 | 54 | # Libraries 55 | *.lib 56 | *.a 57 | *.la 58 | *.lo 59 | 60 | # Shared objects (inc. Windows DLLs) 61 | *.dll 62 | *.so 63 | *.so.* 64 | *.dylib 65 | 66 | # Executables 67 | *.exe 68 | *.out 69 | *.app 70 | *.i*86 71 | *.x86_64 72 | *.hex 73 | *.bin 74 | *.img 75 | 76 | # Debug files 77 | *.dSYM/ 78 | *.su 79 | *.idb 80 | *.pdb 81 | 82 | # Kernel Module Compile Results 83 | *.mod* 84 | *.cmd 85 | .tmp_versions/ 86 | modules.order 87 | Module.symvers 88 | Mkfile.old 89 | dkms.conf 90 | 91 | # Generated by Cargo 92 | # will have compiled files and executables 93 | target/ 94 | 95 | # Remove Cargo.lock from gitignore if creating an executable, leave it for libraries 96 | # More information here http://doc.crates.io/guide.html#cargotoml-vs-cargolock 97 | Cargo.lock 98 | 99 | # These are backup files generated by rustfmt 100 | **/*.rs.bk 101 | 102 | # Windows thumbnail cache files 103 | Thumbs.db 104 | ehthumbs.db 105 | ehthumbs_vista.db 106 | 107 | # Dump file 108 | *.stackdump 109 | 110 | # Folder config file 111 | [Dd]esktop.ini 112 | 113 | # Recycle Bin used on file shares 114 | $RECYCLE.BIN/ 115 | 116 | # Windows Installer files 117 | *.cab 118 | *.msi 119 | *.msm 120 | *.msp 121 | 122 | # Windows shortcuts 123 | *.lnk 124 | 125 | # General 126 | .DS_Store 127 | .AppleDouble 128 | .LSOverride 129 | 130 | # Thumbnails 131 | ._* 132 | 133 | # Files that might appear in the root of a volume 134 | .DocumentRevisions-V100 135 | .fseventsd 136 | .Spotlight-V100 137 | .TemporaryItems 138 | .Trashes 139 | .VolumeIcon.icns 140 | .com.apple.timemachine.donotpresent 141 | 142 | # Directories potentially created on remote AFP share 143 | .AppleDB 144 | .AppleDesktop 145 | Network Trash Folder 146 | Temporary Items 147 | .apdisk 148 | 149 | # Submission files 150 | *.tar.gz 151 | -------------------------------------------------------------------------------- /3-spawn/Makefile: -------------------------------------------------------------------------------- 1 | ASSIGNMENT_NAME := assignment3 2 | BASE_URL := https://web.stanford.edu/class/cs140e 3 | SUBMISSION_SITE := $(BASE_URL)/assignments/submission/ 4 | SUBMIT_TAR := $(ASSIGNMENT_NAME).tar.gz 5 | 6 | CS140E_REL_ROOT := .. 7 | REPO_NAMES := 0-blinky 1-shell 2-fs 3-spawn os 8 | QUESTIONS_DIRS := $(shell find . -type d -name "questions") 9 | 10 | .PHONY: all check submission clean 11 | 12 | all: 13 | @echo "usage: make [target]" 14 | @echo 15 | @echo "available targets:" 16 | @echo "check ensure every question is answered" 17 | @echo "submission create submission tarball" 18 | @echo "clean clean products from all targets" 19 | 20 | check: 21 | @okay=true; \ 22 | for qdir in $(QUESTIONS_DIRS); do \ 23 | for file in "$${qdir}/"*; do \ 24 | if ! [ -s "$${file}" ]; then \ 25 | okay=false; \ 26 | echo "Question file '$${file}' is empty."; \ 27 | fi \ 28 | done \ 29 | done; \ 30 | if ! $$okay; then \ 31 | echo "Questions remain unanswered. Aborting."; \ 32 | exit 1; \ 33 | else \ 34 | echo "All questions appear to be answered."; \ 35 | fi 36 | 37 | .FORCE: 38 | $(SUBMIT_TAR): .FORCE 39 | @rm -f $@ 40 | @cwd="$${PWD}"; \ 41 | for repo in $(REPO_NAMES); do \ 42 | repo_path="$${cwd}/$(CS140E_REL_ROOT)/$${repo}"; \ 43 | cd "$${repo_path}"; \ 44 | if ! [ -z "$$(git status --porcelain)" ]; then \ 45 | echo "There are uncommited changes in $${repo}! Aborting."; \ 46 | rm -f $@; \ 47 | exit 1; \ 48 | else \ 49 | git_files=$$(git ls-files) ; \ 50 | cd "$${repo_path}/.." ; \ 51 | for file in $$git_files; do \ 52 | tar -rf "$${cwd}/$@" "$${repo}/$${file}"; \ 53 | done \ 54 | fi \ 55 | done 56 | @gzip -f $@ 57 | @mv $@.gz $@ 58 | 59 | submission: $(SUBMIT_TAR) 60 | @echo "Your submission file "$^" was successfully created." 61 | @echo "Submit it at $(SUBMISSION_SITE)" 62 | 63 | clean: 64 | rm -f $(SUBMIT_TAR) 65 | -------------------------------------------------------------------------------- /3-spawn/questions/arm-aarch32: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jiegec/cs140e/e0e469a5e6055948a37d9fccd75f5ae8fed18dbc/3-spawn/questions/arm-aarch32 -------------------------------------------------------------------------------- /3-spawn/questions/arm-el: -------------------------------------------------------------------------------- 1 | mrs x0, CurrentEL 2 | and x0, x0, #0b1100 3 | lsr x0, x0, #2 -------------------------------------------------------------------------------- /3-spawn/questions/arm-int: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jiegec/cs140e/e0e469a5e6055948a37d9fccd75f5ae8fed18dbc/3-spawn/questions/arm-int -------------------------------------------------------------------------------- /3-spawn/questions/arm-mask: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jiegec/cs140e/e0e469a5e6055948a37d9fccd75f5ae8fed18dbc/3-spawn/questions/arm-mask -------------------------------------------------------------------------------- /3-spawn/questions/arm-pc: -------------------------------------------------------------------------------- 1 | adr/ldr lr, A 2 | ret 3 | 4 | adr/ldr x0, A 5 | msr ELR_ELx, x0 6 | eret 7 | -------------------------------------------------------------------------------- /3-spawn/questions/arm-sp-el: -------------------------------------------------------------------------------- 1 | adr/ldr x0, B 2 | msr SP_ELn, x0 3 | mov x0, 1 4 | msr SPSR_ELx, x0 -------------------------------------------------------------------------------- /3-spawn/questions/arm-svc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jiegec/cs140e/e0e469a5e6055948a37d9fccd75f5ae8fed18dbc/3-spawn/questions/arm-svc -------------------------------------------------------------------------------- /3-spawn/questions/arm-x30: -------------------------------------------------------------------------------- 1 | lr and w30. 2 | -------------------------------------------------------------------------------- /3-spawn/questions/asm-cbz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jiegec/cs140e/e0e469a5e6055948a37d9fccd75f5ae8fed18dbc/3-spawn/questions/asm-cbz -------------------------------------------------------------------------------- /3-spawn/questions/asm-init: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jiegec/cs140e/e0e469a5e6055948a37d9fccd75f5ae8fed18dbc/3-spawn/questions/asm-init -------------------------------------------------------------------------------- /3-spawn/questions/asm-memcpy: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jiegec/cs140e/e0e469a5e6055948a37d9fccd75f5ae8fed18dbc/3-spawn/questions/asm-memcpy -------------------------------------------------------------------------------- /3-spawn/questions/asm-movk: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jiegec/cs140e/e0e469a5e6055948a37d9fccd75f5ae8fed18dbc/3-spawn/questions/asm-movk -------------------------------------------------------------------------------- /3-spawn/questions/isolated-stacks: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jiegec/cs140e/e0e469a5e6055948a37d9fccd75f5ae8fed18dbc/3-spawn/questions/isolated-stacks -------------------------------------------------------------------------------- /3-spawn/questions/kernel-distrust: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jiegec/cs140e/e0e469a5e6055948a37d9fccd75f5ae8fed18dbc/3-spawn/questions/kernel-distrust -------------------------------------------------------------------------------- /3-spawn/questions/lazy-float: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jiegec/cs140e/e0e469a5e6055948a37d9fccd75f5ae8fed18dbc/3-spawn/questions/lazy-float -------------------------------------------------------------------------------- /3-spawn/questions/lazy-stacks: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jiegec/cs140e/e0e469a5e6055948a37d9fccd75f5ae8fed18dbc/3-spawn/questions/lazy-stacks -------------------------------------------------------------------------------- /3-spawn/questions/new-state: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jiegec/cs140e/e0e469a5e6055948a37d9fccd75f5ae8fed18dbc/3-spawn/questions/new-state -------------------------------------------------------------------------------- /3-spawn/questions/reentrant-irq: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jiegec/cs140e/e0e469a5e6055948a37d9fccd75f5ae8fed18dbc/3-spawn/questions/reentrant-irq -------------------------------------------------------------------------------- /3-spawn/questions/sleep-elapsed: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jiegec/cs140e/e0e469a5e6055948a37d9fccd75f5ae8fed18dbc/3-spawn/questions/sleep-elapsed -------------------------------------------------------------------------------- /3-spawn/questions/stack-drop: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jiegec/cs140e/e0e469a5e6055948a37d9fccd75f5ae8fed18dbc/3-spawn/questions/stack-drop -------------------------------------------------------------------------------- /3-spawn/questions/stack-size: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jiegec/cs140e/e0e469a5e6055948a37d9fccd75f5ae8fed18dbc/3-spawn/questions/stack-size -------------------------------------------------------------------------------- /3-spawn/questions/syscall-error: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jiegec/cs140e/e0e469a5e6055948a37d9fccd75f5ae8fed18dbc/3-spawn/questions/syscall-error -------------------------------------------------------------------------------- /3-spawn/questions/wait-queue: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jiegec/cs140e/e0e469a5e6055948a37d9fccd75f5ae8fed18dbc/3-spawn/questions/wait-queue -------------------------------------------------------------------------------- /3-spawn/questions/wfi: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jiegec/cs140e/e0e469a5e6055948a37d9fccd75f5ae8fed18dbc/3-spawn/questions/wfi -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | cs140e 2 | ======================================= 3 | 4 | My code for Stanford cs140e. See [archived copy of CS140e](https://cs140e.sergio.bz/). 5 | 6 | Using `alias code-rust="env RUST_TARGET_PATH=(pwd) RUST_LOG=rls=debug CARGO_INCREMENTAL=0 code-insiders"` in my fish config. 7 | 8 | Setup 9 | ================================== 10 | 11 | Setup Rust toolchain: 12 | 13 | ``` 14 | rustup toolchain install nightly-2019-01-01 15 | rustup component add rustfmt-preview rls-preview rust-src rust-analysis 16 | # in cs140e directory 17 | cargo install cargo-xbuild 18 | ``` 19 | 20 | Build bootloader first, then 21 | 22 | ``` 23 | cp os/bootloader/build/bootloader.bin /Volumes/boot/kernel8.img 24 | cp os/bootloader/ext/config.txt /Volumes/boot/config.txt 25 | cd os/kernel 26 | make install; and screen /dev/tty.SLAB_USBtoUART 115200 27 | ``` 28 | 29 | Up and running 30 | ================================ 31 | 32 | To run kernel in QEMU, build kernel and then run it: 33 | 34 | ``` 35 | cd os/kernel 36 | make QEMU=1 37 | qemu-system-aarch64 -machine raspi3 -serial null -serial mon:stdio -kernel build/kernel.bin -s -sd ../../2-fs/files/resources/mock1.fat32.img 38 | ``` 39 | 40 | To run in Raspberry Pi 3, please refer to cs140e webpage. 41 | 42 | 43 | See also 44 | ============================== 45 | 46 | 1. [My series blog posts on cs140e in Chinese](https://jiege.ch/programming/2018/02/04/thoughts-on-stanford-cs140e/). 47 | 2. [Original CS140e](https://cs140e.sergio.bz/). 48 | -------------------------------------------------------------------------------- /os/.gitignore: -------------------------------------------------------------------------------- 1 | # Prerequisites 2 | *.d 3 | 4 | # Object files 5 | *.o 6 | *.ko 7 | *.obj 8 | *.elf 9 | 10 | # Linker output 11 | *.ilk 12 | *.map 13 | *.exp 14 | 15 | # Precompiled Headers 16 | *.gch 17 | *.pch 18 | 19 | # Libraries 20 | *.lib 21 | *.a 22 | *.la 23 | *.lo 24 | 25 | # Shared objects (inc. Windows DLLs) 26 | *.dll 27 | *.so 28 | *.so.* 29 | *.dylib 30 | 31 | # Executables 32 | *.exe 33 | *.out 34 | *.app 35 | *.i*86 36 | *.x86_64 37 | *.hex 38 | *.bin 39 | *.img 40 | 41 | # Debug files 42 | *.dSYM/ 43 | *.su 44 | *.idb 45 | *.pdb 46 | 47 | # Kernel Module Compile Results 48 | *.mod* 49 | *.cmd 50 | .tmp_versions/ 51 | modules.order 52 | Module.symvers 53 | Mkfile.old 54 | dkms.conf 55 | 56 | # Generated by Cargo 57 | # will have compiled files and executables 58 | target/ 59 | 60 | # Remove Cargo.lock from gitignore if creating an executable, leave it for libraries 61 | # More information here http://doc.crates.io/guide.html#cargotoml-vs-cargolock 62 | Cargo.lock 63 | 64 | # These are backup files generated by rustfmt 65 | **/*.rs.bk 66 | 67 | # Windows thumbnail cache files 68 | Thumbs.db 69 | ehthumbs.db 70 | ehthumbs_vista.db 71 | 72 | # Dump file 73 | *.stackdump 74 | 75 | # Folder config file 76 | [Dd]esktop.ini 77 | 78 | # Recycle Bin used on file shares 79 | $RECYCLE.BIN/ 80 | 81 | # Windows Installer files 82 | *.cab 83 | *.msi 84 | *.msm 85 | *.msp 86 | 87 | # Windows shortcuts 88 | *.lnk 89 | 90 | # General 91 | .DS_Store 92 | .AppleDouble 93 | .LSOverride 94 | 95 | # Thumbnails 96 | ._* 97 | 98 | # Files that might appear in the root of a volume 99 | .DocumentRevisions-V100 100 | .fseventsd 101 | .Spotlight-V100 102 | .TemporaryItems 103 | .Trashes 104 | .VolumeIcon.icns 105 | .com.apple.timemachine.donotpresent 106 | 107 | # Directories potentially created on remote AFP share 108 | .AppleDB 109 | .AppleDesktop 110 | Network Trash Folder 111 | Temporary Items 112 | .apdisk 113 | 114 | # Build directories 115 | build/ 116 | /files/ 117 | 118 | # Submission files 119 | *.tar.gz 120 | -------------------------------------------------------------------------------- /os/Makefile: -------------------------------------------------------------------------------- 1 | ASSIGNMENT_NAME := assignment1 2 | BASE_URL := https://web.stanford.edu/class/cs140e 3 | 4 | FILES_DIR := files 5 | FIRMWARE_DIR := $(FILES_DIR)/firmware 6 | FIRMWARE_TAR := $(FIRMWARE_DIR).tar.gz 7 | ASSIGNMENT_FILES := $(FIRMWARE_TAR) $(addprefix $(FILES_DIR)/,act-led-blink.bin) 8 | 9 | .PHONY: all fetch 10 | 11 | all: 12 | @echo "usage: make [target]" 13 | @echo "fetch download assignment files" 14 | @echo "clean clean products from all targets" 15 | 16 | fetch: $(FIRMWARE_DIR) $(ASSIGNMENT_FILES) 17 | 18 | $(FILES_DIR): 19 | @mkdir -p $@ 20 | 21 | $(ASSIGNMENT_FILES): | $(FILES_DIR) 22 | wget $(BASE_URL)/files/$(@:$(FILES_DIR)/%=%) -O $@ 23 | 24 | $(FIRMWARE_DIR): $(FIRMWARE_TAR) | $(FILES_DIR) 25 | tar -xzvf $^ -C $(FILES_DIR) 26 | @touch $(FIRMWARE_DIR) 27 | 28 | clean: 29 | rm -rf $(FILES_DIR) 30 | make clean -C kernel 31 | cd volatile && cargo clean 32 | cd pi && cargo clean 33 | -------------------------------------------------------------------------------- /os/bootloader/.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "rust.target": "aarch64-none-elf", 3 | "rust.sysroot": "/Users/macbookpro/.xargo" 4 | } -------------------------------------------------------------------------------- /os/bootloader/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "bootloader" 3 | version = "0.1.0" 4 | authors = ["Sergio Benitez "] 5 | 6 | [lib] 7 | crate-type = ["staticlib"] 8 | path = "src/kmain.rs" 9 | 10 | [profile.dev] 11 | panic = "abort" 12 | lto = true 13 | debug = true 14 | 15 | [profile.test] 16 | panic = "abort" 17 | lto = true 18 | debug = true 19 | 20 | [profile.release] 21 | panic = "abort" 22 | lto = true 23 | 24 | [dependencies] 25 | pi = { path = "../pi", features = ["std"] } 26 | 27 | # from assignment 1 28 | xmodem = { path = "../../1-shell/xmodem/" } 29 | -------------------------------------------------------------------------------- /os/bootloader/Makefile: -------------------------------------------------------------------------------- 1 | TARGET ?= aarch64-none-elf 2 | CROSS ?= $(TARGET) 3 | 4 | CC := $(CROSS)-gcc 5 | CCFLAGS ?= -Wall -O2 -nostdlib -nostartfiles -ffreestanding -pie -fpie 6 | # LDFLAGS ?= --gc-sections -static -pie -nostdlib -nostartfiles --no-dynamic-linker 7 | LDFLAGS ?= --gc-sections -static -nostdlib -nostartfiles --no-dynamic-linker 8 | XARGO ?= CARGO_INCREMENTAL=0 RUST_TARGET_PATH="$(shell pwd)" xargo 9 | 10 | LD_LAYOUT := ext/layout.ld 11 | 12 | RUST_BINARY := $(shell cat Cargo.toml | grep name | cut -d\" -f 2 | tr - _) 13 | RUST_BUILD_DIR := target/$(TARGET) 14 | RUST_DEBUG_LIB := $(RUST_BUILD_DIR)/debug/lib$(RUST_BINARY).a 15 | RUST_RELEASE_LIB := $(RUST_BUILD_DIR)/release/lib$(RUST_BINARY).a 16 | 17 | RUST_DEPS = Xargo.toml Cargo.toml build.rs $(LD_LAYOUT) src/* 18 | EXT_DEPS = $(BUILD_DIR)/init.o 19 | 20 | BUILD_DIR := build 21 | KERNEL := $(BUILD_DIR)/$(RUST_BINARY) 22 | RUST_LIB := $(BUILD_DIR)/$(RUST_BINARY).a 23 | 24 | .PHONY: all clean check 25 | 26 | VPATH = ext 27 | 28 | all: $(KERNEL).hex $(KERNEL).bin 29 | 30 | check: 31 | @$(XARGO) check --target=$(TARGET) 32 | 33 | $(RUST_DEBUG_LIB): $(RUST_DEPS) 34 | @echo "+ Building $@ [xargo]" 35 | @$(XARGO) build --target=$(TARGET) 36 | 37 | $(RUST_RELEASE_LIB): $(RUST_DEPS) 38 | @echo "+ Building $@ [xargo --release]" 39 | @$(XARGO) build --release --target=$(TARGET) 40 | 41 | ifeq ($(DEBUG),1) 42 | $(RUST_LIB): $(RUST_DEBUG_LIB) | $(BUILD_DIR) 43 | @cp $< $@ 44 | else 45 | $(RUST_LIB): $(RUST_RELEASE_LIB) | $(BUILD_DIR) 46 | @cp $< $@ 47 | endif 48 | 49 | $(BUILD_DIR): 50 | @mkdir -p $@ 51 | 52 | $(BUILD_DIR)/%.o: %.c | $(BUILD_DIR) 53 | @echo "+ Building $@ [cc $<]" 54 | @$(CC) $(CCFLAGS) -c $< -o $@ 55 | 56 | $(BUILD_DIR)/%.o: %.S | $(BUILD_DIR) 57 | @echo "+ Building $@ [as $<]" 58 | @$(CC) $(CCFLAGS) -c $< -o $@ 59 | 60 | $(KERNEL).elf: $(EXT_DEPS) $(RUST_LIB) | $(BUILD_DIR) 61 | @echo "+ Building $@ [ld $^]" 62 | @$(CROSS)-ld $(LDFLAGS) -T$(LD_LAYOUT) $^ -o $@ 63 | 64 | $(KERNEL).hex: $(KERNEL).elf | $(BUILD_DIR) 65 | @echo "+ Building $@ [objcopy $<]" 66 | @$(CROSS)-objcopy $< -O ihex $@ 67 | 68 | $(KERNEL).bin: $(KERNEL).elf | $(BUILD_DIR) 69 | @echo "+ Building $@ [objcopy $<]" 70 | @$(CROSS)-objcopy $< -O binary $@ 71 | 72 | clean: 73 | $(XARGO) clean 74 | rm -rf $(BUILD_DIR) 75 | -------------------------------------------------------------------------------- /os/bootloader/Xargo.toml: -------------------------------------------------------------------------------- 1 | [dependencies] 2 | core = {} 3 | std_unicode = {} 4 | alloc = {} 5 | 6 | [dependencies.compiler_builtins] 7 | features = ["mem"] 8 | stage = 1 9 | 10 | [dependencies.std] 11 | path = "../std" 12 | stage = 2 13 | -------------------------------------------------------------------------------- /os/bootloader/aarch64-none-elf.json: -------------------------------------------------------------------------------- 1 | { 2 | "abi-blacklist": [ 3 | "stdcall", 4 | "fastcall", 5 | "vectorcall", 6 | "thiscall", 7 | "win64", 8 | "sysv64" 9 | ], 10 | "arch": "aarch64", 11 | "data-layout": "e-m:e-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128", 12 | "executables": true, 13 | "linker": "aarch64-none-elf-ld", 14 | "linker-flavor": "ld", 15 | "linker-is-gnu": true, 16 | "llvm-target": "aarch64-unknown-none", 17 | "no-compiler-rt": true, 18 | "features": "+a53,+strict-align", 19 | "max-atomic-width": 128, 20 | "os": "none", 21 | "panic": "abort", 22 | "panic-strategy": "abort", 23 | "position-independent-executables": true, 24 | "target-c-int-width": "32", 25 | "target-endian": "little", 26 | "target-pointer-width": "64", 27 | "disable-redzone": true 28 | } 29 | -------------------------------------------------------------------------------- /os/bootloader/build.rs: -------------------------------------------------------------------------------- 1 | pub fn main() { 2 | println!("cargo:rerun-if-changed=ext/layout.ld"); 3 | println!("cargo:rerun-if-changed=ext/init.S"); 4 | } 5 | -------------------------------------------------------------------------------- /os/bootloader/ext/config.txt: -------------------------------------------------------------------------------- 1 | kernel_address=0x4000000 2 | device_tree= 3 | -------------------------------------------------------------------------------- /os/bootloader/ext/init.S: -------------------------------------------------------------------------------- 1 | .section .text.init 2 | 3 | .global _start 4 | 5 | _start: 6 | // read cpu affinity, start core 0, halt rest 7 | mrs x1, mpidr_el1 8 | and x1, x1, #3 9 | cbz x1, 2f 10 | 11 | 1: 12 | // core affinity != 0, halt it 13 | wfe 14 | b 1b 15 | 16 | 2: 17 | // set the stack to start before our boot code 18 | ldr x1, =_start 19 | mov sp, x1 20 | 21 | // load the start address and number of bytes in BSS section 22 | ldr x1, =__bss_start 23 | ldr x2, =__bss_length 24 | 25 | 3: 26 | // zero out the BSS section, 64-bits at a time 27 | cbz x2, 4f 28 | str xzr, [x1], #8 29 | sub x2, x2, #8 30 | cbnz x2, 3b 31 | 32 | 4: 33 | // jump to kmain, which shouldn't return. halt if it does 34 | bl kmain 35 | b 1b 36 | -------------------------------------------------------------------------------- /os/bootloader/ext/layout.ld: -------------------------------------------------------------------------------- 1 | SECTIONS { 2 | . = 0x4000000; /* bootloader start; leave ~64MiB free */ 3 | 4 | /* start of the binary */ 5 | _start = .; 6 | 7 | .text : { 8 | KEEP(*(.text.init)) /* from init.S */ 9 | *(.text .text.* .gnu.linkonce.t*) 10 | } 11 | 12 | .rodata : { 13 | *(.rodata .rodata.* .gnu.linkonce.r*) 14 | } 15 | 16 | .data : { 17 | *(.data .data.* .gnu.linkonce.d*) 18 | } 19 | 20 | .bss (NOLOAD) : { 21 | . = ALIGN(32); 22 | __bss_start = .; 23 | *(.bss .bss.*) 24 | *(COMMON) 25 | . = ALIGN(8); 26 | __bss_end = .; 27 | } 28 | 29 | /* end of the binary */ 30 | _end = ALIGN(8); 31 | 32 | /* number of bytes in BSS section and complete binary */ 33 | __bss_length = (__bss_end - __bss_start); 34 | __binary_length = (_end - _start); 35 | 36 | /DISCARD/ : { *(.comment) *(.gnu*) *(.note*) *(.eh_frame*) } 37 | } 38 | -------------------------------------------------------------------------------- /os/bootloader/src/allocator: -------------------------------------------------------------------------------- 1 | ../../kernel/src/allocator -------------------------------------------------------------------------------- /os/bootloader/src/console.rs: -------------------------------------------------------------------------------- 1 | ../../kernel/src/console.rs -------------------------------------------------------------------------------- /os/bootloader/src/kmain.rs: -------------------------------------------------------------------------------- 1 | #![feature(asm, lang_items)] 2 | #![feature(alloc, allocator_api, global_allocator)] 3 | #![feature(optin_builtin_traits)] 4 | #![feature(const_fn)] 5 | #![feature(decl_macro)] 6 | #![feature(core_intrinsics)] 7 | 8 | extern crate alloc; 9 | extern crate pi; 10 | extern crate xmodem; 11 | 12 | use std::io; 13 | use std::io::Write; 14 | use pi::uart::MiniUart; 15 | 16 | pub mod mutex; 17 | pub mod console; 18 | pub mod allocator; 19 | pub mod lang_items; 20 | 21 | #[cfg(not(test))] 22 | use allocator::Allocator; 23 | 24 | #[cfg(not(test))] 25 | #[global_allocator] 26 | pub static ALLOCATOR: Allocator = Allocator::uninitialized(); 27 | 28 | /// Start address of the binary to load and of the bootloader. 29 | const BINARY_START_ADDR: usize = 0x80000; 30 | const BOOTLOADER_START_ADDR: usize = 0x4000000; 31 | 32 | /// Pointer to where the loaded binary expects to be laoded. 33 | const BINARY_START: *mut u8 = BINARY_START_ADDR as *mut u8; 34 | 35 | /// Free space between the bootloader and the loaded binary's start address. 36 | const MAX_BINARY_SIZE: usize = BOOTLOADER_START_ADDR - BINARY_START_ADDR; 37 | 38 | /// Branches to the address `addr` unconditionally. 39 | fn jump_to(addr: *mut u8) -> ! { 40 | unsafe { 41 | asm!("br $0" : : "r"(addr as usize)); 42 | loop { 43 | asm!("nop" :::: "volatile") 44 | } 45 | } 46 | } 47 | 48 | #[no_mangle] 49 | pub extern "C" fn kmain() { 50 | // FIXME: Implement the bootloader. 51 | ALLOCATOR.initialize(); 52 | let mut uart = MiniUart::new(); 53 | uart.set_read_timeout(750); 54 | 55 | loop { 56 | let dest = unsafe { std::slice::from_raw_parts_mut(BINARY_START, MAX_BINARY_SIZE) }; 57 | match xmodem::Xmodem::receive(&mut uart, io::Cursor::new(dest)) { 58 | Ok(_) => { 59 | // Succeed 60 | jump_to(BINARY_START) 61 | } 62 | Err(err) => match err.kind() { 63 | io::ErrorKind::TimedOut => continue, 64 | io::ErrorKind::InvalidData => continue, // might receive 0x00 when no input 65 | _ => uart.write_fmt(format_args!("Error: {:?}\r\n", err)) 66 | .unwrap(), 67 | }, 68 | } 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /os/bootloader/src/lang_items.rs: -------------------------------------------------------------------------------- 1 | #[lang = "eh_personality"] pub extern fn eh_personality() {} 2 | 3 | #[lang = "panic_fmt"] #[no_mangle] pub extern fn panic_fmt() -> ! { loop{} } 4 | 5 | #[no_mangle] 6 | pub unsafe extern fn memcpy(dest: *mut u8, src: *const u8, n: usize) -> *mut u8 { 7 | let mut i = 0; 8 | while i < n { 9 | *dest.offset(i as isize) = *src.offset(i as isize); 10 | i += 1; 11 | } 12 | return dest; 13 | } 14 | 15 | #[no_mangle] 16 | pub unsafe extern fn memmove(dest: *mut u8, src: *const u8, n: usize) -> *mut u8 { 17 | if src < dest as *const u8 { // copy from end 18 | let mut i = n; 19 | while i != 0 { 20 | i -= 1; 21 | *dest.offset(i as isize) = *src.offset(i as isize); 22 | } 23 | } else { // copy from beginning 24 | let mut i = 0; 25 | while i < n { 26 | *dest.offset(i as isize) = *src.offset(i as isize); 27 | i += 1; 28 | } 29 | } 30 | return dest; 31 | } 32 | 33 | #[no_mangle] 34 | pub unsafe extern fn memset(s: *mut u8, c: i32, n: usize) -> *mut u8 { 35 | let mut i = 0; 36 | while i < n { 37 | *s.offset(i as isize) = c as u8; 38 | i += 1; 39 | } 40 | return s; 41 | } 42 | 43 | #[no_mangle] 44 | pub unsafe extern fn memcmp(s1: *const u8, s2: *const u8, n: usize) -> i32 { 45 | let mut i = 0; 46 | while i < n { 47 | let a = *s1.offset(i as isize); 48 | let b = *s2.offset(i as isize); 49 | if a != b { 50 | return a as i32 - b as i32 51 | } 52 | i += 1; 53 | } 54 | return 0; 55 | } 56 | -------------------------------------------------------------------------------- /os/bootloader/src/mutex.rs: -------------------------------------------------------------------------------- 1 | ../../kernel/src/mutex.rs -------------------------------------------------------------------------------- /os/kernel/.gdbinit: -------------------------------------------------------------------------------- 1 | file build/kernel.elf 2 | target remote localhost:1234 3 | -------------------------------------------------------------------------------- /os/kernel/.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "rust.target": "aarch64-none-elf", 3 | "rust.sysroot": "/Users/macbookpro/.xargo" 4 | } -------------------------------------------------------------------------------- /os/kernel/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "kernel" 3 | version = "0.1.0" 4 | authors = ["Sergio Benitez "] 5 | 6 | [lib] 7 | crate-type = ["staticlib"] 8 | path = "src/kmain.rs" 9 | 10 | [features] 11 | qemu = ["pi/qemu"] 12 | no_test = ["std", "fat32/custom_std", "pi/custom_std"] 13 | 14 | [profile.dev] 15 | panic = "abort" 16 | debug = true 17 | 18 | [profile.test] 19 | debug = true 20 | 21 | [profile.release] 22 | debug = true 23 | panic = "abort" 24 | lto = true 25 | 26 | [dependencies] 27 | gimli = { version = "0.16.1", default-features = false, features = ["alloc"] } 28 | 29 | pi = { path = "../pi" } 30 | 31 | # from assignment 1 32 | stack-vec = { path = "../../1-shell/stack-vec/" } 33 | 34 | # from assignment 2 35 | fat32 = { path = "../../2-fs/fat32/" } 36 | 37 | std = { path = "../std", optional = true } 38 | -------------------------------------------------------------------------------- /os/kernel/aarch64-none-elf.json: -------------------------------------------------------------------------------- 1 | { 2 | "abi-blacklist": [ 3 | "stdcall", 4 | "fastcall", 5 | "vectorcall", 6 | "thiscall", 7 | "win64", 8 | "sysv64" 9 | ], 10 | "arch": "aarch64", 11 | "data-layout": "e-m:e-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128", 12 | "executables": true, 13 | "linker": "aarch64-none-elf-ld", 14 | "linker-flavor": "ld", 15 | "linker-is-gnu": true, 16 | "llvm-target": "aarch64-unknown-none", 17 | "no-compiler-rt": true, 18 | "features": "+a53,+strict-align", 19 | "max-atomic-width": 128, 20 | "os": "none", 21 | "panic": "abort", 22 | "panic-strategy": "abort", 23 | "position-independent-executables": true, 24 | "target-c-int-width": "32", 25 | "target-endian": "little", 26 | "target-family": "unix", 27 | "os": "ros", 28 | "target-pointer-width": "64", 29 | "disable-redzone": true, 30 | "eliminate-frame-pointer": false 31 | } 32 | -------------------------------------------------------------------------------- /os/kernel/build.rs: -------------------------------------------------------------------------------- 1 | pub fn main() { 2 | if ::std::env::var("TARGET").unwrap().contains("aarch64-none-elf") { 3 | println!("cargo:rustc-link-search=native=ext"); 4 | println!("cargo:rustc-link-lib=static=sd"); 5 | println!("cargo:rerun-if-changed=ext/libsd.a"); 6 | } 7 | 8 | println!("cargo:rerun-if-changed=ext/layout.ld"); 9 | println!("cargo:rerun-if-changed=ext/init.S"); 10 | } 11 | -------------------------------------------------------------------------------- /os/kernel/ext/layout.ld: -------------------------------------------------------------------------------- 1 | SECTIONS { 2 | . = 0x80000; /* Raspbery Pi 3 Aarch64 (kernel8.img) load address */ 3 | 4 | /* start of the binary */ 5 | _start = .; 6 | 7 | .text : { 8 | PROVIDE(__text_start = .); 9 | KEEP(*(.text.init)) /* from init.S */ 10 | *(.text .text.* .gnu.linkonce.t*) 11 | PROVIDE(__text_end = .); 12 | } 13 | 14 | .rodata : { 15 | *(.rodata .rodata.* .gnu.linkonce.r*) 16 | } 17 | 18 | .data : { 19 | *(.data .data.* .gnu.linkonce.d*) 20 | } 21 | 22 | .bss (NOLOAD) : { 23 | . = ALIGN(32); 24 | __bss_start = .; 25 | *(.bss .bss.*) 26 | *(COMMON) 27 | . = ALIGN(8); 28 | __bss_end = .; 29 | } 30 | 31 | .debug_info : { 32 | . = ALIGN(32); 33 | PROVIDE(__debug_info_start = .); 34 | KEEP(*(.debug_info .debug_info.*)) 35 | PROVIDE(__debug_info_end = .); 36 | BYTE(0) 37 | } 38 | 39 | .debug_abbrev : { 40 | . = ALIGN(32); 41 | PROVIDE(__debug_abbrev_start = .); 42 | KEEP(*(.debug_abbrev .debug_abbrev.*)) 43 | PROVIDE(__debug_abbrev_end = .); 44 | BYTE(0) 45 | } 46 | 47 | .debug_str : { 48 | . = ALIGN(32); 49 | PROVIDE(__debug_str_start = .); 50 | KEEP(*(.debug_str .debug_str.*)) 51 | PROVIDE(__debug_str_end = .); 52 | BYTE(0) 53 | } 54 | 55 | /* end of the binary */ 56 | _end = ALIGN(8); 57 | 58 | /* number of bytes in BSS section and complete binary */ 59 | __bss_length = (__bss_end - __bss_start); 60 | __binary_length = (_end - _start); 61 | 62 | /DISCARD/ : { *(.comment) *(.gnu*) *(.note*) *(.eh_frame*) } 63 | } 64 | -------------------------------------------------------------------------------- /os/kernel/src/allocator/bump.rs: -------------------------------------------------------------------------------- 1 | use alloc::alloc::{AllocErr, Layout}; 2 | 3 | use allocator::util::*; 4 | 5 | /// A "bump" allocator: allocates memory by bumping a pointer; never frees. 6 | #[derive(Debug)] 7 | pub struct Allocator { 8 | current: usize, 9 | end: usize, 10 | } 11 | 12 | impl Allocator { 13 | /// Creates a new bump allocator that will allocate memory from the region 14 | /// starting at address `start` and ending at address `end`. 15 | pub fn new(start: usize, end: usize) -> Allocator { 16 | Allocator { 17 | current: start, 18 | end: end, 19 | } 20 | } 21 | 22 | /// Allocates memory. Returns a pointer meeting the size and alignment 23 | /// properties of `layout.size()` and `layout.align()`. 24 | /// 25 | /// If this method returns an `Ok(addr)`, `addr` will be non-null address 26 | /// pointing to a block of storage suitable for holding an instance of 27 | /// `layout`. In particular, the block will be at least `layout.size()` 28 | /// bytes large and will be aligned to `layout.align()`. The returned block 29 | /// of storage may or may not have its contents initialized or zeroed. 30 | /// 31 | /// # Safety 32 | /// 33 | /// The _caller_ must ensure that `layout.size() > 0` and that 34 | /// `layout.align()` is a power of two. Parameters not meeting these 35 | /// conditions may result in undefined behavior. 36 | /// 37 | /// # Errors 38 | /// 39 | /// Returning `Err` indicates that either memory is exhausted 40 | /// (`AllocError::Exhausted`) or `layout` does not meet this allocator's 41 | /// size or alignment constraints (`AllocError::Unsupported`). 42 | pub fn alloc(&mut self, layout: Layout) -> Result<*mut u8, AllocErr> { 43 | let new_start = align_up(self.current, layout.align()).saturating_add(layout.size()); 44 | 45 | if new_start >= self.end { 46 | return Err(AllocErr); 47 | } 48 | 49 | self.current = new_start; 50 | Ok((new_start - layout.size()) as *mut u8) 51 | } 52 | 53 | /// Deallocates the memory referenced by `ptr`. 54 | /// 55 | /// # Safety 56 | /// 57 | /// The _caller_ must ensure the following: 58 | /// 59 | /// * `ptr` must denote a block of memory currently allocated via this 60 | /// allocator 61 | /// * `layout` must properly represent the original layout used in the 62 | /// allocation call that returned `ptr` 63 | /// 64 | /// Parameters not meeting these conditions may result in undefined 65 | /// behavior. 66 | pub fn dealloc(&mut self, _ptr: *mut u8, _layout: Layout) { 67 | // Do nothing 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /os/kernel/src/allocator/util.rs: -------------------------------------------------------------------------------- 1 | #![allow(dead_code)] 2 | 3 | use std::mem::size_of; 4 | 5 | /// Align `addr` downwards to the nearest multiple of `align`. 6 | /// 7 | /// The returned usize is always <= `addr.` 8 | /// 9 | /// # Panics 10 | /// 11 | /// Panics if `align` is not a power of 2. 12 | pub fn align_down(addr: usize, align: usize) -> usize { 13 | if !align.is_power_of_two() { 14 | panic!("align_down: align not a power of 2"); 15 | } 16 | 17 | addr & !(align - 1) 18 | } 19 | 20 | /// Align `addr` upwards to the nearest multiple of `align`. 21 | /// 22 | /// The returned `usize` is always >= `addr.` 23 | /// 24 | /// # Panics 25 | /// 26 | /// Panics if `align` is not a power of 2. 27 | pub fn align_up(addr: usize, align: usize) -> usize { 28 | align_down(addr.saturating_add(align - 1), align) 29 | } 30 | 31 | pub fn prev_power_of_two(num: usize) -> usize { 32 | 1 << (8 * (size_of::()) - num.leading_zeros() as usize - 1) 33 | } -------------------------------------------------------------------------------- /os/kernel/src/dwarf.rs: -------------------------------------------------------------------------------- 1 | extern crate gimli; 2 | use std::slice; 3 | use console::kprintln; 4 | 5 | extern "C" { 6 | fn __debug_info_start(); 7 | fn __debug_info_end(); 8 | fn __debug_abbrev_start(); 9 | fn __debug_abbrev_end(); 10 | fn __debug_str_start(); 11 | fn __debug_str_end(); 12 | } 13 | 14 | pub unsafe fn get_function_from_pc(pc: usize) -> Option { 15 | let endian = gimli::LittleEndian; 16 | let debug_info_start = __debug_info_start as usize; 17 | let debug_info_end = __debug_info_end as usize; 18 | let debug_info = gimli::DebugInfo::new(slice::from_raw_parts(debug_info_start as *const u8, debug_info_end - debug_info_start), endian); 19 | // the positions in debug_info are absolute 20 | let debug_abbrev_end = __debug_abbrev_end as usize; 21 | let debug_abbrev = gimli::DebugAbbrev::new(slice::from_raw_parts(0 as *const u8, debug_abbrev_end), endian); 22 | let debug_str_end = __debug_str_end as usize; 23 | let debug_str = gimli::DebugStr::new(slice::from_raw_parts(0 as *const u8, debug_str_end), endian); 24 | match get_function_from_pc_gimli(debug_info, debug_abbrev, debug_str, pc as u64) { 25 | Ok(res) => Some(res), 26 | Err(err) => { 27 | None 28 | } 29 | } 30 | } 31 | 32 | fn get_function_from_pc_gimli(debug_info: gimli::DebugInfo, debug_abbrev: gimli::DebugAbbrev, 33 | debug_str: gimli::DebugStr, pc: u64) -> Result{ 34 | let mut iter = debug_info.units(); 35 | while let Some(unit) = iter.next()? { 36 | let abbrevs = unit.abbreviations(&debug_abbrev)?; 37 | 38 | let mut entries = unit.entries(&abbrevs); 39 | while let Some((_, entry)) = entries.next_dfs()? { 40 | if entry.tag() == gimli::DW_TAG_subprogram { 41 | // a function 42 | if let Some(gimli::AttributeValue::Addr(low_pc)) = entry.attr_value(gimli::DW_AT_low_pc)? { 43 | if let Some(gimli::AttributeValue::Udata(high_pc)) = entry.attr_value(gimli::DW_AT_high_pc)? { 44 | // address: [low_pc, low_pc + high_pc) 45 | if low_pc <= pc && low_pc + high_pc > pc { 46 | if let Some(gimli::AttributeValue::DebugStrRef(str_ref)) = entry.attr_value(gimli::DW_AT_name)? { 47 | return Ok(debug_str.get_str(str_ref)?.to_string()?.to_string()) 48 | } 49 | return Err(gimli::Error::NoEntryAtGivenOffset) 50 | } else if low_pc > pc { 51 | break 52 | } 53 | } 54 | } 55 | } 56 | } 57 | } 58 | Err(gimli::Error::NoEntryAtGivenOffset) 59 | } -------------------------------------------------------------------------------- /os/kernel/src/fs/mod.rs: -------------------------------------------------------------------------------- 1 | pub mod sd; 2 | 3 | use std::io; 4 | use std::path::{Path, PathBuf}; 5 | 6 | use fat32::vfat::{Shared, VFat}; 7 | pub use fat32::traits; 8 | 9 | use mutex::Mutex; 10 | use self::sd::Sd; 11 | 12 | #[derive(Debug)] 13 | pub struct FileSystem(Mutex>>); 14 | 15 | impl FileSystem { 16 | /// Returns an uninitialized `FileSystem`. 17 | /// 18 | /// The file system must be initialized by calling `initialize()` before the 19 | /// first memory allocation. Failure to do will result in panics. 20 | pub const fn uninitialized() -> Self { 21 | FileSystem(Mutex::new(None)) 22 | } 23 | 24 | /// Initializes the file system. 25 | /// 26 | /// # Panics 27 | /// 28 | /// Panics if the underlying disk or file sytem failed to initialize. 29 | pub fn initialize(&self) { 30 | *self.0.lock() = Some(VFat::from(Sd::new().unwrap()).unwrap()); 31 | } 32 | } 33 | 34 | // FIXME: Implement `fat32::traits::FileSystem` for a useful type. 35 | impl<'a> traits::FileSystem for &'a FileSystem { 36 | type File = <&'a Shared as traits::FileSystem>::File; 37 | type Dir = <&'a Shared as traits::FileSystem>::Dir; 38 | type Entry = <&'a Shared as traits::FileSystem>::Entry; 39 | 40 | fn open>(self, path: P) -> io::Result { 41 | self.0.lock().as_ref().unwrap().open(path) 42 | } 43 | 44 | fn canonicalize>(self, path: P) -> io::Result { 45 | self.0.lock().as_ref().unwrap().canonicalize(path) 46 | } 47 | 48 | fn create_file>(self, path: P) -> io::Result { 49 | self.0.lock().as_ref().unwrap().create_file(path) 50 | } 51 | 52 | fn create_dir

(self, path: P, parents: bool) -> io::Result 53 | where 54 | P: AsRef, 55 | { 56 | self.0.lock().as_ref().unwrap().create_dir(path, parents) 57 | } 58 | 59 | fn rename(self, from: P, to: Q) -> io::Result<()> 60 | where 61 | P: AsRef, 62 | Q: AsRef, 63 | { 64 | self.0.lock().as_ref().unwrap().rename(from, to) 65 | } 66 | 67 | fn remove>(self, path: P, children: bool) -> io::Result<()> { 68 | self.0.lock().as_ref().unwrap().remove(path, children) 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /os/kernel/src/kmain.rs: -------------------------------------------------------------------------------- 1 | #![feature(alloc, allocator_api)] 2 | #![feature(asm)] 3 | #![feature(core_intrinsics)] 4 | #![feature(const_fn)] 5 | #![feature(decl_macro)] 6 | #![feature(exclusive_range_pattern)] 7 | #![feature(lang_items)] 8 | #![feature(naked_functions)] 9 | #![feature(never_type)] 10 | #![feature(optin_builtin_traits)] 11 | #![feature(ptr_internals)] 12 | #![feature(panic_info_message)] 13 | #![feature(raw_vec_internals)] 14 | 15 | #[macro_use] 16 | #[allow(unused_imports)] 17 | extern crate alloc; 18 | extern crate core; 19 | extern crate fat32; 20 | extern crate pi; 21 | extern crate stack_vec; 22 | 23 | pub mod allocator; 24 | #[cfg(not(test))] 25 | use pi::timer::spin_sleep_ms; 26 | 27 | pub mod lang_items; 28 | pub mod mutex; 29 | pub mod console; 30 | pub mod user; 31 | pub mod fs; 32 | pub mod traps; 33 | pub mod aarch64; 34 | pub mod process; 35 | pub mod vm; 36 | mod dwarf; 37 | 38 | #[cfg(not(test))] 39 | use allocator::Allocator; 40 | use fs::FileSystem; 41 | use process::GlobalScheduler; 42 | #[cfg(feature = "qemu")] 43 | use pi::timer::Timer; 44 | 45 | #[cfg(not(test))] 46 | #[global_allocator] 47 | pub static ALLOCATOR: Allocator = Allocator::uninitialized(); 48 | 49 | #[cfg(test)] 50 | use std::alloc::System; 51 | #[cfg(test)] 52 | #[global_allocator] 53 | pub static ALLOCATOR: System = System; 54 | 55 | pub static FILE_SYSTEM: FileSystem = FileSystem::uninitialized(); 56 | 57 | pub static SCHEDULER: GlobalScheduler = GlobalScheduler::uninitialized(); 58 | 59 | #[no_mangle] 60 | #[cfg(not(test))] 61 | pub extern "C" fn kmain() { 62 | ALLOCATOR.initialize(); 63 | #[cfg(feature = "qemu")] 64 | Timer::initialize(); 65 | FILE_SYSTEM.initialize(); 66 | spin_sleep_ms(200); 67 | SCHEDULER.start(); 68 | } 69 | 70 | pub extern "C" fn shell_thread() { 71 | loop { 72 | user::shell("$ "); 73 | } 74 | } 75 | 76 | pub extern "C" fn shell_thread_2() { 77 | loop { 78 | user::timer(); 79 | } 80 | } 81 | -------------------------------------------------------------------------------- /os/kernel/src/lang_items.rs: -------------------------------------------------------------------------------- 1 | use core::panic::PanicInfo; 2 | use console::noblock_kprintln; 3 | #[cfg(not(test))] 4 | use std::Layout; 5 | 6 | #[no_mangle] 7 | #[cfg(not(test))] 8 | #[panic_handler] 9 | pub extern fn panic_fmt(panic_info: &PanicInfo) -> ! { 10 | // Avoid deadlock 11 | if let Some(location) = panic_info.location() { 12 | noblock_kprintln!("Kernel Panic at file {} line {}, column {}", 13 | location.file(), location.line(), location.column()); 14 | } 15 | if let Some(fmt) = panic_info.message() { 16 | use console::noblock_kprintln; 17 | noblock_kprintln!("\t message: {}", fmt); 18 | } 19 | 20 | loop { 21 | unsafe { asm!("wfe") } 22 | } 23 | } 24 | 25 | #[cfg(not(test))] 26 | #[lang = "eh_personality"] 27 | pub extern "C" fn eh_personality() {} 28 | 29 | #[cfg(not(test))] 30 | #[lang = "oom"] 31 | pub extern "C" fn oom(layout: Layout) -> ! { 32 | // Avoid deadlock 33 | noblock_kprintln!("Out of memory when allocating {:?}", layout); 34 | 35 | loop { 36 | unsafe { asm!("wfe") } 37 | } 38 | } -------------------------------------------------------------------------------- /os/kernel/src/mutex.rs: -------------------------------------------------------------------------------- 1 | use std::sync::atomic::{AtomicBool, AtomicUsize}; 2 | use std::sync::atomic::Ordering::Relaxed; 3 | use std::cell::UnsafeCell; 4 | use std::ops::{Deref, DerefMut, Drop}; 5 | use std::fmt; 6 | 7 | #[repr(align(32))] 8 | pub struct Mutex { 9 | data: UnsafeCell, 10 | lock: AtomicBool, 11 | owner: AtomicUsize 12 | } 13 | 14 | unsafe impl Send for Mutex {} 15 | unsafe impl Sync for Mutex {} 16 | 17 | pub struct MutexGuard<'a, T: 'a> { 18 | lock: &'a Mutex, 19 | } 20 | 21 | impl<'a, T> !Send for MutexGuard<'a, T> {} 22 | unsafe impl<'a, T: Sync> Sync for MutexGuard<'a, T> {} 23 | 24 | impl Mutex { 25 | pub const fn new(val: T) -> Mutex { 26 | Mutex { 27 | lock: AtomicBool::new(false), 28 | owner: AtomicUsize::new(usize::max_value()), 29 | data: UnsafeCell::new(val), 30 | } 31 | } 32 | } 33 | 34 | impl Mutex { 35 | // Once MMU/cache is enabled, do the right thing here. For now, we don't 36 | // need any real synchronization. 37 | pub fn try_lock(&self) -> Option> { 38 | let this = 0; 39 | if !self.lock.load(Relaxed) || self.owner.load(Relaxed) == this { 40 | self.lock.store(true, Relaxed); 41 | self.owner.store(this, Relaxed); 42 | Some(MutexGuard { lock: &self }) 43 | } else { 44 | None 45 | } 46 | } 47 | 48 | // Once MMU/cache is enabled, do the right thing here. For now, we don't 49 | // need any real synchronization. 50 | #[inline(never)] 51 | pub fn lock(&self) -> MutexGuard { 52 | // Wait until we can "aquire" the lock, then "acquire" it. 53 | loop { 54 | match self.try_lock() { 55 | Some(guard) => return guard, 56 | None => continue, 57 | } 58 | } 59 | } 60 | 61 | fn unlock(&self) { 62 | self.lock.store(false, Relaxed); 63 | } 64 | } 65 | 66 | impl<'a, T: 'a> Deref for MutexGuard<'a, T> { 67 | type Target = T; 68 | 69 | fn deref(&self) -> &T { 70 | unsafe { &*self.lock.data.get() } 71 | } 72 | } 73 | 74 | impl<'a, T: 'a> DerefMut for MutexGuard<'a, T> { 75 | fn deref_mut(&mut self) -> &mut T { 76 | unsafe { &mut *self.lock.data.get() } 77 | } 78 | } 79 | 80 | impl<'a, T: 'a> Drop for MutexGuard<'a, T> { 81 | fn drop(&mut self) { 82 | self.lock.unlock() 83 | } 84 | } 85 | 86 | impl fmt::Debug for Mutex { 87 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 88 | match self.try_lock() { 89 | Some(guard) => f.debug_struct("Mutex").field("data", &&*guard).finish(), 90 | None => f.debug_struct("Mutex").field("data", &"").finish(), 91 | } 92 | } 93 | } 94 | -------------------------------------------------------------------------------- /os/kernel/src/process/mod.rs: -------------------------------------------------------------------------------- 1 | mod process; 2 | mod state; 3 | mod scheduler; 4 | mod stack; 5 | 6 | pub use self::process::{Process, Id}; 7 | pub use self::state::State; 8 | pub use self::scheduler::{GlobalScheduler, TICK}; 9 | pub use self::stack::Stack; 10 | -------------------------------------------------------------------------------- /os/kernel/src/process/process.rs: -------------------------------------------------------------------------------- 1 | use traps::TrapFrame; 2 | use process::{Stack, State}; 3 | use std::mem::replace; 4 | 5 | /// Type alias for the type of a process ID. 6 | pub type Id = u64; 7 | 8 | /// A structure that represents the complete state of a process. 9 | #[derive(Debug)] 10 | pub struct Process { 11 | /// The saved trap frame of a process. 12 | pub trap_frame: Box, 13 | /// The memory allocation used for the process's stack. 14 | pub stack: Stack, 15 | /// The scheduling state of the process. 16 | pub state: State, 17 | } 18 | 19 | impl Process { 20 | /// Creates a new process with a zeroed `TrapFrame` (the default), a zeroed 21 | /// stack of the default size, and a state of `Ready`. 22 | /// 23 | /// If enough memory could not be allocated to start the process, returns 24 | /// `None`. Otherwise returns `Some` of the new `Process`. 25 | pub fn new() -> Option { 26 | match Stack::new() { 27 | Some(stack) => Some(Process { 28 | trap_frame: Box::new(TrapFrame::default()), 29 | stack, 30 | state: State::Ready, 31 | }), 32 | None => None, 33 | } 34 | } 35 | 36 | /// Returns `true` if this process is ready to be scheduled. 37 | /// 38 | /// This functions returns `true` only if one of the following holds: 39 | /// 40 | /// * The state is currently `Ready`. 41 | /// 42 | /// * An event being waited for has arrived. 43 | /// 44 | /// If the process is currently waiting, the corresponding event 45 | /// function is polled to determine if the event being waiting for has 46 | /// occured. If it has, the state is switched to `Ready` and this 47 | /// function returns `true`. 48 | /// 49 | /// Returns `false` in all other cases. 50 | pub fn is_ready(&mut self) -> bool { 51 | if let State::Ready = self.state { 52 | true 53 | } else if let State::Running = self.state { 54 | false 55 | } else { 56 | let state = replace(&mut self.state, State::Ready); 57 | if let State::Waiting(mut event_poll_fn) = state { 58 | if event_poll_fn(self) { 59 | true 60 | } else { 61 | self.state = State::Waiting(event_poll_fn); 62 | false 63 | } 64 | } else { 65 | unreachable!(); 66 | } 67 | } 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /os/kernel/src/process/stack.rs: -------------------------------------------------------------------------------- 1 | use std::fmt; 2 | use std::ptr::Unique; 3 | #[cfg(not(test))] 4 | use std::GlobalAlloc; 5 | #[cfg(test)] 6 | use std::alloc::GlobalAlloc; 7 | 8 | use ALLOCATOR; 9 | use alloc::alloc::Layout; 10 | use vm::PhysicalAddr; 11 | 12 | /// A process stack. The default size is 1M1B with an alignment of 16 bytes. 13 | pub struct Stack { 14 | ptr: Unique<[u8; Stack::SIZE]> 15 | } 16 | 17 | impl Stack { 18 | /// The default stack size is 1MiB. 19 | pub const SIZE: usize = 1 << 20; 20 | 21 | /// The default stack alignment is 16 bytes. 22 | pub const ALIGN: usize = 16; 23 | 24 | /// The default layout for a stack. 25 | fn layout() -> Layout { 26 | unsafe { Layout::from_size_align_unchecked(Self::SIZE, Self::ALIGN) } 27 | } 28 | 29 | /// Returns a newly allocated process stack, zeroed out, if one could be 30 | /// successfully allocated. If there is no memory, or memory allocation 31 | /// fails for some other reason, returns `None`. 32 | pub fn new() -> Option { 33 | let raw_ptr = unsafe { 34 | let raw_ptr: *mut u8 = (&ALLOCATOR).alloc(Stack::layout()); 35 | raw_ptr.write_bytes(0, Self::SIZE); 36 | raw_ptr 37 | }; 38 | 39 | let ptr = Unique::new(raw_ptr as *mut _).expect("non-null"); 40 | Some(Stack { ptr }) 41 | } 42 | 43 | /// Internal method to cast to a `*mut u8`. 44 | unsafe fn as_mut_ptr(&self) -> *mut u8 { 45 | self.ptr.as_ptr() as _ 46 | } 47 | 48 | /// Returns the physical address of top of the stack. 49 | pub fn top(&self) -> PhysicalAddr { 50 | unsafe { self.as_mut_ptr().add(Self::SIZE).into() } 51 | } 52 | 53 | /// Returns the physical address of bottom of the stack. 54 | pub fn bottom(&self) -> PhysicalAddr { 55 | unsafe { self.as_mut_ptr().into() } 56 | } 57 | } 58 | 59 | impl Drop for Stack { 60 | fn drop(&mut self) { 61 | unsafe { 62 | (&ALLOCATOR).dealloc(self.as_mut_ptr(), Self::layout()) 63 | } 64 | } 65 | } 66 | 67 | impl fmt::Debug for Stack { 68 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 69 | f.debug_struct("Stack") 70 | .field("top", &self.top()) 71 | .field("bottom", &self.bottom()) 72 | .field("size", &Self::SIZE) 73 | .finish() 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /os/kernel/src/process/state.rs: -------------------------------------------------------------------------------- 1 | use std::fmt; 2 | 3 | use process::Process; 4 | 5 | /// Type of a function used to determine if a process is ready to be scheduled 6 | /// again. The scheduler calls this function when it is the process's turn to 7 | /// execute. If the function returns `true`, the process is scheduled. If it 8 | /// returns `false`, the process is not scheduled, and this function will be 9 | /// called on the next time slice. 10 | pub type EventPollFn = Box bool + Send>; 11 | 12 | /// The scheduling state of a process. 13 | pub enum State { 14 | /// The process is ready to be scheduled. 15 | Ready, 16 | /// The process is waiting on an event to occur before it can be scheduled. 17 | Waiting(EventPollFn), 18 | /// The process is currently running. 19 | Running, 20 | } 21 | 22 | impl fmt::Debug for State { 23 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 24 | match *self { 25 | State::Ready => write!(f, "State::Ready"), 26 | State::Running => write!(f, "State::Running"), 27 | State::Waiting(_) => write!(f, "State::Waiting"), 28 | } 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /os/kernel/src/shell.rs: -------------------------------------------------------------------------------- 1 | use stack_vec::StackVec; 2 | use console::{kprint, kprintln, CONSOLE}; 3 | 4 | /// Error type for `Command` parse failures. 5 | #[derive(Debug)] 6 | enum Error { 7 | Empty, 8 | TooManyArgs 9 | } 10 | 11 | /// A structure representing a single shell command. 12 | struct Command<'a> { 13 | args: StackVec<'a, &'a str> 14 | } 15 | 16 | impl<'a> Command<'a> { 17 | /// Parse a command from a string `s` using `buf` as storage for the 18 | /// arguments. 19 | /// 20 | /// # Errors 21 | /// 22 | /// If `s` contains no arguments, returns `Error::Empty`. If there are more 23 | /// arguments than `buf` can hold, returns `Error::TooManyArgs`. 24 | fn parse(s: &'a str, buf: &'a mut [&'a str]) -> Result, Error> { 25 | let mut args = StackVec::new(buf); 26 | for arg in s.split(' ').filter(|a| !a.is_empty()) { 27 | args.push(arg).map_err(|_| Error::TooManyArgs)?; 28 | } 29 | 30 | if args.is_empty() { 31 | return Err(Error::Empty); 32 | } 33 | 34 | Ok(Command { args }) 35 | } 36 | 37 | /// Returns this command's path. This is equivalent to the first argument. 38 | fn path(&self) -> &str { 39 | unimplemented!() 40 | } 41 | } 42 | 43 | /// Starts a shell using `prefix` as the prefix for each line. This function 44 | /// returns if the `exit` command is called. 45 | pub fn shell(prefix: &str) { 46 | unimplemented!() 47 | } 48 | -------------------------------------------------------------------------------- /os/kernel/src/traps/irq.rs: -------------------------------------------------------------------------------- 1 | use pi::interrupt::Interrupt; 2 | 3 | use traps::TrapFrame; 4 | use process::State; 5 | use pi::timer::tick_in; 6 | use process::TICK; 7 | use SCHEDULER; 8 | 9 | pub fn handle_irq(interrupt: Interrupt, tf: &mut TrapFrame) { 10 | match interrupt { 11 | Interrupt::Timer1 => { 12 | tick_in(TICK); 13 | SCHEDULER.switch(State::Ready, tf).unwrap(); 14 | } 15 | _ => unimplemented!("handle_irq()"), 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /os/kernel/src/traps/syscall.rs: -------------------------------------------------------------------------------- 1 | use traps::TrapFrame; 2 | use pi::timer::current_time; 3 | use SCHEDULER; 4 | use process::State; 5 | use process::Process; 6 | 7 | /// Sleep for `ms` milliseconds. 8 | /// 9 | /// This system call takes one parameter: the number of milliseconds to sleep. 10 | /// 11 | /// In addition to the usual status value, this system call returns one 12 | /// parameter: the approximate true elapsed time from when `sleep` was called to 13 | /// when `sleep` returned. 14 | pub fn sleep(ms: u32, tf: &mut TrapFrame) { 15 | let begin = current_time(); 16 | let time = begin + ms as u64 * 1000; 17 | let polling_fn = Box::new(move |process: &mut Process| { 18 | let current = current_time(); 19 | if current > time { 20 | process.trap_frame.x1to29[6] = 0; // x7 = 0; succeed 21 | process.trap_frame.x0 = (current - begin) / 1000; // x0 = elapsed time in ms 22 | true 23 | } else { 24 | false 25 | } 26 | }); 27 | SCHEDULER.switch(State::Waiting(polling_fn), tf).unwrap(); 28 | } 29 | 30 | pub fn handle_syscall(num: u16, tf: &mut TrapFrame) { 31 | match num { 32 | 1 => { 33 | sleep(tf.x0 as u32, tf); 34 | } 35 | _ => { 36 | tf.x1to29[6] = 1; // x7 = 1, do not exist 37 | } 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /os/kernel/src/traps/trap_frame.rs: -------------------------------------------------------------------------------- 1 | #[repr(C)] 2 | #[derive(Default, Debug, Copy, Clone)] 3 | pub struct TrapFrame { 4 | // FIXME: Fill me in. 5 | pub elr: u64, 6 | pub spsr: u64, 7 | pub sp: u64, 8 | pub tpidr: u64, 9 | pub q0to31: [u128; 32], 10 | pub x1to29: [u64; 29], 11 | pub __r1: u64, // may be used to store lr temporaily 12 | pub x30: u64, 13 | pub x0: u64, 14 | } 15 | -------------------------------------------------------------------------------- /os/kernel/src/user/mod.rs: -------------------------------------------------------------------------------- 1 | mod shell; 2 | mod syscall; 3 | 4 | pub use self::shell::shell; 5 | pub use self::shell::timer; -------------------------------------------------------------------------------- /os/kernel/src/user/syscall.rs: -------------------------------------------------------------------------------- 1 | #[cfg(not(test))] 2 | pub fn sleep(time: u64) -> (u64, u64) { 3 | let error: u64; 4 | let time_elapsed: u64; 5 | unsafe { 6 | asm!("mov x0, $2 7 | svc 1 8 | mov $0, x0 9 | mov $1, x7" 10 | : "=r"(time_elapsed), "=r"(error) 11 | : "r"(time) 12 | : "x0", "x7") 13 | }; 14 | (error, time_elapsed) 15 | } 16 | 17 | #[cfg(test)] 18 | pub fn sleep(_: u64) -> (u64, u64) { 19 | (0, 0) 20 | } -------------------------------------------------------------------------------- /os/kernel/src/vm/address.rs: -------------------------------------------------------------------------------- 1 | use std::fmt; 2 | 3 | /// A virtual address. 4 | pub struct VirtualAddr(usize); 5 | 6 | /// A physical address. 7 | pub struct PhysicalAddr(usize); 8 | 9 | macro_rules! impl_for { 10 | ($T:tt) => { 11 | impl From<*mut T> for $T { 12 | fn from(raw_ptr: *mut T) -> $T { 13 | $T(raw_ptr as usize) 14 | } 15 | } 16 | 17 | impl $T { 18 | /// Returns the inner address of `self`. 19 | pub fn as_ptr(&self) -> *const u8 { 20 | self.0 as *const u8 21 | } 22 | 23 | /// Returns the inner address of `self`. 24 | /// 25 | /// # Safety 26 | /// 27 | /// This method is marked `unsafe` because it can be used to create 28 | /// multiple mutable aliases to the address represented by `self`. The 29 | /// caller must ensure that they do not alias. 30 | pub fn as_mut_ptr(&mut self) -> *mut u8 { 31 | self.0 as *mut u8 32 | } 33 | 34 | /// Returns the inner address of `self` as a `usize`. 35 | pub fn as_usize(&self) -> usize { 36 | self.0 37 | } 38 | 39 | /// Returns the inner address of `self` as a `u64`. 40 | #[cfg(target_pointer_width = "64")] 41 | pub fn as_u64(&self) -> u64 { 42 | self.0 as u64 43 | } 44 | } 45 | 46 | impl fmt::Debug for $T { 47 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 48 | write!(f, "{}({:#x})", stringify!($T), self.0) 49 | } 50 | } 51 | } 52 | } 53 | 54 | impl_for!(VirtualAddr); 55 | impl_for!(PhysicalAddr); 56 | -------------------------------------------------------------------------------- /os/kernel/src/vm/mod.rs: -------------------------------------------------------------------------------- 1 | mod address; 2 | 3 | pub use self::address::{PhysicalAddr, VirtualAddr}; 4 | -------------------------------------------------------------------------------- /os/pi/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "pi" 3 | version = "0.1.0" 4 | authors = ["Sergio Benitez "] 5 | 6 | [dependencies] 7 | volatile = { path = "../volatile" } 8 | std = { path = "../std" , optional = true} 9 | 10 | [features] 11 | qemu = [] 12 | custom_std = ["std"] -------------------------------------------------------------------------------- /os/pi/src/atags/atag.rs: -------------------------------------------------------------------------------- 1 | use atags::raw; 2 | use std::str; 3 | use std::ffi::CStr; 4 | use std::os::raw::c_char; 5 | 6 | pub use atags::raw::{Core, Mem}; 7 | 8 | /// An ATAG. 9 | #[derive(Debug, Copy, Clone)] 10 | pub enum Atag { 11 | Core(raw::Core), 12 | Mem(raw::Mem), 13 | Cmd(&'static str), 14 | Unknown(u32), 15 | None, 16 | } 17 | 18 | impl Atag { 19 | /// Returns `Some` if this is a `Core` ATAG. Otherwise returns `None`. 20 | pub fn core(self) -> Option { 21 | match self { 22 | Atag::Core(core) => Some(core), 23 | _ => None, 24 | } 25 | } 26 | 27 | /// Returns `Some` if this is a `Mem` ATAG. Otherwise returns `None`. 28 | pub fn mem(self) -> Option { 29 | match self { 30 | Atag::Mem(mem) => Some(mem), 31 | _ => None, 32 | } 33 | } 34 | 35 | /// Returns `Some` with the command line string if this is a `Cmd` ATAG. 36 | /// Otherwise returns `None`. 37 | pub fn cmd(self) -> Option<&'static str> { 38 | match self { 39 | Atag::Cmd(cmd) => Some(cmd), 40 | _ => None, 41 | } 42 | } 43 | } 44 | 45 | // FIXME: Implement `From`, `From`, and `From<&raw::Cmd>` 46 | // for `Atag`. These implementations should be used by the `From<&raw::Atag> for 47 | // Atag` implementation below. 48 | 49 | impl<'a> From<&'a raw::Atag> for Atag { 50 | fn from(atag: &raw::Atag) -> Atag { 51 | // FIXME: Complete the implementation below. 52 | 53 | unsafe { 54 | match (atag.tag, &atag.kind) { 55 | (raw::Atag::CORE, &raw::Kind { core }) => Atag::Core(core), 56 | (raw::Atag::MEM, &raw::Kind { mem }) => Atag::Mem(mem), 57 | (raw::Atag::CMDLINE, &raw::Kind { ref cmd }) => { 58 | let cmdline = CStr::from_ptr((&cmd.cmd as *const u8) as *const c_char); 59 | Atag::Cmd(str::from_utf8_unchecked(cmdline.to_bytes())) 60 | } 61 | (raw::Atag::NONE, _) => Atag::None, 62 | (id, _) => Atag::Unknown(id), 63 | } 64 | } 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /os/pi/src/atags/mod.rs: -------------------------------------------------------------------------------- 1 | mod raw; 2 | mod atag; 3 | 4 | pub use self::atag::*; 5 | 6 | /// The address at which the firmware loads the ATAGS. 7 | const ATAG_BASE: usize = 0x100; 8 | 9 | /// An iterator over the ATAGS on this system. 10 | pub struct Atags { 11 | ptr: &'static raw::Atag, 12 | } 13 | 14 | impl Atags { 15 | /// Returns an instance of `Atags`, an iterator over ATAGS on this system. 16 | pub fn get() -> Atags { 17 | Atags { 18 | ptr: unsafe { &*(ATAG_BASE as *const raw::Atag) } 19 | } 20 | } 21 | } 22 | 23 | impl Iterator for Atags { 24 | type Item = Atag; 25 | 26 | fn next(&mut self) -> Option { 27 | // Skip the first CORE ATAG 28 | match self.ptr.next() { 29 | Some(next_atag) => { 30 | self.ptr = next_atag; 31 | Some(next_atag.into()) 32 | } 33 | None => None 34 | } 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /os/pi/src/atags/raw.rs: -------------------------------------------------------------------------------- 1 | /// A raw `ATAG` as laid out in memory. 2 | #[repr(C)] 3 | pub struct Atag { 4 | pub dwords: u32, 5 | pub tag: u32, 6 | pub kind: Kind, 7 | } 8 | 9 | impl Atag { 10 | pub const NONE: u32 = 0x00000000; 11 | pub const CORE: u32 = 0x54410001; 12 | pub const MEM: u32 = 0x54410002; 13 | pub const VIDEOTEXT: u32 = 0x54410003; 14 | pub const RAMDISK: u32 = 0x54410004; 15 | pub const INITRD2: u32 = 0x54420005; 16 | pub const SERIAL: u32 = 0x54410006; 17 | pub const REVISION: u32 = 0x54410007; 18 | pub const VIDEOLFB: u32 = 0x54410008; 19 | pub const CMDLINE: u32 = 0x54410009; 20 | 21 | /// Returns the ATAG following `self`, if there is one. 22 | pub fn next(&self) -> Option<&Atag> { 23 | unsafe { 24 | let addr = (self as *const Atag) as *const u32; 25 | let next_atag = addr.offset(self.dwords as isize) as *mut Atag; 26 | 27 | match (*next_atag).tag { 28 | super::raw::Atag::NONE => None, 29 | _ => next_atag.as_ref(), 30 | } 31 | } 32 | } 33 | } 34 | 35 | /// The possible variant of an ATAG. 36 | #[repr(C)] 37 | pub union Kind { 38 | pub core: Core, 39 | pub mem: Mem, 40 | pub cmd: Cmd, 41 | } 42 | 43 | /// A `CORE` ATAG. 44 | #[repr(C)] 45 | #[derive(Debug, Copy, Clone)] 46 | pub struct Core { 47 | pub flags: u32, 48 | pub page_size: u32, 49 | pub root_dev: u32, 50 | } 51 | 52 | /// A `MEM` ATAG. 53 | #[repr(C)] 54 | #[derive(Debug, Copy, Clone)] 55 | pub struct Mem { 56 | pub size: u32, 57 | pub start: u32, 58 | } 59 | 60 | /// A `CMDLINE` ATAG. 61 | #[repr(C)] 62 | #[derive(Debug, Copy, Clone)] 63 | pub struct Cmd { 64 | /// The first byte of the command line string. 65 | pub cmd: u8, 66 | } 67 | -------------------------------------------------------------------------------- /os/pi/src/common.rs: -------------------------------------------------------------------------------- 1 | /// The address where I/O peripherals are mapped to. 2 | pub const IO_BASE: usize = 0x3F000000; 3 | 4 | /// Generates `pub enums` with no variants for each `ident` passed in. 5 | pub macro states($($name:ident),*) { 6 | $( 7 | /// A possible state. 8 | #[doc(hidden)] 9 | pub enum $name { } 10 | )* 11 | } 12 | -------------------------------------------------------------------------------- /os/pi/src/interrupt.rs: -------------------------------------------------------------------------------- 1 | use common::IO_BASE; 2 | use volatile::prelude::*; 3 | use volatile::{Volatile, ReadVolatile}; 4 | 5 | const INT_BASE: usize = IO_BASE + 0xB000 + 0x200; 6 | 7 | #[derive(Copy, Clone, PartialEq, Debug)] 8 | pub enum Interrupt { 9 | Timer1 = 1, 10 | Timer3 = 3, 11 | Usb = 9, 12 | Gpio0 = 49, 13 | Gpio1 = 50, 14 | Gpio2 = 51, 15 | Gpio3 = 52, 16 | Uart = 57, 17 | } 18 | 19 | #[repr(C)] 20 | #[allow(non_snake_case)] 21 | struct Registers { 22 | // FIXME: Fill me in. 23 | IRQBasicPending: ReadVolatile, 24 | IRQPending: [ReadVolatile; 2], 25 | FIQControl: Volatile, 26 | EnableIRQ: [Volatile; 2], 27 | EnableBasicIRQ: Volatile, 28 | DisableIRQ: [Volatile; 2], 29 | DisableBasicIRQ: Volatile, 30 | } 31 | 32 | /// An interrupt controller. Used to enable and disable interrupts as well as to 33 | /// check if an interrupt is pending. 34 | pub struct Controller { 35 | registers: &'static mut Registers 36 | } 37 | 38 | impl Controller { 39 | /// Returns a new handle to the interrupt controller. 40 | pub fn new() -> Controller { 41 | Controller { 42 | registers: unsafe { &mut *(INT_BASE as *mut Registers) }, 43 | } 44 | } 45 | 46 | /// Enables the interrupt `int`. 47 | pub fn enable(&mut self, int: Interrupt) { 48 | self.registers.EnableIRQ[int as usize / 32].write(1 << (int as usize) % 32); 49 | } 50 | 51 | /// Disables the interrupt `int`. 52 | pub fn disable(&mut self, int: Interrupt) { 53 | self.registers.DisableIRQ[int as usize / 32].write(1 << (int as usize) % 32); 54 | } 55 | 56 | /// Returns `true` if `int` is pending. Otherwise, returns `false`. 57 | pub fn is_pending(&self, int: Interrupt) -> bool { 58 | self.registers.IRQPending[int as usize / 32].has_mask(1 << (int as usize) % 32) 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /os/pi/src/lib.rs: -------------------------------------------------------------------------------- 1 | #![feature(core_intrinsics)] 2 | #![feature(const_fn)] 3 | #![feature(asm)] 4 | #![feature(decl_macro)] 5 | #![feature(never_type)] 6 | 7 | extern crate core; 8 | extern crate volatile; 9 | 10 | pub mod timer; 11 | pub mod uart; 12 | pub mod gpio; 13 | pub mod common; 14 | pub mod atags; 15 | pub mod interrupt; 16 | -------------------------------------------------------------------------------- /os/pi/src/timer/mod.rs: -------------------------------------------------------------------------------- 1 | #[cfg(feature = "qemu")] 2 | mod generic_timer; 3 | #[cfg(not(feature = "qemu"))] 4 | mod system_timer; 5 | 6 | #[cfg(feature = "qemu")] 7 | pub use self::generic_timer::*; 8 | #[cfg(not(feature = "qemu"))] 9 | pub use self::system_timer::*; -------------------------------------------------------------------------------- /os/pi/src/timer/system_timer.rs: -------------------------------------------------------------------------------- 1 | use common::IO_BASE; 2 | use volatile::prelude::*; 3 | use volatile::{Volatile, ReadVolatile}; 4 | 5 | /// The base address for the ARM system timer registers. 6 | const TIMER_REG_BASE: usize = IO_BASE + 0x3000; 7 | 8 | #[repr(C)] 9 | #[allow(non_snake_case)] 10 | struct Registers { 11 | CS: Volatile, 12 | CLO: ReadVolatile, 13 | CHI: ReadVolatile, 14 | COMPARE: [Volatile; 4] 15 | } 16 | 17 | /// The Raspberry Pi ARM system timer. 18 | pub struct Timer { 19 | registers: &'static mut Registers 20 | } 21 | 22 | impl Timer { 23 | /// Returns a new instance of `Timer`. 24 | pub fn new() -> Timer { 25 | Timer { 26 | registers: unsafe { &mut *(TIMER_REG_BASE as *mut Registers) }, 27 | } 28 | } 29 | 30 | /// Reads the system timer's counter and returns the 64-bit counter value. 31 | /// The returned value is the number of elapsed microseconds. 32 | pub fn read(&self) -> u64 { 33 | let low = self.registers.CLO.read(); 34 | let high = self.registers.CHI.read(); 35 | ((high as u64) << 32) | (low as u64) 36 | } 37 | 38 | /// Sets up a match in timer 1 to occur `us` microseconds from now. If 39 | /// interrupts for timer 1 are enabled and IRQs are unmasked, then a timer 40 | /// interrupt will be issued in `us` microseconds. 41 | pub fn tick_in(&mut self, us: u32) { 42 | let current_low = self.registers.CLO.read(); 43 | let compare = current_low.wrapping_add(us); 44 | self.registers.COMPARE[1].write(compare); // timer 1 45 | self.registers.CS.or_mask(0b0010); // clear timer 1 interrupt 46 | } 47 | } 48 | 49 | /// Returns the current time in microseconds. 50 | pub fn current_time() -> u64 { 51 | Timer::new().read() 52 | } 53 | 54 | /// Spins until `us` microseconds have passed. 55 | pub fn spin_sleep_us(us: u64) { 56 | let old = current_time(); 57 | loop { 58 | let new = current_time(); 59 | if old + us <= new { 60 | break; 61 | } 62 | } 63 | } 64 | 65 | /// Spins until `ms` milliseconds have passed. 66 | pub fn spin_sleep_ms(ms: u64) { 67 | spin_sleep_us(ms * 1000); 68 | } 69 | 70 | /// Sets up a match in timer 1 to occur `us` microseconds from now. If 71 | /// interrupts for timer 1 are enabled and IRQs are unmasked, then a timer 72 | /// interrupt will be issued in `us` microseconds. 73 | pub fn tick_in(us: u32) { 74 | Timer::new().tick_in(us) 75 | } 76 | -------------------------------------------------------------------------------- /os/std/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "std" 3 | version = "0.1.0" 4 | authors = ["Sergio Benitez "] 5 | 6 | [dependencies] -------------------------------------------------------------------------------- /os/std/src/collections/hash/mod.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2014 The Rust Project Developers. See the COPYRIGHT 2 | // file at the top-level directory of this distribution and at 3 | // http://rust-lang.org/COPYRIGHT. 4 | // 5 | // Licensed under the Apache License, Version 2.0 or the MIT license 7 | // , at your 8 | // option. This file may not be copied, modified, or distributed 9 | // except according to those terms. 10 | 11 | //! Unordered containers, implemented as hash-tables 12 | 13 | mod bench; 14 | mod table; 15 | pub mod map; 16 | pub mod set; 17 | 18 | trait Recover { 19 | type Key; 20 | 21 | fn get(&self, key: &Q) -> Option<&Self::Key>; 22 | fn take(&mut self, key: &Q) -> Option; 23 | fn replace(&mut self, key: Self::Key) -> Option; 24 | } 25 | -------------------------------------------------------------------------------- /os/std/src/io/lazy.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2015 The Rust Project Developers. See the COPYRIGHT 2 | // file at the top-level directory of this distribution and at 3 | // http://rust-lang.org/COPYRIGHT. 4 | // 5 | // Licensed under the Apache License, Version 2.0 or the MIT license 7 | // , at your 8 | // option. This file may not be copied, modified, or distributed 9 | // except according to those terms. 10 | 11 | use cell::Cell; 12 | use ptr; 13 | use sync::Arc; 14 | use sys_common; 15 | use sys_common::mutex::Mutex; 16 | 17 | pub struct Lazy { 18 | lock: Mutex, 19 | ptr: Cell<*mut Arc>, 20 | init: fn() -> Arc, 21 | } 22 | 23 | unsafe impl Sync for Lazy {} 24 | 25 | impl Lazy { 26 | pub const fn new(init: fn() -> Arc) -> Lazy { 27 | Lazy { 28 | lock: Mutex::new(), 29 | ptr: Cell::new(ptr::null_mut()), 30 | init, 31 | } 32 | } 33 | 34 | pub fn get(&'static self) -> Option> { 35 | unsafe { 36 | self.lock.lock(); 37 | let ptr = self.ptr.get(); 38 | let ret = if ptr.is_null() { 39 | Some(self.init()) 40 | } else if ptr as usize == 1 { 41 | None 42 | } else { 43 | Some((*ptr).clone()) 44 | }; 45 | self.lock.unlock(); 46 | return ret 47 | } 48 | } 49 | 50 | unsafe fn init(&'static self) -> Arc { 51 | // If we successfully register an at exit handler, then we cache the 52 | // `Arc` allocation in our own internal box (it will get deallocated by 53 | // the at exit handler). Otherwise we just return the freshly allocated 54 | // `Arc`. 55 | let registered = sys_common::at_exit(move || { 56 | self.lock.lock(); 57 | let ptr = self.ptr.get(); 58 | self.ptr.set(1 as *mut _); 59 | self.lock.unlock(); 60 | drop(Box::from_raw(ptr)) 61 | }); 62 | let ret = (self.init)(); 63 | if registered.is_ok() { 64 | self.ptr.set(Box::into_raw(Box::new(ret.clone()))); 65 | } 66 | ret 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /os/std/src/io/prelude.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2015 The Rust Project Developers. See the COPYRIGHT 2 | // file at the top-level directory of this distribution and at 3 | // http://rust-lang.org/COPYRIGHT. 4 | // 5 | // Licensed under the Apache License, Version 2.0 or the MIT license 7 | // , at your 8 | // option. This file may not be copied, modified, or distributed 9 | // except according to those terms. 10 | 11 | //! The I/O Prelude 12 | //! 13 | //! The purpose of this module is to alleviate imports of many common I/O traits 14 | //! by adding a glob import to the top of I/O heavy modules: 15 | //! 16 | //! ``` 17 | //! # #![allow(unused_imports)] 18 | //! use std::io::prelude::*; 19 | //! ``` 20 | 21 | #![stable(feature = "rust1", since = "1.0.0")] 22 | 23 | #[stable(feature = "rust1", since = "1.0.0")] 24 | pub use super::{Read, Write, BufRead, Seek}; 25 | -------------------------------------------------------------------------------- /os/std/src/net/test.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2015 The Rust Project Developers. See the COPYRIGHT 2 | // file at the top-level directory of this distribution and at 3 | // http://rust-lang.org/COPYRIGHT. 4 | // 5 | // Licensed under the Apache License, Version 2.0 or the MIT license 7 | // , at your 8 | // option. This file may not be copied, modified, or distributed 9 | // except according to those terms. 10 | 11 | #![allow(warnings)] // not used on emscripten 12 | 13 | use env; 14 | use net::{SocketAddr, SocketAddrV4, SocketAddrV6, Ipv4Addr, Ipv6Addr, ToSocketAddrs}; 15 | use sync::atomic::{AtomicUsize, Ordering}; 16 | 17 | static PORT: AtomicUsize = AtomicUsize::new(0); 18 | 19 | pub fn next_test_ip4() -> SocketAddr { 20 | let port = PORT.fetch_add(1, Ordering::SeqCst) as u16 + base_port(); 21 | SocketAddr::V4(SocketAddrV4::new(Ipv4Addr::new(127, 0, 0, 1), port)) 22 | } 23 | 24 | pub fn next_test_ip6() -> SocketAddr { 25 | let port = PORT.fetch_add(1, Ordering::SeqCst) as u16 + base_port(); 26 | SocketAddr::V6(SocketAddrV6::new(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1), 27 | port, 0, 0)) 28 | } 29 | 30 | pub fn sa4(a: Ipv4Addr, p: u16) -> SocketAddr { 31 | SocketAddr::V4(SocketAddrV4::new(a, p)) 32 | } 33 | 34 | pub fn sa6(a: Ipv6Addr, p: u16) -> SocketAddr { 35 | SocketAddr::V6(SocketAddrV6::new(a, p, 0, 0)) 36 | } 37 | 38 | pub fn tsa(a: A) -> Result, String> { 39 | match a.to_socket_addrs() { 40 | Ok(a) => Ok(a.collect()), 41 | Err(e) => Err(e.to_string()), 42 | } 43 | } 44 | 45 | // The bots run multiple builds at the same time, and these builds 46 | // all want to use ports. This function figures out which workspace 47 | // it is running in and assigns a port range based on it. 48 | fn base_port() -> u16 { 49 | let cwd = env::current_dir().unwrap(); 50 | let dirs = ["32-opt", "32-nopt", 51 | "musl-64-opt", "cross-opt", 52 | "64-opt", "64-nopt", "64-opt-vg", "64-debug-opt", 53 | "all-opt", "snap3", "dist"]; 54 | dirs.iter().enumerate().find(|&(_, dir)| { 55 | cwd.to_str().unwrap().contains(dir) 56 | }).map(|p| p.0).unwrap_or(0) as u16 * 1000 + 19600 57 | } 58 | -------------------------------------------------------------------------------- /os/std/src/os/mod.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2012-2015 The Rust Project Developers. See the COPYRIGHT 2 | // file at the top-level directory of this distribution and at 3 | // http://rust-lang.org/COPYRIGHT. 4 | // 5 | // Licensed under the Apache License, Version 2.0 or the MIT license 7 | // , at your 8 | // option. This file may not be copied, modified, or distributed 9 | // except according to those terms. 10 | 11 | //! OS-specific functionality. 12 | 13 | #![stable(feature = "os", since = "1.0.0")] 14 | #![allow(missing_docs, bad_style, missing_debug_implementations)] 15 | 16 | //- cfg_if! { 17 | //- if #[cfg(dox)] { 18 | //- 19 | //- // When documenting libstd we want to show unix/windows/linux modules as 20 | //- // these are the "main modules" that are used across platforms. This 21 | //- // should help show platform-specific functionality in a hopefully 22 | //- // cross-platform way in the documentation 23 | //- 24 | //- #[stable(feature = "rust1", since = "1.0.0")] 25 | //- pub use sys::unix_ext as unix; 26 | //- 27 | //- #[stable(feature = "rust1", since = "1.0.0")] 28 | //- pub use sys::windows_ext as windows; 29 | //- 30 | //- #[doc(cfg(target_os = "linux"))] 31 | //- pub mod linux; 32 | //- 33 | //- } else { 34 | //- 35 | //- // If we're not documenting libstd then we just expose everything as we 36 | //- // otherwise would. 37 | //- 38 | //- #[cfg(target_os = "android")] pub mod android; 39 | //- #[cfg(target_os = "bitrig")] pub mod bitrig; 40 | //- #[cfg(target_os = "dragonfly")] pub mod dragonfly; 41 | //- #[cfg(target_os = "freebsd")] pub mod freebsd; 42 | //- #[cfg(target_os = "haiku")] pub mod haiku; 43 | //- #[cfg(target_os = "ios")] pub mod ios; 44 | //- #[cfg(target_os = "macos")] pub mod macos; 45 | //- #[cfg(target_os = "netbsd")] pub mod netbsd; 46 | //- #[cfg(target_os = "openbsd")] pub mod openbsd; 47 | //- #[cfg(target_os = "solaris")] pub mod solaris; 48 | //- #[cfg(target_os = "emscripten")] pub mod emscripten; 49 | //- #[cfg(target_os = "fuchsia")] pub mod fuchsia; 50 | //- 51 | //- #[cfg(any(target_os = "redox", unix))] 52 | //- #[stable(feature = "rust1", since = "1.0.0")] 53 | //- pub use sys::ext as unix; 54 | //- 55 | //- #[cfg(windows)] 56 | //- #[stable(feature = "rust1", since = "1.0.0")] 57 | //- pub use sys::ext as windows; 58 | //- 59 | //- #[cfg(any(target_os = "linux", target_os = "l4re"))] 60 | //- pub mod linux; 61 | //- 62 | //- } 63 | //- } 64 | 65 | pub mod raw; 66 | -------------------------------------------------------------------------------- /os/std/src/prelude/v1.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2013 The Rust Project Developers. See the COPYRIGHT 2 | // file at the top-level directory of this distribution and at 3 | // http://rust-lang.org/COPYRIGHT. 4 | // 5 | // Licensed under the Apache License, Version 2.0 or the MIT license 7 | // , at your 8 | // option. This file may not be copied, modified, or distributed 9 | // except according to those terms. 10 | 11 | //! The first version of the prelude of The Rust Standard Library. 12 | //! 13 | //! See the [module-level documentation](../index.html) for more. 14 | 15 | #![stable(feature = "rust1", since = "1.0.0")] 16 | 17 | // Re-exported core operators 18 | #[stable(feature = "rust1", since = "1.0.0")] 19 | #[doc(no_inline)] pub use marker::{Copy, Send, Sized, Sync}; 20 | #[stable(feature = "rust1", since = "1.0.0")] 21 | #[doc(no_inline)] pub use ops::{Drop, Fn, FnMut, FnOnce}; 22 | 23 | // Re-exported functions 24 | #[stable(feature = "rust1", since = "1.0.0")] 25 | #[doc(no_inline)] pub use mem::drop; 26 | 27 | // Re-exported types and traits 28 | #[stable(feature = "rust1", since = "1.0.0")] 29 | #[doc(no_inline)] pub use boxed::Box; 30 | #[stable(feature = "rust1", since = "1.0.0")] 31 | #[doc(no_inline)] pub use borrow::ToOwned; 32 | #[stable(feature = "rust1", since = "1.0.0")] 33 | #[doc(no_inline)] pub use clone::Clone; 34 | #[stable(feature = "rust1", since = "1.0.0")] 35 | #[doc(no_inline)] pub use cmp::{PartialEq, PartialOrd, Eq, Ord}; 36 | #[stable(feature = "rust1", since = "1.0.0")] 37 | #[doc(no_inline)] pub use convert::{AsRef, AsMut, Into, From}; 38 | #[stable(feature = "rust1", since = "1.0.0")] 39 | #[doc(no_inline)] pub use default::Default; 40 | #[stable(feature = "rust1", since = "1.0.0")] 41 | #[doc(no_inline)] pub use iter::{Iterator, Extend, IntoIterator}; 42 | #[stable(feature = "rust1", since = "1.0.0")] 43 | #[doc(no_inline)] pub use iter::{DoubleEndedIterator, ExactSizeIterator}; 44 | #[stable(feature = "rust1", since = "1.0.0")] 45 | #[doc(no_inline)] pub use option::Option::{self, Some, None}; 46 | #[stable(feature = "rust1", since = "1.0.0")] 47 | #[doc(no_inline)] pub use result::Result::{self, Ok, Err}; 48 | #[stable(feature = "rust1", since = "1.0.0")] 49 | #[doc(no_inline)] pub use slice::SliceConcatExt; 50 | #[stable(feature = "rust1", since = "1.0.0")] 51 | #[doc(no_inline)] pub use string::{String, ToString}; 52 | #[stable(feature = "rust1", since = "1.0.0")] 53 | #[doc(no_inline)] pub use vec::Vec; 54 | -------------------------------------------------------------------------------- /os/std/src/sync/mpsc/blocking.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2014 The Rust Project Developers. See the COPYRIGHT 2 | // file at the top-level directory of this distribution and at 3 | // http://rust-lang.org/COPYRIGHT. 4 | // 5 | // Licensed under the Apache License, Version 2.0 or the MIT license 7 | // , at your 8 | // option. This file may not be copied, modified, or distributed 9 | // except according to those terms. 10 | 11 | //! Generic support for building blocking abstractions. 12 | 13 | use thread::{self, Thread}; 14 | use sync::atomic::{AtomicBool, Ordering}; 15 | use sync::Arc; 16 | use mem; 17 | use time::Instant; 18 | 19 | struct Inner { 20 | thread: Thread, 21 | woken: AtomicBool, 22 | } 23 | 24 | unsafe impl Send for Inner {} 25 | unsafe impl Sync for Inner {} 26 | 27 | #[derive(Clone)] 28 | pub struct SignalToken { 29 | inner: Arc, 30 | } 31 | 32 | pub struct WaitToken { 33 | inner: Arc, 34 | } 35 | 36 | impl !Send for WaitToken {} 37 | 38 | impl !Sync for WaitToken {} 39 | 40 | pub fn tokens() -> (WaitToken, SignalToken) { 41 | let inner = Arc::new(Inner { 42 | thread: thread::current(), 43 | woken: AtomicBool::new(false), 44 | }); 45 | let wait_token = WaitToken { 46 | inner: inner.clone(), 47 | }; 48 | let signal_token = SignalToken { 49 | inner, 50 | }; 51 | (wait_token, signal_token) 52 | } 53 | 54 | impl SignalToken { 55 | pub fn signal(&self) -> bool { 56 | let wake = !self.inner.woken.compare_and_swap(false, true, Ordering::SeqCst); 57 | if wake { 58 | self.inner.thread.unpark(); 59 | } 60 | wake 61 | } 62 | 63 | /// Convert to an unsafe usize value. Useful for storing in a pipe's state 64 | /// flag. 65 | #[inline] 66 | pub unsafe fn cast_to_usize(self) -> usize { 67 | mem::transmute(self.inner) 68 | } 69 | 70 | /// Convert from an unsafe usize value. Useful for retrieving a pipe's state 71 | /// flag. 72 | #[inline] 73 | pub unsafe fn cast_from_usize(signal_ptr: usize) -> SignalToken { 74 | SignalToken { inner: mem::transmute(signal_ptr) } 75 | } 76 | } 77 | 78 | impl WaitToken { 79 | pub fn wait(self) { 80 | while !self.inner.woken.load(Ordering::SeqCst) { 81 | thread::park() 82 | } 83 | } 84 | 85 | /// Returns true if we wake up normally, false otherwise. 86 | pub fn wait_max_until(self, end: Instant) -> bool { 87 | while !self.inner.woken.load(Ordering::SeqCst) { 88 | let now = Instant::now(); 89 | if now >= end { 90 | return false; 91 | } 92 | thread::park_timeout(end - now) 93 | } 94 | true 95 | } 96 | } 97 | -------------------------------------------------------------------------------- /os/std/src/sync/mpsc/cache_aligned.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2017 The Rust Project Developers. See the COPYRIGHT 2 | // file at the top-level directory of this distribution and at 3 | // http://rust-lang.org/COPYRIGHT. 4 | // 5 | // Licensed under the Apache License, Version 2.0 or the MIT license 7 | // , at your 8 | // option. This file may not be copied, modified, or distributed 9 | // except according to those terms. 10 | 11 | use ops::{Deref, DerefMut}; 12 | 13 | #[derive(Copy, Clone, Default, PartialEq, Eq, PartialOrd, Ord, Hash)] 14 | #[repr(align(64))] 15 | pub(super) struct Aligner; 16 | 17 | #[derive(Copy, Clone, Default, PartialEq, Eq, PartialOrd, Ord, Hash)] 18 | pub(super) struct CacheAligned(pub T, pub Aligner); 19 | 20 | impl Deref for CacheAligned { 21 | type Target = T; 22 | fn deref(&self) -> &Self::Target { 23 | &self.0 24 | } 25 | } 26 | 27 | impl DerefMut for CacheAligned { 28 | fn deref_mut(&mut self) -> &mut Self::Target { 29 | &mut self.0 30 | } 31 | } 32 | 33 | impl CacheAligned { 34 | pub(super) fn new(t: T) -> Self { 35 | CacheAligned(t, Aligner) 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /os/std/src/sys/redox/backtrace/mod.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2015 The Rust Project Developers. See the COPYRIGHT 2 | // file at the top-level directory of this distribution and at 3 | // http://rust-lang.org/COPYRIGHT. 4 | // 5 | // Licensed under the Apache License, Version 2.0 or the MIT license 7 | // , at your 8 | // option. This file may not be copied, modified, or distributed 9 | // except according to those terms. 10 | 11 | /// See sys/unix/backtrace/mod.rs for an explanation of the method used here. 12 | 13 | pub use self::tracing::unwind_backtrace; 14 | pub use self::printing::{foreach_symbol_fileline, resolve_symname}; 15 | 16 | // tracing impls: 17 | mod tracing; 18 | // symbol resolvers: 19 | mod printing; 20 | 21 | pub mod gnu { 22 | use io; 23 | use fs; 24 | use libc::c_char; 25 | use vec::Vec; 26 | use ffi::OsStr; 27 | use os::unix::ffi::OsStrExt; 28 | use io::Read; 29 | 30 | pub fn get_executable_filename() -> io::Result<(Vec, fs::File)> { 31 | let mut exefile = fs::File::open("sys:exe")?; 32 | let mut exename = Vec::new(); 33 | exefile.read_to_end(&mut exename)?; 34 | if exename.last() == Some(&b'\n') { 35 | exename.pop(); 36 | } 37 | let file = fs::File::open(OsStr::from_bytes(&exename))?; 38 | Ok((exename.into_iter().map(|c| c as c_char).collect(), file)) 39 | } 40 | } 41 | 42 | pub struct BacktraceContext; 43 | -------------------------------------------------------------------------------- /os/std/src/sys/redox/backtrace/printing.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2014-2015 The Rust Project Developers. See the COPYRIGHT 2 | // file at the top-level directory of this distribution and at 3 | // http://rust-lang.org/COPYRIGHT. 4 | // 5 | // Licensed under the Apache License, Version 2.0 or the MIT license 7 | // , at your 8 | // option. This file may not be copied, modified, or distributed 9 | // except according to those terms. 10 | 11 | pub use sys_common::gnu::libbacktrace::{foreach_symbol_fileline, resolve_symname}; 12 | -------------------------------------------------------------------------------- /os/std/src/sys/redox/cmath.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2017 The Rust Project Developers. See the COPYRIGHT 2 | // file at the top-level directory of this distribution and at 3 | // http://rust-lang.org/COPYRIGHT. 4 | // 5 | // Licensed under the Apache License, Version 2.0 or the MIT license 7 | // , at your 8 | // option. This file may not be copied, modified, or distributed 9 | // except according to those terms. 10 | 11 | #![cfg(not(test))] 12 | 13 | use libc::{c_float, c_double}; 14 | 15 | #[link_name = "m"] 16 | extern { 17 | pub fn acos(n: c_double) -> c_double; 18 | pub fn acosf(n: c_float) -> c_float; 19 | pub fn asin(n: c_double) -> c_double; 20 | pub fn asinf(n: c_float) -> c_float; 21 | pub fn atan(n: c_double) -> c_double; 22 | pub fn atan2(a: c_double, b: c_double) -> c_double; 23 | pub fn atan2f(a: c_float, b: c_float) -> c_float; 24 | pub fn atanf(n: c_float) -> c_float; 25 | pub fn cbrt(n: c_double) -> c_double; 26 | pub fn cbrtf(n: c_float) -> c_float; 27 | pub fn cosh(n: c_double) -> c_double; 28 | pub fn coshf(n: c_float) -> c_float; 29 | pub fn expm1(n: c_double) -> c_double; 30 | pub fn expm1f(n: c_float) -> c_float; 31 | pub fn fdim(a: c_double, b: c_double) -> c_double; 32 | pub fn fdimf(a: c_float, b: c_float) -> c_float; 33 | pub fn hypot(x: c_double, y: c_double) -> c_double; 34 | pub fn hypotf(x: c_float, y: c_float) -> c_float; 35 | pub fn log1p(n: c_double) -> c_double; 36 | pub fn log1pf(n: c_float) -> c_float; 37 | pub fn sinh(n: c_double) -> c_double; 38 | pub fn sinhf(n: c_float) -> c_float; 39 | pub fn tan(n: c_double) -> c_double; 40 | pub fn tanf(n: c_float) -> c_float; 41 | pub fn tanh(n: c_double) -> c_double; 42 | pub fn tanhf(n: c_float) -> c_float; 43 | } 44 | -------------------------------------------------------------------------------- /os/std/src/sys/redox/env.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2016 The Rust Project Developers. See the COPYRIGHT 2 | // file at the top-level directory of this distribution and at 3 | // http://rust-lang.org/COPYRIGHT. 4 | // 5 | // Licensed under the Apache License, Version 2.0 or the MIT license 7 | // , at your 8 | // option. This file may not be copied, modified, or distributed 9 | // except according to those terms. 10 | 11 | pub mod os { 12 | pub const FAMILY: &'static str = "redox"; 13 | pub const OS: &'static str = "redox"; 14 | pub const DLL_PREFIX: &'static str = "lib"; 15 | pub const DLL_SUFFIX: &'static str = ".so"; 16 | pub const DLL_EXTENSION: &'static str = "so"; 17 | pub const EXE_SUFFIX: &'static str = ""; 18 | pub const EXE_EXTENSION: &'static str = ""; 19 | } 20 | -------------------------------------------------------------------------------- /os/std/src/sys/redox/ext/ffi.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2015 The Rust Project Developers. See the COPYRIGHT 2 | // file at the top-level directory of this distribution and at 3 | // http://rust-lang.org/COPYRIGHT. 4 | // 5 | // Licensed under the Apache License, Version 2.0 or the MIT license 7 | // , at your 8 | // option. This file may not be copied, modified, or distributed 9 | // except according to those terms. 10 | 11 | //! Unix-specific extension to the primitives in the `std::ffi` module 12 | 13 | #![stable(feature = "rust1", since = "1.0.0")] 14 | 15 | use ffi::{OsStr, OsString}; 16 | use mem; 17 | use sys::os_str::Buf; 18 | use sys_common::{FromInner, IntoInner, AsInner}; 19 | 20 | /// Unix-specific extensions to `OsString`. 21 | #[stable(feature = "rust1", since = "1.0.0")] 22 | pub trait OsStringExt { 23 | /// Creates an `OsString` from a byte vector. 24 | #[stable(feature = "rust1", since = "1.0.0")] 25 | fn from_vec(vec: Vec) -> Self; 26 | 27 | /// Yields the underlying byte vector of this `OsString`. 28 | #[stable(feature = "rust1", since = "1.0.0")] 29 | fn into_vec(self) -> Vec; 30 | } 31 | 32 | #[stable(feature = "rust1", since = "1.0.0")] 33 | impl OsStringExt for OsString { 34 | fn from_vec(vec: Vec) -> OsString { 35 | FromInner::from_inner(Buf { inner: vec }) 36 | } 37 | fn into_vec(self) -> Vec { 38 | self.into_inner().inner 39 | } 40 | } 41 | 42 | /// Unix-specific extensions to `OsStr`. 43 | #[stable(feature = "rust1", since = "1.0.0")] 44 | pub trait OsStrExt { 45 | #[stable(feature = "rust1", since = "1.0.0")] 46 | fn from_bytes(slice: &[u8]) -> &Self; 47 | 48 | /// Gets the underlying byte view of the `OsStr` slice. 49 | #[stable(feature = "rust1", since = "1.0.0")] 50 | fn as_bytes(&self) -> &[u8]; 51 | } 52 | 53 | #[stable(feature = "rust1", since = "1.0.0")] 54 | impl OsStrExt for OsStr { 55 | fn from_bytes(slice: &[u8]) -> &OsStr { 56 | unsafe { mem::transmute(slice) } 57 | } 58 | fn as_bytes(&self) -> &[u8] { 59 | &self.as_inner().inner 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /os/std/src/sys/redox/ext/mod.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2016 The Rust Project Developers. See the COPYRIGHT 2 | // file at the top-level directory of this distribution and at 3 | // http://rust-lang.org/COPYRIGHT. 4 | // 5 | // Licensed under the Apache License, Version 2.0 or the MIT license 7 | // , at your 8 | // option. This file may not be copied, modified, or distributed 9 | // except according to those terms. 10 | 11 | //! Experimental extensions to `std` for Unix platforms. 12 | //! 13 | //! For now, this module is limited to extracting file descriptors, 14 | //! but its functionality will grow over time. 15 | //! 16 | //! # Examples 17 | //! 18 | //! ```no_run 19 | //! use std::fs::File; 20 | //! use std::os::unix::prelude::*; 21 | //! 22 | //! fn main() { 23 | //! let f = File::create("foo.txt").unwrap(); 24 | //! let fd = f.as_raw_fd(); 25 | //! 26 | //! // use fd with native unix bindings 27 | //! } 28 | //! ``` 29 | 30 | #![stable(feature = "rust1", since = "1.0.0")] 31 | #![doc(cfg(target_os = "redox"))] 32 | 33 | pub mod ffi; 34 | pub mod fs; 35 | pub mod io; 36 | pub mod process; 37 | pub mod thread; 38 | 39 | /// A prelude for conveniently writing platform-specific code. 40 | /// 41 | /// Includes all extension traits, and some important type definitions. 42 | #[stable(feature = "rust1", since = "1.0.0")] 43 | pub mod prelude { 44 | #[doc(no_inline)] #[stable(feature = "rust1", since = "1.0.0")] 45 | pub use super::io::{RawFd, AsRawFd, FromRawFd, IntoRawFd}; 46 | #[doc(no_inline)] #[stable(feature = "rust1", since = "1.0.0")] 47 | pub use super::ffi::{OsStrExt, OsStringExt}; 48 | #[doc(no_inline)] #[stable(feature = "rust1", since = "1.0.0")] 49 | pub use super::fs::{FileTypeExt, PermissionsExt, OpenOptionsExt, MetadataExt}; 50 | #[doc(no_inline)] #[stable(feature = "rust1", since = "1.0.0")] 51 | pub use super::thread::JoinHandleExt; 52 | #[doc(no_inline)] #[stable(feature = "rust1", since = "1.0.0")] 53 | pub use super::process::{CommandExt, ExitStatusExt}; 54 | } 55 | -------------------------------------------------------------------------------- /os/std/src/sys/redox/ext/thread.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2015 The Rust Project Developers. See the COPYRIGHT 2 | // file at the top-level directory of this distribution and at 3 | // http://rust-lang.org/COPYRIGHT. 4 | // 5 | // Licensed under the Apache License, Version 2.0 or the MIT license 7 | // , at your 8 | // option. This file may not be copied, modified, or distributed 9 | // except according to those terms. 10 | 11 | //! Unix-specific extensions to primitives in the `std::thread` module. 12 | 13 | #![stable(feature = "thread_extensions", since = "1.9.0")] 14 | 15 | use sys_common::{AsInner, IntoInner}; 16 | use thread::JoinHandle; 17 | 18 | #[stable(feature = "thread_extensions", since = "1.9.0")] 19 | #[allow(deprecated)] 20 | pub type RawPthread = usize; 21 | 22 | /// Unix-specific extensions to `std::thread::JoinHandle` 23 | #[stable(feature = "thread_extensions", since = "1.9.0")] 24 | pub trait JoinHandleExt { 25 | /// Extracts the raw pthread_t without taking ownership 26 | #[stable(feature = "thread_extensions", since = "1.9.0")] 27 | fn as_pthread_t(&self) -> RawPthread; 28 | 29 | /// Consumes the thread, returning the raw pthread_t 30 | /// 31 | /// This function **transfers ownership** of the underlying pthread_t to 32 | /// the caller. Callers are then the unique owners of the pthread_t and 33 | /// must either detach or join the pthread_t once it's no longer needed. 34 | #[stable(feature = "thread_extensions", since = "1.9.0")] 35 | fn into_pthread_t(self) -> RawPthread; 36 | } 37 | 38 | #[stable(feature = "thread_extensions", since = "1.9.0")] 39 | impl JoinHandleExt for JoinHandle { 40 | fn as_pthread_t(&self) -> RawPthread { 41 | self.as_inner().id() as RawPthread 42 | } 43 | 44 | fn into_pthread_t(self) -> RawPthread { 45 | self.into_inner().into_id() as RawPthread 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /os/std/src/sys/redox/memchr.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2015 The Rust Project Developers. See the COPYRIGHT 2 | // file at the top-level directory of this distribution and at 3 | // http://rust-lang.org/COPYRIGHT. 4 | // 5 | // Licensed under the Apache License, Version 2.0 or the MIT license 7 | // , at your 8 | // option. This file may not be copied, modified, or distributed 9 | // except according to those terms. 10 | // 11 | // Original implementation taken from rust-memchr 12 | // Copyright 2015 Andrew Gallant, bluss and Nicolas Koch 13 | 14 | pub use core::slice::memchr::{memchr, memrchr}; 15 | -------------------------------------------------------------------------------- /os/std/src/sys/redox/mod.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2016 The Rust Project Developers. See the COPYRIGHT 2 | // file at the top-level directory of this distribution and at 3 | // http://rust-lang.org/COPYRIGHT. 4 | // 5 | // Licensed under the Apache License, Version 2.0 or the MIT license 7 | // , at your 8 | // option. This file may not be copied, modified, or distributed 9 | // except according to those terms. 10 | 11 | #![allow(dead_code, missing_docs, bad_style)] 12 | 13 | use io::{self, ErrorKind}; 14 | 15 | pub use libc::strlen; 16 | pub use self::rand::hashmap_random_keys; 17 | 18 | pub mod args; 19 | #[cfg(feature = "backtrace")] 20 | pub mod backtrace; 21 | pub mod cmath; 22 | pub mod condvar; 23 | pub mod env; 24 | pub mod ext; 25 | pub mod fast_thread_local; 26 | pub mod fd; 27 | pub mod fs; 28 | pub mod memchr; 29 | pub mod mutex; 30 | pub mod net; 31 | pub mod os; 32 | pub mod os_str; 33 | pub mod path; 34 | pub mod pipe; 35 | pub mod process; 36 | pub mod rand; 37 | pub mod rwlock; 38 | pub mod stack_overflow; 39 | pub mod stdio; 40 | pub mod syscall; 41 | pub mod thread; 42 | pub mod thread_local; 43 | pub mod time; 44 | 45 | #[cfg(not(test))] 46 | pub fn init() {} 47 | 48 | pub fn decode_error_kind(errno: i32) -> ErrorKind { 49 | match errno { 50 | syscall::ECONNREFUSED => ErrorKind::ConnectionRefused, 51 | syscall::ECONNRESET => ErrorKind::ConnectionReset, 52 | syscall::EPERM | syscall::EACCES => ErrorKind::PermissionDenied, 53 | syscall::EPIPE => ErrorKind::BrokenPipe, 54 | syscall::ENOTCONN => ErrorKind::NotConnected, 55 | syscall::ECONNABORTED => ErrorKind::ConnectionAborted, 56 | syscall::EADDRNOTAVAIL => ErrorKind::AddrNotAvailable, 57 | syscall::EADDRINUSE => ErrorKind::AddrInUse, 58 | syscall::ENOENT => ErrorKind::NotFound, 59 | syscall::EINTR => ErrorKind::Interrupted, 60 | syscall::EINVAL => ErrorKind::InvalidInput, 61 | syscall::ETIMEDOUT => ErrorKind::TimedOut, 62 | syscall::EEXIST => ErrorKind::AlreadyExists, 63 | 64 | // These two constants can have the same value on some systems, 65 | // but different values on others, so we can't use a match 66 | // clause 67 | x if x == syscall::EAGAIN || x == syscall::EWOULDBLOCK => 68 | ErrorKind::WouldBlock, 69 | 70 | _ => ErrorKind::Other, 71 | } 72 | } 73 | 74 | pub fn cvt(result: Result) -> io::Result { 75 | result.map_err(|err| io::Error::from_raw_os_error(err.errno)) 76 | } 77 | 78 | /// On Redox, use an illegal instruction to abort 79 | pub unsafe fn abort_internal() -> ! { 80 | ::core::intrinsics::abort(); 81 | } 82 | -------------------------------------------------------------------------------- /os/std/src/sys/redox/net/dns/answer.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2016 The Rust Project Developers. See the COPYRIGHT 2 | // file at the top-level directory of this distribution and at 3 | // http://rust-lang.org/COPYRIGHT. 4 | // 5 | // Licensed under the Apache License, Version 2.0 or the MIT license 7 | // , at your 8 | // option. This file may not be copied, modified, or distributed 9 | // except according to those terms. 10 | 11 | use string::String; 12 | use vec::Vec; 13 | 14 | #[derive(Clone, Debug)] 15 | pub struct DnsAnswer { 16 | pub name: String, 17 | pub a_type: u16, 18 | pub a_class: u16, 19 | pub ttl_a: u16, 20 | pub ttl_b: u16, 21 | pub data: Vec 22 | } 23 | -------------------------------------------------------------------------------- /os/std/src/sys/redox/net/dns/query.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2016 The Rust Project Developers. See the COPYRIGHT 2 | // file at the top-level directory of this distribution and at 3 | // http://rust-lang.org/COPYRIGHT. 4 | // 5 | // Licensed under the Apache License, Version 2.0 or the MIT license 7 | // , at your 8 | // option. This file may not be copied, modified, or distributed 9 | // except according to those terms. 10 | 11 | use string::String; 12 | 13 | #[derive(Clone, Debug)] 14 | pub struct DnsQuery { 15 | pub name: String, 16 | pub q_type: u16, 17 | pub q_class: u16 18 | } 19 | -------------------------------------------------------------------------------- /os/std/src/sys/redox/net/netc.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2016 The Rust Project Developers. See the COPYRIGHT 2 | // file at the top-level directory of this distribution and at 3 | // http://rust-lang.org/COPYRIGHT. 4 | // 5 | // Licensed under the Apache License, Version 2.0 or the MIT license 7 | // , at your 8 | // option. This file may not be copied, modified, or distributed 9 | // except according to those terms. 10 | 11 | pub type in_addr_t = u32; 12 | pub type in_port_t = u16; 13 | 14 | pub type socklen_t = u32; 15 | pub type sa_family_t = u16; 16 | 17 | pub const AF_INET: sa_family_t = 2; 18 | pub const AF_INET6: sa_family_t = 23; 19 | 20 | #[derive(Copy, Clone)] 21 | #[repr(C)] 22 | pub struct in_addr { 23 | pub s_addr: in_addr_t, 24 | } 25 | 26 | #[derive(Copy, Clone)] 27 | #[repr(C)] 28 | pub struct in6_addr { 29 | pub s6_addr: [u8; 16], 30 | __align: [u32; 0], 31 | } 32 | 33 | #[derive(Copy, Clone)] 34 | #[repr(C)] 35 | pub struct sockaddr { 36 | pub sa_family: sa_family_t, 37 | pub sa_data: [u8; 14], 38 | } 39 | 40 | #[derive(Copy, Clone)] 41 | #[repr(C)] 42 | pub struct sockaddr_in { 43 | pub sin_family: sa_family_t, 44 | pub sin_port: in_port_t, 45 | pub sin_addr: in_addr, 46 | pub sin_zero: [u8; 8], 47 | } 48 | 49 | #[derive(Copy, Clone)] 50 | #[repr(C)] 51 | pub struct sockaddr_in6 { 52 | pub sin6_family: sa_family_t, 53 | pub sin6_port: in_port_t, 54 | pub sin6_flowinfo: u32, 55 | pub sin6_addr: in6_addr, 56 | pub sin6_scope_id: u32, 57 | } 58 | -------------------------------------------------------------------------------- /os/std/src/sys/redox/path.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2016 The Rust Project Developers. See the COPYRIGHT 2 | // file at the top-level directory of this distribution and at 3 | // http://rust-lang.org/COPYRIGHT. 4 | // 5 | // Licensed under the Apache License, Version 2.0 or the MIT license 7 | // , at your 8 | // option. This file may not be copied, modified, or distributed 9 | // except according to those terms. 10 | 11 | use ffi::OsStr; 12 | use path::Prefix; 13 | 14 | #[inline] 15 | pub fn is_sep_byte(b: u8) -> bool { 16 | b == b'/' 17 | } 18 | 19 | #[inline] 20 | pub fn is_verbatim_sep(b: u8) -> bool { 21 | b == b'/' 22 | } 23 | 24 | pub fn parse_prefix(path: &OsStr) -> Option { 25 | if let Some(path_str) = path.to_str() { 26 | if let Some(_i) = path_str.find(':') { 27 | // FIXME: Redox specific prefix 28 | // Some(Prefix::Verbatim(OsStr::new(&path_str[..i]))) 29 | None 30 | } else { 31 | None 32 | } 33 | } else { 34 | None 35 | } 36 | } 37 | 38 | pub const MAIN_SEP_STR: &'static str = "/"; 39 | pub const MAIN_SEP: char = '/'; 40 | -------------------------------------------------------------------------------- /os/std/src/sys/redox/rand.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2016 The Rust Project Developers. See the COPYRIGHT 2 | // file at the top-level directory of this distribution and at 3 | // http://rust-lang.org/COPYRIGHT. 4 | // 5 | // Licensed under the Apache License, Version 2.0 or the MIT license 7 | // , at your 8 | // option. This file may not be copied, modified, or distributed 9 | // except according to those terms. 10 | 11 | pub fn hashmap_random_keys() -> (u64, u64) { 12 | (0, 0) 13 | } 14 | -------------------------------------------------------------------------------- /os/std/src/sys/redox/rwlock.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2016 The Rust Project Developers. See the COPYRIGHT 2 | // file at the top-level directory of this distribution and at 3 | // http://rust-lang.org/COPYRIGHT. 4 | // 5 | // Licensed under the Apache License, Version 2.0 or the MIT license 7 | // , at your 8 | // option. This file may not be copied, modified, or distributed 9 | // except according to those terms. 10 | 11 | use super::mutex::Mutex; 12 | 13 | pub struct RWLock { 14 | mutex: Mutex 15 | } 16 | 17 | unsafe impl Send for RWLock {} 18 | unsafe impl Sync for RWLock {} 19 | 20 | impl RWLock { 21 | pub const fn new() -> RWLock { 22 | RWLock { 23 | mutex: Mutex::new() 24 | } 25 | } 26 | 27 | #[inline] 28 | pub unsafe fn read(&self) { 29 | self.mutex.lock(); 30 | } 31 | 32 | #[inline] 33 | pub unsafe fn try_read(&self) -> bool { 34 | self.mutex.try_lock() 35 | } 36 | 37 | #[inline] 38 | pub unsafe fn write(&self) { 39 | self.mutex.lock(); 40 | } 41 | 42 | #[inline] 43 | pub unsafe fn try_write(&self) -> bool { 44 | self.mutex.try_lock() 45 | } 46 | 47 | #[inline] 48 | pub unsafe fn read_unlock(&self) { 49 | self.mutex.unlock(); 50 | } 51 | 52 | #[inline] 53 | pub unsafe fn write_unlock(&self) { 54 | self.mutex.unlock(); 55 | } 56 | 57 | #[inline] 58 | pub unsafe fn destroy(&self) { 59 | self.mutex.destroy(); 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /os/std/src/sys/redox/stack_overflow.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2016 The Rust Project Developers. See the COPYRIGHT 2 | // file at the top-level directory of this distribution and at 3 | // http://rust-lang.org/COPYRIGHT. 4 | // 5 | // Licensed under the Apache License, Version 2.0 or the MIT license 7 | // , at your 8 | // option. This file may not be copied, modified, or distributed 9 | // except according to those terms. 10 | 11 | #![cfg_attr(test, allow(dead_code))] 12 | 13 | pub struct Handler; 14 | 15 | impl Handler { 16 | pub unsafe fn new() -> Handler { 17 | Handler 18 | } 19 | } 20 | 21 | pub unsafe fn init() { 22 | 23 | } 24 | 25 | pub unsafe fn cleanup() { 26 | 27 | } 28 | -------------------------------------------------------------------------------- /os/std/src/sys/redox/stdio.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2016 The Rust Project Developers. See the COPYRIGHT 2 | // file at the top-level directory of this distribution and at 3 | // http://rust-lang.org/COPYRIGHT. 4 | // 5 | // Licensed under the Apache License, Version 2.0 or the MIT license 7 | // , at your 8 | // option. This file may not be copied, modified, or distributed 9 | // except according to those terms. 10 | 11 | use io; 12 | use sys::{cvt, syscall}; 13 | use sys::fd::FileDesc; 14 | 15 | pub struct Stdin(()); 16 | pub struct Stdout(()); 17 | pub struct Stderr(()); 18 | 19 | impl Stdin { 20 | pub fn new() -> io::Result { Ok(Stdin(())) } 21 | 22 | pub fn read(&self, data: &mut [u8]) -> io::Result { 23 | let fd = FileDesc::new(0); 24 | let ret = fd.read(data); 25 | fd.into_raw(); 26 | ret 27 | } 28 | } 29 | 30 | impl Stdout { 31 | pub fn new() -> io::Result { Ok(Stdout(())) } 32 | 33 | pub fn write(&self, data: &[u8]) -> io::Result { 34 | let fd = FileDesc::new(1); 35 | let ret = fd.write(data); 36 | fd.into_raw(); 37 | ret 38 | } 39 | 40 | pub fn flush(&self) -> io::Result<()> { 41 | cvt(syscall::fsync(1)).and(Ok(())) 42 | } 43 | } 44 | 45 | impl Stderr { 46 | pub fn new() -> io::Result { Ok(Stderr(())) } 47 | 48 | pub fn write(&self, data: &[u8]) -> io::Result { 49 | let fd = FileDesc::new(2); 50 | let ret = fd.write(data); 51 | fd.into_raw(); 52 | ret 53 | } 54 | 55 | pub fn flush(&self) -> io::Result<()> { 56 | cvt(syscall::fsync(2)).and(Ok(())) 57 | } 58 | } 59 | 60 | // FIXME: right now this raw stderr handle is used in a few places because 61 | // std::io::stderr_raw isn't exposed, but once that's exposed this impl 62 | // should go away 63 | impl io::Write for Stderr { 64 | fn write(&mut self, data: &[u8]) -> io::Result { 65 | Stderr::write(self, data) 66 | } 67 | 68 | fn flush(&mut self) -> io::Result<()> { 69 | Stderr::flush(self) 70 | } 71 | } 72 | 73 | pub fn is_ebadf(err: &io::Error) -> bool { 74 | err.raw_os_error() == Some(::sys::syscall::EBADF as i32) 75 | } 76 | 77 | pub const STDIN_BUF_SIZE: usize = ::sys_common::io::DEFAULT_BUF_SIZE; 78 | -------------------------------------------------------------------------------- /os/std/src/sys/redox/syscall/arch/arm.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2016 The Rust Project Developers. See the COPYRIGHT 2 | // file at the top-level directory of this distribution and at 3 | // http://rust-lang.org/COPYRIGHT. 4 | // 5 | // Licensed under the Apache License, Version 2.0 or the MIT license 7 | // , at your 8 | // option. This file may not be copied, modified, or distributed 9 | // except according to those terms. 10 | 11 | use super::error::{Error, Result}; 12 | 13 | pub unsafe fn syscall0(mut a: usize) -> Result { 14 | asm!("swi $$0" 15 | : "={r0}"(a) 16 | : "{r7}"(a) 17 | : "memory" 18 | : "volatile"); 19 | 20 | Error::demux(a) 21 | } 22 | 23 | pub unsafe fn syscall1(mut a: usize, b: usize) -> Result { 24 | asm!("swi $$0" 25 | : "={r0}"(a) 26 | : "{r7}"(a), "{r0}"(b) 27 | : "memory" 28 | : "volatile"); 29 | 30 | Error::demux(a) 31 | } 32 | 33 | // Clobbers all registers - special for clone 34 | pub unsafe fn syscall1_clobber(mut a: usize, b: usize) -> Result { 35 | asm!("swi $$0" 36 | : "={r0}"(a) 37 | : "{r7}"(a), "{r0}"(b) 38 | : "memory", "r0", "r1", "r2", "r3", "r4" 39 | : "volatile"); 40 | 41 | Error::demux(a) 42 | } 43 | 44 | pub unsafe fn syscall2(mut a: usize, b: usize, c: usize) -> Result { 45 | asm!("swi $$0" 46 | : "={r0}"(a) 47 | : "{r7}"(a), "{r0}"(b), "{r1}"(c) 48 | : "memory" 49 | : "volatile"); 50 | 51 | Error::demux(a) 52 | } 53 | 54 | pub unsafe fn syscall3(mut a: usize, b: usize, c: usize, d: usize) -> Result { 55 | asm!("swi $$0" 56 | : "={r0}"(a) 57 | : "{r7}"(a), "{r0}"(b), "{r1}"(c), "{r2}"(d) 58 | : "memory" 59 | : "volatile"); 60 | 61 | Error::demux(a) 62 | } 63 | 64 | pub unsafe fn syscall4(mut a: usize, b: usize, c: usize, d: usize, e: usize) -> Result { 65 | asm!("swi $$0" 66 | : "={r0}"(a) 67 | : "{r7}"(a), "{r0}"(b), "{r1}"(c), "{r2}"(d), "{r3}"(e) 68 | : "memory" 69 | : "volatile"); 70 | 71 | Error::demux(a) 72 | } 73 | 74 | pub unsafe fn syscall5(mut a: usize, b: usize, c: usize, d: usize, e: usize, f: usize) 75 | -> Result { 76 | asm!("swi $$0" 77 | : "={r0}"(a) 78 | : "{r7}"(a), "{r0}"(b), "{r1}"(c), "{r2}"(d), "{r3}"(e), "{r4}"(f) 79 | : "memory" 80 | : "volatile"); 81 | 82 | Error::demux(a) 83 | } 84 | -------------------------------------------------------------------------------- /os/std/src/sys/redox/syscall/arch/x86.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2016 The Rust Project Developers. See the COPYRIGHT 2 | // file at the top-level directory of this distribution and at 3 | // http://rust-lang.org/COPYRIGHT. 4 | // 5 | // Licensed under the Apache License, Version 2.0 or the MIT license 7 | // , at your 8 | // option. This file may not be copied, modified, or distributed 9 | // except according to those terms. 10 | 11 | use super::error::{Error, Result}; 12 | 13 | pub unsafe fn syscall0(mut a: usize) -> Result { 14 | asm!("int 0x80" 15 | : "={eax}"(a) 16 | : "{eax}"(a) 17 | : "memory" 18 | : "intel", "volatile"); 19 | 20 | Error::demux(a) 21 | } 22 | 23 | pub unsafe fn syscall1(mut a: usize, b: usize) -> Result { 24 | asm!("int 0x80" 25 | : "={eax}"(a) 26 | : "{eax}"(a), "{ebx}"(b) 27 | : "memory" 28 | : "intel", "volatile"); 29 | 30 | Error::demux(a) 31 | } 32 | 33 | // Clobbers all registers - special for clone 34 | pub unsafe fn syscall1_clobber(mut a: usize, b: usize) -> Result { 35 | asm!("int 0x80" 36 | : "={eax}"(a) 37 | : "{eax}"(a), "{ebx}"(b) 38 | : "memory", "ebx", "ecx", "edx", "esi", "edi" 39 | : "intel", "volatile"); 40 | 41 | Error::demux(a) 42 | } 43 | 44 | pub unsafe fn syscall2(mut a: usize, b: usize, c: usize) -> Result { 45 | asm!("int 0x80" 46 | : "={eax}"(a) 47 | : "{eax}"(a), "{ebx}"(b), "{ecx}"(c) 48 | : "memory" 49 | : "intel", "volatile"); 50 | 51 | Error::demux(a) 52 | } 53 | 54 | pub unsafe fn syscall3(mut a: usize, b: usize, c: usize, d: usize) -> Result { 55 | asm!("int 0x80" 56 | : "={eax}"(a) 57 | : "{eax}"(a), "{ebx}"(b), "{ecx}"(c), "{edx}"(d) 58 | : "memory" 59 | : "intel", "volatile"); 60 | 61 | Error::demux(a) 62 | } 63 | 64 | pub unsafe fn syscall4(mut a: usize, b: usize, c: usize, d: usize, e: usize) -> Result { 65 | asm!("int 0x80" 66 | : "={eax}"(a) 67 | : "{eax}"(a), "{ebx}"(b), "{ecx}"(c), "{edx}"(d), "{esi}"(e) 68 | : "memory" 69 | : "intel", "volatile"); 70 | 71 | Error::demux(a) 72 | } 73 | 74 | pub unsafe fn syscall5(mut a: usize, b: usize, c: usize, d: usize, e: usize, f: usize) 75 | -> Result { 76 | asm!("int 0x80" 77 | : "={eax}"(a) 78 | : "{eax}"(a), "{ebx}"(b), "{ecx}"(c), "{edx}"(d), "{esi}"(e), "{edi}"(f) 79 | : "memory" 80 | : "intel", "volatile"); 81 | 82 | Error::demux(a) 83 | } 84 | -------------------------------------------------------------------------------- /os/std/src/sys/redox/syscall/arch/x86_64.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2016 The Rust Project Developers. See the COPYRIGHT 2 | // file at the top-level directory of this distribution and at 3 | // http://rust-lang.org/COPYRIGHT. 4 | // 5 | // Licensed under the Apache License, Version 2.0 or the MIT license 7 | // , at your 8 | // option. This file may not be copied, modified, or distributed 9 | // except according to those terms. 10 | 11 | use super::error::{Error, Result}; 12 | 13 | pub unsafe fn syscall0(mut a: usize) -> Result { 14 | asm!("int 0x80" 15 | : "={rax}"(a) 16 | : "{rax}"(a) 17 | : "memory" 18 | : "intel", "volatile"); 19 | 20 | Error::demux(a) 21 | } 22 | 23 | pub unsafe fn syscall1(mut a: usize, b: usize) -> Result { 24 | asm!("int 0x80" 25 | : "={rax}"(a) 26 | : "{rax}"(a), "{rbx}"(b) 27 | : "memory" 28 | : "intel", "volatile"); 29 | 30 | Error::demux(a) 31 | } 32 | 33 | // Clobbers all registers - special for clone 34 | pub unsafe fn syscall1_clobber(mut a: usize, b: usize) -> Result { 35 | asm!("int 0x80" 36 | : "={rax}"(a) 37 | : "{rax}"(a), "{rbx}"(b) 38 | : "memory", "rbx", "rcx", "rdx", "rsi", "rdi", "r8", 39 | "r9", "r10", "r11", "r12", "r13", "r14", "r15" 40 | : "intel", "volatile"); 41 | 42 | Error::demux(a) 43 | } 44 | 45 | pub unsafe fn syscall2(mut a: usize, b: usize, c: usize) -> Result { 46 | asm!("int 0x80" 47 | : "={rax}"(a) 48 | : "{rax}"(a), "{rbx}"(b), "{rcx}"(c) 49 | : "memory" 50 | : "intel", "volatile"); 51 | 52 | Error::demux(a) 53 | } 54 | 55 | pub unsafe fn syscall3(mut a: usize, b: usize, c: usize, d: usize) -> Result { 56 | asm!("int 0x80" 57 | : "={rax}"(a) 58 | : "{rax}"(a), "{rbx}"(b), "{rcx}"(c), "{rdx}"(d) 59 | : "memory" 60 | : "intel", "volatile"); 61 | 62 | Error::demux(a) 63 | } 64 | 65 | pub unsafe fn syscall4(mut a: usize, b: usize, c: usize, d: usize, e: usize) -> Result { 66 | asm!("int 0x80" 67 | : "={rax}"(a) 68 | : "{rax}"(a), "{rbx}"(b), "{rcx}"(c), "{rdx}"(d), "{rsi}"(e) 69 | : "memory" 70 | : "intel", "volatile"); 71 | 72 | Error::demux(a) 73 | } 74 | 75 | pub unsafe fn syscall5(mut a: usize, b: usize, c: usize, d: usize, e: usize, f: usize) 76 | -> Result { 77 | asm!("int 0x80" 78 | : "={rax}"(a) 79 | : "{rax}"(a), "{rbx}"(b), "{rcx}"(c), "{rdx}"(d), "{rsi}"(e), "{rdi}"(f) 80 | : "memory" 81 | : "intel", "volatile"); 82 | 83 | Error::demux(a) 84 | } 85 | -------------------------------------------------------------------------------- /os/std/src/sys/redox/syscall/mod.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2016 The Rust Project Developers. See the COPYRIGHT 2 | // file at the top-level directory of this distribution and at 3 | // http://rust-lang.org/COPYRIGHT. 4 | // 5 | // Licensed under the Apache License, Version 2.0 or the MIT license 7 | // , at your 8 | // option. This file may not be copied, modified, or distributed 9 | // except according to those terms. 10 | 11 | pub use self::arch::*; 12 | pub use self::call::*; 13 | pub use self::data::*; 14 | pub use self::error::*; 15 | pub use self::flag::*; 16 | pub use self::number::*; 17 | 18 | #[cfg(target_arch = "arm")] 19 | #[path="arch/arm.rs"] 20 | mod arch; 21 | 22 | #[cfg(target_arch = "x86")] 23 | #[path="arch/x86.rs"] 24 | mod arch; 25 | 26 | #[cfg(target_arch = "x86_64")] 27 | #[path="arch/x86_64.rs"] 28 | mod arch; 29 | 30 | /// Function definitions 31 | pub mod call; 32 | 33 | /// Complex structures that are used for some system calls 34 | pub mod data; 35 | 36 | /// All errors that can be generated by a system call 37 | pub mod error; 38 | 39 | /// Flags used as an argument to many system calls 40 | pub mod flag; 41 | 42 | /// Call numbers used by each system call 43 | pub mod number; 44 | -------------------------------------------------------------------------------- /os/std/src/sys/redox/thread_local.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2016 The Rust Project Developers. See the COPYRIGHT 2 | // file at the top-level directory of this distribution and at 3 | // http://rust-lang.org/COPYRIGHT. 4 | // 5 | // Licensed under the Apache License, Version 2.0 or the MIT license 7 | // , at your 8 | // option. This file may not be copied, modified, or distributed 9 | // except according to those terms. 10 | 11 | #![allow(dead_code)] // not used on all platforms 12 | 13 | use collections::BTreeMap; 14 | use ptr; 15 | use sync::atomic::{AtomicUsize, ATOMIC_USIZE_INIT, Ordering}; 16 | 17 | pub type Key = usize; 18 | 19 | type Dtor = unsafe extern fn(*mut u8); 20 | 21 | static NEXT_KEY: AtomicUsize = ATOMIC_USIZE_INIT; 22 | 23 | static mut KEYS: *mut BTreeMap> = ptr::null_mut(); 24 | 25 | #[thread_local] 26 | static mut LOCALS: *mut BTreeMap = ptr::null_mut(); 27 | 28 | unsafe fn keys() -> &'static mut BTreeMap> { 29 | if KEYS == ptr::null_mut() { 30 | KEYS = Box::into_raw(Box::new(BTreeMap::new())); 31 | } 32 | &mut *KEYS 33 | } 34 | 35 | unsafe fn locals() -> &'static mut BTreeMap { 36 | if LOCALS == ptr::null_mut() { 37 | LOCALS = Box::into_raw(Box::new(BTreeMap::new())); 38 | } 39 | &mut *LOCALS 40 | } 41 | 42 | #[inline] 43 | pub unsafe fn create(dtor: Option) -> Key { 44 | let key = NEXT_KEY.fetch_add(1, Ordering::SeqCst); 45 | keys().insert(key, dtor); 46 | key 47 | } 48 | 49 | #[inline] 50 | pub unsafe fn get(key: Key) -> *mut u8 { 51 | if let Some(&entry) = locals().get(&key) { 52 | entry 53 | } else { 54 | ptr::null_mut() 55 | } 56 | } 57 | 58 | #[inline] 59 | pub unsafe fn set(key: Key, value: *mut u8) { 60 | locals().insert(key, value); 61 | } 62 | 63 | #[inline] 64 | pub unsafe fn destroy(key: Key) { 65 | keys().remove(&key); 66 | } 67 | 68 | #[inline] 69 | pub fn requires_synchronized_create() -> bool { 70 | false 71 | } 72 | -------------------------------------------------------------------------------- /os/std/src/sys_common/at_exit_imp.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2013 The Rust Project Developers. See the COPYRIGHT 2 | // file at the top-level directory of this distribution and at 3 | // http://rust-lang.org/COPYRIGHT. 4 | // 5 | // Licensed under the Apache License, Version 2.0 or the MIT license 7 | // , at your 8 | // option. This file may not be copied, modified, or distributed 9 | // except according to those terms. 10 | 11 | //! Implementation of running at_exit routines 12 | //! 13 | //! Documentation can be found on the `rt::at_exit` function. 14 | 15 | use alloc::boxed::FnBox; 16 | use ptr; 17 | use sys_common::mutex::Mutex; 18 | 19 | type Queue = Vec>; 20 | 21 | // NB these are specifically not types from `std::sync` as they currently rely 22 | // on poisoning and this module needs to operate at a lower level than requiring 23 | // the thread infrastructure to be in place (useful on the borders of 24 | // initialization/destruction). 25 | static LOCK: Mutex = Mutex::new(); 26 | static mut QUEUE: *mut Queue = ptr::null_mut(); 27 | 28 | // The maximum number of times the cleanup routines will be run. While running 29 | // the at_exit closures new ones may be registered, and this count is the number 30 | // of times the new closures will be allowed to register successfully. After 31 | // this number of iterations all new registrations will return `false`. 32 | const ITERS: usize = 10; 33 | 34 | unsafe fn init() -> bool { 35 | if QUEUE.is_null() { 36 | let state: Box = box Vec::new(); 37 | QUEUE = Box::into_raw(state); 38 | } else if QUEUE as usize == 1 { 39 | // can't re-init after a cleanup 40 | return false 41 | } 42 | 43 | true 44 | } 45 | 46 | pub fn cleanup() { 47 | for i in 0..ITERS { 48 | unsafe { 49 | LOCK.lock(); 50 | let queue = QUEUE; 51 | QUEUE = if i == ITERS - 1 {1} else {0} as *mut _; 52 | LOCK.unlock(); 53 | 54 | // make sure we're not recursively cleaning up 55 | assert!(queue as usize != 1); 56 | 57 | // If we never called init, not need to cleanup! 58 | if queue as usize != 0 { 59 | let queue: Box = Box::from_raw(queue); 60 | for to_run in *queue { 61 | to_run(); 62 | } 63 | } 64 | } 65 | } 66 | } 67 | 68 | pub fn push(f: Box) -> bool { 69 | let mut ret = true; 70 | unsafe { 71 | LOCK.lock(); 72 | if init() { 73 | (*QUEUE).push(f); 74 | } else { 75 | ret = false; 76 | } 77 | LOCK.unlock(); 78 | } 79 | ret 80 | } 81 | -------------------------------------------------------------------------------- /os/std/src/sys_common/bytestring.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2014 The Rust Project Developers. See the COPYRIGHT 2 | // file at the top-level directory of this distribution and at 3 | // http://rust-lang.org/COPYRIGHT. 4 | // 5 | // Licensed under the Apache License, Version 2.0 or the MIT license 7 | // , at your 8 | // option. This file may not be copied, modified, or distributed 9 | // except according to those terms. 10 | 11 | #![allow(dead_code)] 12 | 13 | use fmt::{Formatter, Result, Write}; 14 | use core::str::lossy::{Utf8Lossy, Utf8LossyChunk}; 15 | 16 | pub fn debug_fmt_bytestring(slice: &[u8], f: &mut Formatter) -> Result { 17 | // Writes out a valid unicode string with the correct escape sequences 18 | fn write_str_escaped(f: &mut Formatter, s: &str) -> Result { 19 | for c in s.chars().flat_map(|c| c.escape_debug()) { 20 | f.write_char(c)? 21 | } 22 | Ok(()) 23 | } 24 | 25 | f.write_str("\"")?; 26 | for Utf8LossyChunk { valid, broken } in Utf8Lossy::from_bytes(slice).chunks() { 27 | write_str_escaped(f, valid)?; 28 | for b in broken { 29 | write!(f, "\\x{:02X}", b)?; 30 | } 31 | } 32 | f.write_str("\"") 33 | } 34 | 35 | #[cfg(test)] 36 | mod tests { 37 | use super::*; 38 | use fmt::{Formatter, Result, Debug}; 39 | 40 | #[test] 41 | fn smoke() { 42 | struct Helper<'a>(&'a [u8]); 43 | 44 | impl<'a> Debug for Helper<'a> { 45 | fn fmt(&self, f: &mut Formatter) -> Result { 46 | debug_fmt_bytestring(self.0, f) 47 | } 48 | } 49 | 50 | let input = b"\xF0hello,\tworld"; 51 | let expected = r#""\xF0hello,\tworld""#; 52 | let output = format!("{:?}", Helper(input)); 53 | 54 | assert!(output == expected); 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /os/std/src/sys_common/gnu/mod.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2014 The Rust Project Developers. See the COPYRIGHT 2 | // file at the top-level directory of this distribution and at 3 | // http://rust-lang.org/COPYRIGHT. 4 | // 5 | // Licensed under the Apache License, Version 2.0 or the MIT license 7 | // , at your 8 | // option. This file may not be copied, modified, or distributed 9 | // except according to those terms. 10 | 11 | #![allow(missing_docs)] 12 | #![allow(non_camel_case_types)] 13 | #![allow(non_snake_case)] 14 | 15 | pub mod libbacktrace; 16 | -------------------------------------------------------------------------------- /os/std/src/sys_common/io.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2015 The Rust Project Developers. See the COPYRIGHT 2 | // file at the top-level directory of this distribution and at 3 | // http://rust-lang.org/COPYRIGHT. 4 | // 5 | // Licensed under the Apache License, Version 2.0 or the MIT license 7 | // , at your 8 | // option. This file may not be copied, modified, or distributed 9 | // except according to those terms. 10 | pub const DEFAULT_BUF_SIZE: usize = 8 * 1024; 11 | 12 | #[cfg(test)] 13 | #[allow(dead_code)] // not used on emscripten 14 | pub mod test { 15 | use path::{Path, PathBuf}; 16 | use env; 17 | use rand::{self, Rng}; 18 | use fs; 19 | 20 | pub struct TempDir(PathBuf); 21 | 22 | impl TempDir { 23 | pub fn join(&self, path: &str) -> PathBuf { 24 | let TempDir(ref p) = *self; 25 | p.join(path) 26 | } 27 | 28 | pub fn path<'a>(&'a self) -> &'a Path { 29 | let TempDir(ref p) = *self; 30 | p 31 | } 32 | } 33 | 34 | impl Drop for TempDir { 35 | fn drop(&mut self) { 36 | // Gee, seeing how we're testing the fs module I sure hope that we 37 | // at least implement this correctly! 38 | let TempDir(ref p) = *self; 39 | fs::remove_dir_all(p).unwrap(); 40 | } 41 | } 42 | 43 | pub fn tmpdir() -> TempDir { 44 | let p = env::temp_dir(); 45 | let mut r = rand::thread_rng(); 46 | let ret = p.join(&format!("rust-{}", r.next_u32())); 47 | fs::create_dir(&ret).unwrap(); 48 | TempDir(ret) 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /os/std/src/sys_common/mutex.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2014 The Rust Project Developers. See the COPYRIGHT 2 | // file at the top-level directory of this distribution and at 3 | // http://rust-lang.org/COPYRIGHT. 4 | // 5 | // Licensed under the Apache License, Version 2.0 or the MIT license 7 | // , at your 8 | // option. This file may not be copied, modified, or distributed 9 | // except according to those terms. 10 | 11 | use sys::mutex as imp; 12 | 13 | /// An OS-based mutual exclusion lock. 14 | /// 15 | /// This is the thinnest cross-platform wrapper around OS mutexes. All usage of 16 | /// this mutex is unsafe and it is recommended to instead use the safe wrapper 17 | /// at the top level of the crate instead of this type. 18 | pub struct Mutex(imp::Mutex); 19 | 20 | unsafe impl Sync for Mutex {} 21 | 22 | impl Mutex { 23 | /// Creates a new mutex for use. 24 | /// 25 | /// Behavior is undefined if the mutex is moved after it is 26 | /// first used with any of the functions below. 27 | pub const fn new() -> Mutex { Mutex(imp::Mutex::new()) } 28 | 29 | /// Prepare the mutex for use. 30 | /// 31 | /// This should be called once the mutex is at a stable memory address. 32 | #[inline] 33 | pub unsafe fn init(&mut self) { self.0.init() } 34 | 35 | /// Locks the mutex blocking the current thread until it is available. 36 | /// 37 | /// Behavior is undefined if the mutex has been moved between this and any 38 | /// previous function call. 39 | #[inline] 40 | pub unsafe fn lock(&self) { self.0.lock() } 41 | 42 | /// Attempts to lock the mutex without blocking, returning whether it was 43 | /// successfully acquired or not. 44 | /// 45 | /// Behavior is undefined if the mutex has been moved between this and any 46 | /// previous function call. 47 | #[inline] 48 | pub unsafe fn try_lock(&self) -> bool { self.0.try_lock() } 49 | 50 | /// Unlocks the mutex. 51 | /// 52 | /// Behavior is undefined if the current thread does not actually hold the 53 | /// mutex. 54 | #[inline] 55 | pub unsafe fn unlock(&self) { self.0.unlock() } 56 | 57 | /// Deallocates all resources associated with this mutex. 58 | /// 59 | /// Behavior is undefined if there are current or will be future users of 60 | /// this mutex. 61 | #[inline] 62 | pub unsafe fn destroy(&self) { self.0.destroy() } 63 | } 64 | 65 | // not meant to be exported to the outside world, just the containing module 66 | pub fn raw(mutex: &Mutex) -> &imp::Mutex { &mutex.0 } 67 | -------------------------------------------------------------------------------- /os/std/src/sys_common/thread.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2014 The Rust Project Developers. See the COPYRIGHT 2 | // file at the top-level directory of this distribution and at 3 | // http://rust-lang.org/COPYRIGHT. 4 | // 5 | // Licensed under the Apache License, Version 2.0 or the MIT license 7 | // , at your 8 | // option. This file may not be copied, modified, or distributed 9 | // except according to those terms. 10 | 11 | use alloc::boxed::FnBox; 12 | use env; 13 | use sync::atomic::{self, Ordering}; 14 | use sys::stack_overflow; 15 | use sys::thread as imp; 16 | 17 | #[allow(dead_code)] 18 | pub unsafe fn start_thread(main: *mut u8) { 19 | // Next, set up our stack overflow handler which may get triggered if we run 20 | // out of stack. 21 | let _handler = stack_overflow::Handler::new(); 22 | 23 | // Finally, let's run some code. 24 | Box::from_raw(main as *mut Box)() 25 | } 26 | 27 | pub fn min_stack() -> usize { 28 | static MIN: atomic::AtomicUsize = atomic::AtomicUsize::new(0); 29 | match MIN.load(Ordering::SeqCst) { 30 | 0 => {} 31 | n => return n - 1, 32 | } 33 | let amt = env::var("RUST_MIN_STACK").ok().and_then(|s| s.parse().ok()); 34 | let amt = amt.unwrap_or(imp::DEFAULT_MIN_STACK_SIZE); 35 | 36 | // 0 is our sentinel value, so ensure that we'll never see 0 after 37 | // initialization has run 38 | MIN.store(amt + 1, Ordering::SeqCst); 39 | amt 40 | } 41 | -------------------------------------------------------------------------------- /os/std/src/sys_common/thread_info.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2014 The Rust Project Developers. See the COPYRIGHT 2 | // file at the top-level directory of this distribution and at 3 | // http://rust-lang.org/COPYRIGHT. 4 | // 5 | // Licensed under the Apache License, Version 2.0 or the MIT license 7 | // , at your 8 | // option. This file may not be copied, modified, or distributed 9 | // except according to those terms. 10 | 11 | #![allow(dead_code)] // stack_guard isn't used right now on all platforms 12 | 13 | use cell::RefCell; 14 | use thread::Thread; 15 | 16 | struct ThreadInfo { 17 | stack_guard: Option, 18 | thread: Thread, 19 | } 20 | 21 | thread_local! { static THREAD_INFO: RefCell> = RefCell::new(None) } 22 | 23 | impl ThreadInfo { 24 | fn with(f: F) -> Option where F: FnOnce(&mut ThreadInfo) -> R { 25 | THREAD_INFO.try_with(move |c| { 26 | if c.borrow().is_none() { 27 | *c.borrow_mut() = Some(ThreadInfo { 28 | stack_guard: None, 29 | thread: Thread::new(None), 30 | }) 31 | } 32 | f(c.borrow_mut().as_mut().unwrap()) 33 | }).ok() 34 | } 35 | } 36 | 37 | pub fn current_thread() -> Option { 38 | ThreadInfo::with(|info| info.thread.clone()) 39 | } 40 | 41 | pub fn stack_guard() -> Option { 42 | ThreadInfo::with(|info| info.stack_guard).and_then(|o| o) 43 | } 44 | 45 | pub fn set(stack_guard: Option, thread: Thread) { 46 | THREAD_INFO.with(|c| assert!(c.borrow().is_none())); 47 | THREAD_INFO.with(move |c| *c.borrow_mut() = Some(ThreadInfo{ 48 | stack_guard, 49 | thread, 50 | })); 51 | } 52 | -------------------------------------------------------------------------------- /os/std/src/sys_common/util.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2013 The Rust Project Developers. See the COPYRIGHT 2 | // file at the top-level directory of this distribution and at 3 | // http://rust-lang.org/COPYRIGHT. 4 | // 5 | // Licensed under the Apache License, Version 2.0 or the MIT license 7 | // , at your 8 | // option. This file may not be copied, modified, or distributed 9 | // except according to those terms. 10 | 11 | use fmt; 12 | use io::prelude::*; 13 | use sys::stdio::Stderr; 14 | use thread; 15 | 16 | pub fn dumb_print(args: fmt::Arguments) { 17 | let _ = Stderr::new().map(|mut stderr| stderr.write_fmt(args)); 18 | } 19 | 20 | // Other platforms should use the appropriate platform-specific mechanism for 21 | // aborting the process. If no platform-specific mechanism is available, 22 | // ::intrinsics::abort() may be used instead. The above implementations cover 23 | // all targets currently supported by libstd. 24 | 25 | pub fn abort(args: fmt::Arguments) -> ! { 26 | dumb_print(format_args!("fatal runtime error: {}\n", args)); 27 | unsafe { ::sys::abort_internal(); } 28 | } 29 | 30 | #[allow(dead_code)] // stack overflow detection not enabled on all platforms 31 | pub unsafe fn report_overflow() { 32 | dumb_print(format_args!("\nthread '{}' has overflowed its stack\n", 33 | thread::current().name().unwrap_or(""))); 34 | } 35 | -------------------------------------------------------------------------------- /os/volatile/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "volatile" 3 | version = "0.1.0" 4 | authors = ["Sergio Benitez "] 5 | 6 | [dependencies] 7 | -------------------------------------------------------------------------------- /os/volatile/src/macros.rs: -------------------------------------------------------------------------------- 1 | use traits::*; 2 | 3 | #[doc(hidden)] 4 | pub(crate) macro ptr($type:ident, |$self:ident| $f:expr) { 5 | impl Wrapper for $type { 6 | type Inner = T; 7 | #[inline(always)] fn ptr(&$self) -> *const T { $f } 8 | } 9 | 10 | use core::fmt; 11 | 12 | impl fmt::Debug for $type { 13 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 14 | f.debug_struct(stringify!($type)) 15 | .field("address", &(self.ptr())) 16 | .field("size", &::core::mem::size_of::()) 17 | .finish() 18 | } 19 | } 20 | } 21 | 22 | #[doc(hidden)] 23 | pub(crate) macro readable($type:ident, |$self:ident| $f:expr) { 24 | impl Readable for $type { 25 | #[inline(always)] fn inner(&$self) -> *const T { $f } 26 | } 27 | } 28 | 29 | #[doc(hidden)] 30 | pub(crate) macro writeable($type:ident, |$self:ident| $f:expr) { 31 | impl Writeable for $type { 32 | #[inline(always)] fn inner(&mut $self) -> *mut T { $f } 33 | } 34 | } 35 | 36 | #[doc(hidden)] 37 | pub(crate) macro readable_writeable($type:ident) { 38 | impl ReadableWriteable for $type 39 | where T: ::core::ops::BitAnd, T: ::core::ops::BitOr { } 40 | } 41 | -------------------------------------------------------------------------------- /os/volatile/src/traits.rs: -------------------------------------------------------------------------------- 1 | /// Trait implemented by all of the wrapper types in this crate. 2 | /// 3 | /// The inner type of wrapper is specified as an associated constant `Inner`. 4 | /// This allows for generic implementations over all of the wrapper types. 5 | pub trait Wrapper { 6 | /// The type of the wrapped value. 7 | type Inner; 8 | 9 | /// Returns a pointer to the wrapped item. 10 | fn ptr(&self) -> *const Self::Inner; 11 | } 12 | 13 | /// Trait implemented by **readable** volatile wrappers. 14 | pub trait Readable { 15 | /// Returns the inner pointer. 16 | fn inner(&self) -> *const T; 17 | 18 | /// Reads and returns the value pointed to by `self`. The read is always 19 | /// done using volatile semantics. 20 | #[inline(always)] 21 | fn read(&self) -> T { 22 | unsafe { ::core::ptr::read_volatile(self.inner()) } 23 | } 24 | 25 | /// Returns `true` if the value pointed to by `self` has the mask `mask`. 26 | /// This is equivalent to `(self.read() & mask) == mask`. 27 | #[inline(always)] 28 | fn has_mask(&self, mask: T) -> bool 29 | where T: ::core::ops::BitAnd, 30 | T: PartialEq + Copy 31 | { 32 | (self.read() & mask) == mask 33 | } 34 | } 35 | 36 | /// Trait implemented by **writeable** volatile wrappers. 37 | pub trait Writeable { 38 | /// Returns the inner pointer. 39 | fn inner(&mut self) -> *mut T; 40 | 41 | /// Writes the value `val` to the inner address of `self`. The write is 42 | /// always done using volatile semantics. 43 | #[inline(always)] 44 | fn write(&mut self, val: T) { 45 | unsafe { ::core::ptr::write_volatile(self.inner(), val) } 46 | } 47 | } 48 | 49 | /// Trait implemented by **readable _and_ writeable** volatile wrappers. 50 | pub trait ReadableWriteable: Readable + Writeable 51 | where T: ::core::ops::BitAnd, 52 | T: ::core::ops::BitOr 53 | { 54 | /// Applies the mask `mask` using `&` to the value referred to by `self`. 55 | /// This is equivalent to `self.write(self.read() & mask)`. 56 | fn and_mask(&mut self, mask: T) { 57 | let init_val = self.read(); 58 | self.write(init_val & mask); 59 | } 60 | 61 | /// Applies the mask `mask` using `|` to the value referred to by `self`. 62 | /// This is equivalent to `self.write(self.read() | mask)`. 63 | fn or_mask(&mut self, mask: T) { 64 | let init_val = self.read(); 65 | self.write(init_val | mask); 66 | } 67 | } 68 | 69 | -------------------------------------------------------------------------------- /rust-toolchain: -------------------------------------------------------------------------------- 1 | nightly-2019-01-01 2 | --------------------------------------------------------------------------------