0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017
0018
0019
0020
0021
0022
0023
0024
0025
0026 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
0027
0028 #include <asm-generic/sections.h>
0029 #include <asm/cpu_device_id.h>
0030 #include <asm/imr.h>
0031 #include <asm/iosf_mbi.h>
0032 #include <asm/io.h>
0033
0034 #include <linux/debugfs.h>
0035 #include <linux/init.h>
0036 #include <linux/mm.h>
0037 #include <linux/types.h>
0038
0039 struct imr_device {
0040 bool init;
0041 struct mutex lock;
0042 int max_imr;
0043 int reg_base;
0044 };
0045
0046 static struct imr_device imr_dev;
0047
0048
0049
0050
0051
0052
0053
0054
0055
0056
0057
0058
0059
0060
0061
0062
0063
0064 #define IMR_LOCK BIT(31)
0065
0066 struct imr_regs {
0067 u32 addr_lo;
0068 u32 addr_hi;
0069 u32 rmask;
0070 u32 wmask;
0071 };
0072
0073 #define IMR_NUM_REGS (sizeof(struct imr_regs)/sizeof(u32))
0074 #define IMR_SHIFT 8
0075 #define imr_to_phys(x) ((x) << IMR_SHIFT)
0076 #define phys_to_imr(x) ((x) >> IMR_SHIFT)
0077
0078
0079
0080
0081
0082
0083
0084
0085
0086
0087
0088
0089
0090
0091
0092 static inline int imr_is_enabled(struct imr_regs *imr)
0093 {
0094 return !(imr->rmask == IMR_READ_ACCESS_ALL &&
0095 imr->wmask == IMR_WRITE_ACCESS_ALL &&
0096 imr_to_phys(imr->addr_lo) == 0 &&
0097 imr_to_phys(imr->addr_hi) == 0);
0098 }
0099
0100
0101
0102
0103
0104
0105
0106
0107
0108
0109
0110 static int imr_read(struct imr_device *idev, u32 imr_id, struct imr_regs *imr)
0111 {
0112 u32 reg = imr_id * IMR_NUM_REGS + idev->reg_base;
0113 int ret;
0114
0115 ret = iosf_mbi_read(QRK_MBI_UNIT_MM, MBI_REG_READ, reg++, &imr->addr_lo);
0116 if (ret)
0117 return ret;
0118
0119 ret = iosf_mbi_read(QRK_MBI_UNIT_MM, MBI_REG_READ, reg++, &imr->addr_hi);
0120 if (ret)
0121 return ret;
0122
0123 ret = iosf_mbi_read(QRK_MBI_UNIT_MM, MBI_REG_READ, reg++, &imr->rmask);
0124 if (ret)
0125 return ret;
0126
0127 return iosf_mbi_read(QRK_MBI_UNIT_MM, MBI_REG_READ, reg++, &imr->wmask);
0128 }
0129
0130
0131
0132
0133
0134
0135
0136
0137
0138
0139
0140
0141 static int imr_write(struct imr_device *idev, u32 imr_id, struct imr_regs *imr)
0142 {
0143 unsigned long flags;
0144 u32 reg = imr_id * IMR_NUM_REGS + idev->reg_base;
0145 int ret;
0146
0147 local_irq_save(flags);
0148
0149 ret = iosf_mbi_write(QRK_MBI_UNIT_MM, MBI_REG_WRITE, reg++, imr->addr_lo);
0150 if (ret)
0151 goto failed;
0152
0153 ret = iosf_mbi_write(QRK_MBI_UNIT_MM, MBI_REG_WRITE, reg++, imr->addr_hi);
0154 if (ret)
0155 goto failed;
0156
0157 ret = iosf_mbi_write(QRK_MBI_UNIT_MM, MBI_REG_WRITE, reg++, imr->rmask);
0158 if (ret)
0159 goto failed;
0160
0161 ret = iosf_mbi_write(QRK_MBI_UNIT_MM, MBI_REG_WRITE, reg++, imr->wmask);
0162 if (ret)
0163 goto failed;
0164
0165 local_irq_restore(flags);
0166 return 0;
0167 failed:
0168
0169
0170
0171
0172
0173 local_irq_restore(flags);
0174 WARN(ret, "IOSF-MBI write fail range 0x%08x-0x%08x unreliable\n",
0175 imr_to_phys(imr->addr_lo), imr_to_phys(imr->addr_hi) + IMR_MASK);
0176
0177 return ret;
0178 }
0179
0180
0181
0182
0183
0184
0185
0186
0187 static int imr_dbgfs_state_show(struct seq_file *s, void *unused)
0188 {
0189 phys_addr_t base;
0190 phys_addr_t end;
0191 int i;
0192 struct imr_device *idev = s->private;
0193 struct imr_regs imr;
0194 size_t size;
0195 int ret = -ENODEV;
0196
0197 mutex_lock(&idev->lock);
0198
0199 for (i = 0; i < idev->max_imr; i++) {
0200
0201 ret = imr_read(idev, i, &imr);
0202 if (ret)
0203 break;
0204
0205
0206
0207
0208
0209
0210 if (imr_is_enabled(&imr)) {
0211 base = imr_to_phys(imr.addr_lo);
0212 end = imr_to_phys(imr.addr_hi) + IMR_MASK;
0213 size = end - base + 1;
0214 } else {
0215 base = 0;
0216 end = 0;
0217 size = 0;
0218 }
0219 seq_printf(s, "imr%02i: base=%pa, end=%pa, size=0x%08zx "
0220 "rmask=0x%08x, wmask=0x%08x, %s, %s\n", i,
0221 &base, &end, size, imr.rmask, imr.wmask,
0222 imr_is_enabled(&imr) ? "enabled " : "disabled",
0223 imr.addr_lo & IMR_LOCK ? "locked" : "unlocked");
0224 }
0225
0226 mutex_unlock(&idev->lock);
0227 return ret;
0228 }
0229 DEFINE_SHOW_ATTRIBUTE(imr_dbgfs_state);
0230
0231
0232
0233
0234
0235
0236 static void imr_debugfs_register(struct imr_device *idev)
0237 {
0238 debugfs_create_file("imr_state", 0444, NULL, idev,
0239 &imr_dbgfs_state_fops);
0240 }
0241
0242
0243
0244
0245
0246
0247
0248
0249 static int imr_check_params(phys_addr_t base, size_t size)
0250 {
0251 if ((base & IMR_MASK) || (size & IMR_MASK)) {
0252 pr_err("base %pa size 0x%08zx must align to 1KiB\n",
0253 &base, size);
0254 return -EINVAL;
0255 }
0256 if (size == 0)
0257 return -EINVAL;
0258
0259 return 0;
0260 }
0261
0262
0263
0264
0265
0266
0267
0268
0269
0270
0271
0272 static inline size_t imr_raw_size(size_t size)
0273 {
0274 return size - IMR_ALIGN;
0275 }
0276
0277
0278
0279
0280
0281
0282
0283
0284 static inline int imr_address_overlap(phys_addr_t addr, struct imr_regs *imr)
0285 {
0286 return addr >= imr_to_phys(imr->addr_lo) && addr <= imr_to_phys(imr->addr_hi);
0287 }
0288
0289
0290
0291
0292
0293
0294
0295
0296
0297
0298 int imr_add_range(phys_addr_t base, size_t size,
0299 unsigned int rmask, unsigned int wmask)
0300 {
0301 phys_addr_t end;
0302 unsigned int i;
0303 struct imr_device *idev = &imr_dev;
0304 struct imr_regs imr;
0305 size_t raw_size;
0306 int reg;
0307 int ret;
0308
0309 if (WARN_ONCE(idev->init == false, "driver not initialized"))
0310 return -ENODEV;
0311
0312 ret = imr_check_params(base, size);
0313 if (ret)
0314 return ret;
0315
0316
0317 raw_size = imr_raw_size(size);
0318 end = base + raw_size;
0319
0320
0321
0322
0323
0324 imr.addr_lo = phys_to_imr(base);
0325 imr.addr_hi = phys_to_imr(end);
0326 imr.rmask = rmask;
0327 imr.wmask = wmask;
0328 if (!imr_is_enabled(&imr))
0329 return -ENOTSUPP;
0330
0331 mutex_lock(&idev->lock);
0332
0333
0334
0335
0336
0337
0338
0339 reg = -1;
0340 for (i = 0; i < idev->max_imr; i++) {
0341 ret = imr_read(idev, i, &imr);
0342 if (ret)
0343 goto failed;
0344
0345
0346 ret = -EINVAL;
0347 if (imr_is_enabled(&imr)) {
0348 if (imr_address_overlap(base, &imr))
0349 goto failed;
0350 if (imr_address_overlap(end, &imr))
0351 goto failed;
0352 } else {
0353 reg = i;
0354 }
0355 }
0356
0357
0358 if (reg == -1) {
0359 ret = -ENOMEM;
0360 goto failed;
0361 }
0362
0363 pr_debug("add %d phys %pa-%pa size %zx mask 0x%08x wmask 0x%08x\n",
0364 reg, &base, &end, raw_size, rmask, wmask);
0365
0366
0367 imr.addr_lo = phys_to_imr(base);
0368 imr.addr_hi = phys_to_imr(end);
0369 imr.rmask = rmask;
0370 imr.wmask = wmask;
0371
0372 ret = imr_write(idev, reg, &imr);
0373 if (ret < 0) {
0374
0375
0376
0377
0378
0379 imr.addr_lo = 0;
0380 imr.addr_hi = 0;
0381 imr.rmask = IMR_READ_ACCESS_ALL;
0382 imr.wmask = IMR_WRITE_ACCESS_ALL;
0383 imr_write(idev, reg, &imr);
0384 }
0385 failed:
0386 mutex_unlock(&idev->lock);
0387 return ret;
0388 }
0389 EXPORT_SYMBOL_GPL(imr_add_range);
0390
0391
0392
0393
0394
0395
0396
0397
0398
0399
0400
0401
0402
0403
0404
0405
0406
0407 static int __imr_remove_range(int reg, phys_addr_t base, size_t size)
0408 {
0409 phys_addr_t end;
0410 bool found = false;
0411 unsigned int i;
0412 struct imr_device *idev = &imr_dev;
0413 struct imr_regs imr;
0414 size_t raw_size;
0415 int ret = 0;
0416
0417 if (WARN_ONCE(idev->init == false, "driver not initialized"))
0418 return -ENODEV;
0419
0420
0421
0422
0423
0424 if (reg == -1) {
0425 ret = imr_check_params(base, size);
0426 if (ret)
0427 return ret;
0428 }
0429
0430
0431 raw_size = imr_raw_size(size);
0432 end = base + raw_size;
0433
0434 mutex_lock(&idev->lock);
0435
0436 if (reg >= 0) {
0437
0438 ret = imr_read(idev, reg, &imr);
0439 if (ret)
0440 goto failed;
0441
0442 if (!imr_is_enabled(&imr) || imr.addr_lo & IMR_LOCK) {
0443 ret = -ENODEV;
0444 goto failed;
0445 }
0446 found = true;
0447 } else {
0448
0449 for (i = 0; i < idev->max_imr; i++) {
0450 ret = imr_read(idev, i, &imr);
0451 if (ret)
0452 goto failed;
0453
0454 if (!imr_is_enabled(&imr) || imr.addr_lo & IMR_LOCK)
0455 continue;
0456
0457 if ((imr_to_phys(imr.addr_lo) == base) &&
0458 (imr_to_phys(imr.addr_hi) == end)) {
0459 found = true;
0460 reg = i;
0461 break;
0462 }
0463 }
0464 }
0465
0466 if (!found) {
0467 ret = -ENODEV;
0468 goto failed;
0469 }
0470
0471 pr_debug("remove %d phys %pa-%pa size %zx\n", reg, &base, &end, raw_size);
0472
0473
0474 imr.addr_lo = 0;
0475 imr.addr_hi = 0;
0476 imr.rmask = IMR_READ_ACCESS_ALL;
0477 imr.wmask = IMR_WRITE_ACCESS_ALL;
0478
0479 ret = imr_write(idev, reg, &imr);
0480
0481 failed:
0482 mutex_unlock(&idev->lock);
0483 return ret;
0484 }
0485
0486
0487
0488
0489
0490
0491
0492
0493
0494
0495
0496
0497
0498
0499 int imr_remove_range(phys_addr_t base, size_t size)
0500 {
0501 return __imr_remove_range(-1, base, size);
0502 }
0503 EXPORT_SYMBOL_GPL(imr_remove_range);
0504
0505
0506
0507
0508
0509
0510
0511
0512
0513
0514
0515
0516
0517
0518 static inline int imr_clear(int reg)
0519 {
0520 return __imr_remove_range(reg, 0, 0);
0521 }
0522
0523
0524
0525
0526
0527
0528
0529
0530
0531
0532
0533
0534
0535
0536
0537 static void __init imr_fixup_memmap(struct imr_device *idev)
0538 {
0539 phys_addr_t base = virt_to_phys(&_text);
0540 size_t size = virt_to_phys(&__end_rodata) - base;
0541 unsigned long start, end;
0542 int i;
0543 int ret;
0544
0545
0546 for (i = 0; i < idev->max_imr; i++)
0547 imr_clear(i);
0548
0549 start = (unsigned long)_text;
0550 end = (unsigned long)__end_rodata - 1;
0551
0552
0553
0554
0555
0556
0557
0558
0559
0560 ret = imr_add_range(base, size, IMR_CPU, IMR_CPU);
0561 if (ret < 0) {
0562 pr_err("unable to setup IMR for kernel: %zu KiB (%lx - %lx)\n",
0563 size / 1024, start, end);
0564 } else {
0565 pr_info("protecting kernel .text - .rodata: %zu KiB (%lx - %lx)\n",
0566 size / 1024, start, end);
0567 }
0568
0569 }
0570
0571 static const struct x86_cpu_id imr_ids[] __initconst = {
0572 X86_MATCH_VENDOR_FAM_MODEL(INTEL, 5, INTEL_FAM5_QUARK_X1000, NULL),
0573 {}
0574 };
0575
0576
0577
0578
0579
0580
0581 static int __init imr_init(void)
0582 {
0583 struct imr_device *idev = &imr_dev;
0584
0585 if (!x86_match_cpu(imr_ids) || !iosf_mbi_available())
0586 return -ENODEV;
0587
0588 idev->max_imr = QUARK_X1000_IMR_MAX;
0589 idev->reg_base = QUARK_X1000_IMR_REGBASE;
0590 idev->init = true;
0591
0592 mutex_init(&idev->lock);
0593 imr_debugfs_register(idev);
0594 imr_fixup_memmap(idev);
0595 return 0;
0596 }
0597 device_initcall(imr_init);