static void __iomem *crb_map_res(struct device *dev, struct crb_priv *priv, struct resource *io_res, u64 start, u32 size) { struct resource new_res = { .start = start, .end = start + size - 1, .flags = IORESOURCE_MEM, }; /* Detect a 64 bit address on a 32 bit system */ if (start != new_res.start) return (void __iomem *) ERR_PTR(-EINVAL); if (!resource_contains(io_res, &new_res)) return devm_ioremap_resource(dev, &new_res); return priv->iobase + (new_res.start - io_res->start); } static int crb_map_io(struct acpi_device *device, struct crb_priv *priv, struct acpi_table_tpm2 *buf) { struct list_head resources; struct resource io_res; struct device *dev = &device->dev; u64 cmd_pa; u32 cmd_size; u64 rsp_pa; u32 rsp_size; int ret; INIT_LIST_HEAD(&resources); ret = acpi_dev_get_resources(device, &resources, crb_check_resource, &io_res); if (ret < 0) return ret; acpi_dev_free_resource_list(&resources); if (resource_type(&io_res) != IORESOURCE_MEM) { dev_err(dev, FW_BUG "TPM2 ACPI table does not define a memory resource\n"); return -EINVAL; } priv->iobase = devm_ioremap_resource(dev, &io_res); if (IS_ERR(priv->iobase)) return PTR_ERR(priv->iobase); priv->cca = crb_map_res(dev, priv, &io_res, buf->control_address, sizeof(struct crb_control_area)); if (IS_ERR(priv->cca)) return PTR_ERR(priv->cca); cmd_pa = ((u64) ioread32(&priv->cca->cmd_pa_high) << 32) | (u64) ioread32(&priv->cca->cmd_pa_low); cmd_size = ioread32(&priv->cca->cmd_size); priv->cmd = crb_map_res(dev, priv, &io_res, cmd_pa, cmd_size); if (IS_ERR(priv->cmd)) return PTR_ERR(priv->cmd); memcpy_fromio(&rsp_pa, &priv->cca->rsp_pa, 8); rsp_pa = le64_to_cpu(rsp_pa); rsp_size = ioread32(&priv->cca->rsp_size); if (cmd_pa != rsp_pa) { priv->rsp = crb_map_res(dev, priv, &io_res, rsp_pa, rsp_size); return PTR_ERR_OR_ZERO(priv->rsp); } /* According to the PTP specification, overlapping command and response * buffer sizes must be identical. */ if (cmd_size != rsp_size) { dev_err(dev, FW_BUG "overlapping command and response buffer sizes are not identical"); return -EINVAL; } priv->rsp = priv->cmd; return 0; } static int crb_acpi_add(struct acpi_device *device) { struct acpi_table_tpm2 *buf; struct crb_priv *priv; struct device *dev = &device->dev; acpi_status status; u32 sm; int rc; status = acpi_get_table(ACPI_SIG_TPM2, 1, (struct acpi_table_header **) &buf); if (ACPI_FAILURE(status) || buf->header.length < sizeof(*buf)) { dev_err(dev, FW_BUG "failed to get TPM2 ACPI table\n"); return -EINVAL; } /* Should the FIFO driver handle this? */ sm = buf->start_method; if (sm == ACPI_TPM2_MEMORY_MAPPED) return -ENODEV; priv = devm_kzalloc(dev, sizeof(struct crb_priv), GFP_KERNEL); if (!priv) return -ENOMEM; /* The reason for the extra quirk is that the PTT in 4th Gen Core CPUs * report only ACPI start but in practice seems to require both * ACPI start and CRB start. */ if (sm == ACPI_TPM2_COMMAND_BUFFER || sm == ACPI_TPM2_MEMORY_MAPPED || !strcmp(acpi_device_hid(device), "MSFT0101")) priv->flags |= CRB_FL_CRB_START; if (sm == ACPI_TPM2_START_METHOD || sm == ACPI_TPM2_COMMAND_BUFFER_WITH_START_METHOD) priv->flags |= CRB_FL_ACPI_START; rc = crb_map_io(device, priv, buf); if (rc) return rc; return crb_init(device, priv); } static int crb_acpi_remove(struct acpi_device *device) { struct device *dev = &device->dev; struct tpm_chip *chip = dev_get_drvdata(dev); tpm_chip_unregister(chip); return 0; } static struct acpi_device_id crb_device_ids[] = { {"MSFT0101", 0}, {"", 0}, }; MODULE_DEVICE_TABLE(acpi, crb_device_ids); static struct acpi_driver crb_acpi_driver = { .name = "tpm_crb", .ids = crb_device_ids, .ops = { .add = crb_acpi_add, .remove = crb_acpi_remove, }, .drv = { .pm = &crb_pm, }, };
int main(int argc, char **argv) { int i,j; int res; crb_init(); for (i=1; i < argc; i++) { if (strcmp("--", argv[i])==0) { VALUE vargv; vargv = rb_gv_get("$*"); for (j = i+1; j < argc; j++) { rb_ary_push(vargv, rb_str_new2(argv[j])); } break; } else if ((strcmp("--debug", argv[i])==0) || (strcmp("-d", argv[i])==0)) { debug_flag = "true"; } else if ((strcmp("--help", argv[i])==0) || (strcmp("-h", argv[i])==0)) { help_flag = 1; } } snprintf(evalStr, MAX-400, "require 'rbconfig'\n" "$DEBUG=%s\n" "\n" "puts %%Q{ARGV: #{ARGV}} if $DEBUG\n" "$:.unshift '.'\n" "puts %%Q{LOAD_PATH: #{$:}} if $DEBUG\n" "argv0 = %%q*%s*\n" "puts %%Q{ARGV0: #{argv0}} if $DEBUG\n" "dir, rbfn = File.split(argv0)\n" "rbfn = rbfn.chomp(RbConfig::CONFIG['EXEEXT'])\n" "puts %%Q{Chdir: #{dir} RubyFile: #{rbfn}} if $DEBUG\n" "\n" "Dir.chdir(dir) do\n" " require rbfn\n" "end\n" ,debug_flag, argv[0]); if (help_flag) { printf( "%s syntax:\n" "\n" " -h --help show this message\n" " -d --debug set $DEBUG to true\n" " -- [arg1 [arg2 [...]]] all arguments pass to ruby program after '--'\n" "\n" //"---- this program will run ----\n" //"%s\n" //"--------\n" , argv[0] /*, evalStr */); exit(0); } res = crb_eval_string(evalStr); crb_cleanup(); if (res != 0) { fprintf(stderr, "\nerror %d\n", res); } return res; }