2018-10-14 07:00:39 +00:00
: ( before " End Initialize Op Names " )
put_new ( Name , " cd " , " software interrupt (int) " ) ;
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)
2019-02-25 08:17:46 +00:00
trace ( Callstack_depth + 1 , " 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 :
2019-02-25 08:17:46 +00:00
trace ( Callstack_depth + 1 , " run " ) < < " read: " < < Reg [ EBX ] . u < < ' ' < < Reg [ ECX ] . u < < ' ' < < Reg [ EDX ] . 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 ) ;
2019-02-25 08:17:46 +00:00
trace ( Callstack_depth + 1 , " run " ) < < " result: " < < Reg [ EAX ] . i < < end ( ) ;
2019-05-10 23:45:22 +00:00
if ( Reg [ EAX ] . i = = - 1 ) raise < < " read: " < < strerror ( errno ) < < ' \n ' < < end ( ) ;
2018-07-08 06:38:59 +00:00
break ;
2018-07-16 15:19:20 +00:00
case 4 :
2019-02-25 08:17:46 +00:00
trace ( Callstack_depth + 1 , " run " ) < < " write: " < < Reg [ EBX ] . u < < ' ' < < Reg [ ECX ] . u < < ' ' < < Reg [ EDX ] . u < < end ( ) ;
trace ( Callstack_depth + 1 , " run " ) < < Reg [ ECX ] . u < < " => " < < mem_addr_string ( Reg [ ECX ] . u , Reg [ EDX ] . 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 ) ;
2019-02-25 08:17:46 +00:00
trace ( Callstack_depth + 1 , " run " ) < < " result: " < < Reg [ EAX ] . i < < end ( ) ;
2019-05-10 23:45:22 +00:00
if ( Reg [ EAX ] . i = = - 1 ) raise < < " write: " < < strerror ( errno ) < < ' \n ' < < end ( ) ;
2018-08-14 03:44:28 +00:00
break ;
case 5 : {
check_flags ( ECX ) ;
check_mode ( EDX ) ;
2019-02-25 08:17:46 +00:00
trace ( Callstack_depth + 1 , " run " ) < < " open: " < < Reg [ EBX ] . u < < ' ' < < Reg [ ECX ] . u < < end ( ) ;
trace ( Callstack_depth + 1 , " run " ) < < Reg [ EBX ] . u < < " => " < < mem_addr_kernel_string ( Reg [ EBX ] . u ) < < end ( ) ;
2018-10-05 21:14:30 +00:00
Reg [ EAX ] . i = open ( /*filename*/ mem_addr_kernel_string ( Reg [ EBX ] . u ) , /*flags*/ Reg [ ECX ] . u , /*mode*/ 0640 ) ;
2019-02-25 08:17:46 +00:00
trace ( Callstack_depth + 1 , " run " ) < < " result: " < < Reg [ EAX ] . i < < end ( ) ;
2019-05-10 23:45:22 +00:00
if ( Reg [ EAX ] . i = = - 1 ) raise < < " open: " < < strerror ( errno ) < < ' \n ' < < end ( ) ;
2018-08-14 03:44:28 +00:00
break ;
}
case 6 :
2019-02-25 08:17:46 +00:00
trace ( Callstack_depth + 1 , " run " ) < < " close: " < < Reg [ EBX ] . u < < end ( ) ;
2018-08-14 03:44:28 +00:00
Reg [ EAX ] . i = close ( /*file descriptor*/ Reg [ EBX ] . u ) ;
2019-02-25 08:17:46 +00:00
trace ( Callstack_depth + 1 , " run " ) < < " result: " < < Reg [ EAX ] . i < < end ( ) ;
2019-05-10 23:45:22 +00:00
if ( Reg [ EAX ] . i = = - 1 ) raise < < " close: " < < strerror ( errno ) < < ' \n ' < < end ( ) ;
2018-08-14 03:44:28 +00:00
break ;
case 8 :
check_mode ( ECX ) ;
2019-02-25 08:17:46 +00:00
trace ( Callstack_depth + 1 , " run " ) < < " creat: " < < Reg [ EBX ] . u < < end ( ) ;
trace ( Callstack_depth + 1 , " run " ) < < Reg [ EBX ] . u < < " => " < < mem_addr_kernel_string ( Reg [ EBX ] . u ) < < end ( ) ;
2018-10-05 21:14:30 +00:00
Reg [ EAX ] . i = creat ( /*filename*/ mem_addr_kernel_string ( Reg [ EBX ] . u ) , /*mode*/ 0640 ) ;
2019-02-25 08:17:46 +00:00
trace ( Callstack_depth + 1 , " run " ) < < " result: " < < Reg [ EAX ] . i < < end ( ) ;
2019-05-10 23:45:22 +00:00
if ( Reg [ EAX ] . i = = - 1 ) raise < < " creat: " < < strerror ( errno ) < < ' \n ' < < end ( ) ;
2018-08-14 03:44:28 +00:00
break ;
case 10 :
2019-02-25 08:17:46 +00:00
trace ( Callstack_depth + 1 , " run " ) < < " unlink: " < < Reg [ EBX ] . u < < end ( ) ;
trace ( Callstack_depth + 1 , " run " ) < < Reg [ EBX ] . u < < " => " < < mem_addr_kernel_string ( Reg [ EBX ] . u ) < < end ( ) ;
2018-10-05 21:14:30 +00:00
Reg [ EAX ] . i = unlink ( /*filename*/ mem_addr_kernel_string ( Reg [ EBX ] . u ) ) ;
2019-02-25 08:17:46 +00:00
trace ( Callstack_depth + 1 , " run " ) < < " result: " < < Reg [ EAX ] . i < < end ( ) ;
2019-05-10 23:45:22 +00:00
if ( Reg [ EAX ] . i = = - 1 ) raise < < " unlink: " < < strerror ( errno ) < < ' \n ' < < end ( ) ;
2018-08-14 03:44:28 +00:00
break ;
case 38 :
2019-02-25 08:17:46 +00:00
trace ( Callstack_depth + 1 , " run " ) < < " rename: " < < Reg [ EBX ] . u < < " -> " < < Reg [ ECX ] . u < < end ( ) ;
trace ( Callstack_depth + 1 , " run " ) < < Reg [ EBX ] . u < < " => " < < mem_addr_kernel_string ( Reg [ EBX ] . u ) < < end ( ) ;
trace ( Callstack_depth + 1 , " run " ) < < Reg [ ECX ] . u < < " => " < < mem_addr_kernel_string ( Reg [ ECX ] . u ) < < end ( ) ;
2018-10-05 21:14:30 +00:00
Reg [ EAX ] . i = rename ( /*old filename*/ mem_addr_kernel_string ( Reg [ EBX ] . u ) , /*new filename*/ mem_addr_kernel_string ( Reg [ ECX ] . u ) ) ;
2019-02-25 08:17:46 +00:00
trace ( Callstack_depth + 1 , " run " ) < < " result: " < < Reg [ EAX ] . i < < end ( ) ;
2019-05-10 23:45:22 +00:00
if ( Reg [ EAX ] . i = = - 1 ) raise < < " rename: " < < strerror ( errno ) < < ' \n ' < < end ( ) ;
2018-08-14 03:44:28 +00:00
break ;
2018-09-29 23:17:11 +00:00
case 90 : // mmap: allocate memory outside existing segment allocations
2019-02-25 08:17:46 +00:00
trace ( Callstack_depth + 1 , " run " ) < < " mmap: allocate new segment " < < end ( ) ;
2018-09-29 23:17:11 +00:00
// Ignore most arguments for now: address hint, protection flags, sharing flags, fd, offset.
// We only support anonymous maps.
Reg [ EAX ] . u = new_segment ( /*length*/ read_mem_u32 ( Reg [ EBX ] . u + 0x4 ) ) ;
2019-02-25 08:17:46 +00:00
trace ( Callstack_depth + 1 , " run " ) < < " result: " < < Reg [ EAX ] . u < < end ( ) ;
2018-09-29 23:17:11 +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 ) ;
}
}
2018-09-29 23:17:11 +00:00
: ( before " End Globals " )
2019-05-10 23:45:22 +00:00
// Very primitive/fixed/insecure mmap segments for now.
2019-05-12 06:10:42 +00:00
uint32_t Segments_allocated_above = END_HEAP ;
2018-09-29 23:17:11 +00:00
: ( code )
2019-05-12 06:10:42 +00:00
// always allocate multiples of the segment size
2018-09-29 23:17:11 +00:00
uint32_t new_segment ( uint32_t length ) {
2019-05-12 06:10:42 +00:00
assert ( length > 0 ) ;
2019-05-18 08:02:22 +00:00
uint32_t result = ( Segments_allocated_above - length ) & 0xff000000 ; // same number of zeroes as SEGMENT_ALIGNMENT
2019-05-12 06:10:42 +00:00
if ( result < = START_HEAP ) {
2019-05-12 02:11:13 +00:00
raise < < " Allocated too many segments; the VM ran out of memory. "
2019-07-15 22:47:35 +00:00
< < " Maybe SEGMENT_ALIGNMENT can be smaller? \n " < < die ( ) ;
2019-05-12 02:11:13 +00:00
}
2019-05-12 06:10:42 +00:00
Mem . push_back ( vma ( result , result + length ) ) ;
Segments_allocated_above = result ;
2018-09-29 23:17:11 +00:00
return result ;
}