github.com/racerxdl/gonx@v0.0.0-20210103083128-c5afc43bcbd2/svc/svc_nintendoswitch.go (about)

     1  // +build nintendoswitch
     2  
     3  // Named wrappers to Runtime SVC
     4  package svc
     5  
     6  import (
     7  	"device/arm64"
     8  	"fmt"
     9  	"github.com/racerxdl/gonx/nx/nxerrors"
    10  	"github.com/racerxdl/gonx/nx/nxtypes"
    11  	"time"
    12  	"unsafe"
    13  )
    14  
    15  // SvcGetInfo Retrieves information about the system, or a certain kernel object.
    16  // svc 0x29
    17  //go:inline
    18  func GetInfo(output *uint64, id0 uint32, handle nxtypes.Handle, id1 uint64) uint64 {
    19  	return uint64(arm64.SVCall4(0x29, output, id0, handle, id1))
    20  }
    21  
    22  // SendSyncRequest Sends an IPC synchronization request to a session.
    23  // svc 0x21
    24  //go:inline
    25  func SendSyncRequest(session uint64) uint64 {
    26  	return uint64(arm64.SVCall1(0x21, session))
    27  }
    28  
    29  // CloseHandle Closes a handle, decrementing the reference count of the corresponding kernel object.
    30  // This might result in the kernel freeing the object.
    31  // svc 0x16.
    32  //go:inline
    33  func CloseHandle(session nxtypes.Handle) uint64 {
    34  	return uint64(arm64.SVCall1(0x16, uint64(session)))
    35  }
    36  
    37  // ConnectToNamedPort Connects to a registered named port.
    38  // Expects byte to be a null terminated string
    39  // svc 0x1F
    40  //go:inline
    41  func ConnectToNamedPort(session *nxtypes.Handle, name *byte) uint64 {
    42  	res := arm64.AsmFull(`
    43  		str {session}, [sp, #-16]!
    44  		mov x1, {name}
    45  		svc 0x1F
    46  		mov {}, x0
    47  		ldr x2, [sp], #16
    48  		str w1, [x2]
    49  	`, map[string]interface{}{
    50  		"name":    uintptr(unsafe.Pointer(name)),
    51  		"session": uintptr(unsafe.Pointer(session)),
    52  	})
    53  
    54  	return uint64(res)
    55  }
    56  
    57  // CreateTransferMemory Creates a block of transfer memory.
    58  // svc 0x15
    59  //go:inline
    60  func CreateTransferMemory(handle *nxtypes.Handle, addr uintptr, size uintptr, perm uint32) uint64 {
    61  	// X1 => Addr
    62  	// X2 => Size
    63  	// W3 => Memory Perms
    64  	// Output Result W0
    65  	// Output TransferMemoryhandle W1
    66  	res := arm64.AsmFull(`
    67  		mov x1, {addr}
    68  		mov x2, {size}
    69  		mov x3, {perms}
    70  		str {handle}, [sp, #-16]!
    71  		svc 0x15
    72  		ldr x2, [sp], #16
    73  		str w1, [x2]
    74  	`, map[string]interface{}{
    75  		"addr":   addr,
    76  		"size":   size,
    77  		"perms":  perm,
    78  		"handle": uintptr(unsafe.Pointer(handle)),
    79  	})
    80  	return uint64(res)
    81  }
    82  
    83  // SetMemoryAttribute Sets memory attributes
    84  // svc 0x03
    85  //go:inline
    86  func SetMemoryAttribute(addr uintptr, size uintptr, mask, value uint32) uint64 {
    87  	return uint64(arm64.SVCall4(0x03, addr, size, mask, value))
    88  }
    89  
    90  // WaitSynchronization Waits the specified handles to be finished or the specified timeout
    91  // Returns the Handle Index and error if timeout
    92  // svc 0x18
    93  //go:inline
    94  func WaitSynchronization(handles []nxtypes.Handle, timeout time.Duration) (uint32, error) {
    95  	if len(handles) > 0x40 {
    96  		// HOS Kernel Limit
    97  		return 0, nxerrors.TooManyHandles
    98  	}
    99  	index := ^uint32(0)
   100  	//
   101  	r := arm64.AsmFull(`
   102  		str {index}, [sp, #-16]!
   103  		mov x1, {handleptr}
   104  		mov x2, {handlesnum}
   105  		mov x3, {timeout}
   106  		svc 0x18
   107  		mov {}, x0
   108  		ldr x2, [sp], #16
   109  		str w1, [x2]
   110  	`, map[string]interface{}{
   111  		"handleptr":  uintptr(unsafe.Pointer(&handles[0])),
   112  		"handlesnum": len(handles),
   113  		"timeout":    uint64(timeout),
   114  		"index":      uintptr(unsafe.Pointer(&index)),
   115  	})
   116  
   117  	if r != nxtypes.ResultOK {
   118  		return uint32(index), nxerrors.Timeout
   119  	}
   120  
   121  	return uint32(index), nil
   122  }
   123  
   124  // WaitSynchronization Waits a single handle to be finished with the specified timeout
   125  // Calls WaitSynchronization
   126  //go:inline
   127  func WaitSynchronizationSingle(handle nxtypes.Handle, timeout time.Duration) error {
   128  	_, err := WaitSynchronization([]nxtypes.Handle{handle}, timeout)
   129  	return err
   130  }
   131  
   132  // Break calls to a SVC Break
   133  func Break(breakReason, v0, info uint64) uint64 {
   134  	return uint64(arm64.SVCall3(0x26, breakReason, v0, info))
   135  }
   136  
   137  // GetTLS returns a pointer to thread local storage
   138  func GetTLS() *TLS {
   139  	tlsPtr := arm64.AsmFull(`mrs {}, tpidrro_el0`, nil)
   140  	return (*TLS)(unsafe.Pointer(tlsPtr))
   141  }
   142  
   143  func GetIPCBuffer() *[64]uint32 {
   144  	return &GetTLS().IPCBuffer
   145  }
   146  
   147  func ClearIPCBuffer() {
   148  	buff := GetIPCBuffer()
   149  	for i := 0; i < 64; i++ {
   150  		buff[i] = 0
   151  	}
   152  }
   153  
   154  func DumpIPCBuffer() {
   155  	buff := GetIPCBuffer()
   156  	println("TLS IPC Buffer Dump:")
   157  	for i := 0; i < 64; i++ {
   158  		if i%4 == 0 {
   159  			fmt.Printf("\n%04x: ", i*4)
   160  		}
   161  		fmt.Printf("%08x ", buff[i])
   162  	}
   163  	println("")
   164  }