tbgpu: shim binary + remote apl pci dev (#14124)

* shim binary + remote pci dev

* v2

* rip out apl

* cmds

* rename

* clean

* remove

* rm gitignore

* ui

* install

* linter

* um

* cleaner

* assets

* normal install in ui

* cleaner app

* install script

* support fd mmap

* cleaner

* kill server when disconn

* rename + pcidevs

* sign

* install and reinstall

* no sip install

* will trigger update

* nv

* ugh

* this

* fix

* nv

* use nosip sign

* auto install

* remove

* mypy

* upd

* ditto

* print

* simpler

* ditto

* um

* simpler

* upd

* upd

* cleaner

* autogen

* cleaner

* move

* annotations

* server cleaner
This commit is contained in:
nimlgen
2026-01-20 16:15:18 +03:00
committed by GitHub
parent 4548fcc1b8
commit dc82856084
26 changed files with 1485 additions and 406 deletions

View File

@@ -43,7 +43,7 @@ jobs:
run: sudo apt-get install -y --no-install-recommends libclang-20-dev llvm-20-dev hip-dev libusb-1.0-0-dev
- name: Regenerate autogen files
run: |
find tinygrad/runtime/autogen -type f -name "*.py" -not -name "__init__.py" -not -name "comgr_3.py" -not -name "metal.py" -not -name "libclang.py" -delete
find tinygrad/runtime/autogen -type f -name "*.py" -not -name "__init__.py" -not -name "comgr_3.py" -not -name "metal.py" -not -name "iokit.py" -not -name "corefoundation.py" -not -name "libclang.py" -delete
python3 -c "from tinygrad.runtime.autogen import opencl"
python3 -c "from tinygrad.runtime.autogen import cuda, nvrtc, nvjitlink, nv_570, nv_580, nv"
python3 -c "from tinygrad.runtime.autogen import comgr, hsa, hip, amd_gpu, sqtt, rocprof, amdgpu_kd"
@@ -83,8 +83,8 @@ jobs:
llvm: 'true'
- name: Regenerate autogen files
run: |
rm tinygrad/runtime/autogen/metal.py
LIBCLANG_PATH=/opt/homebrew/opt/llvm@20/lib/libclang.dylib python3 -c "from tinygrad.runtime.autogen import metal"
rm tinygrad/runtime/autogen/metal.py tinygrad/runtime/autogen/iokit.py tinygrad/runtime/autogen/corefoundation.py
LIBCLANG_PATH=/opt/homebrew/opt/llvm@20/lib/libclang.dylib python3 -c "from tinygrad.runtime.autogen import metal, iokit, corefoundation"
- name: Check for differences
run: |
if ! git diff --quiet; then

View File

@@ -0,0 +1,22 @@
#!/bin/bash
set -e
APP_PATH="/Applications/TinyGPU.app"
DEXT_ID="org.tinygrad.tinygpu.edriver"
# Install app if not present. TODO: url
if [[ ! -d "$APP_PATH" ]]; then
echo "TinyGPU.app not found in /Applications"
exit 1
fi
# Ask user to install
read -n1 -p "Install TinyGPU driver extension now? [y/N] " answer
echo
if [[ "$answer" =~ ^[Yy]$ ]]; then
"$APP_PATH/Contents/MacOS/TinyGPU" install
else
echo "Skipped."
exit 0
fi

View File

@@ -0,0 +1 @@
int run_server(const char *sock_path);

View File

@@ -1,19 +1,48 @@
import AppKit
import SwiftUI
final class AppDelegate: NSObject, NSApplicationDelegate {
func applicationShouldTerminateAfterLastWindowClosed(_ sender: NSApplication) -> Bool {
true
}
}
private let dextID = "org.tinygrad.tinygpu.edriver"
@main
struct TinyGPUApp: App {
@NSApplicationDelegateAdaptor(AppDelegate.self) var appDelegate
private static var runner: TinyGPUCLIRunner? // prevent dealloc before callback
@State private var text = ""
@NSApplicationDelegateAdaptor(AppDelegate.self) var appDelegate
var body: some Scene {
WindowGroup {
TinyGPUView()
}
init() {
guard CommandLine.arguments.count > 1 else { return }
Self.runner = TinyGPUCLIRunner(dextID)
Self.runner?.run(args: CommandLine.arguments) { exit($0.rawValue) }
dispatchMain()
}
var body: some Scene {
WindowGroup("TinyGPU") {
ScrollView {
Text(text).font(.custom("Menlo", size: 11)).frame(maxWidth: .infinity, alignment: .leading).padding(8)
}
.frame(width: 500, height: 300).padding()
.onAppear { setup() }
}
.commands { CommandGroup(replacing: .newItem) {} }
}
func setup() {
let bundlePath = Bundle.main.bundlePath
guard bundlePath.hasPrefix("/Applications/") else {
var error: NSDictionary?
NSAppleScript(source: "do shell script \"mv '\(bundlePath)' '/Applications/'\" with administrator privileges")?.executeAndReturnError(&error)
text = error == nil ? "Moved! Please reopen from /Applications/\n" : "Move TinyGPU to /Applications first.\n"
return
}
let state = TinyGPUCLIRunner.queryDextState(dextID)
if state == .unloaded || state == .activating {
Self.runner = TinyGPUCLIRunner(dextID)
Self.runner?.run(args: ["", "install"]) { _ in }
}
text = "TinyGPU - Remote PCI Device Server\n\n" + TinyGPUCLIRunner.statusText(state)
}
}
class AppDelegate: NSObject, NSApplicationDelegate {
func applicationShouldTerminateAfterLastWindowClosed(_ sender: NSApplication) -> Bool { true }
}

View File

@@ -0,0 +1,122 @@
import Foundation
import SystemExtensions
enum TinyGPUCLIExit: Int32 { case ok = 0, usage = 2, failed = 3, needsApproval = 4 }
enum DextState { case unloaded, activating, needsApproval, activated }
final class TinyGPUCLIRunner: NSObject, OSSystemExtensionRequestDelegate {
private let dextID: String
private var done: ((TinyGPUCLIExit) -> Void)?
private var isInstall = true
init(_ dextID: String) { self.dextID = dextID }
static func queryDextState(_ bundleID: String) -> DextState {
let p = Process()
p.executableURL = URL(fileURLWithPath: "/usr/bin/systemextensionsctl")
p.arguments = ["list"]
let pipe = Pipe()
p.standardOutput = pipe
p.standardError = Pipe()
guard (try? p.run()) != nil else { return .unloaded }
p.waitUntilExit()
guard let output = String(data: pipe.fileHandleForReading.readDataToEndOfFile(), encoding: .utf8),
let line = output.split(separator: "\n").first(where: { $0.contains(bundleID) }) else { return .unloaded }
if line.contains("[activated enabled]") { return .activated }
if line.contains("[activated waiting for user]") { return .needsApproval }
return line.contains("terminated waiting to uninstall") ? .unloaded : .activating
}
private static let approvalHelp = """
Please go to System Settings > Privacy & Security and allow the extension.
If previously disabled: System Settings > General > Login Items & Extensions > Driver Extensions > Toggle TinyGPU ON
"""
static func statusText(_ state: DextState) -> String {
switch state {
case .unloaded: return "Driver extension not installed.\n\n"
case .activating: return "Extension is activating...\n\n"
case .needsApproval: return "Extension awaiting approval.\n\n" + approvalHelp
case .activated: return "Extension is ready! Run tinygrad to use your eGPU.\n\n"
}
}
func run(args: [String], done: @escaping (TinyGPUCLIExit) -> Void) {
self.done = done
guard args.count > 1 else { return usage() }
switch args[1] {
case "status":
print(Self.statusText(Self.queryDextState(dextID)))
done(.ok)
case "install":
if Self.queryDextState(dextID) == .needsApproval { print(Self.statusText(.needsApproval)); return done(.needsApproval) }
print("Installing TinyGPU driver extension...\nYou may need to approve in System Settings.\n")
submitRequest(activate: true)
case "uninstall":
guard Self.queryDextState(dextID) != .unloaded else { print("Not installed.\n"); return done(.ok) }
print("Uninstalling TinyGPU driver extension...\n")
isInstall = false
submitRequest(activate: false)
case "server":
guard args.count > 2 else { print("Error: server requires socket path\n"); return usage() }
done(run_server(args[2]) == 0 ? .ok : .failed)
case "help", "-h", "--help":
usage(); done(.ok)
default:
print("Unknown command: \(args[1])\n"); usage()
}
}
private func usage() {
print("""
Usage: TinyGPU <command>
status Show extension status
install Install the driver extension
uninstall Remove the driver extension
server <path> Start server on Unix socket
""")
done?(.usage)
}
private func submitRequest(activate: Bool) {
let req = activate
? OSSystemExtensionRequest.activationRequest(forExtensionWithIdentifier: dextID, queue: .main)
: OSSystemExtensionRequest.deactivationRequest(forExtensionWithIdentifier: dextID, queue: .main)
req.delegate = self
OSSystemExtensionManager.shared.submitRequest(req)
}
// MARK: - OSSystemExtensionRequestDelegate
func requestNeedsUserApproval(_ request: OSSystemExtensionRequest) {
print("\nUser approval required!\n\n\(Self.approvalHelp)After approval, connect the gpu and use it with tinygrad.\n")
done?(.needsApproval)
}
func request(_ request: OSSystemExtensionRequest, didFinishWithResult result: OSSystemExtensionRequest.Result) {
switch result {
case .completed: print("Driver extension \(isInstall ? "installed" : "uninstalled") successfully!\n")
case .willCompleteAfterReboot: print("Will complete after reboot.\n")
@unknown default: print("Completed: \(result)\n")
}
done?(.ok)
}
func request(_ request: OSSystemExtensionRequest, didFailWithError error: Error) {
print("\nError: \(error.localizedDescription)\n")
let code = (error as NSError).code
if code == 4 { print("Missing entitlements. Rebuild with proper signing.\n") }
else if code == 8 { print("Extension not found in app bundle.\n") }
else if code == 9 { print("Extension disabled by user.\n\n\(Self.approvalHelp)") }
done?(.failed)
}
func request(_ request: OSSystemExtensionRequest, actionForReplacingExtension existing: OSSystemExtensionProperties,
withExtension ext: OSSystemExtensionProperties) -> OSSystemExtensionRequest.ReplacementAction {
print("Updating v\(existing.bundleShortVersion) -> v\(ext.bundleShortVersion)...\n")
return .replace
}
}

View File

@@ -1,33 +0,0 @@
import SwiftUI
struct TinyGPUView: View {
@ObservedObject var viewModel = TinyGPUViewModel()
var body: some View {
#if os(macOS)
VStack(alignment: .center) {
Text("TinyGPU Intsaller")
.padding()
.font(.title)
Text(self.viewModel.dextLoadingState)
.multilineTextAlignment(.center)
HStack {
Button(
action: {
self.viewModel.activateMyDext()
}, label: {
Text("Install extension")
}
)
}
}
.frame(width: 500, height: 200, alignment: .center)
#endif
}
}
struct TinyGPUView_Previews: PreviewProvider {
static var previews: some View {
TinyGPUView()
}
}

View File

@@ -1,142 +0,0 @@
import Foundation
import os.log
import SystemExtensions
class TinyGPUDriverLoadingStateMachine {
enum State { case unloaded, activating, needsApproval, activated, activationError }
}
class TinyGPUViewModel: NSObject {
@Published private var state: TinyGPUDriverLoadingStateMachine.State = .unloaded
override init() {
super.init()
refreshInitialDextState()
}
private func refreshInitialDextState() {
#if os(macOS)
Task.detached { [dextIdentifier] in
let newState = Self.queryDextState(bundleID: dextIdentifier)
await MainActor.run { self.state = newState }
}
#endif
}
#if os(macOS)
private static func queryDextState(bundleID: String) -> TinyGPUDriverLoadingStateMachine.State {
let tool = "/usr/bin/systemextensionsctl"
let p = Process()
p.executableURL = URL(fileURLWithPath: tool)
p.arguments = ["list"]
let pipe = Pipe()
p.standardOutput = pipe
p.standardError = Pipe()
do {
try p.run()
p.waitUntilExit()
let data = pipe.fileHandleForReading.readDataToEndOfFile()
guard let output = String(data: data, encoding: .utf8) else { return .unloaded }
// Look for our bundle id line
if let line = output.split(separator: "\n").first(where: { $0.contains(bundleID) }) {
if line.contains("[activated enabled]") { return .activated }
if line.contains("[activated waiting for user]") { return .needsApproval }
if line.contains("terminated waiting to uninstall") { return .unloaded }
return .activating
} else {
return .unloaded
}
} catch {
return .unloaded
}
}
#endif
private let dextIdentifier: String = "org.tinygrad.tinygpu.edriver"
public var dextLoadingState: String {
switch state {
case .unloaded:
return "TinyGPUDriver isn't loaded."
case .activating:
return "Activating TinyGPUDriver, please wait."
case .needsApproval:
return "Please follow the prompt to approve TinyGPUDriver."
case .activated:
return "TinyGPUDriver has been activated and is ready to use. You can close the installer."
case .activationError:
return "TinyGPUDriver has experienced an error during activation.\nPlease check the logs to find the error."
}
}
}
extension TinyGPUViewModel: ObservableObject {
#if os(macOS)
func activateMyDext() {
activateExtension(dextIdentifier)
}
func deactivateMyDext() {
deactivateExtension(dextIdentifier)
}
func activateExtension(_ dextIdentifier: String) {
let request = OSSystemExtensionRequest
.activationRequest(forExtensionWithIdentifier: dextIdentifier,
queue: .main)
request.delegate = self
OSSystemExtensionManager.shared.submitRequest(request)
self.state = .activating
}
func deactivateExtension(_ dextIdentifier: String) {
let request = OSSystemExtensionRequest.deactivationRequest(forExtensionWithIdentifier: dextIdentifier, queue: .main)
request.delegate = self
OSSystemExtensionManager.shared.submitRequest(request)
self.state = .unloaded
}
#endif
}
#if os(macOS)
extension TinyGPUViewModel: OSSystemExtensionRequestDelegate {
func request(
_ request: OSSystemExtensionRequest,
actionForReplacingExtension existing: OSSystemExtensionProperties,
withExtension ext: OSSystemExtensionProperties) -> OSSystemExtensionRequest.ReplacementAction {
var replacementAction: OSSystemExtensionRequest.ReplacementAction
os_log("sysex actionForReplacingExtension: %@ %@", existing, ext)
replacementAction = .replace
self.state = .activating
return replacementAction
}
func requestNeedsUserApproval(_ request: OSSystemExtensionRequest) {
os_log("sysex requestNeedsUserApproval")
self.state = .needsApproval
}
func request(_ request: OSSystemExtensionRequest, didFinishWithResult result: OSSystemExtensionRequest.Result) {
os_log("sysex didFinishWithResult: %d", result.rawValue)
self.state = .activated
}
func request(_ request: OSSystemExtensionRequest, didFailWithError error: Error) {
os_log("sysex didFailWithError: %@", error.localizedDescription)
self.state = .activationError
}
}
#endif

View File

@@ -0,0 +1,277 @@
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <string.h>
#include <unistd.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <sys/mman.h>
#include <fcntl.h>
#include <errno.h>
#include <dispatch/dispatch.h>
#include <CoreFoundation/CoreFoundation.h>
#include <IOKit/IOKitLib.h>
#include <IOKit/IOMessage.h>
#include <mach/mach.h>
// Protocol
enum {
CMD_MAP_BAR = 1, // map PCI BAR, returns size
CMD_MAP_SYSMEM_FD = 2, // alloc DMA memory, returns fd via SCM_RIGHTS
CMD_CFG_READ = 3, // read PCI config space
CMD_CFG_WRITE = 4, // write PCI config space
CMD_RESET = 5, // reset device
CMD_MMIO_READ = 6, // bulk read from BAR
CMD_MMIO_WRITE = 7, // bulk write to BAR
RESP_OK = 0, RESP_ERR = 1,
};
typedef struct { uint8_t cmd, bar; uint64_t offset, size, value; } __attribute__((packed)) request_t;
typedef struct { uint8_t status; uint64_t value, addr; } __attribute__((packed)) response_t;
// Constants and state
#define BULK_BUF_SIZE (64 << 20)
#define MAX_BARS 6
#define MAX_SYSMEM 128
static uint8_t g_bulk_buf[BULK_BUF_SIZE];
static io_connect_t g_conn = IO_OBJECT_NULL;
static int g_client_active = 0;
static struct { mach_vm_address_t addr; mach_vm_size_t size; } g_bars[MAX_BARS];
static struct { mach_vm_address_t addr; mach_vm_size_t size; int shm_fd; char shm_name[32]; } g_sysmem[MAX_SYSMEM];
static int g_sysmem_count = 0;
// Utilities
static void recvall(int fd, void *buf, size_t len) {
for (size_t off = 0; off < len; ) {
ssize_t r = recv(fd, (uint8_t*)buf + off, len - off, 0);
if (r <= 0) break;
off += r;
}
}
// MMIO requires 32-bit aligned volatile accesses
static void mmio_copy(void *dst, void *src, size_t len) {
volatile uint32_t *d = dst, *s = src;
for (size_t i = 0; i < len / 4; i++) d[i] = s[i];
for (size_t i = len & ~3; i < len; i++) ((volatile uint8_t*)dst)[i] = ((volatile uint8_t*)src)[i];
}
static int send_response(int fd, response_t *resp, int send_fd) {
char cmsgbuf[CMSG_SPACE(sizeof(int))];
struct iovec iov = {resp, sizeof(*resp)};
struct msghdr msg = {.msg_iov = &iov, .msg_iovlen = 1};
if (send_fd >= 0) {
msg.msg_control = cmsgbuf;
msg.msg_controllen = sizeof(cmsgbuf);
struct cmsghdr *cmsg = CMSG_FIRSTHDR(&msg);
*cmsg = (struct cmsghdr){.cmsg_level = SOL_SOCKET, .cmsg_type = SCM_RIGHTS, .cmsg_len = CMSG_LEN(sizeof(int))};
memcpy(CMSG_DATA(cmsg), &send_fd, sizeof(int));
}
return sendmsg(fd, &msg, 0) > 0 ? 0 : -1;
}
static void send_error(int fd, const char *msg) {
response_t resp = {.status = RESP_ERR, .value = strlen(msg)};
send_response(fd, &resp, -1);
send(fd, msg, strlen(msg), 0);
}
// Driver interface
static void on_disconnect(void *refcon, io_service_t svc, uint32_t msg, void *arg) {
if (msg == kIOMessageServiceIsTerminated) _exit(0);
}
static io_connect_t open_tinygpu(void) {
static io_object_t notif;
io_service_t svc = IOServiceGetMatchingService(kIOMainPortDefault, IOServiceNameMatching("tinygpu"));
if (!svc) return IO_OBJECT_NULL;
if (!notif) {
IONotificationPortRef port = IONotificationPortCreate(kIOMainPortDefault);
IONotificationPortSetDispatchQueue(port, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0));
IOServiceAddInterestNotification(port, svc, kIOGeneralInterest, on_disconnect, NULL, &notif);
}
io_connect_t conn;
kern_return_t kr = IOServiceOpen(svc, mach_task_self(), 0, &conn);
IOObjectRelease(svc);
return kr == KERN_SUCCESS ? conn : IO_OBJECT_NULL;
}
static int dext_rpc(uint32_t sel, uint64_t *in, uint32_t in_cnt, uint64_t *out_val) {
uint64_t out[2];
uint32_t out_cnt = 2;
if (IOConnectCallMethod(g_conn, sel, in, in_cnt, NULL, 0, out, &out_cnt, NULL, NULL) != KERN_SUCCESS) return -1;
if (out_val) *out_val = out[0];
return 0;
}
static int map_bar(uint32_t bar, response_t *resp) {
if (bar >= MAX_BARS) return -1;
if (!g_bars[bar].addr && IOConnectMapMemory64(g_conn, bar, mach_task_self(), &g_bars[bar].addr, &g_bars[bar].size, kIOMapAnywhere)) return -1;
resp->addr = g_bars[bar].addr;
resp->value = g_bars[bar].size;
return 0;
}
static int map_sysmem_fd(uint64_t size, response_t *resp, int *out_fd) {
if (g_sysmem_count >= MAX_SYSMEM) return -1;
int idx = g_sysmem_count;
int fd = -1;
void *ptr = MAP_FAILED;
char shm_name[32];
// page-align, min 16KB for IOMemoryDescriptor
size_t alloc_sz = (size + 0xfff) & ~0xfff;
if (alloc_sz < 0x4000) alloc_sz = 0x4000;
snprintf(shm_name, sizeof(shm_name), "/tinygpu_%d", idx);
shm_unlink(shm_name);
if ((fd = shm_open(shm_name, O_CREAT | O_RDWR, 0600)) < 0) goto fail;
if (ftruncate(fd, alloc_sz) < 0) goto fail;
if ((ptr = mmap(NULL, alloc_sz, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0)) == MAP_FAILED) goto fail;
// PrepareDMA writes physical addresses to output buffer, copy to shared mem
uint8_t paddr_buf[8192] = {0};
size_t out_sz = sizeof(paddr_buf);
if (IOConnectCallStructMethod(g_conn, 3, ptr, alloc_sz, paddr_buf, &out_sz) != KERN_SUCCESS) goto fail;
memcpy(ptr, paddr_buf, out_sz);
g_sysmem[idx] = (typeof(g_sysmem[idx])){.addr = (mach_vm_address_t)ptr, .size = alloc_sz, .shm_fd = fd};
strncpy(g_sysmem[idx].shm_name, shm_name, sizeof(g_sysmem[idx].shm_name));
g_sysmem_count++;
*resp = (response_t){.addr = idx, .value = alloc_sz};
*out_fd = fd;
return 0;
fail:
if (ptr != MAP_FAILED) munmap(ptr, alloc_sz);
if (fd >= 0) close(fd);
shm_unlink(shm_name);
return -1;
}
static int validate_bar(uint8_t bar, uint64_t off, uint64_t sz) {
return (bar < MAX_BARS && g_bars[bar].addr && off + sz <= g_bars[bar].size && sz <= BULK_BUF_SIZE) ? 0 : -1;
}
static void cleanup(void) {
for (int i = 0; i < MAX_BARS; i++)
if (g_bars[i].addr) { IOConnectUnmapMemory64(g_conn, i, mach_task_self(), g_bars[i].addr); g_bars[i].addr = 0; }
for (int i = 0; i < g_sysmem_count; i++) {
munmap((void*)g_sysmem[i].addr, g_sysmem[i].size);
close(g_sysmem[i].shm_fd);
shm_unlink(g_sysmem[i].shm_name);
}
g_sysmem_count = 0;
if (g_conn != IO_OBJECT_NULL) { IOServiceClose(g_conn); g_conn = IO_OBJECT_NULL; }
}
static void handle_client(int fd) {
int bufsize = BULK_BUF_SIZE;
setsockopt(fd, SOL_SOCKET, SO_SNDBUF, &bufsize, sizeof(bufsize));
setsockopt(fd, SOL_SOCKET, SO_RCVBUF, &bufsize, sizeof(bufsize));
printf("client connected\n");
g_conn = open_tinygpu();
if (g_conn == IO_OBJECT_NULL) {
fprintf(stderr, "failed to connect to tinygpu driver\n");
request_t req; recv(fd, &req, sizeof(req), 0);
send_error(fd, "Driver not available. Check: System Report > PCI for GPU, System Settings > Privacy & Security.");
return;
}
request_t req;
response_t resp;
while (recv(fd, &req, sizeof(req), 0) == sizeof(req)) {
resp = (response_t){0};
switch (req.cmd) {
case CMD_MAP_BAR:
resp.status = map_bar(req.bar, &resp) ? 1 : 0;
break;
case CMD_MAP_SYSMEM_FD: {
int shm_fd = -1;
resp.status = map_sysmem_fd(req.size, &resp, &shm_fd) ? 1 : 0;
send_response(fd, &resp, shm_fd);
continue;
}
case CMD_CFG_READ: {
uint64_t in[2] = {req.offset, req.size};
resp.status = dext_rpc(0, in, 2, &resp.value) ? 1 : 0;
break;
}
case CMD_CFG_WRITE: {
uint64_t in[3] = {req.offset, req.size, req.value};
resp.status = dext_rpc(1, in, 3, NULL) ? 1 : 0;
break;
}
case CMD_RESET:
resp.status = dext_rpc(2, NULL, 0, NULL) ? 1 : 0;
break;
case CMD_MMIO_READ:
if (validate_bar(req.bar, req.offset, req.size)) { resp.status = 1; break; }
mmio_copy(g_bulk_buf, (void*)(g_bars[req.bar].addr + req.offset), req.size);
resp.value = req.size;
send_response(fd, &resp, -1);
send(fd, g_bulk_buf, req.size, 0);
continue;
case CMD_MMIO_WRITE:
recvall(fd, g_bulk_buf, req.size);
if (!validate_bar(req.bar, req.offset, req.size))
mmio_copy((void*)(g_bars[req.bar].addr + req.offset), g_bulk_buf, req.size);
continue;
default:
resp.status = 1;
}
send_response(fd, &resp, -1);
}
printf("client disconnected\n");
cleanup();
}
int run_server(const char *sock_path) {
int server_fd = socket(AF_UNIX, SOCK_STREAM, 0);
if (server_fd < 0) { perror("socket"); return 1; }
struct sockaddr_un addr = {.sun_family = AF_UNIX};
strncpy(addr.sun_path, sock_path, sizeof(addr.sun_path) - 1);
unlink(sock_path);
if (bind(server_fd, (struct sockaddr*)&addr, sizeof(addr)) < 0) { perror("bind"); close(server_fd); return 1; }
if (listen(server_fd, 1) < 0) { perror("listen"); close(server_fd); return 1; }
printf("listening on %s\n", sock_path);
while (1) {
int client_fd = accept(server_fd, NULL, NULL);
if (client_fd < 0) { if (errno == EINTR) continue; perror("accept"); break; }
if (g_client_active) { printf("rejected: client already connected\n"); close(client_fd); continue; }
g_client_active = 1;
handle_client(client_fd);
g_client_active = 0;
close(client_fd);
}
close(server_fd);
unlink(sock_path);
cleanup();
return 0;
}

View File

@@ -0,0 +1,18 @@
<svg viewBox="0 0 130 50" xmlns="http://www.w3.org/2000/svg">
<!-- t -->
<rect x="10" y="0" width="10" height="40" fill="#000000"></rect>
<rect x="0" y="10" width="30" height="10" fill="#000000"></rect>
<rect x="10" y="30" width="20" height="10" fill="#000000"></rect>
<!-- i -->
<rect x="40" y="0" width="10" height="10" fill="#000000"></rect>
<rect x="40" y="20" width="10" height="20" fill="#000000"></rect>
<!-- n -->
<rect x="60" y="10" width="10" height="30" fill="#000000"></rect>
<rect x="60" y="10" width="20" height="10" fill="#000000"></rect>
<rect x="80" y="20" width="10" height="20" fill="#000000"></rect>
<!-- y -->
<rect x="100" y="10" width="10" height="20" fill="#000000"></rect>
<rect x="100" y="20" width="30" height="10" fill="#000000"></rect>
<rect x="120" y="10" width="10" height="30" fill="#000000"></rect>
<rect x="100" y="40" width="20" height="10" fill="#000000"></rect>
</svg>

After

Width:  |  Height:  |  Size: 1.0 KiB

View File

@@ -0,0 +1,52 @@
{
"fill" : "automatic",
"groups" : [
{
"layers" : [
{
"fill-specializations" : [
{
"value" : "automatic"
},
{
"appearance" : "dark",
"value" : {
"solid" : "display-p3:0.94011,0.96611,0.94301,1.00000"
}
},
{
"appearance" : "tinted",
"value" : {
"solid" : "display-p3:0.79528,0.79528,0.79528,1.00000"
}
}
],
"hidden" : false,
"image-name" : "tiny.svg",
"name" : "tiny_svg",
"position" : {
"scale" : 5,
"translation-in-points" : [
0,
19
]
}
}
],
"shadow" : {
"kind" : "neutral",
"opacity" : 0.5
},
"translucency" : {
"enabled" : true,
"value" : 0.5
}
}
],
"supported-platforms" : {
"circles" : [
"watchOS"
],
"squares" : "shared"
}
}

View File

@@ -7,13 +7,14 @@
objects = {
/* Begin PBXBuildFile section */
0A52E8692F18FC6900A816CD /* tiny_icon.icon in Resources */ = {isa = PBXBuildFile; fileRef = 0A52E8682F18FC6900A816CD /* tiny_icon.icon */; };
0A5C11DD2F18E466006DBBCA /* server.c in Sources */ = {isa = PBXBuildFile; fileRef = 0A5C11DC2F18E461006DBBCA /* server.c */; };
0ACB55392E9CB880007029EF /* PCIDriverKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 0ACB55382E9CB880007029EF /* PCIDriverKit.framework */; };
0AD7C2E52F18DEBC00562D1A /* TinyGPUCLIRunner.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0AD7C2E42F18DEB800562D1A /* TinyGPUCLIRunner.swift */; };
54798269286A3512009785F6 /* CoreAudio.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 54798268286A3512009785F6 /* CoreAudio.framework */; };
549EB121286A1A37009D38AB /* TinyGPUViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 549EB11F286A1A37009D38AB /* TinyGPUViewModel.swift */; };
549EB123286A1D48009D38AB /* org.tinygrad.tinygpu.edriver.dext in Embed System Extensions */ = {isa = PBXBuildFile; fileRef = C5B7D9BC26128AC50089B4C3 /* org.tinygrad.tinygpu.edriver.dext */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; };
549EB131286A2B98009D38AB /* IOKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 549EB130286A2B98009D38AB /* IOKit.framework */; };
54E42BC8286A1697000E1E9A /* TinyGPUApp.swift in Sources */ = {isa = PBXBuildFile; fileRef = 54E42BB8286A1696000E1E9A /* TinyGPUApp.swift */; };
54E42BCA286A1697000E1E9A /* TinyGPUView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 54E42BB9286A1696000E1E9A /* TinyGPUView.swift */; };
54E42BCC286A1697000E1E9A /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 54E42BBA286A1697000E1E9A /* Assets.xcassets */; };
C5B7D9C326128AC50089B4C3 /* TinyGPUDriver.cpp in Sources */ = {isa = PBXBuildFile; fileRef = C5B7D9C226128AC50089B4C3 /* TinyGPUDriver.cpp */; };
C5B7D9C526128AC50089B4C3 /* TinyGPUDriver.iig in Sources */ = {isa = PBXBuildFile; fileRef = C5B7D9C426128AC50089B4C3 /* TinyGPUDriver.iig */; };
@@ -34,6 +35,15 @@
/* End PBXContainerItemProxy section */
/* Begin PBXCopyFilesBuildPhase section */
0AD7C2DB2F18D7D500562D1A /* CopyFiles */ = {
isa = PBXCopyFilesBuildPhase;
buildActionMask = 2147483647;
dstPath = "";
dstSubfolderSpec = 6;
files = (
);
runOnlyForDeploymentPostprocessing = 0;
};
549EB122286A1D3A009D38AB /* Embed System Extensions */ = {
isa = PBXCopyFilesBuildPhase;
buildActionMask = 2147483647;
@@ -48,13 +58,18 @@
/* End PBXCopyFilesBuildPhase section */
/* Begin PBXFileReference section */
0A52E8682F18FC6900A816CD /* tiny_icon.icon */ = {isa = PBXFileReference; lastKnownFileType = folder.iconcomposer.icon; path = tiny_icon.icon; sourceTree = "<group>"; };
0A5C11DC2F18E461006DBBCA /* server.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = server.c; sourceTree = "<group>"; };
0A5C11DE2F18E468006DBBCA /* TinyGPU-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "TinyGPU-Bridging-Header.h"; sourceTree = "<group>"; };
0ACB55382E9CB880007029EF /* PCIDriverKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = PCIDriverKit.framework; path = System/DriverKit/System/Library/Frameworks/PCIDriverKit.framework; sourceTree = SDKROOT; };
0AD7C2D62F18D3DB00562D1A /* IOKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = IOKit.framework; path = Platforms/MacOSX.platform/Developer/SDKs/MacOSX26.2.sdk/System/Library/Frameworks/IOKit.framework; sourceTree = DEVELOPER_DIR; };
0AD7C2D82F18D3E300562D1A /* CoreFoundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreFoundation.framework; path = Platforms/MacOSX.platform/Developer/SDKs/MacOSX26.2.sdk/System/Library/Frameworks/CoreFoundation.framework; sourceTree = DEVELOPER_DIR; };
0AD7C2E42F18DEB800562D1A /* TinyGPUCLIRunner.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TinyGPUCLIRunner.swift; sourceTree = "<group>"; };
0AFA851D2F1CE486005FDAC2 /* TinyGPUDriver.Release.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = TinyGPUDriver.Release.entitlements; sourceTree = "<group>"; };
54798268286A3512009785F6 /* CoreAudio.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreAudio.framework; path = Platforms/MacOSX.platform/Developer/SDKs/MacOSX13.0.sdk/System/Library/Frameworks/CoreAudio.framework; sourceTree = DEVELOPER_DIR; };
549EB11F286A1A37009D38AB /* TinyGPUViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TinyGPUViewModel.swift; sourceTree = "<group>"; usesTabs = 1; };
549EB130286A2B98009D38AB /* IOKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = IOKit.framework; path = Platforms/MacOSX.platform/Developer/SDKs/MacOSX13.0.sdk/System/Library/Frameworks/IOKit.framework; sourceTree = DEVELOPER_DIR; };
549EB132286A2B9D009D38AB /* IOKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = IOKit.framework; path = Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS16.0.sdk/System/Library/Frameworks/IOKit.framework; sourceTree = DEVELOPER_DIR; };
54E42BB8286A1696000E1E9A /* TinyGPUApp.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TinyGPUApp.swift; sourceTree = "<group>"; };
54E42BB9286A1696000E1E9A /* TinyGPUView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TinyGPUView.swift; sourceTree = "<group>"; };
54E42BBA286A1697000E1E9A /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; };
54E42BC4286A1697000E1E9A /* TinyGPU.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = TinyGPU.app; sourceTree = BUILT_PRODUCTS_DIR; };
54E42BC6286A1697000E1E9A /* macOS.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = macOS.entitlements; sourceTree = "<group>"; };
@@ -102,10 +117,12 @@
54E42BB7286A1696000E1E9A /* Shared */ = {
isa = PBXGroup;
children = (
0A5C11DC2F18E461006DBBCA /* server.c */,
0AD7C2E42F18DEB800562D1A /* TinyGPUCLIRunner.swift */,
54E42BB8286A1696000E1E9A /* TinyGPUApp.swift */,
54E42BB9286A1696000E1E9A /* TinyGPUView.swift */,
549EB11F286A1A37009D38AB /* TinyGPUViewModel.swift */,
54E42BBA286A1697000E1E9A /* Assets.xcassets */,
0A52E8682F18FC6900A816CD /* tiny_icon.icon */,
0A5C11DE2F18E468006DBBCA /* TinyGPU-Bridging-Header.h */,
);
path = Shared;
sourceTree = "<group>";
@@ -142,6 +159,8 @@
C5B7D9BE26128AC50089B4C3 /* Frameworks */ = {
isa = PBXGroup;
children = (
0AD7C2D82F18D3E300562D1A /* CoreFoundation.framework */,
0AD7C2D62F18D3DB00562D1A /* IOKit.framework */,
0ACB55382E9CB880007029EF /* PCIDriverKit.framework */,
54798268286A3512009785F6 /* CoreAudio.framework */,
549EB130286A2B98009D38AB /* IOKit.framework */,
@@ -168,6 +187,7 @@
C5D787AB261667FC006047E5 /* TinyGPUDriverUserClient.iig */,
C5B7D9C626128AC50089B4C3 /* Info.plist */,
C5B7D9CE26128B150089B4C3 /* TinyGPUDriver.entitlements */,
0AFA851D2F1CE486005FDAC2 /* TinyGPUDriver.Release.entitlements */,
);
path = TinyGPUDriverExtension;
sourceTree = "<group>";
@@ -185,21 +205,22 @@
/* End PBXHeadersBuildPhase section */
/* Begin PBXNativeTarget section */
54E42BC3286A1697000E1E9A /* TinyGPU Installer (macOS) */ = {
54E42BC3286A1697000E1E9A /* TinyGPU */ = {
isa = PBXNativeTarget;
buildConfigurationList = 54E42BD2286A1697000E1E9A /* Build configuration list for PBXNativeTarget "TinyGPU Installer (macOS)" */;
buildConfigurationList = 54E42BD2286A1697000E1E9A /* Build configuration list for PBXNativeTarget "TinyGPU" */;
buildPhases = (
54E42BC0286A1697000E1E9A /* Sources */,
54E42BC1286A1697000E1E9A /* Frameworks */,
54E42BC2286A1697000E1E9A /* Resources */,
549EB122286A1D3A009D38AB /* Embed System Extensions */,
0AD7C2DB2F18D7D500562D1A /* CopyFiles */,
);
buildRules = (
);
dependencies = (
549EB127286A1D66009D38AB /* PBXTargetDependency */,
);
name = "TinyGPU Installer (macOS)";
name = TinyGPU;
productName = "SimpleAudioDriverExtension2 (macOS)";
productReference = 54E42BC4286A1697000E1E9A /* TinyGPU.app */;
productType = "com.apple.product-type.application";
@@ -236,7 +257,7 @@
TargetAttributes = {
54E42BC3286A1697000E1E9A = {
CreatedOnToolsVersion = 14.0;
LastSwiftMigration = 1400;
LastSwiftMigration = 2620;
};
C5B7D9BB26128AC50089B4C3 = {
CreatedOnToolsVersion = 13.0;
@@ -257,7 +278,7 @@
projectRoot = "";
targets = (
C5B7D9BB26128AC50089B4C3 /* TinyGPUDriver */,
54E42BC3286A1697000E1E9A /* TinyGPU Installer (macOS) */,
54E42BC3286A1697000E1E9A /* TinyGPU */,
);
};
/* End PBXProject section */
@@ -268,6 +289,7 @@
buildActionMask = 2147483647;
files = (
54E42BCC286A1697000E1E9A /* Assets.xcassets in Resources */,
0A52E8692F18FC6900A816CD /* tiny_icon.icon in Resources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@@ -285,9 +307,9 @@
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
549EB121286A1A37009D38AB /* TinyGPUViewModel.swift in Sources */,
54E42BCA286A1697000E1E9A /* TinyGPUView.swift in Sources */,
54E42BC8286A1697000E1E9A /* TinyGPUApp.swift in Sources */,
0A5C11DD2F18E466006DBBCA /* server.c in Sources */,
0AD7C2E52F18DEBC00562D1A /* TinyGPUCLIRunner.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@@ -316,12 +338,12 @@
54E42BCF286A1697000E1E9A /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
ASSETCATALOG_COMPILER_APPICON_NAME = tiny_icon;
ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
CLANG_ENABLE_MODULES = YES;
CODE_SIGN_ENTITLEMENTS = macOS/macOS.entitlements;
CODE_SIGN_IDENTITY = "-";
"CODE_SIGN_IDENTITY[sdk=macosx*]" = "-";
CODE_SIGN_IDENTITY = "Apple Development";
"CODE_SIGN_IDENTITY[sdk=macosx*]" = "Apple Development";
CODE_SIGN_STYLE = Automatic;
COMBINE_HIDPI_IMAGES = YES;
CURRENT_PROJECT_VERSION = 1;
@@ -331,19 +353,21 @@
ENABLE_PREVIEWS = YES;
ENABLE_USER_SCRIPT_SANDBOXING = YES;
GENERATE_INFOPLIST_FILE = YES;
INFOPLIST_KEY_LSApplicationCategoryType = "public.app-category.utilities";
INFOPLIST_KEY_NSHumanReadableCopyright = "";
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/../Frameworks",
);
MACOSX_DEPLOYMENT_TARGET = 12.1;
MARKETING_VERSION = 1.0;
MARKETING_VERSION = 1.0.0;
PRODUCT_BUNDLE_IDENTIFIER = org.tinygrad.tinygpu.installer;
PRODUCT_NAME = TinyGPU;
PROVISIONING_PROFILE_SPECIFIER = "";
SDKROOT = macosx;
SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG;
SWIFT_EMIT_LOC_STRINGS = YES;
SWIFT_OBJC_BRIDGING_HEADER = "Shared/TinyGPU-Bridging-Header.h";
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
SWIFT_VERSION = 5.0;
};
@@ -352,12 +376,12 @@
54E42BD0286A1697000E1E9A /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
ASSETCATALOG_COMPILER_APPICON_NAME = tiny_icon;
ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
CLANG_ENABLE_MODULES = YES;
CODE_SIGN_ENTITLEMENTS = macOS/macOS.entitlements;
CODE_SIGN_IDENTITY = "-";
"CODE_SIGN_IDENTITY[sdk=macosx*]" = "-";
CODE_SIGN_IDENTITY = "Apple Development";
"CODE_SIGN_IDENTITY[sdk=macosx*]" = "Apple Development";
CODE_SIGN_STYLE = Automatic;
COMBINE_HIDPI_IMAGES = YES;
CURRENT_PROJECT_VERSION = 1;
@@ -367,19 +391,21 @@
ENABLE_PREVIEWS = YES;
ENABLE_USER_SCRIPT_SANDBOXING = YES;
GENERATE_INFOPLIST_FILE = YES;
INFOPLIST_KEY_LSApplicationCategoryType = "public.app-category.utilities";
INFOPLIST_KEY_NSHumanReadableCopyright = "";
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/../Frameworks",
);
MACOSX_DEPLOYMENT_TARGET = 12.1;
MARKETING_VERSION = 1.0;
MARKETING_VERSION = 1.0.0;
PRODUCT_BUNDLE_IDENTIFIER = org.tinygrad.tinygpu.installer;
PRODUCT_NAME = TinyGPU;
PROVISIONING_PROFILE_SPECIFIER = "";
SDKROOT = macosx;
SWIFT_COMPILATION_MODE = wholemodule;
SWIFT_EMIT_LOC_STRINGS = YES;
SWIFT_OBJC_BRIDGING_HEADER = "Shared/TinyGPU-Bridging-Header.h";
SWIFT_OPTIMIZATION_LEVEL = "-O";
SWIFT_VERSION = 5.0;
};
@@ -477,6 +503,7 @@
CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
CODE_SIGN_IDENTITY = "Apple Development";
COPY_PHASE_STRIP = NO;
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
DRIVERKIT_DEPLOYMENT_TARGET = 21.0;
@@ -502,26 +529,29 @@
buildSettings = {
AD_HOC_CODE_SIGNING_ALLOWED = YES;
CODE_SIGN_ENTITLEMENTS = TinyGPUDriverExtension/TinyGPUDriver.entitlements;
CODE_SIGN_IDENTITY = "-";
CODE_SIGN_IDENTITY = "Apple Development";
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 1;
CURRENT_PROJECT_VERSION = 2;
DEVELOPMENT_TEAM = 9YG3G8543N;
DRIVERKIT_DEPLOYMENT_TARGET = 21.0;
ENABLE_USER_SCRIPT_SANDBOXING = YES;
EXCLUDED_ARCHS = "";
FRAMEWORK_SEARCH_PATHS = (
"$(inherited)",
"$(SDKROOT)/System/DriverKit/System/Library/Frameworks",
);
GENERATE_INFOPLIST_FILE = YES;
INFOPLIST_FILE = TinyGPUDriverExtension/Info.plist;
INFOPLIST_KEY_OSBundleUsageDescription = "Sample Code Audio Driver Kit Extension";
MARKETING_VERSION = 1.0;
INFOPLIST_KEY_OSBundleUsageDescription = "TinyGPU Driver";
IPHONEOS_DEPLOYMENT_TARGET = 17.6;
MARKETING_VERSION = 1.0.0;
PRODUCT_BUNDLE_IDENTIFIER = org.tinygrad.tinygpu.edriver;
PRODUCT_NAME = "$(inherited)";
PROVISIONING_PROFILE_SPECIFIER = "";
RUN_CLANG_STATIC_ANALYZER = YES;
SDKROOT = driverkit;
SKIP_INSTALL = YES;
SUPPORTED_PLATFORMS = driverkit;
};
name = Debug;
};
@@ -529,34 +559,40 @@
isa = XCBuildConfiguration;
buildSettings = {
AD_HOC_CODE_SIGNING_ALLOWED = YES;
CODE_SIGN_ENTITLEMENTS = TinyGPUDriverExtension/TinyGPUDriver.entitlements;
CODE_SIGN_IDENTITY = "-";
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 1;
DEVELOPMENT_TEAM = 9YG3G8543N;
CODE_SIGN_ENTITLEMENTS = TinyGPUDriverExtension/TinyGPUDriver.Release.entitlements;
CODE_SIGN_IDENTITY = "Apple Development";
"CODE_SIGN_IDENTITY[sdk=driverkit*]" = "Apple Development";
CODE_SIGN_STYLE = Manual;
CURRENT_PROJECT_VERSION = 2;
DEVELOPMENT_TEAM = "";
"DEVELOPMENT_TEAM[sdk=driverkit*]" = 9YG3G8543N;
DRIVERKIT_DEPLOYMENT_TARGET = 21.0;
ENABLE_USER_SCRIPT_SANDBOXING = YES;
EXCLUDED_ARCHS = "";
FRAMEWORK_SEARCH_PATHS = (
"$(inherited)",
"$(SDKROOT)/System/DriverKit/System/Library/Frameworks",
);
GENERATE_INFOPLIST_FILE = YES;
INFOPLIST_FILE = TinyGPUDriverExtension/Info.plist;
INFOPLIST_KEY_OSBundleUsageDescription = "Sample Code Audio Driver Kit Extension";
MARKETING_VERSION = 1.0;
INFOPLIST_KEY_OSBundleUsageDescription = "TinyGPU Driver";
IPHONEOS_DEPLOYMENT_TARGET = 17.6;
MARKETING_VERSION = 1.0.0;
ONLY_ACTIVE_ARCH = YES;
PRODUCT_BUNDLE_IDENTIFIER = org.tinygrad.tinygpu.edriver;
PRODUCT_NAME = "$(inherited)";
PROVISIONING_PROFILE_SPECIFIER = "";
RUN_CLANG_STATIC_ANALYZER = YES;
SDKROOT = driverkit;
SKIP_INSTALL = YES;
SUPPORTED_PLATFORMS = driverkit;
};
name = Release;
};
/* End XCBuildConfiguration section */
/* Begin XCConfigurationList section */
54E42BD2286A1697000E1E9A /* Build configuration list for PBXNativeTarget "TinyGPU Installer (macOS)" */ = {
54E42BD2286A1697000E1E9A /* Build configuration list for PBXNativeTarget "TinyGPU" */ = {
isa = XCConfigurationList;
buildConfigurations = (
54E42BCF286A1697000E1E9A /* Debug */,

View File

@@ -0,0 +1,17 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>com.apple.developer.driverkit</key>
<true/>
<key>com.apple.developer.driverkit.transport.pci</key>
<array>
<dict>
<key>IOPCIPrimaryMatch</key>
<string>0xFFFFFFFF&amp;0x00000000</string>
</dict>
</array>
<key>com.apple.developer.driverkit.allow-any-userclient-access</key>
<true/>
</dict>
</plist>

View File

@@ -0,0 +1,17 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>com.apple.application-identifier</key>
<string>9YG3G8543N.org.tinygrad.tinygpu.edriver</string>
<key>com.apple.developer.driverkit</key>
<true/>
<key>com.apple.developer.driverkit.transport.pci</key>
<array>
<dict>
<key>IOPCIPrimaryMatch</key>
<string>4098</string>
</dict>
</array>
</dict>
</plist>

View File

@@ -11,7 +11,5 @@
<string>0xFFFFFFFF&amp;0x00000000</string>
</dict>
</array>
<key>com.apple.developer.driverkit.allow-any-userclient-access</key>
<true/>
</dict>
</plist>

View File

@@ -0,0 +1,33 @@
#!/bin/bash
set -e
xcodebuild clean build CODE_SIGN_IDENTITY="" CODE_SIGNING_REQUIRED=NO -alltargets -configuration Release build
cp "../profiles/devid_provisioning.provisionprofile" "./build/Release/TinyGPU.app/Contents/Library/SystemExtensions/org.tinygrad.tinygpu.edriver.dext/embedded.provisionprofile"
cp "../profiles/installer_provisioning.provisionprofile" "./build/Release/TinyGPU.app/Contents/embedded.provisionprofile"
codesign \
--sign "Developer ID Application: tinygrad, Corp. (9YG3G8543N)" \
--entitlements ./TinyGPUDriverExtension/TinyGPUDriver.Release.entitlements \
--verbose \
--options runtime \
--timestamp \
--force \
./build/Release/TinyGPU.app/Contents/Library/SystemExtensions/org.tinygrad.tinygpu.edriver.dext
codesign \
--sign "Developer ID Application: tinygrad, Corp. (9YG3G8543N)" \
--entitlements ./macOS/macOS.entitlements \
--options runtime \
--verbose \
--timestamp \
--force \
./build/Release/TinyGPU.app
codesign --verify --deep --strict --verbose=4 ./build/Release/TinyGPU.app/Contents/Library/SystemExtensions/org.tinygrad.tinygpu.edriver.dext
codesign --verify --deep --strict --verbose=4 ./build/Release/TinyGPU.app
spctl -a -vv ./build/Release/TinyGPU.app
spctl -a -vv ./build/Release/TinyGPU.app/Contents/Library/SystemExtensions/org.tinygrad.tinygpu.edriver.dext

View File

@@ -0,0 +1,52 @@
#!/bin/bash
set -e
# Check SIP status if not building only
if [[ "$1" != "--build" ]]; then
SIP_STATUS=$(csrutil status 2>&1)
if [[ "$SIP_STATUS" == *"enabled"* ]]; then
echo "ERROR: System Integrity Protection (SIP) is enabled."
echo "This dev build requires SIP to be disabled to load unsigned dexts."
echo ""
echo "To disable SIP:"
echo " 1. Restart and hold Power button (M1+) or Cmd+R (Intel)"
echo " 2. Open Terminal from Recovery menu"
echo " 3. Run: csrutil disable"
echo " 4. Restart"
exit 1
fi
fi
echo "SIP is disabled, proceeding with dev build..."
cd "$(dirname "$0")"
# Build without code signing
xcodebuild clean build CODE_SIGN_IDENTITY="" CODE_SIGNING_REQUIRED=NO -alltargets -configuration Debug build
APP_PATH="./build/Debug/TinyGPU.app"
DEXT_PATH="$APP_PATH/Contents/Library/SystemExtensions/org.tinygrad.tinygpu.edriver.dext"
# Ad-hoc sign with dev entitlements (matches any GPU)
codesign --sign - --entitlements ./TinyGPUDriverExtension/TinyGPUDriver.NoSIP.entitlements --force --timestamp --verbose "$DEXT_PATH"
codesign --sign - --entitlements ./macOS/macOS.entitlements --force --timestamp --verbose "$APP_PATH"
echo "Build complete: $APP_PATH"
if [[ "$1" == "--build" ]]; then
exit 0
fi
# Install
echo "Installing to /Applications..."
if [ -d "/Applications/TinyGPU.app" ]; then
echo "Removing existing /Applications/TinyGPU.app..."
rm -rf "/Applications/TinyGPU.app"
fi
cp -r "$APP_PATH" /Applications/
echo "Installed to /Applications/TinyGPU.app"
echo "Activating driver extension..."
/Applications/TinyGPU.app/Contents/MacOS/TinyGPU install

View File

@@ -8,5 +8,9 @@
<true/>
<key>com.apple.developer.system-extension.install</key>
<true/>
<key>com.apple.developer.driverkit.userclient-access</key>
<array>
<string>org.tinygrad.tinygpu.edriver</string>
</array>
</dict>
</plist>

View File

@@ -0,0 +1,5 @@
#!/bin/bash
set -e
ditto -c -k --keepParent ./build/Release/TinyGPU.app ./build/Release/TinyGPU.zip
xcrun notarytool submit ./build/Release/TinyGPU.zip --keychain-profile "hgwJFhdheiIEy82nDN" --wait

View File

@@ -0,0 +1,2 @@
#!/bin/bash
pkill -f "tinygpu.sock"

View File

@@ -1,39 +0,0 @@
#include <CoreFoundation/CoreFoundation.h>
#include <IOKit/IOKitLib.h>
#include <mach/mach.h>
#include <stdio.h>
#include <inttypes.h>
static io_connect_t open_uc_by_name(const char *svc_name) {
io_connect_t conn = IO_OBJECT_NULL;
io_service_t service = IOServiceGetMatchingService(kIOMasterPortDefault, IOServiceNameMatching(svc_name));
if (!service) { fprintf(stderr, "service not found: %s\n", svc_name); return IO_OBJECT_NULL; }
kern_return_t kr = IOServiceOpen(service, mach_task_self(), /*type*/0, &conn);
IOObjectRelease(service);
if (kr) { fprintf(stderr, "IOServiceOpen 0x%x\n", kr); return IO_OBJECT_NULL; }
return conn;
}
int main(int argc, char **argv) {
uint32_t bar = (argc > 1) ? (uint32_t)strtoul(argv[1], NULL, 0) : 0; // pick BAR index
io_connect_t conn = open_uc_by_name("tinygpu");
if (!conn) return 2;
mach_vm_address_t addr = 0;
mach_vm_size_t size = 0;
kern_return_t kr = IOConnectMapMemory64(conn, bar, mach_task_self(), &addr, &size, kIOMapAnywhere);
if (kr) { fprintf(stderr, "Map BAR%u failed 0x%x\n", bar, kr); IOServiceClose(conn); return 3; }
printf("BAR%u mapped at 0x%llx, size 0x%llx\n", bar, (unsigned long long)addr, (unsigned long long)size);
// example: read a 32-bit register at offset 0x0 (make sure its safe!)
volatile uint32_t *mmio = (volatile uint32_t*)(uintptr_t)addr;
uint32_t v = mmio[0];
printf("mmio[0]=0x%08x\n", v);
kr = IOConnectUnmapMemory64(conn, bar, mach_task_self(), addr);
if (kr) fprintf(stderr, "Unmap failed 0x%x\n", kr);
IOServiceClose(conn);
return 0;
}

View File

@@ -1,82 +0,0 @@
import ctypes, ctypes.util, sys
cf = ctypes.CDLL(ctypes.util.find_library("CoreFoundation"))
iokit = ctypes.CDLL(ctypes.util.find_library("IOKit"))
libsys = ctypes.CDLL(ctypes.util.find_library("System"))
kern_return_t = ctypes.c_int
mach_port_t = ctypes.c_uint
io_object_t = mach_port_t
io_service_t = io_object_t
io_connect_t = mach_port_t
CFMutableDictionaryRef = ctypes.c_void_p
CFStringRef = ctypes.c_void_p
kIOMasterPortDefault = mach_port_t(0)
libsys.mach_task_self_.restype = mach_port_t
iokit.IOServiceNameMatching.argtypes = [ctypes.c_char_p]
iokit.IOServiceNameMatching.restype = CFMutableDictionaryRef
iokit.IOServiceGetMatchingService.argtypes = [mach_port_t, CFMutableDictionaryRef]
iokit.IOServiceGetMatchingService.restype = io_service_t
iokit.IOObjectRelease.argtypes = [io_object_t]
iokit.IOObjectRelease.restype = kern_return_t
iokit.IOServiceOpen.argtypes = [io_service_t, mach_port_t, ctypes.c_uint32, ctypes.POINTER(io_connect_t)]
iokit.IOServiceOpen.restype = kern_return_t
iokit.IOConnectCallMethod.argtypes = [io_connect_t, ctypes.c_uint32, ctypes.POINTER(ctypes.c_uint64), ctypes.c_uint32, ctypes.c_void_p,
ctypes.c_size_t, ctypes.POINTER(ctypes.c_uint64), ctypes.POINTER(ctypes.c_uint32), ctypes.c_void_p, ctypes.POINTER(ctypes.c_size_t)]
iokit.IOConnectCallMethod.restype = kern_return_t
def open_userclient_by_name(name: str, uc_type: int = 0) -> io_connect_t:
mdict = iokit.IOServiceNameMatching(name.encode("utf-8"))
if not mdict: raise RuntimeError("IOServiceNameMatching returned NULL")
# Grab the first matching service
service = iokit.IOServiceGetMatchingService(kIOMasterPortDefault, mdict)
if not service: raise RuntimeError(f'service "{name}" not found')
# print("lol", service)
# print(libsys.mach_task_self_)
# cast libsys.mach_task_self_ to uint and print
# print("lol", ctypes.cast(libsys.mach_task_self_, ctypes.POINTER(ctypes.c_uint)).contents.value)
try:
# Open user client (type -> passed to NewUserClient_Impl)
conn = io_connect_t(0)
# print("lol", libsys.mach_task_self_)
kr = iokit.IOServiceOpen(service, ctypes.cast(libsys.mach_task_self_, ctypes.POINTER(ctypes.c_uint)).contents.value,
ctypes.c_uint32(uc_type), ctypes.byref(conn))
if kr != 0: raise OSError(kr, f"IOServiceOpen failed (0x{kr:08x})")
return conn
finally: iokit.IOObjectRelease(service)
def external_method(conn: io_connect_t, selector: int = 0) -> int:
# no scalars in/out, no struct in/out — just ping selector 0
in_scalars = ctypes.POINTER(ctypes.c_uint64)() # NULL
out_scalars = (ctypes.c_uint64 * 1)() # space if driver returns something
out_scalars_cnt = ctypes.c_uint32(0) # driver can set this
return iokit.IOConnectCallMethod(conn, ctypes.c_uint32(selector), in_scalars, ctypes.c_uint32(0), None, ctypes.c_size_t(0),
out_scalars, ctypes.byref(out_scalars_cnt), None, ctypes.byref(ctypes.c_size_t(0)))
def close_userclient(conn: io_connect_t) -> None:
# IOServiceClose is a macro; exported symbol is IOServiceClose in IOKit
iokit.IOServiceClose.argtypes = [io_connect_t]
iokit.IOServiceClose.restype = kern_return_t
iokit.IOServiceClose(conn)
if __name__ == "__main__":
try:
conn = open_userclient_by_name("tinygpu", uc_type=0)
kr = external_method(conn, selector=0)
print(f"ExternalMethod(0) -> 0x{kr:08x}")
except Exception as e:
print(e)
sys.exit(1)
finally:
if 'conn' in locals() and conn.value: close_userclient(conn)

View File

@@ -141,4 +141,9 @@ def __getattr__(nm):
return load("metal", "'Metal'", [f"{macossdk}/System/Library/Frameworks/Metal.framework/Headers/MTL{s}.h" for s in
["ComputeCommandEncoder", "ComputePipeline", "CommandQueue", "Device", "IndirectCommandBuffer", "Resource", "CommandEncoder"]],
args=["-xobjective-c","-isysroot",macossdk], types={"dispatch_data_t":"objc.id_"})
case "iokit": return load("iokit", "'IOKit'", [f"{macossdk}/System/Library/Frameworks/IOKit.framework/Headers/IOKitLib.h"],
args=["-isysroot", macossdk])
case "corefoundation": return load("corefoundation", "'CoreFoundation'",
[f"{macossdk}/System/Library/Frameworks/CoreFoundation.framework/Headers/CF{s}.h" for s in ["String", "Data"]],
args=["-isysroot", macossdk])
case _: raise AttributeError(f"no such autogen: {nm}")

View File

@@ -0,0 +1,345 @@
# mypy: disable-error-code="empty-body"
from __future__ import annotations
import ctypes
from typing import Annotated, Literal, TypeAlias
from tinygrad.runtime.support.c import _IO, _IOW, _IOR, _IOWR
from tinygrad.runtime.support import c
dll = c.DLL('corefoundation', 'CoreFoundation')
CFStringEncoding: TypeAlias = Annotated[int, ctypes.c_uint32]
CFStringBuiltInEncodings: TypeAlias = Annotated[int, ctypes.c_uint32]
class _anonenum0(Annotated[int, ctypes.c_uint32], c.Enum): pass
kCFStringEncodingMacRoman = _anonenum0.define('kCFStringEncodingMacRoman', 0)
kCFStringEncodingWindowsLatin1 = _anonenum0.define('kCFStringEncodingWindowsLatin1', 1280)
kCFStringEncodingISOLatin1 = _anonenum0.define('kCFStringEncodingISOLatin1', 513)
kCFStringEncodingNextStepLatin = _anonenum0.define('kCFStringEncodingNextStepLatin', 2817)
kCFStringEncodingASCII = _anonenum0.define('kCFStringEncodingASCII', 1536)
kCFStringEncodingUnicode = _anonenum0.define('kCFStringEncodingUnicode', 256)
kCFStringEncodingUTF8 = _anonenum0.define('kCFStringEncodingUTF8', 134217984)
kCFStringEncodingNonLossyASCII = _anonenum0.define('kCFStringEncodingNonLossyASCII', 3071)
kCFStringEncodingUTF16 = _anonenum0.define('kCFStringEncodingUTF16', 256)
kCFStringEncodingUTF16BE = _anonenum0.define('kCFStringEncodingUTF16BE', 268435712)
kCFStringEncodingUTF16LE = _anonenum0.define('kCFStringEncodingUTF16LE', 335544576)
kCFStringEncodingUTF32 = _anonenum0.define('kCFStringEncodingUTF32', 201326848)
kCFStringEncodingUTF32BE = _anonenum0.define('kCFStringEncodingUTF32BE', 402653440)
kCFStringEncodingUTF32LE = _anonenum0.define('kCFStringEncodingUTF32LE', 469762304)
CFTypeID: TypeAlias = Annotated[int, ctypes.c_uint64]
@dll.bind
def CFStringGetTypeID() -> CFTypeID: ...
class struct___CFAllocator(ctypes.Structure): pass
CFAllocatorRef: TypeAlias = c.POINTER[struct___CFAllocator]
ConstStr255Param: TypeAlias = c.POINTER[Annotated[int, ctypes.c_ubyte]]
class struct___CFString(ctypes.Structure): pass
CFStringRef: TypeAlias = c.POINTER[struct___CFString]
@dll.bind
def CFStringCreateWithPascalString(alloc:CFAllocatorRef, pStr:ConstStr255Param, encoding:CFStringEncoding) -> CFStringRef: ...
@dll.bind
def CFStringCreateWithCString(alloc:CFAllocatorRef, cStr:c.POINTER[Annotated[bytes, ctypes.c_char]], encoding:CFStringEncoding) -> CFStringRef: ...
UInt8: TypeAlias = Annotated[int, ctypes.c_ubyte]
CFIndex: TypeAlias = Annotated[int, ctypes.c_int64]
Boolean: TypeAlias = Annotated[int, ctypes.c_ubyte]
@dll.bind
def CFStringCreateWithBytes(alloc:CFAllocatorRef, bytes:c.POINTER[UInt8], numBytes:CFIndex, encoding:CFStringEncoding, isExternalRepresentation:Boolean) -> CFStringRef: ...
UniChar: TypeAlias = Annotated[int, ctypes.c_uint16]
@dll.bind
def CFStringCreateWithCharacters(alloc:CFAllocatorRef, chars:c.POINTER[UniChar], numChars:CFIndex) -> CFStringRef: ...
@dll.bind
def CFStringCreateWithPascalStringNoCopy(alloc:CFAllocatorRef, pStr:ConstStr255Param, encoding:CFStringEncoding, contentsDeallocator:CFAllocatorRef) -> CFStringRef: ...
@dll.bind
def CFStringCreateWithCStringNoCopy(alloc:CFAllocatorRef, cStr:c.POINTER[Annotated[bytes, ctypes.c_char]], encoding:CFStringEncoding, contentsDeallocator:CFAllocatorRef) -> CFStringRef: ...
@dll.bind
def CFStringCreateWithBytesNoCopy(alloc:CFAllocatorRef, bytes:c.POINTER[UInt8], numBytes:CFIndex, encoding:CFStringEncoding, isExternalRepresentation:Boolean, contentsDeallocator:CFAllocatorRef) -> CFStringRef: ...
@dll.bind
def CFStringCreateWithCharactersNoCopy(alloc:CFAllocatorRef, chars:c.POINTER[UniChar], numChars:CFIndex, contentsDeallocator:CFAllocatorRef) -> CFStringRef: ...
@c.record
class CFRange(c.Struct):
SIZE = 16
location: Annotated[CFIndex, 0]
length: Annotated[CFIndex, 8]
@dll.bind
def CFStringCreateWithSubstring(alloc:CFAllocatorRef, str:CFStringRef, range:CFRange) -> CFStringRef: ...
@dll.bind
def CFStringCreateCopy(alloc:CFAllocatorRef, theString:CFStringRef) -> CFStringRef: ...
class struct___CFDictionary(ctypes.Structure): pass
CFDictionaryRef: TypeAlias = c.POINTER[struct___CFDictionary]
@dll.bind
def CFStringCreateWithFormat(alloc:CFAllocatorRef, formatOptions:CFDictionaryRef, format:CFStringRef) -> CFStringRef: ...
@dll.bind
def CFStringCreateWithFormatAndArguments(alloc:CFAllocatorRef, formatOptions:CFDictionaryRef, format:CFStringRef, arguments:Annotated[int, ctypes.c_int32]) -> CFStringRef: ...
class struct___CFError(ctypes.Structure): pass
CFErrorRef: TypeAlias = c.POINTER[struct___CFError]
@dll.bind
def CFStringCreateStringWithValidatedFormat(alloc:CFAllocatorRef, formatOptions:CFDictionaryRef, validFormatSpecifiers:CFStringRef, format:CFStringRef, errorPtr:c.POINTER[CFErrorRef]) -> CFStringRef: ...
@dll.bind
def CFStringCreateStringWithValidatedFormatAndArguments(alloc:CFAllocatorRef, formatOptions:CFDictionaryRef, validFormatSpecifiers:CFStringRef, format:CFStringRef, arguments:Annotated[int, ctypes.c_int32], errorPtr:c.POINTER[CFErrorRef]) -> CFStringRef: ...
CFMutableStringRef: TypeAlias = c.POINTER[struct___CFString]
@dll.bind
def CFStringCreateMutable(alloc:CFAllocatorRef, maxLength:CFIndex) -> CFMutableStringRef: ...
@dll.bind
def CFStringCreateMutableCopy(alloc:CFAllocatorRef, maxLength:CFIndex, theString:CFStringRef) -> CFMutableStringRef: ...
@dll.bind
def CFStringCreateMutableWithExternalCharactersNoCopy(alloc:CFAllocatorRef, chars:c.POINTER[UniChar], numChars:CFIndex, capacity:CFIndex, externalCharactersAllocator:CFAllocatorRef) -> CFMutableStringRef: ...
@dll.bind
def CFStringGetLength(theString:CFStringRef) -> CFIndex: ...
@dll.bind
def CFStringGetCharacterAtIndex(theString:CFStringRef, idx:CFIndex) -> UniChar: ...
@dll.bind
def CFStringGetCharacters(theString:CFStringRef, range:CFRange, buffer:c.POINTER[UniChar]) -> None: ...
StringPtr: TypeAlias = c.POINTER[Annotated[int, ctypes.c_ubyte]]
@dll.bind
def CFStringGetPascalString(theString:CFStringRef, buffer:StringPtr, bufferSize:CFIndex, encoding:CFStringEncoding) -> Boolean: ...
@dll.bind
def CFStringGetCString(theString:CFStringRef, buffer:c.POINTER[Annotated[bytes, ctypes.c_char]], bufferSize:CFIndex, encoding:CFStringEncoding) -> Boolean: ...
ConstStringPtr: TypeAlias = c.POINTER[Annotated[int, ctypes.c_ubyte]]
@dll.bind
def CFStringGetPascalStringPtr(theString:CFStringRef, encoding:CFStringEncoding) -> ConstStringPtr: ...
@dll.bind
def CFStringGetCStringPtr(theString:CFStringRef, encoding:CFStringEncoding) -> c.POINTER[Annotated[bytes, ctypes.c_char]]: ...
@dll.bind
def CFStringGetCharactersPtr(theString:CFStringRef) -> c.POINTER[UniChar]: ...
@dll.bind
def CFStringGetBytes(theString:CFStringRef, range:CFRange, encoding:CFStringEncoding, lossByte:UInt8, isExternalRepresentation:Boolean, buffer:c.POINTER[UInt8], maxBufLen:CFIndex, usedBufLen:c.POINTER[CFIndex]) -> CFIndex: ...
class struct___CFData(ctypes.Structure): pass
CFDataRef: TypeAlias = c.POINTER[struct___CFData]
@dll.bind
def CFStringCreateFromExternalRepresentation(alloc:CFAllocatorRef, data:CFDataRef, encoding:CFStringEncoding) -> CFStringRef: ...
@dll.bind
def CFStringCreateExternalRepresentation(alloc:CFAllocatorRef, theString:CFStringRef, encoding:CFStringEncoding, lossByte:UInt8) -> CFDataRef: ...
@dll.bind
def CFStringGetSmallestEncoding(theString:CFStringRef) -> CFStringEncoding: ...
@dll.bind
def CFStringGetFastestEncoding(theString:CFStringRef) -> CFStringEncoding: ...
@dll.bind
def CFStringGetSystemEncoding() -> CFStringEncoding: ...
@dll.bind
def CFStringGetMaximumSizeForEncoding(length:CFIndex, encoding:CFStringEncoding) -> CFIndex: ...
@dll.bind
def CFStringGetFileSystemRepresentation(string:CFStringRef, buffer:c.POINTER[Annotated[bytes, ctypes.c_char]], maxBufLen:CFIndex) -> Boolean: ...
@dll.bind
def CFStringGetMaximumSizeOfFileSystemRepresentation(string:CFStringRef) -> CFIndex: ...
@dll.bind
def CFStringCreateWithFileSystemRepresentation(alloc:CFAllocatorRef, buffer:c.POINTER[Annotated[bytes, ctypes.c_char]]) -> CFStringRef: ...
CFStringCompareFlags: TypeAlias = Annotated[int, ctypes.c_uint64]
class _anonenum1(Annotated[int, ctypes.c_uint32], c.Enum): pass
kCFCompareCaseInsensitive = _anonenum1.define('kCFCompareCaseInsensitive', 1)
kCFCompareBackwards = _anonenum1.define('kCFCompareBackwards', 4)
kCFCompareAnchored = _anonenum1.define('kCFCompareAnchored', 8)
kCFCompareNonliteral = _anonenum1.define('kCFCompareNonliteral', 16)
kCFCompareLocalized = _anonenum1.define('kCFCompareLocalized', 32)
kCFCompareNumerically = _anonenum1.define('kCFCompareNumerically', 64)
kCFCompareDiacriticInsensitive = _anonenum1.define('kCFCompareDiacriticInsensitive', 128)
kCFCompareWidthInsensitive = _anonenum1.define('kCFCompareWidthInsensitive', 256)
kCFCompareForcedOrdering = _anonenum1.define('kCFCompareForcedOrdering', 512)
class struct___CFLocale(ctypes.Structure): pass
CFLocaleRef: TypeAlias = c.POINTER[struct___CFLocale]
CFComparisonResult: TypeAlias = Annotated[int, ctypes.c_int64]
@dll.bind
def CFStringCompareWithOptionsAndLocale(theString1:CFStringRef, theString2:CFStringRef, rangeToCompare:CFRange, compareOptions:CFStringCompareFlags, locale:CFLocaleRef) -> CFComparisonResult: ...
@dll.bind
def CFStringCompareWithOptions(theString1:CFStringRef, theString2:CFStringRef, rangeToCompare:CFRange, compareOptions:CFStringCompareFlags) -> CFComparisonResult: ...
@dll.bind
def CFStringCompare(theString1:CFStringRef, theString2:CFStringRef, compareOptions:CFStringCompareFlags) -> CFComparisonResult: ...
@dll.bind
def CFStringFindWithOptionsAndLocale(theString:CFStringRef, stringToFind:CFStringRef, rangeToSearch:CFRange, searchOptions:CFStringCompareFlags, locale:CFLocaleRef, result:c.POINTER[CFRange]) -> Boolean: ...
@dll.bind
def CFStringFindWithOptions(theString:CFStringRef, stringToFind:CFStringRef, rangeToSearch:CFRange, searchOptions:CFStringCompareFlags, result:c.POINTER[CFRange]) -> Boolean: ...
class struct___CFArray(ctypes.Structure): pass
CFArrayRef: TypeAlias = c.POINTER[struct___CFArray]
@dll.bind
def CFStringCreateArrayWithFindResults(alloc:CFAllocatorRef, theString:CFStringRef, stringToFind:CFStringRef, rangeToSearch:CFRange, compareOptions:CFStringCompareFlags) -> CFArrayRef: ...
@dll.bind
def CFStringFind(theString:CFStringRef, stringToFind:CFStringRef, compareOptions:CFStringCompareFlags) -> CFRange: ...
@dll.bind
def CFStringHasPrefix(theString:CFStringRef, prefix:CFStringRef) -> Boolean: ...
@dll.bind
def CFStringHasSuffix(theString:CFStringRef, suffix:CFStringRef) -> Boolean: ...
@dll.bind
def CFStringGetRangeOfComposedCharactersAtIndex(theString:CFStringRef, theIndex:CFIndex) -> CFRange: ...
class struct___CFCharacterSet(ctypes.Structure): pass
CFCharacterSetRef: TypeAlias = c.POINTER[struct___CFCharacterSet]
@dll.bind
def CFStringFindCharacterFromSet(theString:CFStringRef, theSet:CFCharacterSetRef, rangeToSearch:CFRange, searchOptions:CFStringCompareFlags, result:c.POINTER[CFRange]) -> Boolean: ...
@dll.bind
def CFStringGetLineBounds(theString:CFStringRef, range:CFRange, lineBeginIndex:c.POINTER[CFIndex], lineEndIndex:c.POINTER[CFIndex], contentsEndIndex:c.POINTER[CFIndex]) -> None: ...
@dll.bind
def CFStringGetParagraphBounds(string:CFStringRef, range:CFRange, parBeginIndex:c.POINTER[CFIndex], parEndIndex:c.POINTER[CFIndex], contentsEndIndex:c.POINTER[CFIndex]) -> None: ...
CFOptionFlags: TypeAlias = Annotated[int, ctypes.c_uint64]
UTF32Char: TypeAlias = Annotated[int, ctypes.c_uint32]
@dll.bind
def CFStringGetHyphenationLocationBeforeIndex(string:CFStringRef, location:CFIndex, limitRange:CFRange, options:CFOptionFlags, locale:CFLocaleRef, character:c.POINTER[UTF32Char]) -> CFIndex: ...
@dll.bind
def CFStringIsHyphenationAvailableForLocale(locale:CFLocaleRef) -> Boolean: ...
@dll.bind
def CFStringCreateByCombiningStrings(alloc:CFAllocatorRef, theArray:CFArrayRef, separatorString:CFStringRef) -> CFStringRef: ...
@dll.bind
def CFStringCreateArrayBySeparatingStrings(alloc:CFAllocatorRef, theString:CFStringRef, separatorString:CFStringRef) -> CFArrayRef: ...
SInt32: TypeAlias = Annotated[int, ctypes.c_int32]
@dll.bind
def CFStringGetIntValue(str:CFStringRef) -> SInt32: ...
@dll.bind
def CFStringGetDoubleValue(str:CFStringRef) -> Annotated[float, ctypes.c_double]: ...
@dll.bind
def CFStringAppend(theString:CFMutableStringRef, appendedString:CFStringRef) -> None: ...
@dll.bind
def CFStringAppendCharacters(theString:CFMutableStringRef, chars:c.POINTER[UniChar], numChars:CFIndex) -> None: ...
@dll.bind
def CFStringAppendPascalString(theString:CFMutableStringRef, pStr:ConstStr255Param, encoding:CFStringEncoding) -> None: ...
@dll.bind
def CFStringAppendCString(theString:CFMutableStringRef, cStr:c.POINTER[Annotated[bytes, ctypes.c_char]], encoding:CFStringEncoding) -> None: ...
@dll.bind
def CFStringAppendFormat(theString:CFMutableStringRef, formatOptions:CFDictionaryRef, format:CFStringRef) -> None: ...
@dll.bind
def CFStringAppendFormatAndArguments(theString:CFMutableStringRef, formatOptions:CFDictionaryRef, format:CFStringRef, arguments:Annotated[int, ctypes.c_int32]) -> None: ...
@dll.bind
def CFStringInsert(str:CFMutableStringRef, idx:CFIndex, insertedStr:CFStringRef) -> None: ...
@dll.bind
def CFStringDelete(theString:CFMutableStringRef, range:CFRange) -> None: ...
@dll.bind
def CFStringReplace(theString:CFMutableStringRef, range:CFRange, replacement:CFStringRef) -> None: ...
@dll.bind
def CFStringReplaceAll(theString:CFMutableStringRef, replacement:CFStringRef) -> None: ...
@dll.bind
def CFStringFindAndReplace(theString:CFMutableStringRef, stringToFind:CFStringRef, replacementString:CFStringRef, rangeToSearch:CFRange, compareOptions:CFStringCompareFlags) -> CFIndex: ...
@dll.bind
def CFStringSetExternalCharactersNoCopy(theString:CFMutableStringRef, chars:c.POINTER[UniChar], length:CFIndex, capacity:CFIndex) -> None: ...
@dll.bind
def CFStringPad(theString:CFMutableStringRef, padString:CFStringRef, length:CFIndex, indexIntoPad:CFIndex) -> None: ...
@dll.bind
def CFStringTrim(theString:CFMutableStringRef, trimString:CFStringRef) -> None: ...
@dll.bind
def CFStringTrimWhitespace(theString:CFMutableStringRef) -> None: ...
@dll.bind
def CFStringLowercase(theString:CFMutableStringRef, locale:CFLocaleRef) -> None: ...
@dll.bind
def CFStringUppercase(theString:CFMutableStringRef, locale:CFLocaleRef) -> None: ...
@dll.bind
def CFStringCapitalize(theString:CFMutableStringRef, locale:CFLocaleRef) -> None: ...
CFStringNormalizationForm: TypeAlias = Annotated[int, ctypes.c_int64]
class _anonenum2(Annotated[int, ctypes.c_uint32], c.Enum): pass
kCFStringNormalizationFormD = _anonenum2.define('kCFStringNormalizationFormD', 0)
kCFStringNormalizationFormKD = _anonenum2.define('kCFStringNormalizationFormKD', 1)
kCFStringNormalizationFormC = _anonenum2.define('kCFStringNormalizationFormC', 2)
kCFStringNormalizationFormKC = _anonenum2.define('kCFStringNormalizationFormKC', 3)
@dll.bind
def CFStringNormalize(theString:CFMutableStringRef, theForm:CFStringNormalizationForm) -> None: ...
@dll.bind
def CFStringFold(theString:CFMutableStringRef, theFlags:CFStringCompareFlags, theLocale:CFLocaleRef) -> None: ...
@dll.bind
def CFStringTransform(string:CFMutableStringRef, range:c.POINTER[CFRange], transform:CFStringRef, reverse:Boolean) -> Boolean: ...
try: kCFStringTransformStripCombiningMarks = CFStringRef.in_dll(dll, 'kCFStringTransformStripCombiningMarks') # type: ignore
except (ValueError,AttributeError): pass
try: kCFStringTransformToLatin = CFStringRef.in_dll(dll, 'kCFStringTransformToLatin') # type: ignore
except (ValueError,AttributeError): pass
try: kCFStringTransformFullwidthHalfwidth = CFStringRef.in_dll(dll, 'kCFStringTransformFullwidthHalfwidth') # type: ignore
except (ValueError,AttributeError): pass
try: kCFStringTransformLatinKatakana = CFStringRef.in_dll(dll, 'kCFStringTransformLatinKatakana') # type: ignore
except (ValueError,AttributeError): pass
try: kCFStringTransformLatinHiragana = CFStringRef.in_dll(dll, 'kCFStringTransformLatinHiragana') # type: ignore
except (ValueError,AttributeError): pass
try: kCFStringTransformHiraganaKatakana = CFStringRef.in_dll(dll, 'kCFStringTransformHiraganaKatakana') # type: ignore
except (ValueError,AttributeError): pass
try: kCFStringTransformMandarinLatin = CFStringRef.in_dll(dll, 'kCFStringTransformMandarinLatin') # type: ignore
except (ValueError,AttributeError): pass
try: kCFStringTransformLatinHangul = CFStringRef.in_dll(dll, 'kCFStringTransformLatinHangul') # type: ignore
except (ValueError,AttributeError): pass
try: kCFStringTransformLatinArabic = CFStringRef.in_dll(dll, 'kCFStringTransformLatinArabic') # type: ignore
except (ValueError,AttributeError): pass
try: kCFStringTransformLatinHebrew = CFStringRef.in_dll(dll, 'kCFStringTransformLatinHebrew') # type: ignore
except (ValueError,AttributeError): pass
try: kCFStringTransformLatinThai = CFStringRef.in_dll(dll, 'kCFStringTransformLatinThai') # type: ignore
except (ValueError,AttributeError): pass
try: kCFStringTransformLatinCyrillic = CFStringRef.in_dll(dll, 'kCFStringTransformLatinCyrillic') # type: ignore
except (ValueError,AttributeError): pass
try: kCFStringTransformLatinGreek = CFStringRef.in_dll(dll, 'kCFStringTransformLatinGreek') # type: ignore
except (ValueError,AttributeError): pass
try: kCFStringTransformToXMLHex = CFStringRef.in_dll(dll, 'kCFStringTransformToXMLHex') # type: ignore
except (ValueError,AttributeError): pass
try: kCFStringTransformToUnicodeName = CFStringRef.in_dll(dll, 'kCFStringTransformToUnicodeName') # type: ignore
except (ValueError,AttributeError): pass
try: kCFStringTransformStripDiacritics = CFStringRef.in_dll(dll, 'kCFStringTransformStripDiacritics') # type: ignore
except (ValueError,AttributeError): pass
@dll.bind
def CFStringIsEncodingAvailable(encoding:CFStringEncoding) -> Boolean: ...
@dll.bind
def CFStringGetListOfAvailableEncodings() -> c.POINTER[CFStringEncoding]: ...
@dll.bind
def CFStringGetNameOfEncoding(encoding:CFStringEncoding) -> CFStringRef: ...
@dll.bind
def CFStringConvertEncodingToNSStringEncoding(encoding:CFStringEncoding) -> Annotated[int, ctypes.c_uint64]: ...
@dll.bind
def CFStringConvertNSStringEncodingToEncoding(encoding:Annotated[int, ctypes.c_uint64]) -> CFStringEncoding: ...
UInt32: TypeAlias = Annotated[int, ctypes.c_uint32]
@dll.bind
def CFStringConvertEncodingToWindowsCodepage(encoding:CFStringEncoding) -> UInt32: ...
@dll.bind
def CFStringConvertWindowsCodepageToEncoding(codepage:UInt32) -> CFStringEncoding: ...
@dll.bind
def CFStringConvertIANACharSetNameToEncoding(theString:CFStringRef) -> CFStringEncoding: ...
@dll.bind
def CFStringConvertEncodingToIANACharSetName(encoding:CFStringEncoding) -> CFStringRef: ...
@dll.bind
def CFStringGetMostCompatibleMacStringEncoding(encoding:CFStringEncoding) -> CFStringEncoding: ...
@c.record
class CFStringInlineBuffer(c.Struct):
SIZE = 184
buffer: Annotated[c.Array[UniChar, Literal[64]], 0]
theString: Annotated[CFStringRef, 128]
directUniCharBuffer: Annotated[c.POINTER[UniChar], 136]
directCStringBuffer: Annotated[c.POINTER[Annotated[bytes, ctypes.c_char]], 144]
rangeToBuffer: Annotated[CFRange, 152]
bufferedRangeStart: Annotated[CFIndex, 168]
bufferedRangeEnd: Annotated[CFIndex, 176]
CFTypeRef: TypeAlias = ctypes.c_void_p
@dll.bind
def CFShow(obj:CFTypeRef) -> None: ...
@dll.bind
def CFShowStr(str:CFStringRef) -> None: ...
@dll.bind
def __CFStringMakeConstantString(cStr:c.POINTER[Annotated[bytes, ctypes.c_char]]) -> CFStringRef: ...
CFMutableDataRef: TypeAlias = c.POINTER[struct___CFData]
@dll.bind
def CFDataGetTypeID() -> CFTypeID: ...
@dll.bind
def CFDataCreate(allocator:CFAllocatorRef, bytes:c.POINTER[UInt8], length:CFIndex) -> CFDataRef: ...
@dll.bind
def CFDataCreateWithBytesNoCopy(allocator:CFAllocatorRef, bytes:c.POINTER[UInt8], length:CFIndex, bytesDeallocator:CFAllocatorRef) -> CFDataRef: ...
@dll.bind
def CFDataCreateCopy(allocator:CFAllocatorRef, theData:CFDataRef) -> CFDataRef: ...
@dll.bind
def CFDataCreateMutable(allocator:CFAllocatorRef, capacity:CFIndex) -> CFMutableDataRef: ...
@dll.bind
def CFDataCreateMutableCopy(allocator:CFAllocatorRef, capacity:CFIndex, theData:CFDataRef) -> CFMutableDataRef: ...
@dll.bind
def CFDataGetLength(theData:CFDataRef) -> CFIndex: ...
@dll.bind
def CFDataGetBytePtr(theData:CFDataRef) -> c.POINTER[UInt8]: ...
@dll.bind
def CFDataGetMutableBytePtr(theData:CFMutableDataRef) -> c.POINTER[UInt8]: ...
@dll.bind
def CFDataGetBytes(theData:CFDataRef, range:CFRange, buffer:c.POINTER[UInt8]) -> None: ...
@dll.bind
def CFDataSetLength(theData:CFMutableDataRef, length:CFIndex) -> None: ...
@dll.bind
def CFDataIncreaseLength(theData:CFMutableDataRef, extraLength:CFIndex) -> None: ...
@dll.bind
def CFDataAppendBytes(theData:CFMutableDataRef, bytes:c.POINTER[UInt8], length:CFIndex) -> None: ...
@dll.bind
def CFDataReplaceBytes(theData:CFMutableDataRef, range:CFRange, newBytes:c.POINTER[UInt8], newLength:CFIndex) -> None: ...
@dll.bind
def CFDataDeleteBytes(theData:CFMutableDataRef, range:CFRange) -> None: ...
CFDataSearchFlags: TypeAlias = Annotated[int, ctypes.c_uint64]
class _anonenum3(Annotated[int, ctypes.c_uint32], c.Enum): pass
kCFDataSearchBackwards = _anonenum3.define('kCFDataSearchBackwards', 1)
kCFDataSearchAnchored = _anonenum3.define('kCFDataSearchAnchored', 2)
@dll.bind
def CFDataFind(theData:CFDataRef, dataToFind:CFDataRef, searchRange:CFRange, compareOptions:CFDataSearchFlags) -> CFRange: ...
c.init_records()
__COREFOUNDATION_CFSTRING__ = 1 # type: ignore
kCFStringEncodingInvalidId = (0xffffffff) # type: ignore
CF_FORMAT_FUNCTION = lambda F,A: __attribute__((format(CFString, F, A))) # type: ignore
CF_FORMAT_ARGUMENT = lambda A: __attribute__((format_arg(A))) # type: ignore
__kCFStringInlineBufferLength = 64 # type: ignore
__COREFOUNDATION_CFDATA__ = 1 # type: ignore

View File

@@ -0,0 +1,279 @@
# mypy: disable-error-code="empty-body"
from __future__ import annotations
import ctypes
from typing import Annotated, Literal, TypeAlias
from tinygrad.runtime.support.c import _IO, _IOW, _IOR, _IOWR
from tinygrad.runtime.support import c
dll = c.DLL('iokit', 'IOKit')
class struct_IONotificationPort(ctypes.Structure): pass
IONotificationPortRef: TypeAlias = c.POINTER[struct_IONotificationPort]
IOServiceMatchingCallback: TypeAlias = c.CFUNCTYPE[None, [ctypes.c_void_p, Annotated[int, ctypes.c_uint32]]]
IOServiceInterestCallback: TypeAlias = c.CFUNCTYPE[None, [ctypes.c_void_p, Annotated[int, ctypes.c_uint32], Annotated[int, ctypes.c_uint32], ctypes.c_void_p]]
mach_port_t: TypeAlias = Annotated[int, ctypes.c_uint32]
try: kIOMainPortDefault = mach_port_t.in_dll(dll, 'kIOMainPortDefault') # type: ignore
except (ValueError,AttributeError): pass
kern_return_t: TypeAlias = Annotated[int, ctypes.c_int32]
@dll.bind
def IOMainPort(bootstrapPort:mach_port_t, mainPort:c.POINTER[mach_port_t]) -> kern_return_t: ...
try: kIOMasterPortDefault = mach_port_t.in_dll(dll, 'kIOMasterPortDefault') # type: ignore
except (ValueError,AttributeError): pass
@dll.bind
def IOMasterPort(bootstrapPort:mach_port_t, mainPort:c.POINTER[mach_port_t]) -> kern_return_t: ...
@dll.bind
def IONotificationPortCreate(mainPort:mach_port_t) -> IONotificationPortRef: ...
@dll.bind
def IONotificationPortDestroy(notify:IONotificationPortRef) -> None: ...
class struct___CFRunLoopSource(ctypes.Structure): pass
CFRunLoopSourceRef: TypeAlias = c.POINTER[struct___CFRunLoopSource]
@dll.bind
def IONotificationPortGetRunLoopSource(notify:IONotificationPortRef) -> CFRunLoopSourceRef: ...
@dll.bind
def IONotificationPortGetMachPort(notify:IONotificationPortRef) -> mach_port_t: ...
@dll.bind
def IONotificationPortSetImportanceReceiver(notify:IONotificationPortRef) -> kern_return_t: ...
class struct_dispatch_queue_s(ctypes.Structure): pass
dispatch_queue_t: TypeAlias = c.POINTER[struct_dispatch_queue_s]
@dll.bind
def IONotificationPortSetDispatchQueue(notify:IONotificationPortRef, queue:dispatch_queue_t) -> None: ...
@c.record
class mach_msg_header_t(c.Struct):
SIZE = 24
msgh_bits: Annotated[mach_msg_bits_t, 0]
msgh_size: Annotated[mach_msg_size_t, 4]
msgh_remote_port: Annotated[mach_port_t, 8]
msgh_local_port: Annotated[mach_port_t, 12]
msgh_voucher_port: Annotated[mach_port_name_t, 16]
msgh_id: Annotated[mach_msg_id_t, 20]
mach_msg_bits_t: TypeAlias = Annotated[int, ctypes.c_uint32]
mach_msg_size_t: TypeAlias = Annotated[int, ctypes.c_uint32]
mach_port_name_t: TypeAlias = Annotated[int, ctypes.c_uint32]
mach_msg_id_t: TypeAlias = Annotated[int, ctypes.c_int32]
@dll.bind
def IODispatchCalloutFromMessage(unused:ctypes.c_void_p, msg:c.POINTER[mach_msg_header_t], reference:ctypes.c_void_p) -> None: ...
uint32_t: TypeAlias = Annotated[int, ctypes.c_uint32]
@dll.bind
def IOCreateReceivePort(msgType:uint32_t, recvPort:c.POINTER[mach_port_t]) -> kern_return_t: ...
io_object_t: TypeAlias = Annotated[int, ctypes.c_uint32]
@dll.bind
def IOObjectRelease(object:io_object_t) -> kern_return_t: ...
@dll.bind
def IOObjectRetain(object:io_object_t) -> kern_return_t: ...
io_name_t: TypeAlias = c.Array[Annotated[bytes, ctypes.c_char], Literal[128]]
@dll.bind
def IOObjectGetClass(object:io_object_t, className:io_name_t) -> kern_return_t: ...
class struct___CFString(ctypes.Structure): pass
CFStringRef: TypeAlias = c.POINTER[struct___CFString]
@dll.bind
def IOObjectCopyClass(object:io_object_t) -> CFStringRef: ...
@dll.bind
def IOObjectCopySuperclassForClass(classname:CFStringRef) -> CFStringRef: ...
@dll.bind
def IOObjectCopyBundleIdentifierForClass(classname:CFStringRef) -> CFStringRef: ...
boolean_t: TypeAlias = Annotated[int, ctypes.c_int32]
@dll.bind
def IOObjectConformsTo(object:io_object_t, className:io_name_t) -> boolean_t: ...
@dll.bind
def IOObjectIsEqualTo(object:io_object_t, anObject:io_object_t) -> boolean_t: ...
@dll.bind
def IOObjectGetKernelRetainCount(object:io_object_t) -> uint32_t: ...
@dll.bind
def IOObjectGetUserRetainCount(object:io_object_t) -> uint32_t: ...
@dll.bind
def IOObjectGetRetainCount(object:io_object_t) -> uint32_t: ...
io_iterator_t: TypeAlias = Annotated[int, ctypes.c_uint32]
@dll.bind
def IOIteratorNext(iterator:io_iterator_t) -> io_object_t: ...
@dll.bind
def IOIteratorReset(iterator:io_iterator_t) -> None: ...
@dll.bind
def IOIteratorIsValid(iterator:io_iterator_t) -> boolean_t: ...
class struct___CFDictionary(ctypes.Structure): pass
CFDictionaryRef: TypeAlias = c.POINTER[struct___CFDictionary]
io_service_t: TypeAlias = Annotated[int, ctypes.c_uint32]
@dll.bind
def IOServiceGetMatchingService(mainPort:mach_port_t, matching:CFDictionaryRef) -> io_service_t: ...
@dll.bind
def IOServiceGetMatchingServices(mainPort:mach_port_t, matching:CFDictionaryRef, existing:c.POINTER[io_iterator_t]) -> kern_return_t: ...
uintptr_t: TypeAlias = Annotated[int, ctypes.c_uint64]
@dll.bind
def IOServiceAddNotification(mainPort:mach_port_t, notificationType:io_name_t, matching:CFDictionaryRef, wakePort:mach_port_t, reference:uintptr_t, notification:c.POINTER[io_iterator_t]) -> kern_return_t: ...
@dll.bind
def IOServiceAddMatchingNotification(notifyPort:IONotificationPortRef, notificationType:io_name_t, matching:CFDictionaryRef, callback:IOServiceMatchingCallback, refCon:ctypes.c_void_p, notification:c.POINTER[io_iterator_t]) -> kern_return_t: ...
@dll.bind
def IOServiceAddInterestNotification(notifyPort:IONotificationPortRef, service:io_service_t, interestType:io_name_t, callback:IOServiceInterestCallback, refCon:ctypes.c_void_p, notification:c.POINTER[io_object_t]) -> kern_return_t: ...
@dll.bind
def IOServiceMatchPropertyTable(service:io_service_t, matching:CFDictionaryRef, matches:c.POINTER[boolean_t]) -> kern_return_t: ...
@dll.bind
def IOServiceGetBusyState(service:io_service_t, busyState:c.POINTER[uint32_t]) -> kern_return_t: ...
@c.record
class struct_mach_timespec(c.Struct):
SIZE = 8
tv_sec: Annotated[Annotated[int, ctypes.c_uint32], 0]
tv_nsec: Annotated[clock_res_t, 4]
mach_timespec_t: TypeAlias = struct_mach_timespec
clock_res_t: TypeAlias = Annotated[int, ctypes.c_int32]
@dll.bind
def IOServiceWaitQuiet(service:io_service_t, waitTime:c.POINTER[mach_timespec_t]) -> kern_return_t: ...
@dll.bind
def IOKitGetBusyState(mainPort:mach_port_t, busyState:c.POINTER[uint32_t]) -> kern_return_t: ...
IOOptionBits: TypeAlias = Annotated[int, ctypes.c_uint32]
@dll.bind
def IOKitWaitQuietWithOptions(mainPort:mach_port_t, waitTime:c.POINTER[mach_timespec_t], options:IOOptionBits) -> kern_return_t: ...
@dll.bind
def IOKitWaitQuiet(mainPort:mach_port_t, waitTime:c.POINTER[mach_timespec_t]) -> kern_return_t: ...
task_port_t: TypeAlias = Annotated[int, ctypes.c_uint32]
io_connect_t: TypeAlias = Annotated[int, ctypes.c_uint32]
@dll.bind
def IOServiceOpen(service:io_service_t, owningTask:task_port_t, type:uint32_t, connect:c.POINTER[io_connect_t]) -> kern_return_t: ...
@dll.bind
def IOServiceRequestProbe(service:io_service_t, options:uint32_t) -> kern_return_t: ...
class _anonenum0(Annotated[int, ctypes.c_uint32], c.Enum): pass
kIOServiceInteractionAllowed = _anonenum0.define('kIOServiceInteractionAllowed', 1)
@dll.bind
def IOServiceAuthorize(service:io_service_t, options:uint32_t) -> kern_return_t: ...
@dll.bind
def IOServiceOpenAsFileDescriptor(service:io_service_t, oflag:Annotated[int, ctypes.c_int32]) -> Annotated[int, ctypes.c_int32]: ...
@dll.bind
def IOServiceClose(connect:io_connect_t) -> kern_return_t: ...
@dll.bind
def IOConnectAddRef(connect:io_connect_t) -> kern_return_t: ...
@dll.bind
def IOConnectRelease(connect:io_connect_t) -> kern_return_t: ...
@dll.bind
def IOConnectGetService(connect:io_connect_t, service:c.POINTER[io_service_t]) -> kern_return_t: ...
@dll.bind
def IOConnectSetNotificationPort(connect:io_connect_t, type:uint32_t, port:mach_port_t, reference:uintptr_t) -> kern_return_t: ...
mach_vm_address_t: TypeAlias = Annotated[int, ctypes.c_uint64]
mach_vm_size_t: TypeAlias = Annotated[int, ctypes.c_uint64]
@dll.bind
def IOConnectMapMemory(connect:io_connect_t, memoryType:uint32_t, intoTask:task_port_t, atAddress:c.POINTER[mach_vm_address_t], ofSize:c.POINTER[mach_vm_size_t], options:IOOptionBits) -> kern_return_t: ...
@dll.bind
def IOConnectMapMemory64(connect:io_connect_t, memoryType:uint32_t, intoTask:task_port_t, atAddress:c.POINTER[mach_vm_address_t], ofSize:c.POINTER[mach_vm_size_t], options:IOOptionBits) -> kern_return_t: ...
@dll.bind
def IOConnectUnmapMemory(connect:io_connect_t, memoryType:uint32_t, fromTask:task_port_t, atAddress:mach_vm_address_t) -> kern_return_t: ...
@dll.bind
def IOConnectUnmapMemory64(connect:io_connect_t, memoryType:uint32_t, fromTask:task_port_t, atAddress:mach_vm_address_t) -> kern_return_t: ...
CFTypeRef: TypeAlias = ctypes.c_void_p
@dll.bind
def IOConnectSetCFProperties(connect:io_connect_t, properties:CFTypeRef) -> kern_return_t: ...
@dll.bind
def IOConnectSetCFProperty(connect:io_connect_t, propertyName:CFStringRef, property:CFTypeRef) -> kern_return_t: ...
uint64_t: TypeAlias = Annotated[int, ctypes.c_uint64]
size_t: TypeAlias = Annotated[int, ctypes.c_uint64]
@dll.bind
def IOConnectCallMethod(connection:mach_port_t, selector:uint32_t, input:c.POINTER[uint64_t], inputCnt:uint32_t, inputStruct:ctypes.c_void_p, inputStructCnt:size_t, output:c.POINTER[uint64_t], outputCnt:c.POINTER[uint32_t], outputStruct:ctypes.c_void_p, outputStructCnt:c.POINTER[size_t]) -> kern_return_t: ...
@dll.bind
def IOConnectCallAsyncMethod(connection:mach_port_t, selector:uint32_t, wake_port:mach_port_t, reference:c.POINTER[uint64_t], referenceCnt:uint32_t, input:c.POINTER[uint64_t], inputCnt:uint32_t, inputStruct:ctypes.c_void_p, inputStructCnt:size_t, output:c.POINTER[uint64_t], outputCnt:c.POINTER[uint32_t], outputStruct:ctypes.c_void_p, outputStructCnt:c.POINTER[size_t]) -> kern_return_t: ...
@dll.bind
def IOConnectCallStructMethod(connection:mach_port_t, selector:uint32_t, inputStruct:ctypes.c_void_p, inputStructCnt:size_t, outputStruct:ctypes.c_void_p, outputStructCnt:c.POINTER[size_t]) -> kern_return_t: ...
@dll.bind
def IOConnectCallAsyncStructMethod(connection:mach_port_t, selector:uint32_t, wake_port:mach_port_t, reference:c.POINTER[uint64_t], referenceCnt:uint32_t, inputStruct:ctypes.c_void_p, inputStructCnt:size_t, outputStruct:ctypes.c_void_p, outputStructCnt:c.POINTER[size_t]) -> kern_return_t: ...
@dll.bind
def IOConnectCallScalarMethod(connection:mach_port_t, selector:uint32_t, input:c.POINTER[uint64_t], inputCnt:uint32_t, output:c.POINTER[uint64_t], outputCnt:c.POINTER[uint32_t]) -> kern_return_t: ...
@dll.bind
def IOConnectCallAsyncScalarMethod(connection:mach_port_t, selector:uint32_t, wake_port:mach_port_t, reference:c.POINTER[uint64_t], referenceCnt:uint32_t, input:c.POINTER[uint64_t], inputCnt:uint32_t, output:c.POINTER[uint64_t], outputCnt:c.POINTER[uint32_t]) -> kern_return_t: ...
@dll.bind
def IOConnectTrap0(connect:io_connect_t, index:uint32_t) -> kern_return_t: ...
@dll.bind
def IOConnectTrap1(connect:io_connect_t, index:uint32_t, p1:uintptr_t) -> kern_return_t: ...
@dll.bind
def IOConnectTrap2(connect:io_connect_t, index:uint32_t, p1:uintptr_t, p2:uintptr_t) -> kern_return_t: ...
@dll.bind
def IOConnectTrap3(connect:io_connect_t, index:uint32_t, p1:uintptr_t, p2:uintptr_t, p3:uintptr_t) -> kern_return_t: ...
@dll.bind
def IOConnectTrap4(connect:io_connect_t, index:uint32_t, p1:uintptr_t, p2:uintptr_t, p3:uintptr_t, p4:uintptr_t) -> kern_return_t: ...
@dll.bind
def IOConnectTrap5(connect:io_connect_t, index:uint32_t, p1:uintptr_t, p2:uintptr_t, p3:uintptr_t, p4:uintptr_t, p5:uintptr_t) -> kern_return_t: ...
@dll.bind
def IOConnectTrap6(connect:io_connect_t, index:uint32_t, p1:uintptr_t, p2:uintptr_t, p3:uintptr_t, p4:uintptr_t, p5:uintptr_t, p6:uintptr_t) -> kern_return_t: ...
@dll.bind
def IOConnectAddClient(connect:io_connect_t, client:io_connect_t) -> kern_return_t: ...
io_registry_entry_t: TypeAlias = Annotated[int, ctypes.c_uint32]
@dll.bind
def IORegistryGetRootEntry(mainPort:mach_port_t) -> io_registry_entry_t: ...
io_string_t: TypeAlias = c.Array[Annotated[bytes, ctypes.c_char], Literal[512]]
@dll.bind
def IORegistryEntryFromPath(mainPort:mach_port_t, path:io_string_t) -> io_registry_entry_t: ...
@dll.bind
def IORegistryEntryCopyFromPath(mainPort:mach_port_t, path:CFStringRef) -> io_registry_entry_t: ...
class _anonenum1(Annotated[int, ctypes.c_uint32], c.Enum): pass
kIORegistryIterateRecursively = _anonenum1.define('kIORegistryIterateRecursively', 1)
kIORegistryIterateParents = _anonenum1.define('kIORegistryIterateParents', 2)
@dll.bind
def IORegistryCreateIterator(mainPort:mach_port_t, plane:io_name_t, options:IOOptionBits, iterator:c.POINTER[io_iterator_t]) -> kern_return_t: ...
@dll.bind
def IORegistryEntryCreateIterator(entry:io_registry_entry_t, plane:io_name_t, options:IOOptionBits, iterator:c.POINTER[io_iterator_t]) -> kern_return_t: ...
@dll.bind
def IORegistryIteratorEnterEntry(iterator:io_iterator_t) -> kern_return_t: ...
@dll.bind
def IORegistryIteratorExitEntry(iterator:io_iterator_t) -> kern_return_t: ...
@dll.bind
def IORegistryEntryGetName(entry:io_registry_entry_t, name:io_name_t) -> kern_return_t: ...
@dll.bind
def IORegistryEntryGetNameInPlane(entry:io_registry_entry_t, plane:io_name_t, name:io_name_t) -> kern_return_t: ...
@dll.bind
def IORegistryEntryGetLocationInPlane(entry:io_registry_entry_t, plane:io_name_t, location:io_name_t) -> kern_return_t: ...
@dll.bind
def IORegistryEntryGetPath(entry:io_registry_entry_t, plane:io_name_t, path:io_string_t) -> kern_return_t: ...
@dll.bind
def IORegistryEntryCopyPath(entry:io_registry_entry_t, plane:io_name_t) -> CFStringRef: ...
@dll.bind
def IORegistryEntryGetRegistryEntryID(entry:io_registry_entry_t, entryID:c.POINTER[uint64_t]) -> kern_return_t: ...
CFMutableDictionaryRef: TypeAlias = c.POINTER[struct___CFDictionary]
class struct___CFAllocator(ctypes.Structure): pass
CFAllocatorRef: TypeAlias = c.POINTER[struct___CFAllocator]
@dll.bind
def IORegistryEntryCreateCFProperties(entry:io_registry_entry_t, properties:c.POINTER[CFMutableDictionaryRef], allocator:CFAllocatorRef, options:IOOptionBits) -> kern_return_t: ...
@dll.bind
def IORegistryEntryCreateCFProperty(entry:io_registry_entry_t, key:CFStringRef, allocator:CFAllocatorRef, options:IOOptionBits) -> CFTypeRef: ...
@dll.bind
def IORegistryEntrySearchCFProperty(entry:io_registry_entry_t, plane:io_name_t, key:CFStringRef, allocator:CFAllocatorRef, options:IOOptionBits) -> CFTypeRef: ...
io_struct_inband_t: TypeAlias = c.Array[Annotated[bytes, ctypes.c_char], Literal[4096]]
@dll.bind
def IORegistryEntryGetProperty(entry:io_registry_entry_t, propertyName:io_name_t, buffer:io_struct_inband_t, size:c.POINTER[uint32_t]) -> kern_return_t: ...
@dll.bind
def IORegistryEntrySetCFProperties(entry:io_registry_entry_t, properties:CFTypeRef) -> kern_return_t: ...
@dll.bind
def IORegistryEntrySetCFProperty(entry:io_registry_entry_t, propertyName:CFStringRef, property:CFTypeRef) -> kern_return_t: ...
@dll.bind
def IORegistryEntryGetChildIterator(entry:io_registry_entry_t, plane:io_name_t, iterator:c.POINTER[io_iterator_t]) -> kern_return_t: ...
@dll.bind
def IORegistryEntryGetChildEntry(entry:io_registry_entry_t, plane:io_name_t, child:c.POINTER[io_registry_entry_t]) -> kern_return_t: ...
@dll.bind
def IORegistryEntryGetParentIterator(entry:io_registry_entry_t, plane:io_name_t, iterator:c.POINTER[io_iterator_t]) -> kern_return_t: ...
@dll.bind
def IORegistryEntryGetParentEntry(entry:io_registry_entry_t, plane:io_name_t, parent:c.POINTER[io_registry_entry_t]) -> kern_return_t: ...
@dll.bind
def IORegistryEntryInPlane(entry:io_registry_entry_t, plane:io_name_t) -> boolean_t: ...
@dll.bind
def IOServiceMatching(name:c.POINTER[Annotated[bytes, ctypes.c_char]]) -> CFMutableDictionaryRef: ...
@dll.bind
def IOServiceNameMatching(name:c.POINTER[Annotated[bytes, ctypes.c_char]]) -> CFMutableDictionaryRef: ...
@dll.bind
def IOBSDNameMatching(mainPort:mach_port_t, options:uint32_t, bsdName:c.POINTER[Annotated[bytes, ctypes.c_char]]) -> CFMutableDictionaryRef: ...
@dll.bind
def IOOpenFirmwarePathMatching(mainPort:mach_port_t, options:uint32_t, path:c.POINTER[Annotated[bytes, ctypes.c_char]]) -> CFMutableDictionaryRef: ...
@dll.bind
def IORegistryEntryIDMatching(entryID:uint64_t) -> CFMutableDictionaryRef: ...
@dll.bind
def IOServiceOFPathToBSDName(mainPort:mach_port_t, openFirmwarePath:io_name_t, bsdName:io_name_t) -> kern_return_t: ...
IOAsyncCallback0: TypeAlias = c.CFUNCTYPE[None, [ctypes.c_void_p, Annotated[int, ctypes.c_int32]]]
IOAsyncCallback1: TypeAlias = c.CFUNCTYPE[None, [ctypes.c_void_p, Annotated[int, ctypes.c_int32], ctypes.c_void_p]]
IOAsyncCallback2: TypeAlias = c.CFUNCTYPE[None, [ctypes.c_void_p, Annotated[int, ctypes.c_int32], ctypes.c_void_p, ctypes.c_void_p]]
IOAsyncCallback: TypeAlias = c.CFUNCTYPE[None, [ctypes.c_void_p, Annotated[int, ctypes.c_int32], c.POINTER[ctypes.c_void_p], Annotated[int, ctypes.c_uint32]]]
vm_size_t: TypeAlias = Annotated[int, ctypes.c_uint64]
@dll.bind
def OSGetNotificationFromMessage(msg:c.POINTER[mach_msg_header_t], index:uint32_t, type:c.POINTER[uint32_t], reference:c.POINTER[uintptr_t], content:c.POINTER[ctypes.c_void_p], size:c.POINTER[vm_size_t]) -> kern_return_t: ...
@dll.bind
def IOCatalogueSendData(mainPort:mach_port_t, flag:uint32_t, buffer:c.POINTER[Annotated[bytes, ctypes.c_char]], size:uint32_t) -> kern_return_t: ...
@dll.bind
def IOCatalogueTerminate(mainPort:mach_port_t, flag:uint32_t, description:io_name_t) -> kern_return_t: ...
@dll.bind
def IOCatalogueGetData(mainPort:mach_port_t, flag:uint32_t, buffer:c.POINTER[c.POINTER[Annotated[bytes, ctypes.c_char]]], size:c.POINTER[uint32_t]) -> kern_return_t: ...
@dll.bind
def IOCatalogueModuleLoaded(mainPort:mach_port_t, name:io_name_t) -> kern_return_t: ...
@dll.bind
def IOCatalogueReset(mainPort:mach_port_t, flag:uint32_t) -> kern_return_t: ...
c.init_records()

View File

@@ -539,7 +539,7 @@ class NV_GSP(NV_IP):
self.stat_q.wait_resp(nv.NV_VGPU_MSG_FUNCTION_SET_PAGE_DIRECTORY)
def rpc_set_gsp_system_info(self):
def bdf_as_int(s): return 0x000 if s.startswith("usb") else (int(s[5:7],16)<<8) | (int(s[8:10],16)<<3) | int(s[-1],16)
def bdf_as_int(s): return 0x000 if s.startswith("usb") or s.startswith("remote") else (int(s[5:7],16)<<8) | (int(s[8:10],16)<<3) | int(s[-1],16)
pcidev = self.nvdev.pci_dev
data = nv.GspSystemInfo(gpuPhysAddr=pcidev.bar_info[0].addr, gpuPhysFbAddr=pcidev.bar_info[1].addr, gpuPhysInstAddr=pcidev.bar_info[3].addr,

View File

@@ -1,7 +1,8 @@
import os, mmap, array, functools, ctypes, select, contextlib, dataclasses, sys, itertools
from __future__ import annotations
import os, mmap, array, functools, ctypes, select, contextlib, dataclasses, sys, itertools, struct, socket, subprocess, time, enum
from typing import ClassVar
from tinygrad.helpers import round_up, getenv, OSX, temp, ceildiv
from tinygrad.runtime.autogen import libc, vfio, pci
from tinygrad.helpers import round_up, getenv, OSX, temp, ceildiv, unwrap, fetch, system
from tinygrad.runtime.autogen import libc, pci, vfio, iokit, corefoundation
from tinygrad.runtime.support.hcq import FileIOInterface, MMIOInterface, HCQBuffer, hcq_filter_visible_devices
from tinygrad.runtime.support.memory import MemoryManager, VirtMapping, AddrSpace
from tinygrad.runtime.support.usb import ASM24Controller, USBMMIOInterface
@@ -20,15 +21,9 @@ class _System:
@functools.cached_property
def atomic_lib(self): return ctypes.CDLL(ctypes.util.find_library('atomic')) if sys.platform == "linux" else None
@functools.cached_property
def iokit(self): return ctypes.CDLL(ctypes.util.find_library("IOKit"))
@functools.cached_property
def libsys(self): return ctypes.CDLL(ctypes.util.find_library("System"))
@functools.cached_property
def mach_task_self(self): return ctypes.cast(self.libsys.mach_task_self_, ctypes.POINTER(ctypes.c_uint)).contents.value
@functools.cached_property
def pagemap(self) -> FileIOInterface:
self.write_sysfs("/proc/sys/vm/compact_unevictable_allowed", "0", "Failed to disable migration of locked pages")
@@ -46,28 +41,6 @@ class _System:
return vfio_fd
except OSError: return None
@functools.cached_property
def macos_tinygpu_conn(self):
self.iokit.IOServiceNameMatching.restype = ctypes.c_void_p # CFMutableDictionaryRef
if not (mdict:=self.iokit.IOServiceNameMatching("tinygpu".encode("utf-8"))): raise RuntimeError("IOServiceNameMatching returned NULL")
if not (service:=self.iokit.IOServiceGetMatchingService(ctypes.c_uint(0), ctypes.c_void_p(mdict))):
raise RuntimeError('Service "tinygpu" is not running')
if self.iokit.IOServiceOpen(service, self.mach_task_self, ctypes.c_uint32(0), ctypes.byref(conn:=ctypes.c_uint(0))):
raise RuntimeError("IOServiceOpen failed")
return conn
def iokit_pci_memmap(self, typ:int):
if self.iokit.IOConnectMapMemory64(self.macos_tinygpu_conn, ctypes.c_uint32(typ), System.mach_task_self,
ctypes.byref(addr:=ctypes.c_uint64(0)), ctypes.byref(size:=ctypes.c_uint64(0)), 0x1): raise RuntimeError(f"IOConnectMapMemory64({typ=}) failed")
return MMIOInterface(addr.value, size.value)
def iokit_pci_rpc(self, sel:int, *args:int):
in_scalars = (ctypes.c_uint64 * len(args))(*args) if args else ctypes.POINTER(ctypes.c_uint64)()
if (self.iokit.IOConnectCallMethod(self.macos_tinygpu_conn, sel, in_scalars, len(args), None, ctypes.c_size_t(0),
out_scalars:=(ctypes.c_uint64*16)(), ctypes.byref(outcnt:=ctypes.c_uint32(16)), None, ctypes.byref(ctypes.c_size_t(0)))):
raise RuntimeError(f"IOConnectCallMethod({sel=}, {args=}) failed")
return out_scalars[:outcnt.value]
def reserve_hugepages(self, cnt): os.system(f"sudo sh -c 'echo {cnt} > /proc/sys/vm/nr_hugepages'")
def memory_barrier(self): lib.atomic_thread_fence(__ATOMIC_SEQ_CST:=5) if (lib:=self.libsys if OSX else self.atomic_lib) is not None else None
@@ -79,14 +52,24 @@ class _System:
self.pagemap.seek(vaddr // mmap.PAGESIZE * 8)
return [(x & ((1<<55) - 1)) * mmap.PAGESIZE for x in array.array('Q', self.pagemap.read(size//mmap.PAGESIZE*8, binary=True))]
def pci_scan_bus(self, target_vendor:int, target_devices:list[tuple[int, list[int]]], base_class:int|None=None) -> list[str]:
result = []
for pcibus in FileIOInterface("/sys/bus/pci/devices").listdir():
vendor = int(FileIOInterface(f"/sys/bus/pci/devices/{pcibus}/vendor").read(), 16)
device = int(FileIOInterface(f"/sys/bus/pci/devices/{pcibus}/device").read(), 16)
if base_class is not None and int(FileIOInterface(f"/sys/bus/pci/devices/{pcibus}/class").read(), 16) >> 16 != base_class: continue
if vendor == target_vendor and any((device & mask) in devlist for mask, devlist in target_devices): result.append(pcibus)
return sorted(result)
def pci_scan_bus(self, vendor:int, devices:list[tuple[int, list[int]]], base_class:int|None=None) -> list[str]:
all_devs = []
if OSX:
def read_prop(svc, key) -> int:
cfkey = corefoundation.CFStringCreateWithCString(None, key.encode(), corefoundation.kCFStringEncodingUTF8)
cfdata = ctypes.cast(iokit.IORegistryEntryCreateCFProperty(svc, ctypes.cast(cfkey, iokit.CFStringRef), None, 0), corefoundation.CFDataRef)
corefoundation.CFDataGetBytes(cfdata, corefoundation.CFRange(0, corefoundation.CFDataGetLength(cfdata)), buf:=(ctypes.c_uint8*8)())
return int.from_bytes(bytes(buf), "little")
iokit.IOServiceGetMatchingServices(0, iokit.IOServiceMatching(b"IOPCIDevice"), ctypes.byref(iterator:=ctypes.c_uint()))
while svc:=iokit.IOIteratorNext(iterator): all_devs.append((v:=read_prop(svc, "vendor-id"), d:=read_prop(svc, "device-id"), f"{v:x}:{d:x}"))
else:
for pcibus in FileIOInterface("/sys/bus/pci/devices").listdir():
if base_class is not None and int(FileIOInterface(f"/sys/bus/pci/devices/{pcibus}/class").read(), 16) >> 16 != base_class: continue
all_devs.append((int(FileIOInterface(f"/sys/bus/pci/devices/{pcibus}/vendor").read(), 16),
int(FileIOInterface(f"/sys/bus/pci/devices/{pcibus}/device").read(), 16), pcibus))
return sorted([val for vendor, device, val in all_devs if vendor == vendor and any((device & mask) in devlist for mask, devlist in devices)])
def pci_setup_usb_bars(self, usb:ASM24Controller, gpu_bus:int, mem_base:int, pref_mem_base:int) -> dict[int, PCIBarInfo]:
for bus in range(gpu_bus):
@@ -154,6 +137,8 @@ class _System:
System = _System()
# *** PCI Devices
class PCIDevice:
def __init__(self, devpref:str, pcibus:str, bars:list[int], resize_bars:list[int]|None=None):
self.lock_fd = System.flock_acquire(f"{devpref.lower()}_{pcibus.lower()}.lock")
@@ -210,21 +195,6 @@ class PCIDevice:
return MMIOInterface(loc, sz, fmt=fmt)
def reset(self): os.system(f"sudo sh -c 'echo 1 > /sys/bus/pci/devices/{self.pcibus}/reset'")
class APLPCIDevice(PCIDevice):
def __init__(self, devpref:str, pcibus:str, bars:list[int], resize_bars:list[int]|None=None):
self.lock_fd = System.flock_acquire(f"{devpref.lower()}_{pcibus.lower()}.lock")
self.pcibus, self.bars = pcibus, {b: System.iokit_pci_memmap(b) for b in bars}
self.bar_info = {b:PCIBarInfo(0, self.bars[b].nbytes-1 if b in self.bars else 0) for b in range(6)} # NOTE: fake bar info for nv.
def alloc_sysmem(self, size:int, vaddr:int=0, contiguous:bool=False) -> tuple[MMIOInterface, list[int]]:
sysmem_view = System.iokit_pci_memmap(round_up(size, mmap.PAGESIZE))
paddrs = list(itertools.takewhile(lambda p: p[1] != 0, zip(sysmem_view.view(fmt='Q')[0::2], sysmem_view.view(fmt='Q')[1::2])))
assert not contiguous or len(paddrs) == 1, "not contiguous, but required"
return sysmem_view, [p + i for p, sz in paddrs for i in range(0, sz, 0x1000)][:ceildiv(size, 0x1000)]
def map_bar(self, bar:int, off:int=0, addr:int=0, size:int|None=None, fmt='B') -> MMIOInterface: return self.bars[bar].view(off, size, fmt)
def read_config(self, offset:int, size:int): return System.iokit_pci_rpc(__TinyGPURPCReadCfg:=0, offset, size)[0]
def write_config(self, offset:int, value:int, size:int): System.iokit_pci_rpc(__TinyGPURPCWriteCfg:=1, offset, size, value)
def reset(self): System.iokit_pci_rpc(__TinyGPURPCReset:=2)
class USBPCIDevice(PCIDevice):
def __init__(self, devpref:str, pcibus:str, bars:list[int], resize_bars:list[int]|None=None):
self.lock_fd = System.flock_acquire(f"{devpref.lower()}_{pcibus.lower()}.lock")
@@ -286,10 +256,101 @@ class LNXPCIIfaceBase:
self.dev_impl.mm.map_range(int(b.va_addr), round_up(b.size, 0x1000), paddrs, aspace=aspace, snooped=snooped, uncached=uncached)
class APLPCIIfaceBase(LNXPCIIfaceBase):
def __init__(self, dev, dev_id, vendor, devices, bars, vram_bar, va_start, va_size, base_class:int|None=None):
self.pci_dev, self.dev, self.vram_bar = APLPCIDevice(dev.__class__.__name__[:2], pcibus=f'usb4:{dev_id}', bars=bars), dev, vram_bar
assert (read_vendor:=self.pci_dev.read_config(pci.PCI_VENDOR_ID, 2)) == vendor, f"Vendor ID mismatch: expected {vendor:#x}, got {read_vendor:#x}"
def map(self, b:HCQBuffer): raise RuntimeError(f"map failed: {b.owner} -> {self.dev}")
# *** Remote PCI Devices
PCIIfaceBase:type = APLPCIIfaceBase if OSX else LNXPCIIfaceBase
class RemoteCmd(enum.IntEnum): MAP_BAR, MAP_SYSMEM_FD, CFG_READ, CFG_WRITE, RESET, MMIO_READ, MMIO_WRITE = 1, 2, 3, 4, 5, 6, 7
class RemoteMMIOInterface(MMIOInterface):
def __init__(self, dev:RemotePCIDevice, residx:int, nbytes:int, fmt='B', off=0):
self.dev, self.residx, self.nbytes, self.fmt, self.off, self.el_sz = dev, residx, nbytes, fmt, off, struct.calcsize(fmt)
def __getitem__(self, index):
sl = index if isinstance(index, slice) else slice(index, index + 1)
start, stop = (sl.start or 0) * self.el_sz, (sl.stop or len(self)) * self.el_sz
data = self.dev._bulk_read(RemoteCmd.MMIO_READ, self.residx, self.off + start, stop - start)
result = data if self.fmt == 'B' else list(struct.unpack(f'<{(stop - start) // self.el_sz}{self.fmt}', data))
return result if isinstance(index, slice) else result[0]
def __setitem__(self, index, val):
start = (index.start or 0) * self.el_sz if isinstance(index, slice) else index * self.el_sz
data = (val if self.fmt == 'B' else struct.pack(f'<{len(val)}{self.fmt}', *val)) if isinstance(index, slice) else struct.pack(f'<{self.fmt}', val)
self.dev._bulk_write(RemoteCmd.MMIO_WRITE, self.residx, self.off + start, data)
def view(self, offset:int=0, size:int|None=None, fmt=None):
return RemoteMMIOInterface(self.dev, self.residx, size or (self.nbytes - offset), fmt or self.fmt, self.off + offset)
class RemotePCIDevice(PCIDevice):
def __init__(self, devpref:str, pcibus:str, bars:list[int], sock:socket.socket):
self.lock_fd = System.flock_acquire(f"{devpref.lower()}_{pcibus.lower()}.lock")
self.pcibus, self.sock = pcibus, sock
for buft in [socket.SO_SNDBUF, socket.SO_RCVBUF]: self.sock.setsockopt(socket.SOL_SOCKET, buft, 64 << 20)
self.bar_info = {b: PCIBarInfo(0, self._rpc(RemoteCmd.MAP_BAR, b)[0]) for b in bars}
def _recvall(self, n:int) -> bytes:
data = b''
while len(data) < n and (chunk:=self.sock.recv(n - len(data))): data += chunk
if len(data) < n: raise RuntimeError("Connection closed")
return data
def _recv_with_fd(self) -> tuple[bytes, int|None]:
msg, anc, _, _ = self.sock.recvmsg(17, socket.CMSG_LEN(4))
return msg, struct.unpack('<i', anc[0][2][:4])[0]
def _rpc(self, cmd:int, *args:int, readout_size:int=0, has_fd=False) -> tuple[int, int, bytes|None, int|None]:
self.sock.sendall(struct.pack('<BBQQQ', cmd, *(*args, 0, 0, 0, 0)[:4]))
msg, fd = self._recv_with_fd() if has_fd else (self._recvall(17), None)
if (resp:=struct.unpack('<BQQ', msg))[0] != 0:
raise RuntimeError(f"RPC failed: {self._recvall(resp[1]).decode('utf-8') if resp[1] > 0 else 'unknown error'}")
return (resp[1], resp[2]) + ((self._recvall(readout_size) if readout_size > 0 else None),) + (fd,)
def _bulk_read(self, cmd:int, idx:int, offset:int, size:int) -> bytes: return unwrap(self._rpc(cmd, idx, offset, size, readout_size=size)[2])
def _bulk_write(self, cmd:int, idx:int, offset:int, data:bytes): self.sock.sendall(struct.pack('<BBQQQ', cmd, idx, offset, len(data), 0) + data)
def alloc_sysmem(self, size:int, vaddr:int=0, contiguous:bool=False) -> tuple[MMIOInterface, list[int]]:
mapped_size, _, _, fd = self._rpc(RemoteCmd.MAP_SYSMEM_FD, 0, 0, size, has_fd=True)
memview = MMIOInterface(FileIOInterface(fd=fd).mmap(0, mapped_size, mmap.PROT_READ | mmap.PROT_WRITE, mmap.MAP_SHARED, 0), mapped_size, fmt='B')
# paddrs are returned as (paddr, size) pairs until a (paddr=0, size=0) terminator in the beginning of the mapping.
paddrs_raw = list(itertools.takewhile(lambda p: p[1] != 0, zip(memview.view(fmt='Q')[0::2], memview.view(fmt='Q')[1::2])))
return memview, [p + i for p, sz in paddrs_raw for i in range(0, sz, 0x1000)][:ceildiv(size, 0x1000)]
def read_config(self, offset:int, size:int): return self._rpc(RemoteCmd.CFG_READ, 0, offset, size)[0]
def write_config(self, offset:int, value:int, size:int): self._rpc(RemoteCmd.CFG_WRITE, 0, offset, size, value)
def reset(self): self._rpc(RemoteCmd.RESET, 0, 0, 0)
def map_bar(self, bar:int, off:int=0, addr:int=0, size:int|None=None, fmt='B') -> MMIOInterface:
return RemoteMMIOInterface(self, bar, size or self.bar_info[bar].size, fmt).view(off, size, fmt)
class APLRemotePCIDevice(RemotePCIDevice):
APP_PATH = "/Applications/TinyGPU.app/Contents/MacOS/TinyGPU"
@staticmethod
def install_tinygpu():
print("Downloading TinyGPU.app...")
system(f"ditto -xk {fetch('https://github.com/nimlgen/tinygpu_releases/raw/8120b5508b43149d27bf22f9a4e6d7c5a4b401e9/TinyGPU.zip')} /Applications")
print(system(f"{APLRemotePCIDevice.APP_PATH} install"))
def __init__(self, devpref:str, pcibus:str, bars:list[int], resize_bars:list[int]|None=None):
sock_path, sock = getenv("APL_REMOTE_SOCK", temp("tinygpu.sock")), socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
for i in range(100):
with contextlib.suppress(ConnectionRefusedError, FileNotFoundError):
sock.connect(sock_path)
break
if i == 0: subprocess.Popen([self.APP_PATH, "server", sock_path], stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
time.sleep(0.05)
else: raise RuntimeError(f"Failed to connect to TinyGPU server at {sock_path}.")
super().__init__(devpref, pcibus, bars, sock)
class APLRemoteIfaceBase(LNXPCIIfaceBase):
def __init__(self, dev, dev_id, vendor, devices:list[tuple[int, list[int]]], bars, vram_bar, va_start, va_size, base_class:int|None=None):
if not (cls:=type(self)).gpus:
cls.gpus = System.pci_scan_bus(vendor, devices, base_class)
if not cls.gpus: raise RuntimeError("No supported GPUs found")
if not os.path.exists(APLRemotePCIDevice.APP_PATH): APLRemotePCIDevice.install_tinygpu()
self.pci_dev = APLRemotePCIDevice(dev.__class__.__name__[:2], f'remote:{dev_id}', bars)
self.dev, self.vram_bar = dev, vram_bar
def free(self, b:HCQBuffer):
for dev in b.mapped_devs[1:]: dev.iface.dev_impl.mm.unmap_range(b.va_addr, b.size)
def map(self, b:HCQBuffer): raise RuntimeError(f"P2P mapping not supported for remote devices: {b.owner} -> {self.dev}")
PCIIfaceBase:type = APLRemoteIfaceBase if OSX else LNXPCIIfaceBase