catm.P1pp (4729B)
1 # catm.P1pp -- P1pp implementation of `catm`. 2 # 3 # Mirrors vendor/seed/$ARCH/catm.hex2 (Jeremiah Orians' stage0 catm): 4 # catm OUT IN1 IN2 ... -> writes the concatenation of IN1..INn to OUT. 5 # 6 # OUT is opened O_WRONLY|O_CREAT|O_TRUNC with mode 0640. With zero inputs 7 # OUT is created and left empty. Errors (open/read/write) print to stderr 8 # and exit nonzero. 9 # 10 # Built once M1pp + hex2pp exist (boot1) so later stages can replace the 11 # seed boot0 catm. The pipeline is the standard P1pp shape: 12 # 13 # catm P1-<arch>.M1pp P1.M1pp P1pp.P1pp catm/catm.P1pp -> combined.M1pp 14 # M1pp combined.M1pp -> expanded.hex2pp 15 # catm ELF.hex2 expanded.hex2pp -> linked.hex2pp 16 # hex2pp -B 0x600000 linked.hex2pp -> ELF binary 17 18 %macro CATM_BUFSIZE() 0x100000 %endm # 1 MiB read/write chunk 19 %macro CATM_O_RDONLY() 0 %endm 20 %macro CATM_O_WRONLY_CREAT_TRUNC() 0x241 %endm # O_WRONLY|O_CREAT|O_TRUNC 21 %macro CATM_MODE_0640() 0x1A0 %endm # 0640 octal 22 23 # 8-aligned NUL-terminated string (mirrors scheme1.P1pp's helper). 24 %macro cstr8(str) 25 str 26 00 27 .align 8 28 %endm 29 30 # argc / argv / out_fd / i live in callee-saved s0..s3 across the whole 31 # function. The inner copy/write loop spills in_fd / remaining-bytes / 32 # write-cursor to the frame because t-regs are clobbered by the sys_* 33 # %calls. %fn2 synthesizes a p1_main_FRAME struct from the local list. 34 %fn2(p1_main, {in_fd, remain, wptr}, { 35 %mov(s0, a0) # s0 = argc 36 %mov(s1, a1) # s1 = argv 37 38 # Initialize buf_ptr from &ELF_end via libp1pp's arena helper. 39 %la(a0, &ELF_end) 40 %la(a1, &arena_table) 41 %la(a2, &arena_table_end) 42 %call(&init_arenas) 43 44 # Need at least: catm OUT 45 %li(t0, 2) 46 %bltu(s0, t0, &.usage) 47 48 # Open OUT = argv[1]. 49 %ld(a0, s1, 8) 50 %li(a1, %CATM_O_WRONLY_CREAT_TRUNC) 51 %li(a2, %CATM_MODE_0640) 52 %call(&sys_open) 53 %bltz(a0, &.open_fail) 54 %mov(s2, a0) # s2 = out_fd 55 56 # i = 2; while (i < argc) { copy argv[i] -> out_fd; i++ } 57 %li(s3, 2) 58 :.arg_loop 59 %beq(s3, s0, &.arg_done) # i == argc -> done 60 61 # in_path = argv[i] 62 %shli(t0, s3, 3) 63 %add(t0, s1, t0) 64 %ld(a0, t0, 0) 65 %li(a1, %CATM_O_RDONLY) 66 %li(a2, 0) 67 %call(&sys_open) 68 %bltz(a0, &.open_fail) 69 %stl(a0, in_fd) 70 71 :.copy_loop 72 %ldl(a0, in_fd) 73 %ld_global(a1, &buf_ptr) 74 %li(a2, %CATM_BUFSIZE) 75 %call(&sys_read) 76 %beqz(a0, &.copy_done) # EOF 77 %bltz(a0, &.read_fail) 78 79 # write_all(out_fd, buf, n) 80 %stl(a0, remain) 81 %ld_global(t0, &buf_ptr) 82 %stl(t0, wptr) 83 :.write_loop 84 %ldl(a2, remain) 85 %beqz(a2, &.write_done) 86 %mov(a0, s2) 87 %ldl(a1, wptr) 88 %call(&sys_write) 89 %bltz(a0, &.write_fail) 90 %ldl(t0, wptr) 91 %add(t0, t0, a0) 92 %stl(t0, wptr) 93 %ldl(t0, remain) 94 %sub(t0, t0, a0) 95 %stl(t0, remain) 96 %b(&.write_loop) 97 :.write_done 98 99 %b(&.copy_loop) 100 :.copy_done 101 102 %ldl(a0, in_fd) 103 %call(&sys_close) 104 105 %addi(s3, s3, 1) 106 %b(&.arg_loop) 107 :.arg_done 108 109 %mov(a0, s2) 110 %call(&sys_close) 111 %li(a0, 0) 112 %b(&.exit) 113 114 :.usage 115 %la(a0, &msg_usage) 116 %call(&eprint_cstr) 117 %li(a0, 2) 118 %b(&.exit) 119 120 :.open_fail 121 %la(a0, &msg_open_fail) 122 %call(&eprint_cstr) 123 %li(a0, 1) 124 %b(&.exit) 125 126 :.read_fail 127 %la(a0, &msg_read_fail) 128 %call(&eprint_cstr) 129 %li(a0, 1) 130 %b(&.exit) 131 132 :.write_fail 133 %la(a0, &msg_write_fail) 134 %call(&eprint_cstr) 135 %li(a0, 1) 136 137 :.exit 138 }) 139 140 # ---- read-only data ------------------------------------------------------- 141 142 :msg_usage %cstr8("usage: catm OUT [IN ...] 143 ") 144 :msg_open_fail %cstr8("catm: open failed 145 ") 146 :msg_read_fail %cstr8("catm: read failed 147 ") 148 :msg_write_fail %cstr8("catm: write failed 149 ") 150 151 # ---- BSS arena table ------------------------------------------------------ 152 # 153 # One arena past :ELF_end: a single 1 MiB read/write buffer. init_arenas 154 # walks the (slot, size) rows once at startup and writes &ELF_end into 155 # &buf_ptr. The ELF p_memsz reservation in vendor/seed/$ARCH/ELF.hex2 156 # (512 MiB) covers it with plenty of headroom. 157 158 :arena_table 159 %arena_entry(&buf_ptr, %CATM_BUFSIZE) 160 :arena_table_end 161 162 # ---- BSS slots (file-resident, zero-initialized) -------------------------- 163 164 :buf_ptr $(0) 165 166 :ELF_end