Files
MemProcFS/vmmjava/vmm/internal/LeechCoreImpl.java
2023-09-21 23:19:19 +02:00

457 lines
16 KiB
Java

package vmm.internal;
import java.nio.charset.StandardCharsets;
import com.sun.jna.*;
import com.sun.jna.ptr.*;
import leechcore.*;
import leechcore.entry.*;
import vmm.internal.LeechCoreNative.LC_BAR_REQUEST;
/**
* JNA native code wrapper for LeechCore.
* @see https://github.com/ufrisk/MemProcFS
* @author Ulf Frisk - pcileech@frizk.net
*/
public class LeechCoreImpl implements ILeechCore
{
//-----------------------------------------------------------------------------
// INITIALIZATION FUNCTIONALITY BELOW:
//-----------------------------------------------------------------------------
Pointer hLC = null;
String lcNativeLibraryPath = null;
/*
* Do not allow direct class instantiation from outside.
*/
private LeechCoreImpl()
{
}
private LeechCoreImpl(String lcNativeLibraryPath, String strDevice, String strRemote, int flagsVerbose, long paMax)
{
byte[] bDevice = strDevice.getBytes(StandardCharsets.UTF_8);
byte[] bRemote = strRemote.getBytes(StandardCharsets.UTF_8);
LeechCoreNative.LC_CONFIG lcConfig = new LeechCoreNative.LC_CONFIG();
lcConfig.dwVersion = LeechCoreNative.LC_CONFIG_VERSION;
System.arraycopy(bDevice, 0, lcConfig.szDevice, 0, Math.min(lcConfig.szDevice.length - 1, bDevice.length));
System.arraycopy(bRemote, 0, lcConfig.szRemote, 0, Math.min(lcConfig.szRemote.length - 1, bRemote.length));
lcConfig.dwPrintfVerbosity = flagsVerbose;
lcConfig.paMax = paMax;
System.setProperty("jna.library.path", lcNativeLibraryPath);
hLC = LeechCoreNative.INSTANCE.LcCreate(lcConfig);
if(hLC == null) { throw new LeechCoreException("LeechCore Init: failed in native code."); }
this.lcNativeLibraryPath = lcNativeLibraryPath;
}
public static ILeechCore Initialize(vmm.IVmm vmmInstance)
{
if((vmmInstance == null) || !vmmInstance.isValid()) {
return null;
}
long lcHandle = vmmInstance.getConfig(vmm.IVmm.OPT_CORE_LEECHCORE_HANDLE);
String strDevice = "existing://0x" + Long.toHexString(lcHandle);
String lcNativeLibraryPath = vmmInstance.getNativeLibraryPath();
return new LeechCoreImpl(lcNativeLibraryPath, strDevice, "", 0, 0);
}
public static ILeechCore Initialize(String lcNativeLibraryPath, String strDevice)
{
return new LeechCoreImpl(lcNativeLibraryPath, strDevice, "", 0, 0);
}
public static ILeechCore Initialize(String lcNativeLibraryPath, String strDevice, String strRemote, int flagsVerbose, long paMax)
{
return new LeechCoreImpl(lcNativeLibraryPath, strDevice, strRemote, flagsVerbose, paMax);
}
public boolean isValid() {
return hLC != null;
}
public String getNativeLibraryPath() {
return lcNativeLibraryPath;
}
public void close()
{
LeechCoreNative.INSTANCE.LcClose(hLC);
hLC = null;
}
/*
* Always close native implementation upon finalization.
*/
@Override
public void finalize()
{
try {
this.close();
} catch (Exception e) {}
}
/*
* Custom toString() method.
*/
@Override
public String toString()
{
return (hLC != null) ? "LeechCore" : "LeechCoreNotValid";
}
//-----------------------------------------------------------------------------
// CONFIGURATION SETTINGS BELOW:
//-----------------------------------------------------------------------------
@Override
public long getOption(long fOption)
{
LongByReference pqw = new LongByReference();
boolean f = LeechCoreNative.INSTANCE.LcGetOption(hLC, fOption, pqw);
if(!f) { throw new LeechCoreException("LeechCore.LcGetOption(): failed."); }
return pqw.getValue();
}
@Override
public void setOption(long fOption, long qw)
{
boolean f = LeechCoreNative.INSTANCE.LcSetOption(hLC, fOption, qw);
if(!f) { throw new LeechCoreException("LeechCore.LcSetOption(): failed."); }
}
@Override
public byte[] memRead(long pa, int size)
{
byte[] pbResult = new byte[size];
boolean f = LeechCoreNative.INSTANCE.LcRead(hLC, pa, size, pbResult);
if(!f) { throw new LeechCoreException("LeechCore.LcRead(): failed."); }
return pbResult;
}
@Override
public void memWrite(long pa, byte[] data)
{
boolean f = LeechCoreNative.INSTANCE.LcWrite(hLC, pa, data.length, data);
if(!f) { throw new LeechCoreException("LeechCore.LcWrite(): failed."); }
}
@Override
public String getMemMap()
{
return new String(command(ILeechCore.LC_CMD_MEMMAP_GET, null), StandardCharsets.UTF_8);
}
@Override
public void setMemMap(String strMemMap)
{
byte[] bMemMap = strMemMap.getBytes(StandardCharsets.UTF_8);
command(ILeechCore.LC_CMD_MEMMAP_SET, bMemMap);
}
@Override
public byte[] command(long fCommand, byte[] data)
{
PointerByReference ppbDataOut = new PointerByReference();
IntByReference pcbDataOut = new IntByReference();
int dataInLen = 0;
Pointer dataInPtr = null;
if((data != null) && (data.length > 0)) {
dataInLen = data.length;
dataInPtr = new Memory(dataInLen);
dataInPtr.write(0, data, 0, dataInLen);
}
boolean f = LeechCoreNative.INSTANCE.LcCommand(hLC, fCommand, dataInLen, dataInPtr, ppbDataOut, pcbDataOut);
if(!f) { throw new LeechCoreException("LeechCore.LcCommand(): failed."); }
int cbDataOut = pcbDataOut.getValue();
if(0 == cbDataOut) { return null; }
Pointer pbDataOut = ppbDataOut.getValue();
if(0 == Pointer.nativeValue(pbDataOut)) { return null; }
byte[] dataOut = pbDataOut.getByteArray(0, cbDataOut);
LeechCoreNative.INSTANCE.LcMemFree(pbDataOut);
return dataOut;
}
//-----------------------------------------------------------------------------
// LEECHCORE TLP FUNCTIONALITY BELOW:
//-----------------------------------------------------------------------------
@Override
public void writePCIeTLP(byte[] tlp)
{
if((tlp != null) && (tlp.length > 0) || ((tlp.length % 4) == 0)) {
command(ILeechCore.LC_CMD_FPGA_TLP_WRITE_SINGLE, tlp);
}
}
@Override
public ILeechCoreTlpContext setPCIeTlpCallback(ILeechCoreTlpCallback callback)
{
return LeechCoreTlpContextImpl.initializeLeechCoreTlpContextImpl(this, callback);
}
//-----------------------------------------------------------------------------
// LEECHCORE BAR FUNCTIONALITY BELOW:
//-----------------------------------------------------------------------------
@Override
public LeechCoreBar[] getBarInfo()
{
IntByReference pcbDataOut = new IntByReference();
PointerByReference ppbDataOut = new PointerByReference();
boolean f = LeechCoreNative.INSTANCE.LcCommand(hLC, ILeechCore.LC_CMD_FPGA_BAR_INFO, 0, null, ppbDataOut, pcbDataOut);
if(!f) { throw new LeechCoreException("LeechCore.LcCommand(): failed."); }
Pointer pbDataOut = ppbDataOut.getValue();
if(0 == Pointer.nativeValue(pbDataOut)) { return null; }
LeechCoreNative.LC_BAR_6 nativeBars = new LeechCoreNative.LC_BAR_6(pbDataOut);
LeechCoreBar lcBars[] = new LeechCoreBar[6];
// process result:
for(LeechCoreNative.LC_BAR n : nativeBars.bars) {
LeechCoreBar e = new LeechCoreBar();
e.fValid = n.fValid;
e.f64Bit = n.f64Bit;
e.fPrefetchable = n.fPrefetchable;
e.iBar = n.iBar;
e.pa = n.pa;
e.cb = n.cb;
lcBars[e.iBar] = e;
}
LeechCoreNative.INSTANCE.LcMemFree(pbDataOut);
return lcBars;
}
@Override
public ILeechCoreBarContext setPCIeBarCallback(ILeechCoreBarCallback callback)
{
return LeechCoreBarContextImpl.initializeLeechCoreBarContextImpl(this, callback);
}
}
//-----------------------------------------------------------------------------
// LEECHCORE INTERNAL TLP FUNCTIONALITY BELOW:
//-----------------------------------------------------------------------------
class LeechCoreTlpContextImpl implements ILeechCoreTlpContext
{
private LeechCoreImpl lc;
private Integer key;
private Pointer keyPointer;
private ILeechCoreTlpCallback cbUser;
private LeechCoreNative.CALLBACK_TLP cbNative;
static LeechCoreTlpContextImpl initializeLeechCoreTlpContextImpl(LeechCoreImpl lc, ILeechCoreTlpCallback cbUser)
{
LeechCoreTlpContextImpl ctx = new LeechCoreTlpContextImpl();
ctx.cbNative = new LeechCoreNative.CALLBACK_TLP() {
@Override
public void invoke(int ctxNative, int cbTlp, Pointer pbTlp, int cbInfo, String szInfo) {
try {
byte[] tlp = pbTlp.getByteArray(0, cbTlp);
Integer key = Integer.valueOf(ctxNative);
LeechCoreTlpContextImpl ctx = (LeechCoreTlpContextImpl)JnaObjectMap.getInstance().get(key);
ctx.cbUser.LeechCoreTlpCallback(ctx.lc, tlp, szInfo);
} catch (Exception e) {}
}
};
ctx.lc = lc;
ctx.cbUser = cbUser;
ctx.key = JnaObjectMap.getInstance().put(ctx);
ctx.keyPointer = new Pointer(ctx.key.longValue());
if(!LeechCoreNative.INSTANCE.LcSetOption(lc.hLC, ILeechCore.LC_OPT_FPGA_TLP_READ_CB_WITHINFO, 1)) {
ctx.close();
return null;
}
if(!LeechCoreNative.INSTANCE.LcCommand(lc.hLC, ILeechCore.LC_CMD_FPGA_TLP_CONTEXT, 0, ctx.keyPointer, null, null)) {
ctx.close();
return null;
}
if(!LeechCoreNativeEx.INSTANCE.LcCommand(lc.hLC, ILeechCore.LC_CMD_FPGA_TLP_FUNCTION_CALLBACK, 0, ctx.cbNative, null, null)) {
ctx.close();
return null;
}
return ctx;
}
@Override
public void close()
{
if((lc == null) || (key == null)) {
return;
}
PointerByReference pptr = new PointerByReference();
if(!LeechCoreNative.INSTANCE.LcCommand(lc.hLC, ILeechCore.LC_CMD_FPGA_TLP_CONTEXT_RD, 0, null, pptr, null)) {
return;
}
if(Pointer.nativeValue(pptr.getPointer()) != key.longValue()) {
return;
}
LeechCoreNative.INSTANCE.LcCommand(lc.hLC, ILeechCore.LC_CMD_FPGA_TLP_FUNCTION_CALLBACK, 0, null, null, null);
LeechCoreNative.INSTANCE.LcCommand(lc.hLC, ILeechCore.LC_CMD_FPGA_TLP_CONTEXT, 0, null, null, null);
JnaObjectMap.getInstance().remove(key);
keyPointer = null;
cbNative = null;
cbUser = null;
key = null;
lc = null;
}
/*
* Always close native implementation upon finalization.
*/
@Override
public void finalize()
{
try {
close();
} catch (Exception e) {}
}
@Override
public String toString()
{
return "LeechCoreTlpContext";
}
}
//-----------------------------------------------------------------------------
// LEECHCORE INTERNAL BAR FUNCTIONALITY BELOW:
//-----------------------------------------------------------------------------
class LeechCoreBarReplyImpl implements ILeechCoreBarReply
{
LC_BAR_REQUEST n;
@Override
public void reply(byte[] data) {
if(!n.fRead) {
throw new LeechCoreException("LeechCore.replyBarRead(): only possible to reply to read requests.");
}
if(data == null) {
n.cbData = 0;
n.fReadReply = true;
return;
}
if(n.cbData != data.length) {
throw new LeechCoreException("LeechCore.replyBarRead(): data length of reply mis-matches requested data length.");
}
n.fReadReply = true;
System.arraycopy(data, 0, n.pbData, 0, n.cbData);
}
}
class LeechCoreBarContextImpl implements ILeechCoreBarContext
{
private LeechCoreImpl lc;
private Integer key;
private Pointer keyPointer;
private ILeechCoreBarCallback cbUser;
private LeechCoreNative.CALLBACK_BAR cbNative;
static LeechCoreBarContextImpl initializeLeechCoreBarContextImpl(LeechCoreImpl lc, ILeechCoreBarCallback cbUser)
{
LeechCoreBarContextImpl ctx = new LeechCoreBarContextImpl();
ctx.cbNative = new LeechCoreNative.CALLBACK_BAR() {
@Override
public void invoke(LC_BAR_REQUEST n) {
try {
LeechCoreNative.LC_BAR nbar = new LeechCoreNative.LC_BAR(n.pBar);
LeechCoreBar bar = new LeechCoreBar();
bar.fValid = nbar.fValid;
bar.fIO = nbar.fIO;
bar.f64Bit = nbar.f64Bit;
bar.fPrefetchable = nbar.fPrefetchable;
bar.iBar = nbar.iBar;
bar.pa = nbar.pa;
bar.cb = nbar.cb;
LeechCoreBarReplyImpl reply = new LeechCoreBarReplyImpl();
reply.n = n;
LeechCoreBarRequest req = new LeechCoreBarRequest();
req.reply = reply;
req.bar = bar;
req.bTag = n.bTag;
req.bFirstBE = n.bFirstBE;
req.bLastBE = n.bLastBE;
req.is64Bit = n.f64;
req.isRead = n.fRead;
req.isWrite = n.fWrite;
req.cbData = n.cbData;
req.oData = n.oData;
if(req.isWrite) {
req.pbDataWrite = new byte[req.cbData];
System.arraycopy(n.pbData, 0, req.pbDataWrite, 0, req.cbData);
}
// call into user-defined function:
// user may optionally call back to reply.reply() which updated native data.
Integer key = Integer.valueOf((int)Pointer.nativeValue(n.ctx));
LeechCoreBarContextImpl ctx = (LeechCoreBarContextImpl)JnaObjectMap.getInstance().get(key);
ctx.cbUser.LeechCoreBarCallback(req);
} catch (Exception e) {}
}
};
ctx.lc = lc;
ctx.cbUser = cbUser;
ctx.key = JnaObjectMap.getInstance().put(ctx);
ctx.keyPointer = new Pointer(ctx.key.longValue());
if(!LeechCoreNative.INSTANCE.LcCommand(lc.hLC, ILeechCore.LC_CMD_FPGA_BAR_CONTEXT, 0, ctx.keyPointer, null, null)) {
ctx.close();
return null;
}
if(!LeechCoreNativeEx.INSTANCE.LcCommand(lc.hLC, ILeechCore.LC_CMD_FPGA_BAR_FUNCTION_CALLBACK, 0, ctx.cbNative, null, null)) {
ctx.close();
return null;
}
return ctx;
}
@Override
public void close()
{
if((lc == null) || (key == null)) {
return;
}
PointerByReference pptr = new PointerByReference();
if(!LeechCoreNative.INSTANCE.LcCommand(lc.hLC, ILeechCore.LC_CMD_FPGA_BAR_CONTEXT_RD, 0, null, pptr, null)) {
return;
}
if(Pointer.nativeValue(pptr.getPointer()) != key.longValue()) {
return;
}
LeechCoreNative.INSTANCE.LcCommand(lc.hLC, ILeechCore.LC_CMD_FPGA_BAR_FUNCTION_CALLBACK, 0, null, null, null);
LeechCoreNative.INSTANCE.LcCommand(lc.hLC, ILeechCore.LC_CMD_FPGA_BAR_CONTEXT, 0, null, null, null);
JnaObjectMap.getInstance().remove(key);
keyPointer = null;
cbNative = null;
cbUser = null;
key = null;
lc = null;
}
/*
* Always close native implementation upon finalization.
*/
@Override
public void finalize()
{
try {
close();
} catch (Exception e) {}
}
@Override
public String toString()
{
return "LeechCoreBarContext";
}
}