diff --git a/.github/workflows/autogen.yml b/.github/workflows/autogen.yml index 0ed5c404d6..874ea0eb14 100644 --- a/.github/workflows/autogen.yml +++ b/.github/workflows/autogen.yml @@ -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 diff --git a/extra/usbgpu/tbgpu/install_tinygpu.sh b/extra/usbgpu/tbgpu/install_tinygpu.sh new file mode 100755 index 0000000000..5606565b1f --- /dev/null +++ b/extra/usbgpu/tbgpu/install_tinygpu.sh @@ -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 diff --git a/extra/usbgpu/tbgpu/installer/Shared/TinyGPU-Bridging-Header.h b/extra/usbgpu/tbgpu/installer/Shared/TinyGPU-Bridging-Header.h new file mode 100644 index 0000000000..003a0e26f1 --- /dev/null +++ b/extra/usbgpu/tbgpu/installer/Shared/TinyGPU-Bridging-Header.h @@ -0,0 +1 @@ +int run_server(const char *sock_path); diff --git a/extra/usbgpu/tbgpu/installer/Shared/TinyGPUApp.swift b/extra/usbgpu/tbgpu/installer/Shared/TinyGPUApp.swift index 1f4f6d4248..5bdb4bdedf 100644 --- a/extra/usbgpu/tbgpu/installer/Shared/TinyGPUApp.swift +++ b/extra/usbgpu/tbgpu/installer/Shared/TinyGPUApp.swift @@ -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 } } diff --git a/extra/usbgpu/tbgpu/installer/Shared/TinyGPUCLIRunner.swift b/extra/usbgpu/tbgpu/installer/Shared/TinyGPUCLIRunner.swift new file mode 100644 index 0000000000..c1bb1793ae --- /dev/null +++ b/extra/usbgpu/tbgpu/installer/Shared/TinyGPUCLIRunner.swift @@ -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 + status Show extension status + install Install the driver extension + uninstall Remove the driver extension + server 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 + } +} diff --git a/extra/usbgpu/tbgpu/installer/Shared/TinyGPUView.swift b/extra/usbgpu/tbgpu/installer/Shared/TinyGPUView.swift deleted file mode 100644 index f4a6b14efc..0000000000 --- a/extra/usbgpu/tbgpu/installer/Shared/TinyGPUView.swift +++ /dev/null @@ -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() - } -} diff --git a/extra/usbgpu/tbgpu/installer/Shared/TinyGPUViewModel.swift b/extra/usbgpu/tbgpu/installer/Shared/TinyGPUViewModel.swift deleted file mode 100644 index 58f1d8090b..0000000000 --- a/extra/usbgpu/tbgpu/installer/Shared/TinyGPUViewModel.swift +++ /dev/null @@ -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 diff --git a/extra/usbgpu/tbgpu/installer/Shared/server.c b/extra/usbgpu/tbgpu/installer/Shared/server.c new file mode 100644 index 0000000000..10e952ca12 --- /dev/null +++ b/extra/usbgpu/tbgpu/installer/Shared/server.c @@ -0,0 +1,277 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +// 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, ¬if); + } + + 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; +} diff --git a/extra/usbgpu/tbgpu/installer/Shared/tiny_icon.icon/Assets/tiny.svg b/extra/usbgpu/tbgpu/installer/Shared/tiny_icon.icon/Assets/tiny.svg new file mode 100644 index 0000000000..995ede1d72 --- /dev/null +++ b/extra/usbgpu/tbgpu/installer/Shared/tiny_icon.icon/Assets/tiny.svg @@ -0,0 +1,18 @@ + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/extra/usbgpu/tbgpu/installer/Shared/tiny_icon.icon/icon.json b/extra/usbgpu/tbgpu/installer/Shared/tiny_icon.icon/icon.json new file mode 100644 index 0000000000..8484e2dad3 --- /dev/null +++ b/extra/usbgpu/tbgpu/installer/Shared/tiny_icon.icon/icon.json @@ -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" + } +} \ No newline at end of file diff --git a/extra/usbgpu/tbgpu/installer/TinyGPUDriverExtension.xcodeproj/project.pbxproj b/extra/usbgpu/tbgpu/installer/TinyGPUDriverExtension.xcodeproj/project.pbxproj index 5d7cf10710..98f3abc3ac 100644 --- a/extra/usbgpu/tbgpu/installer/TinyGPUDriverExtension.xcodeproj/project.pbxproj +++ b/extra/usbgpu/tbgpu/installer/TinyGPUDriverExtension.xcodeproj/project.pbxproj @@ -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 = ""; }; + 0A5C11DC2F18E461006DBBCA /* server.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = server.c; sourceTree = ""; }; + 0A5C11DE2F18E468006DBBCA /* TinyGPU-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "TinyGPU-Bridging-Header.h"; sourceTree = ""; }; 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 = ""; }; + 0AFA851D2F1CE486005FDAC2 /* TinyGPUDriver.Release.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = TinyGPUDriver.Release.entitlements; sourceTree = ""; }; 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 = ""; 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 = ""; }; - 54E42BB9286A1696000E1E9A /* TinyGPUView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TinyGPUView.swift; sourceTree = ""; }; 54E42BBA286A1697000E1E9A /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; 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 = ""; }; @@ -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 = ""; @@ -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 = ""; @@ -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 */, diff --git a/extra/usbgpu/tbgpu/installer/TinyGPUDriverExtension/TinyGPUDriver.NoSIP.entitlements b/extra/usbgpu/tbgpu/installer/TinyGPUDriverExtension/TinyGPUDriver.NoSIP.entitlements new file mode 100644 index 0000000000..5a95806978 --- /dev/null +++ b/extra/usbgpu/tbgpu/installer/TinyGPUDriverExtension/TinyGPUDriver.NoSIP.entitlements @@ -0,0 +1,17 @@ + + + + + com.apple.developer.driverkit + + com.apple.developer.driverkit.transport.pci + + + IOPCIPrimaryMatch + 0xFFFFFFFF&0x00000000 + + + com.apple.developer.driverkit.allow-any-userclient-access + + + diff --git a/extra/usbgpu/tbgpu/installer/TinyGPUDriverExtension/TinyGPUDriver.Release.entitlements b/extra/usbgpu/tbgpu/installer/TinyGPUDriverExtension/TinyGPUDriver.Release.entitlements new file mode 100644 index 0000000000..89f68e0160 --- /dev/null +++ b/extra/usbgpu/tbgpu/installer/TinyGPUDriverExtension/TinyGPUDriver.Release.entitlements @@ -0,0 +1,17 @@ + + + + + com.apple.application-identifier + 9YG3G8543N.org.tinygrad.tinygpu.edriver + com.apple.developer.driverkit + + com.apple.developer.driverkit.transport.pci + + + IOPCIPrimaryMatch + 4098 + + + + diff --git a/extra/usbgpu/tbgpu/installer/TinyGPUDriverExtension/TinyGPUDriver.entitlements b/extra/usbgpu/tbgpu/installer/TinyGPUDriverExtension/TinyGPUDriver.entitlements index 5a95806978..dab698ffb0 100644 --- a/extra/usbgpu/tbgpu/installer/TinyGPUDriverExtension/TinyGPUDriver.entitlements +++ b/extra/usbgpu/tbgpu/installer/TinyGPUDriverExtension/TinyGPUDriver.entitlements @@ -11,7 +11,5 @@ 0xFFFFFFFF&0x00000000 - com.apple.developer.driverkit.allow-any-userclient-access - diff --git a/extra/usbgpu/tbgpu/installer/build_and_sign.sh b/extra/usbgpu/tbgpu/installer/build_and_sign.sh new file mode 100755 index 0000000000..2ce4543eb1 --- /dev/null +++ b/extra/usbgpu/tbgpu/installer/build_and_sign.sh @@ -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 diff --git a/extra/usbgpu/tbgpu/installer/install_nosip.sh b/extra/usbgpu/tbgpu/installer/install_nosip.sh new file mode 100755 index 0000000000..d07a083ede --- /dev/null +++ b/extra/usbgpu/tbgpu/installer/install_nosip.sh @@ -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 diff --git a/extra/usbgpu/tbgpu/installer/macOS/macOS.entitlements b/extra/usbgpu/tbgpu/installer/macOS/macOS.entitlements index 729c9e7634..b2ab3b2a99 100644 --- a/extra/usbgpu/tbgpu/installer/macOS/macOS.entitlements +++ b/extra/usbgpu/tbgpu/installer/macOS/macOS.entitlements @@ -8,5 +8,9 @@ com.apple.developer.system-extension.install + com.apple.developer.driverkit.userclient-access + + org.tinygrad.tinygpu.edriver + diff --git a/extra/usbgpu/tbgpu/installer/notary_tool.sh b/extra/usbgpu/tbgpu/installer/notary_tool.sh new file mode 100755 index 0000000000..11c09984a4 --- /dev/null +++ b/extra/usbgpu/tbgpu/installer/notary_tool.sh @@ -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 diff --git a/extra/usbgpu/tbgpu/kill_tinygpu.sh b/extra/usbgpu/tbgpu/kill_tinygpu.sh new file mode 100755 index 0000000000..6cf30a316f --- /dev/null +++ b/extra/usbgpu/tbgpu/kill_tinygpu.sh @@ -0,0 +1,2 @@ +#!/bin/bash +pkill -f "tinygpu.sock" diff --git a/extra/usbgpu/tbgpu/main.cpp b/extra/usbgpu/tbgpu/main.cpp deleted file mode 100644 index 98e7da6a0c..0000000000 --- a/extra/usbgpu/tbgpu/main.cpp +++ /dev/null @@ -1,39 +0,0 @@ -#include -#include -#include -#include -#include - -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 it’s 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; -} \ No newline at end of file diff --git a/extra/usbgpu/tbgpu/main.py b/extra/usbgpu/tbgpu/main.py deleted file mode 100644 index 74719f5953..0000000000 --- a/extra/usbgpu/tbgpu/main.py +++ /dev/null @@ -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) diff --git a/tinygrad/runtime/autogen/__init__.py b/tinygrad/runtime/autogen/__init__.py index 9a0a2a506d..9ad96bb33f 100644 --- a/tinygrad/runtime/autogen/__init__.py +++ b/tinygrad/runtime/autogen/__init__.py @@ -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}") diff --git a/tinygrad/runtime/autogen/corefoundation.py b/tinygrad/runtime/autogen/corefoundation.py new file mode 100644 index 0000000000..b95c12b124 --- /dev/null +++ b/tinygrad/runtime/autogen/corefoundation.py @@ -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 \ No newline at end of file diff --git a/tinygrad/runtime/autogen/iokit.py b/tinygrad/runtime/autogen/iokit.py new file mode 100644 index 0000000000..4cc0360fb2 --- /dev/null +++ b/tinygrad/runtime/autogen/iokit.py @@ -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() diff --git a/tinygrad/runtime/support/nv/ip.py b/tinygrad/runtime/support/nv/ip.py index e74206c7d3..2413155865 100644 --- a/tinygrad/runtime/support/nv/ip.py +++ b/tinygrad/runtime/support/nv/ip.py @@ -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, diff --git a/tinygrad/runtime/support/system.py b/tinygrad/runtime/support/system.py index d307e8727a..2388c7cef4 100644 --- a/tinygrad/runtime/support/system.py +++ b/tinygrad/runtime/support/system.py @@ -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(' tuple[int, int, bytes|None, int|None]: + self.sock.sendall(struct.pack(' 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(' 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