diff --git a/main.S b/main.S index 5e7a784..0ca144d 100644 --- a/main.S +++ b/main.S @@ -1,27 +1,48 @@ .global _start -exit: - @ Exit the program with a status code of 0 - @mov r0, #0 @ `exit` syscall requires the status code to be written to r0 - mov r7, #1 @ `exit` syscall's number is 1. Move it to r7 (which is the register svc reads to know which syscall to execute) +exit: @ r0 should have the status code to exit with + mov r7, #SYS_EXIT @ Move the exit syscall number to r7 (which is the register svc reads to know which syscall to execute) svc 0 @ execute the syscall -print: @ r1 => buffer to print. r2 => how many bytes to print +print: @ r1 => buffer to print. r2 => how many bytes to print. clobbers r0 @ print to stdout mov r0, #1 @ Use STDOUT fd as the write fd - mov r7, #4 @ call write(2) + mov r7, #SYS_WRITE @ call write(2) svc 0 bx lr @ return to caller -fail: - @ push the result of open() onto the stack before calling print() - push {r0} +open_fail: + push {r0} @ push the result of open() onto the stack before calling print() ldr r1, =OPEN_FAIL mov r2, #31 bl print pop {r0} - @mov r0, #1 + bl exit + +dir_read_fail: + push {r0} @ save the result of open() because print() clobbers r0 + ldr r1, =DIR_READ_FAIL + mov r2, #29 + bl print + pop {r0} + + bl exit + +fd_not_dir: + ldr r1, =FD_NOT_DIR + mov r2, #24 + bl print + + mov r0, #1 + bl exit + +fd_not_found: + ldr r1, =FD_NOT_FOUND + mov r2, #58 + bl print + + mov r0, #1 bl exit open_and_read_file: @@ -29,22 +50,22 @@ open_and_read_file: ldr r0, =FILE @ filepath mov r1, #0 @ flags mov r2, #0 @ mode_t - mov r7, #5 + mov r7, #SYS_OPEN svc 0 cmp r0, #0 - blt fail + blt open_fail @ read the file contents @ r0 needs the fd, which it should already be since the call to open() set r0 to the fd. ldr r1, =buffer @ pointer to buffer to read into mov r2, #50 @ how many bytes to read - mov r7, #3 + mov r7, #SYS_READ svc 0 @ print the contents of the buffer ldr r1, =buffer - mov r2, #50 + mov r2, #50 @ FIXME: hardcoded badness bl print ldr r1, =NEWLINE @@ -54,7 +75,7 @@ open_and_read_file: mov r0, #0 bl exit -strlen: +strlen: @ r0 holds the string length. r1 should be a pointer to the start of the string. mov r0, #0 strlen_loop: ldrb r2, [r1, r0] @@ -90,27 +111,37 @@ direntry_loop: b direntry_loop -@ TODO: read args -@ TODO: if no arg passed, use current directory. _start: + ldr r0, [sp] + cmp r0, #1 + ldrgt r0, [sp, #8] + ldrle r0, =FALLBACK_DIR + @ open file - ldr r0, =DIR @ filepath + @ldr r0, =FALLBACK_DIR @ filepath mov r1, #0 @ flags mov r2, #0 @ mode_t - mov r7, #5 + mov r7, #SYS_OPEN svc 0 + cmp r0, #ENOENT + beq fd_not_found cmp r0, #0 - blt fail + blt open_fail @ read the directory contents @ r0 needs the fd, which it should already be since the call to open() set r0 to the fd. ldr r1, =buffer @ pointer to linux_dirent structure @ TODO: we can allocate the required memory on the stack instead of in the bss section I think. mov r2, #16384 @ how many bytes to read - mov r7, #0x8d @ getdents(2) + mov r7, #SYS_GETDENTS svc 0 + cmp r0, #ENOTDIR + beq fd_not_dir + cmp r0, #0 + blt dir_read_fail + mov r8, r0 @ store how many bytes the getdents syscall read, so we can use that to exit the direntry loop mov r4, #0 @ initialize r4 to 0 ldr r5, =buffer @@ -120,11 +151,24 @@ _start: bl exit .data - FILE: .asciz "/home/hisham/asm.txt" - DIR: .asciz "/home/hisham" - OPEN_FAIL: .ascii "Failed to open file descriptor\n" + FILE: .asciz "/home/illusion/asm.txt" + FALLBACK_DIR: .asciz "." + OPEN_FAIL: .ascii "Failed to open file descriptor" + DIR_READ_FAIL: .ascii "Failed to read the directory\n" + FD_NOT_DIR: .ascii "File is not a directory\n" + FD_NOT_FOUND: .ascii "Failed to open file descriptor: No such file or directory\n" NEWLINE: .ascii "\n" +.equ SYS_EXIT, 0x01 +.equ SYS_READ, 0x03 +.equ SYS_WRITE, 0x04 +.equ SYS_OPEN, 0x05 +.equ SYS_FSTAT, 0x6C +.equ SYS_GETDENTS, 0x8D + +.equ ENOENT, 0xFFFFFFFE +.equ ENOTDIR, 0xFFFFFFEC + .bss buffer: .skip 16384