2018-07-21 01:26:10 +00:00
: ( before " End Initialize Op Names(name) " )
2018-07-27 17:15:03 +00:00
put ( name , " cd " , " software interrupt " ) ;
2018-07-21 01:26:10 +00:00
2018-06-28 23:12:33 +00:00
: ( before " End Single-Byte Opcodes " )
case 0xcd : { // int imm8 (software interrupt)
2018-07-27 18:55:47 +00:00
trace ( 90 , " run " ) < < " syscall " < < end ( ) ;
2018-06-28 23:12:33 +00:00
uint8_t code = next ( ) ;
if ( code ! = 0x80 ) {
raise < < " Unimplemented interrupt code " < < HEXBYTE < < code < < ' \n ' < < end ( ) ;
raise < < " Only `int 80h` supported for now. \n " < < end ( ) ;
break ;
}
process_int80 ( ) ;
break ;
}
: ( code )
void process_int80 ( ) {
switch ( Reg [ EAX ] . u ) {
case 1 :
2018-07-16 15:19:20 +00:00
exit ( /*exit code*/ Reg [ EBX ] . u ) ;
2018-07-08 06:38:59 +00:00
break ;
case 3 :
2018-09-20 21:01:53 +00:00
trace ( 91 , " run " ) < < " read: " < < Reg [ EBX ] . u < < ' ' < < Reg [ ECX ] . u < < ' ' < < Reg [ EDX ] . u < < end ( ) ;
trace ( 91 , " run " ) < < Reg [ ECX ] . u < < " => " < < mem_addr_string ( Reg [ ECX ] . u ) < < end ( ) ;
2018-07-10 14:14:07 +00:00
Reg [ EAX ] . i = read ( /*file descriptor*/ Reg [ EBX ] . u , /*memory buffer*/ mem_addr_u8 ( Reg [ ECX ] . u ) , /*size*/ Reg [ EDX ] . u ) ;
2018-08-14 03:44:28 +00:00
trace ( 91 , " run " ) < < " result: " < < Reg [ EAX ] . i < < end ( ) ;
if ( Reg [ EAX ] . i = = - 1 ) raise < < strerror ( errno ) < < ' \n ' < < end ( ) ;
2018-07-08 06:38:59 +00:00
break ;
2018-07-16 15:19:20 +00:00
case 4 :
2018-09-20 21:01:53 +00:00
trace ( 91 , " run " ) < < " write: " < < Reg [ EBX ] . u < < ' ' < < Reg [ ECX ] . u < < ' ' < < Reg [ EDX ] . u < < end ( ) ;
trace ( 91 , " run " ) < < Reg [ ECX ] . u < < " => " < < mem_addr_string ( Reg [ ECX ] . u ) < < end ( ) ;
2018-07-16 15:19:20 +00:00
Reg [ EAX ] . i = write ( /*file descriptor*/ Reg [ EBX ] . u , /*memory buffer*/ mem_addr_u8 ( Reg [ ECX ] . u ) , /*size*/ Reg [ EDX ] . u ) ;
2018-08-14 03:44:28 +00:00
trace ( 91 , " run " ) < < " result: " < < Reg [ EAX ] . i < < end ( ) ;
if ( Reg [ EAX ] . i = = - 1 ) raise < < strerror ( errno ) < < ' \n ' < < end ( ) ;
break ;
case 5 : {
check_flags ( ECX ) ;
check_mode ( EDX ) ;
2018-09-20 21:01:53 +00:00
trace ( 91 , " run " ) < < " open: " < < Reg [ EBX ] . u < < ' ' < < Reg [ ECX ] . u < < end ( ) ;
trace ( 91 , " run " ) < < Reg [ EBX ] . u < < " => " < < mem_addr_string ( Reg [ EBX ] . u ) < < end ( ) ;
2018-08-14 03:44:28 +00:00
Reg [ EAX ] . i = open ( /*filename*/ mem_addr_string ( Reg [ EBX ] . u ) , /*flags*/ Reg [ ECX ] . u , /*mode*/ 0640 ) ;
trace ( 91 , " run " ) < < " result: " < < Reg [ EAX ] . i < < end ( ) ;
if ( Reg [ EAX ] . i = = - 1 ) raise < < strerror ( errno ) < < ' \n ' < < end ( ) ;
break ;
}
case 6 :
trace ( 91 , " run " ) < < " close: " < < Reg [ EBX ] . u < < end ( ) ;
Reg [ EAX ] . i = close ( /*file descriptor*/ Reg [ EBX ] . u ) ;
trace ( 91 , " run " ) < < " result: " < < Reg [ EAX ] . i < < end ( ) ;
if ( Reg [ EAX ] . i = = - 1 ) raise < < strerror ( errno ) < < ' \n ' < < end ( ) ;
break ;
case 8 :
check_mode ( ECX ) ;
2018-09-20 21:01:53 +00:00
trace ( 91 , " run " ) < < " creat: " < < Reg [ EBX ] . u < < end ( ) ;
trace ( 91 , " run " ) < < Reg [ EBX ] . u < < " => " < < mem_addr_string ( Reg [ EBX ] . u ) < < end ( ) ;
2018-08-14 03:44:28 +00:00
Reg [ EAX ] . i = creat ( /*filename*/ mem_addr_string ( Reg [ EBX ] . u ) , /*mode*/ 0640 ) ;
trace ( 91 , " run " ) < < " result: " < < Reg [ EAX ] . i < < end ( ) ;
if ( Reg [ EAX ] . i = = - 1 ) raise < < strerror ( errno ) < < ' \n ' < < end ( ) ;
break ;
case 10 :
2018-09-20 21:01:53 +00:00
trace ( 91 , " run " ) < < " unlink: " < < Reg [ EBX ] . u < < end ( ) ;
trace ( 91 , " run " ) < < Reg [ EBX ] . u < < " => " < < mem_addr_string ( Reg [ EBX ] . u ) < < end ( ) ;
2018-08-14 03:44:28 +00:00
Reg [ EAX ] . i = unlink ( /*filename*/ mem_addr_string ( Reg [ EBX ] . u ) ) ;
trace ( 91 , " run " ) < < " result: " < < Reg [ EAX ] . i < < end ( ) ;
if ( Reg [ EAX ] . i = = - 1 ) raise < < strerror ( errno ) < < ' \n ' < < end ( ) ;
break ;
case 38 :
2018-09-20 21:01:53 +00:00
trace ( 91 , " run " ) < < " rename: " < < Reg [ EBX ] . u < < " -> " < < Reg [ ECX ] . u < < end ( ) ;
trace ( 91 , " run " ) < < Reg [ EBX ] . u < < " => " < < mem_addr_string ( Reg [ EBX ] . u ) < < end ( ) ;
trace ( 91 , " run " ) < < Reg [ ECX ] . u < < " => " < < mem_addr_string ( Reg [ ECX ] . u ) < < end ( ) ;
2018-08-14 03:44:28 +00:00
Reg [ EAX ] . i = rename ( /*old filename*/ mem_addr_string ( Reg [ EBX ] . u ) , /*new filename*/ mem_addr_string ( Reg [ ECX ] . u ) ) ;
trace ( 91 , " run " ) < < " result: " < < Reg [ EAX ] . i < < end ( ) ;
if ( Reg [ EAX ] . i = = - 1 ) raise < < strerror ( errno ) < < ' \n ' < < end ( ) ;
break ;
case 45 : // brk: modify size of data segment
trace ( 91 , " run " ) < < " grow data segment to " < < Reg [ EBX ] . u < < end ( ) ;
resize_mem ( /*new end address*/ Reg [ EBX ] . u ) ;
2018-07-16 15:19:20 +00:00
break ;
2018-07-25 22:34:55 +00:00
default :
raise < < HEXWORD < < EIP < < " : unimplemented syscall " < < Reg [ EAX ] . u < < ' \n ' < < end ( ) ;
2018-06-28 23:12:33 +00:00
}
}
2018-08-14 03:44:28 +00:00
// SubX is oblivious to file permissions, directories, symbolic links, terminals, and much else besides.
// Also ignoring any concurrency considerations for now.
void check_flags ( int reg ) {
uint32_t flags = Reg [ reg ] . u ;
if ( flags ! = ( ( flags & O_RDONLY ) | ( flags & O_WRONLY ) ) ) {
2018-08-14 17:55:00 +00:00
cerr < < HEXWORD < < EIP < < " : most POSIX flags to the open() syscall are not supported. Just O_RDONLY and O_WRONLY for now. Zero concurrent access support. \n " ;
2018-08-14 03:44:28 +00:00
exit ( 1 ) ;
}
if ( ( flags & O_RDONLY ) & & ( flags & O_WRONLY ) ) {
2018-08-14 17:55:00 +00:00
cerr < < HEXWORD < < EIP < < " : can't open a file for both reading and writing at once. See http://man7.org/linux/man-pages/man2/open.2.html. \n " ;
2018-08-14 03:44:28 +00:00
exit ( 1 ) ;
}
}
void check_mode ( int reg ) {
if ( Reg [ reg ] . u ! = 0600 ) {
2018-08-14 17:55:00 +00:00
cerr < < HEXWORD < < EIP < < " : SubX is oblivious to file permissions; register " < < reg < < " must be 0. \n " ;
2018-08-14 03:44:28 +00:00
exit ( 1 ) ;
}
}
void resize_mem ( uint32_t new_end_address ) {
if ( new_end_address < Mem_offset ) {
2018-09-29 06:00:07 +00:00
raise < < HEXWORD < < EIP < < " : can't shrink data segment to before code segment \n " < < end ( ) ;
2018-08-14 03:44:28 +00:00
return ;
}
int32_t new_size = new_end_address - Mem_offset ;
if ( new_size < SIZE ( Mem ) ) {
raise < < HEXWORD < < EIP < < " : shrinking data segment is not supported. \n " < < end ( ) ;
return ;
}
Mem . resize ( new_size ) ; // will throw exception on failure
}