summaryrefslogtreecommitdiffstats
path: root/tboot/tboot.c
blob: a5f773b546b97ab55eb217e7c6548a7512350442 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
/*
 * tboot.c: main entry point and "generic" routines for measured launch
 *          support
 *
 * Copyright (c) 2006-2010, Intel Corporation
 * All rights reserved.
 *
 * Copyright (c) 2017 Assured Information Security.
 * Ross Philipson <philipsonr@ainfosec.com>
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 *   * Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *   * Redistributions in binary form must reproduce the above
 *     copyright notice, this list of conditions and the following
 *     disclaimer in the documentation and/or other materials provided
 *     with the distribution.
 *   * Neither the name of the Intel Corporation nor the names of its
 *     contributors may be used to endorse or promote products derived
 *     from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
 * OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 */

#include <config.h>
#include <efibase.h>
#include <types.h>
#include <stdbool.h>
#include <stdarg.h>
#include <compiler.h>
#include <string.h>
#include <printk.h>
#include <uuid.h>
#include <misc.h>
#include <processor.h>
#include <cmdline.h>
#include <eficore.h>
#include <eficonfig.h>
#include <msr.h>
#include <atomic.h>
#include <hash.h>
#include <io.h>
#include <mutex.h>
#include <mle.h>
#include <tpm.h>
#include <tb_error.h>
#include <tb_policy.h>
#include <tboot.h>
#include <acpi.h>
#include <txt/acmod.h>
#include <txt/mtrrs.h>
#include <txt/vmcs.h>
#include <txt/config_regs.h>
#include <txt/heap.h>
#include <txt/verify.h>
#include <txt/txt.h>

/* counter timeout for waiting for all APs to exit guests */
#define AP_GUEST_EXIT_TIMEOUT     0x01000000

__data long s3_flag = 0;

#ifdef EFI_DEBUG
static void efi_debug_print_d(efi_xen_tboot_data_t *d)
{
    const efi_file_t *xen_file = efi_get_xen();

    printk("Xen TBOOT shared data:\n");
    printk("  xen              = %p\n", xen_file->u.buffer);
    printk("  xen_size         = 0x%llx\n", xen_file->size);
    printk("  kernel           = %p\n", d->kernel);
    printk("  kernel_size      = 0x%llx\n", d->kernel_size);
    printk("  ramdisk          = %p\n", d->ramdisk);
    printk("  ramdisk_size     = 0x%llx\n", d->ramdisk_size);
    printk("  memory_map       = %p\n", d->memory_map);
    printk("  memory_map_size  = 0x%llx\n", d->memory_map_size);
    printk("  memory_desc_size = 0x%llx\n", d->memory_desc_size);
    printk("  _tboot_shared    = %p\n", &_tboot_shared);
    printk("  shared size      = 0x%x\n", sizeof(tboot_shared_t));
}
#else
#define efi_debug_print_d(d)
#endif

static void store_section_sizes(void)
{
    uint64_t mle_start_ref;
    uint64_t mle_size_ref;
    uint64_t bss_start_ref;
    uint64_t bss_size_ref;

    /*
     * The _mle_start symbol is exactly at the beginning of the .text section.
     * The _bss_start symbol is exactly at the beginning of the .bss section.
     * The .text and .bss section sizes are gotten from the PE information but
     * for a given build, they will always be the same. So that means they can
     * be put in the MLE and measured.
     */

    lea_reference(_mle_start, mle_start_ref);
    lea_reference(_mle_size, mle_size_ref);
    lea_reference(_bss_start, bss_start_ref);
    lea_reference(_bss_size, bss_size_ref);

    if ((void*)mle_start_ref != g_text_base) {
        printk(TBOOT_ERR"_mle_start != g_text_base\n");
        apply_policy(TB_ERR_FATAL);
    }

    *((uint64_t*)mle_size_ref) = g_text_size;
    printk(TBOOT_INFO"_mle_start: 0x%llx _mle_size: 0x%llx\n",
           mle_start_ref, *((uint64_t*)mle_size_ref));

    if ((void*)bss_start_ref != g_bss_base) {
        printk(TBOOT_ERR"_bss_start != g_bss_base\n");
        apply_policy(TB_ERR_FATAL);
    }

    *((uint64_t*)bss_size_ref) = g_bss_size;
    printk(TBOOT_INFO"_bss_start: 0x%llx _bss_size: 0x%llx\n",
           bss_start_ref, *((uint64_t*)bss_size_ref));
}

static tb_error_t verify_platform(void)
{
    return txt_verify_platform();
}

static bool is_launched(void)
{
    if ( supports_txt() == TB_ERR_NONE )
        return txt_is_launched();
    else return false;
}

static bool prepare_cpu(void)
{
    return txt_prepare_cpu();
}

static void copy_s3_wakeup_entry(void)
{
    /* TODO deal with S3 later */
}

void cpu_wakeup(uint32_t cpuid, uint64_t sipi_vec)
{
    printk(TBOOT_INFO"cpu %u waking up, SIPI vector=%llx\n", cpuid, sipi_vec);

    /* change to real mode and then jump to SIPI vector */
    /* TODO _prot_to_real(sipi_vec); */
}

#define ICR_LOW 0x300

/*static*/ void startup_rlps(void)
{
    uint32_t rlp_count = ((cpuid_ecx(1) >> 16) & 0xff) - 1;
    uint64_t apicbase = rdmsr(MSR_APICBASE) & 0xfffffffffffff000;

    if ( rlp_count == 0 )
        return;

    /* send init ipi to all rlp -- Dest Shorthand: 11, Delivery Mode: 101 */
    writel(apicbase + ICR_LOW, 0xc0500);
}

void launch_racm(void)
{
    /* TODO this is gonna do GETSEC[ENTERACCS] */
    /* This means IA-32e */
}

static void shutdown_system(uint32_t);
void check_racm_result(void)
{
    txt_get_racm_error();
    shutdown_system(TB_SHUTDOWN_HALT); 
}

void begin_initial_launch(void)
{
    const char *cmdline;
    const efi_file_t *sinit_file;
    acm_hdr_t *sinit;
    tb_error_t err;

    /* always load cmdline defaults */
    tboot_parse_cmdline(true);

    /* on pre-SENTER boot, copy command line to buffer in tboot image
     * (so that it will be measured); buffer must be 0 -filled */
    if ( !is_launched() && !s3_flag ) {
        memset(g_cmdline, '\0', sizeof(g_cmdline));
        cmdline = efi_cfg_get_value(EFI_CONFIG_TBOOT_PARSED,
                                    SECTION_TBOOT, ITEM_OPTIONS);
        if (cmdline)
            strncpy(g_cmdline, cmdline, sizeof(g_cmdline)-1);
    }

    /* always parse cmdline */
    tboot_parse_cmdline(false);

    /* initialize all logging targets */
    printk_init(INIT_PRE_LAUNCH);

    /* DEBUG */
    print_test_chars();

    printk(TBOOT_INFO"******************* TBOOT *******************\n");
    printk(TBOOT_INFO"   %s\n", TBOOT_CHANGESET);
    printk(TBOOT_INFO"*********************************************\n");

    printk(TBOOT_INFO"command line: %s\n", g_cmdline);

    /* DEBUG */
    print_system_values();

    /* if telled to check revocation acm result, go with simplified path */
    if ( get_tboot_call_racm_check() )
        check_racm_result(); /* never return */

    /* TODO if (is_launched()) printk(TBOOT_INFO"SINIT ACM successfully returned...\n");*/
    if ( s3_flag ) printk(TBOOT_INFO"Resume from S3...\n");

    /* clear resume vector on S3 resume so any resets will not use it */
    /* TODO if ( !is_launched() && s3_flag )        set_s3_resume_vector(&_tboot_shared.acpi_sinfo, 0);*/

    /* we should only be executing on the BSP */
    if ( !(rdmsr(MSR_APICBASE) & APICBASE_BSP) ) {
        printk(TBOOT_INFO"entry processor is not BSP\n");
        apply_policy(TB_ERR_FATAL);
    }
    printk(TBOOT_INFO"BSP is cpu %u\n", get_apicid());

    /*
     * TODO e820 copied here but TBOOT will not be using it. Xen will have to
     * do e820 fixup work and present it to dom0. We still need to read the
     * min_ram value from the config that used to happen in that call
     */
    get_tboot_min_ram();

    /* make TPM ready for measured launch */
    if (!tpm_detect())
        apply_policy(TB_ERR_TPM_NOT_READY);

    /* we need to make sure this is a (TXT-) capable platform before using */
    /* any of the features, incl. those required to check if the environment */
    /* has already been launched */

    if (!g_sinit) {
        sinit_file = efi_get_platform_sinit();
        if (sinit_file == NULL) 
            apply_policy(TB_ERR_SINIT_NOT_PRESENT);
        /* check if it is newer than BIOS provided version, then copy it to BIOS reserved region */
        g_sinit = copy_sinit((const acm_hdr_t*)sinit_file->u.buffer);
        if (g_sinit == NULL) 
            apply_policy(TB_ERR_SINIT_NOT_PRESENT);
        if (!verify_acmod(g_sinit)) 
            apply_policy(TB_ERR_ACMOD_VERIFY_FAILED);
    }
    test_virt_to_phys((uint64_t)g_sinit);

    /* read tboot verified launch control policy from TPM-NV (will use default if none in TPM-NV) */
    err = set_policy();
    apply_policy(err);

    /* if telled to call revocation acm, go with simplified path */
    if ( get_tboot_call_racm() )
        launch_racm(); /* never return */

    /* need to verify that platform supports TXT before we can check error */
    /* (this includes TPM support) */
    err = supports_txt();
    apply_policy(err);

    /* print any errors on last boot, which must be from TXT launch */
    txt_get_error();

    /* need to verify that platform can perform measured launch */
    err = verify_platform();
    apply_policy(err);

    /*
     * Check for modules was here but that is not how things work any longer.
     * Xen will load the other modules and have to tell us about them later.
     */

    /* prepare_cpu() will be done later */

    /* check for error from previous boot */
    printk(TBOOT_INFO"checking previous errors on the last boot.\n\t");
    if ( was_last_boot_error() )
        printk(TBOOT_INFO"last boot has error.\n");
    else
        printk(TBOOT_INFO"last boot has no error.\n");

    if ( !prepare_tpm() )
        apply_policy(TB_ERR_TPM_NOT_READY);

    /*
     * Some of the MLE bits can be setup early before we jump off to
     * the next gig. First setup the MLE header with offest relative to
     * where we are then build the MLE page tables. Also load RIP
     * relative addresses for VMCS structures.
     */
    txt_init_mle_header();

    if ( !txt_build_mle_pagetable() )
        apply_policy(TB_ERR_FATAL);

    store_section_sizes();

    /* This is the end of the line for the initial launch. It is time to start
     * Xen and transfer control. The actual SMX launch will be done in a
     * callback from Xen after EBS.
     */
}

void begin_launch(efi_xen_tboot_data_t *xtd)
{
    tb_error_t err;

    /* initialize post EBS logging targets - this must be done first */
    printk_init(INIT_POST_EBS);

    /* store kernel and ramdisk module information */
    if ( !efi_store_xen_tboot_data(xtd) )
        apply_policy(TB_ERR_FATAL);

    /* DEBUG */
    print_system_values();

    efi_debug_print_d(xtd);

    if ( !efi_scan_memory_map() )
        apply_policy(TB_ERR_FATAL);

    /* DEBUG */
    /*dump_page_tables();*/

    /* make the CPU ready for measured launch */
    if ( !prepare_cpu() )
        apply_policy(TB_ERR_FATAL);

    /* launch the measured environment */
    err = txt_launch_environment();
    apply_policy(err);

    /* TODO have to figure out how to return to Xen when we pop
     * out elsewhere. Save the ret addr and mock up the function
     * return.
     */
}

void post_launch(void)
{
    /* always load cmdline defaults */
    tboot_parse_cmdline(true);

    /* always parse cmdline */
    tboot_parse_cmdline(false);

    /* initialize all logging targets */
    printk_init(INIT_POST_LAUNCH);

    printk(TBOOT_INFO"******************** MLE ********************\n");
    printk(TBOOT_INFO"   %s\n", TBOOT_CHANGESET);
    printk(TBOOT_INFO"*********************************************\n");

    /* init the bits needed to run APs in mini-VMs */
    init_vmcs_addrs();

    /* TODO reparse and load configs stored in the MLE */

    /* TODO measure the memory map */

    /* TODO call efi_scan_memory_map again after measured launch to rebuild map */

    /* TODO hash Xen text section before transferring control back to it */
}

void s3_launch(void)
{
    /* TODO deal with later */
}

static void shutdown_system(uint32_t shutdown_type)
{
    static const char *types[] = { "TB_SHUTDOWN_REBOOT", "TB_SHUTDOWN_S5",
                                   "TB_SHUTDOWN_S4", "TB_SHUTDOWN_S3",
                                   "TB_SHUTDOWN_HALT" };
    char type[32];

    if ( shutdown_type >= ARRAY_SIZE(types) )
        snprintf(type, sizeof(type), "unknown: %u", shutdown_type);
    else
        strncpy(type, types[shutdown_type], sizeof(type));
    printk(TBOOT_INFO"shutdown_system() called for shutdown_type: %s\n", type);

    switch( shutdown_type ) {
        case TB_SHUTDOWN_S3:
            copy_s3_wakeup_entry();
            /* write our S3 resume vector to ACPI resume addr */
            /* TODO handle S3 later set_s3_resume_vector(&_tboot_shared.acpi_sinfo,  TBOOT_S3_WAKEUP_ADDR);*/
            /* fall through for rest of Sx handling */
        case TB_SHUTDOWN_S4:
        case TB_SHUTDOWN_S5:
            machine_sleep(&_tboot_shared.acpi_sinfo);
            /* if machine_sleep() fails, fall through to reset */

        case TB_SHUTDOWN_REBOOT:
            if ( txt_is_powercycle_required() ) {
                /* powercycle by writing 0x0a+0x0e to port 0xcf9 */
                /* (supported by all TXT-capable chipsets) */
                outb(0xcf9, 0x0a);
                outb(0xcf9, 0x0e);
            }
            else {
                /* soft reset by writing 0xfe to keyboard reset vector 0x64 */
                /* BIOSes (that are not performing some special operation, */
                /* such as update) will turn this into a platform reset as */
                /* expected. */
                outb(0x64, 0xfe);
                /* fall back to soft reset by writing 0x06 to port 0xcf9 */
                /* (supported by all TXT-capable chipsets) */
                outb(0xcf9, 0x06);
            }

        case TB_SHUTDOWN_HALT:
        default:
            while ( true )
                halt();
    }
}

void shutdown(void)
{
    /* TODO fill me in */
}

void handle_exception(void)
{
    printk(TBOOT_INFO"received exception; shutting down...\n");
    _tboot_shared.shutdown_type = TB_SHUTDOWN_REBOOT;
    shutdown();
}

/*
 * Local variables:
 * mode: C
 * c-set-style: "BSD"
 * c-basic-offset: 4
 * tab-width: 4
 * indent-tabs-mode: nil
 * End:
 */