1 #include <xen/init.h>
2 #include <xen/types.h>
3 #include <xen/lib.h>
4 #include <xen/param.h>
5 #include <xen/sched.h>
6 #include <xen/domain_page.h>
7 #include <xen/iommu.h>
8 #include <xen/acpi.h>
9 #include <xen/pfn.h>
10 #include <asm/fixmap.h>
11 #include <asm/page.h>
12 #include <asm/processor.h>
13 #include <asm/e820.h>
14 #include <asm/tboot.h>
15 #include <asm/setup.h>
16 #include <crypto/vmac.h>
17 
18 /* tboot=<physical address of shared page> */
19 static unsigned long __initdata opt_tboot_pa;
20 integer_param("tboot", opt_tboot_pa);
21 
22 /* Global pointer to shared data; NULL means no measured launch. */
23 tboot_shared_t *g_tboot_shared;
24 
25 static vmac_t domain_mac;     /* MAC for all domains during S3 */
26 static vmac_t xenheap_mac;    /* MAC for xen heap during S3 */
27 static vmac_t frametable_mac; /* MAC for frame table during S3 */
28 
29 static const uuid_t tboot_shared_uuid = TBOOT_SHARED_UUID;
30 
31 /* used by tboot_protect_mem_regions() and/or tboot_parse_dmar_table() */
32 static uint64_t __initdata txt_heap_base, __initdata txt_heap_size;
33 static uint64_t __initdata sinit_base, __initdata sinit_size;
34 
35 /*
36  * TXT configuration registers (offsets from TXT_{PUB, PRIV}_CONFIG_REGS_BASE)
37  */
38 
39 #define TXT_PUB_CONFIG_REGS_BASE       0xfed30000
40 #define TXT_PRIV_CONFIG_REGS_BASE      0xfed20000
41 
42 /* # pages for each config regs space - used by fixmap */
43 #define NR_TXT_CONFIG_PAGES     ((TXT_PUB_CONFIG_REGS_BASE -                \
44                                   TXT_PRIV_CONFIG_REGS_BASE) >> PAGE_SHIFT)
45 
46 /* offsets from pub/priv config space */
47 #define TXTCR_SINIT_BASE            0x0270
48 #define TXTCR_SINIT_SIZE            0x0278
49 #define TXTCR_HEAP_BASE             0x0300
50 #define TXTCR_HEAP_SIZE             0x0308
51 
52 #define SHA1_SIZE      20
53 typedef uint8_t   sha1_hash_t[SHA1_SIZE];
54 
55 typedef struct __packed {
56     uint32_t     version;             /* currently 6 */
57     sha1_hash_t  bios_acm_id;
58     uint32_t     edx_senter_flags;
59     uint64_t     mseg_valid;
60     sha1_hash_t  sinit_hash;
61     sha1_hash_t  mle_hash;
62     sha1_hash_t  stm_hash;
63     sha1_hash_t  lcp_policy_hash;
64     uint32_t     lcp_policy_control;
65     uint32_t     rlp_wakeup_addr;
66     uint32_t     reserved;
67     uint32_t     num_mdrs;
68     uint32_t     mdrs_off;
69     uint32_t     num_vtd_dmars;
70     uint32_t     vtd_dmars_off;
71 } sinit_mle_data_t;
72 
tboot_copy_memory(unsigned char * va,uint32_t size,unsigned long pa)73 static void __init tboot_copy_memory(unsigned char *va, uint32_t size,
74                                      unsigned long pa)
75 {
76     unsigned long map_base = 0;
77     unsigned char *map_addr = NULL;
78     unsigned int i;
79 
80     for ( i = 0; i < size; i++ )
81     {
82         if ( map_base != PFN_DOWN(pa + i) )
83         {
84             map_base = PFN_DOWN(pa + i);
85             set_fixmap(FIX_TBOOT_MAP_ADDRESS, map_base << PAGE_SHIFT);
86             map_addr = fix_to_virt(FIX_TBOOT_MAP_ADDRESS);
87         }
88         va[i] = map_addr[pa + i - (map_base << PAGE_SHIFT)];
89     }
90 }
91 
tboot_probe(void)92 void __init tboot_probe(void)
93 {
94     tboot_shared_t *tboot_shared;
95 
96     /* Look for valid page-aligned address for shared page. */
97     if ( !opt_tboot_pa || (opt_tboot_pa & ~PAGE_MASK) )
98         return;
99 
100     /* Map and check for tboot UUID. */
101     set_fixmap(FIX_TBOOT_SHARED_BASE, opt_tboot_pa);
102     tboot_shared = fix_to_virt(FIX_TBOOT_SHARED_BASE);
103     if ( tboot_shared == NULL )
104         return;
105     if ( memcmp(&tboot_shared_uuid, (uuid_t *)tboot_shared, sizeof(uuid_t)) )
106         return;
107 
108     /* new tboot_shared (w/ GAS support, integrity, etc.) is not backwards
109        compatible */
110     if ( tboot_shared->version < 4 )
111     {
112         printk("unsupported version of tboot (%u)\n", tboot_shared->version);
113         return;
114     }
115 
116     g_tboot_shared = tboot_shared;
117     printk("TBOOT: found shared page at phys addr %#lx:\n", opt_tboot_pa);
118     printk("  version: %d\n", tboot_shared->version);
119     printk("  log_addr: %#x\n", tboot_shared->log_addr);
120     printk("  shutdown_entry: %#x\n", tboot_shared->shutdown_entry);
121     printk("  tboot_base: %#x\n", tboot_shared->tboot_base);
122     printk("  tboot_size: %#x\n", tboot_shared->tboot_size);
123     if ( tboot_shared->version >= 6 )
124         printk("  flags: %#x\n", tboot_shared->flags);
125 
126     /* these will be needed by tboot_protect_mem_regions() and/or
127        tboot_parse_dmar_table(), so get them now */
128 
129     txt_heap_base = txt_heap_size = sinit_base = sinit_size = 0;
130     /* TXT Heap */
131     tboot_copy_memory((unsigned char *)&txt_heap_base, sizeof(txt_heap_base),
132                       TXT_PUB_CONFIG_REGS_BASE + TXTCR_HEAP_BASE);
133     tboot_copy_memory((unsigned char *)&txt_heap_size, sizeof(txt_heap_size),
134                       TXT_PUB_CONFIG_REGS_BASE + TXTCR_HEAP_SIZE);
135     /* SINIT */
136     tboot_copy_memory((unsigned char *)&sinit_base, sizeof(sinit_base),
137                       TXT_PUB_CONFIG_REGS_BASE + TXTCR_SINIT_BASE);
138     tboot_copy_memory((unsigned char *)&sinit_size, sizeof(sinit_size),
139                       TXT_PUB_CONFIG_REGS_BASE + TXTCR_SINIT_SIZE);
140     clear_fixmap(FIX_TBOOT_MAP_ADDRESS);
141 }
142 
143 /* definitions from xen/drivers/passthrough/vtd/iommu.h
144  * used to walk through vtd page tables */
145 #define LEVEL_STRIDE (9)
146 #define PTE_NUM (1<<LEVEL_STRIDE)
147 #define dma_pte_present(p) (((p).val & 3) != 0)
148 #define dma_pte_addr(p) ((p).val & PAGE_MASK_4K)
149 #define agaw_to_level(val) ((val)+2)
150 struct dma_pte {
151     u64 val;
152 };
153 
update_iommu_mac(vmac_ctx_t * ctx,uint64_t pt_maddr,int level)154 static void update_iommu_mac(vmac_ctx_t *ctx, uint64_t pt_maddr, int level)
155 {
156     int i;
157     struct dma_pte *pt_vaddr, *pte;
158     int next_level = level - 1;
159 
160     if ( pt_maddr == 0 )
161         return;
162 
163     pt_vaddr = (struct dma_pte *)map_domain_page(_mfn(paddr_to_pfn(pt_maddr)));
164     vmac_update((void *)pt_vaddr, PAGE_SIZE, ctx);
165 
166     for ( i = 0; i < PTE_NUM; i++ )
167     {
168         pte = &pt_vaddr[i];
169         if ( !dma_pte_present(*pte) )
170             continue;
171 
172         if ( next_level >= 1 )
173             update_iommu_mac(ctx, dma_pte_addr(*pte), next_level);
174     }
175 
176     unmap_domain_page(pt_vaddr);
177 }
178 
179 #define is_page_in_use(page) \
180     (page_state_is(page, inuse) || page_state_is(page, offlining))
181 
update_pagetable_mac(vmac_ctx_t * ctx)182 static void update_pagetable_mac(vmac_ctx_t *ctx)
183 {
184     unsigned long mfn;
185 
186     for ( mfn = 0; mfn < max_page; mfn++ )
187     {
188         struct page_info *page = mfn_to_page(_mfn(mfn));
189 
190         if ( !mfn_valid(_mfn(mfn)) )
191             continue;
192         if ( is_page_in_use(page) && !is_special_page(page) )
193         {
194             if ( page->count_info & PGC_page_table )
195             {
196                 void *pg = map_domain_page(_mfn(mfn));
197 
198                 vmac_update(pg, PAGE_SIZE, ctx);
199                 unmap_domain_page(pg);
200             }
201         }
202     }
203 }
204 
tboot_gen_domain_integrity(const uint8_t key[TB_KEY_SIZE],vmac_t * mac)205 static void tboot_gen_domain_integrity(const uint8_t key[TB_KEY_SIZE],
206                                        vmac_t *mac)
207 {
208     struct domain *d;
209     struct page_info *page;
210     uint8_t nonce[16] = {};
211     vmac_ctx_t ctx;
212 
213     vmac_set_key((uint8_t *)key, &ctx);
214     for_each_domain( d )
215     {
216         if ( !(d->options & XEN_DOMCTL_CDF_s3_integrity) )
217             continue;
218         printk("MACing Domain %u\n", d->domain_id);
219 
220         spin_lock(&d->page_alloc_lock);
221         page_list_for_each(page, &d->page_list)
222         {
223             void *pg = __map_domain_page(page);
224             vmac_update(pg, PAGE_SIZE, &ctx);
225             unmap_domain_page(pg);
226         }
227         spin_unlock(&d->page_alloc_lock);
228 
229         if ( !is_idle_domain(d) )
230         {
231             const struct domain_iommu *dio = dom_iommu(d);
232 
233             update_iommu_mac(&ctx, dio->arch.pgd_maddr,
234                              agaw_to_level(dio->arch.agaw));
235         }
236     }
237 
238     /* MAC all shadow page tables */
239     update_pagetable_mac(&ctx);
240 
241     *mac = vmac(NULL, 0, nonce, NULL, &ctx);
242 
243     /* wipe ctx to ensure key is not left in memory */
244     memset(&ctx, 0, sizeof(ctx));
245 }
246 
247 /*
248  * For stack overflow detection in debug build, a guard page is set up.
249  * This fn is used to detect whether a page is in the guarded pages for
250  * the above reason.
251  */
mfn_in_guarded_stack(unsigned long mfn)252 static int mfn_in_guarded_stack(unsigned long mfn)
253 {
254     void *p;
255     int i;
256 
257     for ( i = 0; i < nr_cpu_ids; i++ )
258     {
259         if ( !stack_base[i] )
260             continue;
261         p = (void *)((unsigned long)stack_base[i] + STACK_SIZE -
262                      PRIMARY_STACK_SIZE - PAGE_SIZE);
263         if ( mfn == virt_to_mfn(p) )
264             return -1;
265     }
266 
267     return 0;
268 }
269 
tboot_gen_xenheap_integrity(const uint8_t key[TB_KEY_SIZE],vmac_t * mac)270 static void tboot_gen_xenheap_integrity(const uint8_t key[TB_KEY_SIZE],
271                                         vmac_t *mac)
272 {
273     unsigned long mfn;
274     uint8_t nonce[16] = {};
275     vmac_ctx_t ctx;
276 
277     vmac_set_key((uint8_t *)key, &ctx);
278     for ( mfn = 0; mfn < max_page; mfn++ )
279     {
280         struct page_info *page = mfn_to_page(_mfn(mfn));
281 
282         if ( !mfn_valid(_mfn(mfn)) )
283             continue;
284         if ( is_xen_fixed_mfn(_mfn(mfn)) )
285             continue; /* skip Xen */
286         if ( (mfn >= PFN_DOWN(g_tboot_shared->tboot_base - 3 * PAGE_SIZE))
287              && (mfn < PFN_UP(g_tboot_shared->tboot_base
288                               + g_tboot_shared->tboot_size
289                               + 3 * PAGE_SIZE)) )
290             continue; /* skip tboot and its page tables */
291 
292         if ( is_page_in_use(page) && is_special_page(page) )
293         {
294             void *pg;
295 
296             if ( mfn_in_guarded_stack(mfn) )
297                 continue; /* skip guard stack, see memguard_guard_stack() in mm.c */
298 
299             pg = mfn_to_virt(mfn);
300             vmac_update((uint8_t *)pg, PAGE_SIZE, &ctx);
301         }
302     }
303     *mac = vmac(NULL, 0, nonce, NULL, &ctx);
304 
305     /* wipe ctx to ensure key is not left in memory */
306     memset(&ctx, 0, sizeof(ctx));
307 }
308 
tboot_gen_frametable_integrity(const uint8_t key[TB_KEY_SIZE],vmac_t * mac)309 static void tboot_gen_frametable_integrity(const uint8_t key[TB_KEY_SIZE],
310                                            vmac_t *mac)
311 {
312     unsigned int sidx, eidx, nidx;
313     unsigned int max_idx = DIV_ROUND_UP(max_pdx, PDX_GROUP_COUNT);
314     uint8_t nonce[16] = {};
315     vmac_ctx_t ctx;
316 
317     vmac_set_key((uint8_t *)key, &ctx);
318     for ( sidx = 0; ; sidx = nidx )
319     {
320         eidx = find_next_zero_bit(pdx_group_valid, max_idx, sidx);
321         nidx = find_next_bit(pdx_group_valid, max_idx, eidx);
322         if ( nidx >= max_idx )
323             break;
324         vmac_update((uint8_t *)pdx_to_page(sidx * PDX_GROUP_COUNT),
325                        pdx_to_page(eidx * PDX_GROUP_COUNT)
326                        - pdx_to_page(sidx * PDX_GROUP_COUNT), &ctx);
327     }
328     vmac_update((uint8_t *)pdx_to_page(sidx * PDX_GROUP_COUNT),
329                    pdx_to_page(max_pdx - 1) + 1
330                    - pdx_to_page(sidx * PDX_GROUP_COUNT), &ctx);
331 
332     *mac = vmac(NULL, 0, nonce, NULL, &ctx);
333 
334     /* wipe ctx to ensure key is not left in memory */
335     memset(&ctx, 0, sizeof(ctx));
336 }
337 
tboot_shutdown(uint32_t shutdown_type)338 void tboot_shutdown(uint32_t shutdown_type)
339 {
340     mfn_t map_base;
341     uint32_t map_size;
342     int err;
343 
344     g_tboot_shared->shutdown_type = shutdown_type;
345 
346     /* Create identity map for tboot shutdown code. */
347     /* do before S3 integrity because mapping tboot may change xenheap */
348     map_base = maddr_to_mfn(g_tboot_shared->tboot_base);
349     map_size = PFN_UP(g_tboot_shared->tboot_size);
350 
351     err = map_pages_to_xen(mfn_to_maddr(map_base), map_base, map_size,
352                            __PAGE_HYPERVISOR);
353     if ( err != 0 )
354     {
355         printk("error (%#x) mapping tboot pages (mfns) @ %"PRI_mfn", %#x\n",
356                err, mfn_x(map_base), map_size);
357         return;
358     }
359 
360     /* Disable interrupts as early as possible but not prior to */
361     /* calling map_pages_to_xen */
362     local_irq_disable();
363 
364     /* if this is S3 then set regions to MAC */
365     if ( shutdown_type == TB_SHUTDOWN_S3 )
366     {
367         /*
368          * Xen regions for tboot to MAC. This needs to remain in sync with
369          * xen_in_range().
370          */
371         g_tboot_shared->num_mac_regions = 3;
372         /* S3 resume code (and other real mode trampoline code) */
373         g_tboot_shared->mac_regions[0].start = bootsym_phys(trampoline_start);
374         g_tboot_shared->mac_regions[0].size = trampoline_end - trampoline_start;
375         /* hypervisor .text + .rodata */
376         g_tboot_shared->mac_regions[1].start = (uint64_t)__pa(&_stext);
377         g_tboot_shared->mac_regions[1].size = __2M_rodata_end - _stext;
378         /* hypervisor .data + .bss */
379         g_tboot_shared->mac_regions[2].start = (uint64_t)__pa(&__2M_rwdata_start);
380         g_tboot_shared->mac_regions[2].size = __2M_rwdata_end - __2M_rwdata_start;
381 
382         /*
383          * MAC domains and other Xen memory
384          */
385         /* Xen has no better entropy source for MAC key than tboot's */
386         /* MAC domains first in case it perturbs xenheap */
387         tboot_gen_domain_integrity(g_tboot_shared->s3_key, &domain_mac);
388         tboot_gen_frametable_integrity(g_tboot_shared->s3_key, &frametable_mac);
389         tboot_gen_xenheap_integrity(g_tboot_shared->s3_key, &xenheap_mac);
390     }
391 
392     /*
393      * During early boot, we can be called by panic before idle_vcpu[0] is
394      * setup, but in that case we don't need to change page tables.
395      */
396     if ( idle_vcpu[0] )
397         write_ptbase(idle_vcpu[0]);
398 
399     ((void(*)(void))(unsigned long)g_tboot_shared->shutdown_entry)();
400 
401     BUG(); /* should not reach here */
402 }
403 
tboot_in_measured_env(void)404 int tboot_in_measured_env(void)
405 {
406     return (g_tboot_shared != NULL);
407 }
408 
tboot_protect_mem_regions(void)409 int __init tboot_protect_mem_regions(void)
410 {
411     int rc;
412 
413     if ( !tboot_in_measured_env() )
414         return 1;
415 
416     /* TXT Heap */
417     if ( txt_heap_base == 0 )
418         return 0;
419     rc = e820_change_range_type(&e820, txt_heap_base,
420                                 txt_heap_base + txt_heap_size,
421                                 E820_RESERVED, E820_UNUSABLE);
422     if ( !rc )
423         return 0;
424 
425     /* SINIT */
426     if ( sinit_base == 0 )
427         return 0;
428     rc = e820_change_range_type(&e820, sinit_base,
429                                 sinit_base + sinit_size,
430                                 E820_RESERVED, E820_UNUSABLE);
431     if ( !rc )
432         return 0;
433 
434     /* TXT Private Space */
435     rc = e820_change_range_type(&e820, TXT_PRIV_CONFIG_REGS_BASE,
436                  TXT_PRIV_CONFIG_REGS_BASE + NR_TXT_CONFIG_PAGES * PAGE_SIZE,
437                  E820_RESERVED, E820_UNUSABLE);
438     if ( !rc )
439         return 0;
440 
441     return 1;
442 }
443 
tboot_parse_dmar_table(acpi_table_handler dmar_handler)444 int __init tboot_parse_dmar_table(acpi_table_handler dmar_handler)
445 {
446     int rc;
447     uint64_t size;
448     uint32_t dmar_table_length;
449     unsigned long pa;
450     sinit_mle_data_t sinit_mle_data;
451     void *dmar_table;
452 
453     if ( !tboot_in_measured_env() )
454         return acpi_table_parse(ACPI_SIG_DMAR, dmar_handler);
455 
456     /* ACPI tables may not be DMA protected by tboot, so use DMAR copy */
457     /* SINIT saved in SinitMleData in TXT heap (which is DMA protected) */
458 
459     if ( txt_heap_base == 0 )
460         return 1;
461 
462     /* walk heap to SinitMleData */
463     pa = txt_heap_base;
464     /* skip BiosData */
465     tboot_copy_memory((unsigned char *)&size, sizeof(size), pa);
466     pa += size;
467     /* skip OsMleData */
468     tboot_copy_memory((unsigned char *)&size, sizeof(size), pa);
469     pa += size;
470     /* skip OsSinitData */
471     tboot_copy_memory((unsigned char *)&size, sizeof(size), pa);
472     pa += size;
473     /* now points to SinitMleDataSize; set to SinitMleData */
474     pa += sizeof(uint64_t);
475     tboot_copy_memory((unsigned char *)&sinit_mle_data, sizeof(sinit_mle_data),
476                       pa);
477     /* get addr of DMAR table */
478     pa += sinit_mle_data.vtd_dmars_off - sizeof(uint64_t);
479     tboot_copy_memory((unsigned char *)&dmar_table_length,
480                       sizeof(dmar_table_length),
481                       pa + sizeof(char) * ACPI_NAME_SIZE);
482     dmar_table = xmalloc_bytes(dmar_table_length);
483     if ( !dmar_table )
484         return -ENOMEM;
485     tboot_copy_memory(dmar_table, dmar_table_length, pa);
486     clear_fixmap(FIX_TBOOT_MAP_ADDRESS);
487 
488     rc = dmar_handler(dmar_table);
489     xfree(dmar_table);
490 
491     return rc;
492 }
493 
494 static vmac_t orig_mac, resume_mac;
495 
tboot_s3_resume(void)496 int tboot_s3_resume(void)
497 {
498     if ( !tboot_in_measured_env() )
499         return 0;
500 
501     /* need to do these in reverse order of shutdown */
502     tboot_gen_xenheap_integrity(g_tboot_shared->s3_key, &resume_mac);
503     orig_mac = xenheap_mac;
504     if ( resume_mac != xenheap_mac )
505         return -1;
506 
507     tboot_gen_frametable_integrity(g_tboot_shared->s3_key, &resume_mac);
508     orig_mac = frametable_mac;
509     if ( resume_mac != frametable_mac )
510         return -2;
511 
512     tboot_gen_domain_integrity(g_tboot_shared->s3_key, &resume_mac);
513     orig_mac = domain_mac;
514     if ( resume_mac != domain_mac )
515         return -3;
516 
517     return 0;
518 }
519 
tboot_s3_error(int error)520 void tboot_s3_error(int error)
521 {
522     const char *what = "???";
523 
524     BUG_ON(!error || !tboot_in_measured_env());
525 
526     switch ( error )
527     {
528     case -1: what = "Xen heap"; break;
529     case -2: what = "frame table"; break;
530     case -3: what = "domains"; break;
531     }
532 
533     printk("MAC for %s before S3 is: 0x%08"PRIx64"\n", what, orig_mac);
534     printk("MAC for %s after S3 is: 0x%08"PRIx64"\n", what, resume_mac);
535     panic("Memory integrity was lost on resume (%d)\n", error);
536 }
537 
tboot_wake_ap(int apicid,unsigned long sipi_vec)538 int tboot_wake_ap(int apicid, unsigned long sipi_vec)
539 {
540     if ( g_tboot_shared->version >= 6 &&
541          (g_tboot_shared->flags & TB_FLAG_AP_WAKE_SUPPORT) )
542     {
543         g_tboot_shared->ap_wake_addr = sipi_vec;
544         g_tboot_shared->ap_wake_trigger = apicid;
545         return 0;
546     }
547     return 1;
548 }
549 
550 /*
551  * Local variables:
552  * mode: C
553  * c-file-style: "BSD"
554  * c-basic-offset: 4
555  * tab-width: 4
556  * indent-tabs-mode: nil
557  * End:
558  */
559