Transfering Large Files to Prime - t5-mini-high - 2026-06-24 06:22, edited 2026-06-26 11:30
Prime G1 only.
QuickTransfer uses the backdoor to hjiack the system's usb functionality, enabling large file tranfer without a system crash(oom).
Usage
QuickTransfer includes a server(QuickTransfer.hpappdir) and a client(QuickTransfer.exe).
1. Use HP Connectivity Kit to transfer QuickTransfer.hpappdir to your PrimeG1 first.
2. Open QuickTransfer app.
3. Use QuickTransfer.exe CLI:
ping Test connectivity
ls <pattern> List directory (e.g., ls "C:\DATA\*")
get <remote> <local> Download file
put <local> <remote> Upload file
rm <remote> Delete file
mkdir <remote> Create directory
info <remote> Get file info
Note
Use Shift+ON to flush file buffers to avoid potential file loss.
Create a new xxx.hpappdir won't appear in Apps view until you reboot it(ON+Symb).
Requires backdoor to be installed.(Use BackdoorInstaller)
Prime G1 only.
QuickTransfer is written in C#, so you need to install .Net 8 first.here
See here for a better approach.
RE: QuickTransfer: Transfering Large Files between Windows and Prime - t5-mini-high - 2026-06-25 07:33
(2026-06-24, 22:54)parisse Wrote: Is there any pointer to the source code of the elf? Some functions I see inside like usb_send, usb_receive_callback,... would be useful to add USB support to UpsilonG1 (https://www.hpmuseum.org/forum/thread-25183.html).
Thanks!
It uses BestaRTOS's USB functionality.(\\?\USB)
Code: if (g_vdev_table[handle].ends_with("USB")) {
// ── USB Slave (Device) IOCTLs ──
// S3C2416 USB Device Controller emulation
switch (request) {
case 4:
// DeviceIoEnable: pull up USB connection, start descriptor handshake
std::cout << " +USB Slave: Enable (connect to host)\n";
return 1;
case 5:
// DeviceIoDisable: disconnect / power down
std::cout << " +USB Slave: Disable (disconnect)\n";
return 1;
case 10:
// DeviceIoChkwake: check wake/suspend status
// Return 1 = awake, 0 = suspended
std::cout << " +USB Slave: ChkWake -> awake\n";
return 1;
case 256: {
// Status query: is USB Slave connected to external host (PC)?
// Return connection status in output buffer
std::cout << " +USB Slave: Status query -> connected\n";
if (out && outlen >= 4) {
*(uint32_t *)out = 1; // 1 = connected
}
if (retlen)
*retlen = 4;
return 1;
}
case 258:
// USBDRV_IO_SET_REVCALLBACK / Bulk Out:
// Send data from guest to host PC via named pipe bridge
std::cout << " +USB Slave: Bulk Out " << size << " bytes\n";
if (usb_out_cb)
usb_out_cb(in, size);
return 1;
case 259:
// Set receive callback: guest registers function pointer for
// async notification when host PC sends data to device
std::cout << " +USB Slave: Set IN callback -> 0x" << std::hex
<< (uint32_t)args->r2 << std::dec << "\n";
usb_in_cb = args->r2;
return 1;
case 263:
// Extended status / capability query
return 0;
default:
std::cout << " +USB Slave: unknown IOCTL " << request << "\n";
return 1;
}
}
if (g_vdev_table[handle].ends_with("USBHOST")) {
// ── USB Host (OHCI) IOCTLs ──
// S3C2416 OHCI Host Controller emulation
switch (request) {
case 4:
// Enable host controller / root hub power
std::cout << " +USB Host: Enable (power on root hub)\n";
return 1;
case 5:
// Disable host controller
std::cout << " +USB Host: Disable\n";
return 1;
case 256: {
return 0;
}
case 257: {
return 0;
}
case 258: {
std::cout << " +USB Host: SendData " << size << " bytes\n";
if (usb_out_cb)
usb_out_cb(in, size);
return 1;
}
case 259: {
std::cout << " +USB Host: Set receive callback -> 0x" << std::hex
<< (uint32_t)args->r2 << std::dec << "\n";
usb_in_cb = args->r2;
return 1;
}
case 260: {
// dword_30015318 + 1: status check (sub_300155A8 ? 2 : sub_3001307C)
std::cout << " +USB Host: Extended status check\n";
return 1; // device present
}
case 261: {
// dword_30015318 + 2: init_usb_host() re-init
std::cout << " +USB Host: Re-init host controller\n";
return 1;
}
case 262: {
// dword_30015318 + 3: sub_30018E54(1) - set device address
std::cout << " +USB Host: Set device address\n";
return 1;
}
case 263: {
// dword_30015318 + 4: return *off_30015330 (device address/speed)
std::cout << " +USB Host: Get device speed\n";
return 0;
}
default:
std::cout << " +USB Host: unknown IOCTL " << request << "\n";
return 1;
}
}
I'll upload both my ida database(ida9+) and the source code.(code shown above is my prime emulator impl)
RE: QuickTransfer: Transfering Large Files between Windows and Prime - parisse - 2026-06-25 12:25
Thank you, but I'm afraid it's much more complicated than what I can understand...
What about trying the Besta OS syscall 0x1024b USBMassStorageRun ? Is it not functional on the G1? Or does it expose something different from g1 drive c:?
RE: QuickTransfer: Transfering Large Files between Windows and Prime - parisse - 2026-06-26 10:58
USBMassStorageRun expects a callback as 1st argument. The 2nd arg is probably 0 if the callback is ignored, and 1 if it is called during the process. I tried with 0 as first arg, but it fails (there is probably a check for a non null callback).
Try this, while the G1 is connected:
typedef short (*usb_cb_t)(unsigned short , unsigned short);
extern "C" void USBMassStorageRun(usb_cb_t usb_cb,unsigned short u);
short usb_cb(unsigned short, unsigned short){
return 0;
}
USBMassStorageRun(usb_cb,false);
RE: QuickTransfer: Transfering Large Files between Windows and Prime - t5-mini-high - 2026-06-26 11:19
This should be better than my original approach.
Code: import ustruct as struct
import uio
class PrimeDebug:
def __init__(self, filename="debug"):
try:
self.f = uio.FileIO("debug")
except:
self.f = open(filename, "rb")
print("[+] Debug interface opened.")
def close(self):
if self.f: self.f.close()
def set_addr(self, addr):
cmd = struct.pack("<III", 0, addr, 0)
self.f.write(cmd)
def read_mem(self, addr, size):
self.set_addr(addr)
return self.f.read(size)
def write_mem(self, addr, val):
cmd = struct.pack("<III", 1, addr, val)
self.f.write(cmd)
def call(self, func_addr, *args):
arg_count = len(args)
buf = bytearray(12 + (arg_count * 4))
struct.pack_into("<III", buf, 0, 2, func_addr, arg_count)
offset = 12
for arg in args:
struct.pack_into("<I", buf, offset, arg)
offset += 4
self.f.write(buf)
return struct.unpack_from("<I", buf, 0)[0]
class CodeLoader:
ADDR_MALLOC = 0x307FBF40
ADDR_FREE = 0x307FBF64
ADDR_ICACHE = 0x3007E7E4
def __init__(self, debug_interface):
self.dbg = debug_interface
self.allocations = []
def load(self, machine_code_bytes):
length = len(machine_code_bytes)
if length % 4 != 0:
machine_code_bytes += b'\x00' * (4 - (length % 4))
length = len(machine_code_bytes)
addr = self.dbg.call(self.ADDR_MALLOC, length)
if addr == 0:
print("[-] Malloc failed!")
return None
self.allocations.append(addr)
for i in range(0, length, 4):
val = struct.unpack("<I", machine_code_bytes[i:i+4])[0]
self.dbg.write_mem(addr + i, val)
self.dbg.call(self.ADDR_ICACHE)
return addr
def free(self, addr):
if addr in self.allocations:
self.dbg.call(self.ADDR_FREE, addr)
self.allocations.remove(addr)
CALLBACK_STUB = bytes([
0x00, 0x20, # MOVS r0, #0
0x70, 0x47, # BX lr
])
USB_MASS_STORAGE_RUN = 0x300135AC
dbg = PrimeDebug()
loader = CodeLoader(dbg)
cb_addr = loader.load(CALLBACK_STUB)
if cb_addr is None:
pass
else:
cb_thumb_ptr = cb_addr | 1
result = dbg.call(USB_MASS_STORAGE_RUN, cb_thumb_ptr, 0)
loader.free(cb_addr)
|