int nvrm_ioctl_create_vspace(struct nvrm_device *dev, uint32_t parent, uint32_t handle, uint32_t cls, uint32_t flags, uint64_t *limit, uint64_t *foffset) { struct nvrm_ioctl_create_vspace arg = { .cid = dev->ctx->cid, .parent = parent, .handle = handle, .cls = cls, .flags = flags, .foffset = 0, .limit = *limit, .status = 0, }; if (ioctl(dev->fd, NVRM_IOCTL_CREATE_VSPACE, &arg) < 0) return -1; if (foffset) *foffset = arg.foffset; *limit = arg.limit; return arg.status; } int nvrm_ioctl_create_dma(struct nvrm_context *ctx, uint32_t parent, uint32_t handle, uint32_t cls, uint32_t flags, uint64_t base, uint64_t limit) { struct nvrm_ioctl_create_dma arg = { .cid = ctx->cid, .handle = handle, .cls = cls, .flags = flags, .unk10 = 0, .parent = parent, .base = base, .limit = limit, .status = 0, }; if (ioctl(ctx->fd_ctl, NVRM_IOCTL_CREATE_DMA, &arg) < 0) return -1; return arg.status; } int nvrm_ioctl_call(struct nvrm_context *ctx, uint32_t handle, uint32_t mthd, void *ptr, uint32_t size) { struct nvrm_ioctl_call arg = { .cid = ctx->cid, .handle = handle, .mthd = mthd, .ptr = (uint64_t)ptr, .size = size, .status = 0, }; if (ioctl(ctx->fd_ctl, NVRM_IOCTL_CALL, &arg) < 0) return -1; return arg.status; } int nvrm_ioctl_create(struct nvrm_context *ctx, uint32_t parent, uint32_t handle, uint32_t cls, void *ptr) { struct nvrm_ioctl_create arg = { .cid = ctx->cid, .parent = parent, .handle = handle, .cls = cls, .ptr = (uint64_t)ptr, .status = 0, }; if (ioctl(ctx->fd_ctl, NVRM_IOCTL_CREATE, &arg) < 0) return -1; return arg.status; } int nvrm_ioctl_destroy(struct nvrm_context *ctx, uint32_t parent, uint32_t handle) { struct nvrm_ioctl_destroy arg = { .cid = ctx->cid, .parent = parent, .handle = handle, .status = 0, }; if (ioctl(ctx->fd_ctl, NVRM_IOCTL_DESTROY, &arg) < 0) return -1; return arg.status; } int nvrm_ioctl_query(struct nvrm_context *ctx, uint32_t handle, uint32_t query, void *ptr, uint32_t size) { struct nvrm_ioctl_query arg = { .cid = ctx->cid, .handle = handle, .query = query, .ptr = (uint64_t)ptr, .size = size, .status = 0, }; if (ioctl(ctx->fd_ctl, NVRM_IOCTL_QUERY, &arg) < 0) return -1; return arg.status; } int nvrm_ioctl_unk4d(struct nvrm_context *ctx, uint32_t handle, const char *str) { struct nvrm_ioctl_unk4d arg = { .cid = ctx->cid, .handle = handle, .unk08 = 1, .unk10 = 0, .slen = strlen(str), .sptr = (uint64_t)str, .status = 0, }; if (ioctl(ctx->fd_ctl, NVRM_IOCTL_UNK4D, &arg) < 0) return -1; return arg.status; } int nvrm_ioctl_card_info(struct nvrm_context *ctx) { struct nvrm_ioctl_card_info2 arg2 = { { { 0xffffffff }, } }; struct nvrm_ioctl_card_info *arg = (struct nvrm_ioctl_card_info *)&arg2; if (ioctl(ctx->fd_ctl, NVRM_IOCTL_CARD_INFO, arg) < 0) return -1; return 0; } int nvrm_ioctl_get_fb_size(struct nvrm_context *ctx, int idx, uint64_t *size) { struct nvrm_ioctl_card_info2 arg2 = { { { 0xffffffff }, } }; struct nvrm_ioctl_card_info *arg = (struct nvrm_ioctl_card_info *)&arg2; if (ioctl(ctx->fd_ctl, NVRM_IOCTL_CARD_INFO, arg) < 0) return -1; if (ctx->ver_major < 331) *size = arg->card[idx].fb_size; else *size = arg2.card[idx].fb_size; return 0; } int nvrm_ioctl_get_vendor_id(struct nvrm_context *ctx, int idx, uint16_t *id) { struct nvrm_ioctl_card_info2 arg2 = { { { 0xffffffff }, } }; struct nvrm_ioctl_card_info *arg = (struct nvrm_ioctl_card_info *)&arg2; if (ioctl(ctx->fd_ctl, NVRM_IOCTL_CARD_INFO, arg) < 0) return -1; if (ctx->ver_major < 331) *id = arg->card[idx].vendor_id; else *id = arg2.card[idx].vendor_id; return 0; } int nvrm_ioctl_get_device_id(struct nvrm_context *ctx, int idx, uint16_t *id) { struct nvrm_ioctl_card_info2 arg2 = { { { 0xffffffff }, } }; struct nvrm_ioctl_card_info *arg = (struct nvrm_ioctl_card_info *)&arg2; if (ioctl(ctx->fd_ctl, NVRM_IOCTL_CARD_INFO, arg) < 0) return -1; if (ctx->ver_major < 331) *id = arg->card[idx].device_id; else *id = arg2.card[idx].device_id; return 0; } int nvrm_ioctl_env_info(struct nvrm_context *ctx, uint32_t *pat_supported) { struct nvrm_ioctl_env_info arg = { }; if (ioctl(ctx->fd_ctl, NVRM_IOCTL_ENV_INFO, &arg) < 0) return -1; if (pat_supported) *pat_supported = arg.pat_supported; return 0; } int nvrm_ioctl_check_version_str(struct nvrm_context *ctx, uint32_t cmd, const char *vernum) { struct nvrm_ioctl_check_version_str arg = { .cmd = cmd, .reply = 0, }; strncpy(arg.vernum, vernum, sizeof arg.vernum); if (ioctl(ctx->fd_ctl, NVRM_IOCTL_CHECK_VERSION_STR, &arg) < 0) return -1; return arg.reply; } int nvrm_ioctl_vspace_map(struct nvrm_context *ctx, uint32_t dev, uint32_t vspace, uint32_t handle, uint64_t base, uint64_t size, uint64_t *addr) { struct nvrm_ioctl_vspace_map arg = { .cid = ctx->cid, .dev = dev, .vspace = vspace, .handle = handle, .base = base, .size = size, .flags = 0x00000, .status = 0, }; if (ioctl(ctx->fd_ctl, NVRM_IOCTL_VSPACE_MAP, &arg) < 0) return -1; *addr = arg.addr; return arg.status; } int nvrm_ioctl_vspace_unmap(struct nvrm_context *ctx, uint32_t dev, uint32_t vspace, uint32_t handle, uint64_t addr) { struct nvrm_ioctl_vspace_unmap arg = { .cid = ctx->cid, .dev = dev, .vspace = vspace, .handle = handle, .status = 0, }; if (ioctl(ctx->fd_ctl, NVRM_IOCTL_VSPACE_UNMAP, &arg) < 0) return -1; return arg.status; } int nvrm_ioctl_host_map(struct nvrm_context *ctx, uint32_t subdev, uint32_t handle, uint64_t base, uint64_t size, uint64_t *foffset) { struct nvrm_ioctl_host_map arg = { .cid = ctx->cid, .subdev = subdev, .handle = handle, .base = base, .limit = size-1, .status = 0, }; if (ioctl(ctx->fd_ctl, NVRM_IOCTL_HOST_MAP, &arg) < 0) return -1; *foffset = arg.foffset; return arg.status; } int nvrm_ioctl_host_unmap(struct nvrm_context *ctx, uint32_t subdev, uint32_t handle, uint64_t foffset) { struct nvrm_ioctl_host_unmap arg = { .cid = ctx->cid, .subdev = subdev, .handle = handle, .foffset = foffset, .status = 0, }; if (ioctl(ctx->fd_ctl, NVRM_IOCTL_HOST_UNMAP, &arg) < 0) return -1; return arg.status; } int nvrm_ioctl_memory(struct nvrm_context *ctx, uint32_t parent, uint32_t vspace, uint32_t handle, uint32_t flags1, uint32_t flags2, uint64_t base, uint64_t size) { struct nvrm_ioctl_memory arg = { .cid = ctx->cid, .parent = parent, .cls = 2, .vspace = vspace, .handle = handle, .flags1 = flags1, .flags2 = flags2, .size = size, .base = base, .status = 0, }; if (ioctl(ctx->fd_ctl, NVRM_IOCTL_MEMORY, &arg) < 0) return -1; return arg.status; } int nvrm_create_cid(struct nvrm_context *ctx) { return nvrm_ioctl_create(ctx, 0, 0, NVRM_CLASS_CONTEXT_NEW, &ctx->cid); }
struct nvrm_device *nvrm_device_open(struct nvrm_context *ctx, int idx) { idx = nvrm_xlat_device(ctx, idx); struct nvrm_device *dev = &ctx->devs[idx]; if (dev->open++) { if (!dev->open) { fprintf(stderr, "nvrm: open counter overflow\n"); abort(); } return 0; } if (nvrm_mthd_context_enable_device(ctx, ctx->cid, dev->gpu_id)) { goto out_enable; } char buf[20]; snprintf(buf, 20, "/dev/nvidia%d", idx); dev->fd = nvrm_open_file(buf); if (dev->fd < 0) goto out_open; #if 0 if (nvrm_ioctl_unk4d(ctx, ctx->cid)) goto out_unk4d; #endif struct nvrm_create_device arg = { .idx = idx, .cid = ctx->cid, }; dev->odev = nvrm_handle_alloc(ctx); if (nvrm_ioctl_create(ctx, ctx->cid, dev->odev, NVRM_CLASS_DEVICE_0, &arg)) goto out_dev; dev->osubdev = nvrm_handle_alloc(ctx); if (nvrm_ioctl_create(ctx, dev->odev, dev->osubdev, NVRM_CLASS_SUBDEVICE_0, 0)) goto out_subdev; return dev; out_subdev: nvrm_handle_free(ctx, dev->osubdev); nvrm_ioctl_destroy(ctx, ctx->cid, dev->odev); out_dev: nvrm_handle_free(ctx, dev->odev); close(dev->fd); out_open: nvrm_mthd_context_disable_device(ctx, ctx->cid, dev->gpu_id); out_enable: dev->open--; return 0; } void nvrm_device_close(struct nvrm_device *dev) { struct nvrm_context *ctx = dev->ctx; int idx = dev->idx; if (!dev->open) { fprintf(stderr, "nvrm: closing closed device %d\n", idx); abort(); } if (--dev->open) { return; } nvrm_ioctl_call(ctx, dev->osubdev, NVRM_MTHD_SUBDEVICE_UNK0146, 0, 0); nvrm_ioctl_destroy(ctx, dev->odev, dev->osubdev); nvrm_handle_free(ctx, dev->osubdev); nvrm_ioctl_destroy(ctx, ctx->cid, dev->odev); nvrm_handle_free(ctx, dev->odev); close(dev->fd); nvrm_mthd_context_disable_device(ctx, ctx->cid, dev->gpu_id); }