Coverage Report

Created: 2017-10-25 09:10

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