diff -r 950fec11ef90 tboot/common/cmdline.c
--- a/tboot/common/cmdline.c	Sun Jan 15 23:21:20 2012 +0800
+++ b/tboot/common/cmdline.c	Wed Jan 25 16:41:09 2012 -0800
@@ -1,7 +1,7 @@
 /*
  * cmdline.c: command line parsing fns
  *
- * Copyright (c) 2006-2010, Intel Corporation
+ * Copyright (c) 2006-2011, Intel Corporation
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -41,8 +41,12 @@
 #include <string.h>
 #include <misc.h>
 #include <printk.h>
+#include <multiboot.h>
+#include <e820.h>
 #include <cmdline.h>
 
+extern prot_mem_t g_prot_mem;
+
 /*
  * copy of original command line
  * part of tboot measurement (hence in .text section)
@@ -73,6 +77,7 @@
     { "vga_delay",  "0" },           /* # secs */
     { "ap_wake_mwait", "false" },    /* true|false */
     { "pcr_map", "legacy" },         /* legacy|da */
+    { "prot_mem",   "nores" },       /* all|nores|type1 */
     { NULL, NULL }
 };
 static char g_tboot_param_values[ARRAY_SIZE(g_tboot_cmdline_options)][MAX_VALUE_LEN];
@@ -525,6 +530,21 @@
     return cmdline;
 }
 
+void get_tboot_prot_mem(void)
+{
+    const char *prot_mem = get_option_val(g_tboot_cmdline_options,
+                                          g_tboot_param_values, "prot_mem");
+    if ( prot_mem == NULL )
+        return;
+
+    if ( strcmp(prot_mem, "all") == 0 )
+        g_prot_mem = all;
+    else if ( strcmp(prot_mem, "type1") == 0 )
+        g_prot_mem = type1;
+    else                        /* this is also the default */
+        g_prot_mem = nores;
+}
+
 
 /*
  * Local variables:
diff -r 950fec11ef90 tboot/common/e820.c
--- a/tboot/common/e820.c	Sun Jan 15 23:21:20 2012 +0800
+++ b/tboot/common/e820.c	Wed Jan 25 16:41:09 2012 -0800
@@ -1,7 +1,7 @@
 /*
  * e820.c: support functions for manipulating the e820 table
  *
- * Copyright (c) 2006-2010, Intel Corporation
+ * Copyright (c) 2006-2011, Intel Corporation
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -45,6 +45,8 @@
 #include <e820.h>
 #include <txt/config_regs.h>
 
+prot_mem_t g_prot_mem;
+
 /*
  * copy of bootloader/BIOS e820 table with adjusted entries
  * this version will replace original in mbi
@@ -298,6 +300,7 @@
             printk("Too many e820 entries\n");
             return false;
         }
+e820_reserve_ram(0x60000000ULL, 0x200000ULL);
     }
     else if ( mbi->flags & MBI_MEMLIMITS ) {
         printk("no e820 map, mem_lower=%x, mem_upper=%x\n",
@@ -558,52 +561,99 @@
          min_hi_ram == NULL || max_hi_ram == NULL )
         return false;
 
-    *min_lo_ram = *min_hi_ram = ~0ULL;
-    *max_lo_ram = *max_hi_ram = 0;
-    bool found_reserved_region = false;
+    get_tboot_prot_mem();
 
-    for ( unsigned int i = 0; i < g_nr_map; i++ ) {
-        memory_map_t *entry = &g_copy_e820_map[i];
-        uint64_t base = e820_base_64(entry);
-        uint64_t limit = base + e820_length_64(entry);
+    if ( g_prot_mem == all ) {
+        uint64_t above_base, above_size;
 
-        if ( entry->type == E820_RAM ) {
-            /* if range straddles 4GB boundary, that is an error */
-            if ( base < 0x100000000ULL && limit > 0x100000000ULL ) {
-                printk("e820 memory range straddles 4GB boundary\n");
-                return false;
+        /* don't use TOLUD since that covers stolen regions; bottom of
+           DPR is the memory usable by OS and that needs DMA protection */
+        txt_dpr_t dpr;
+        dpr._raw = read_pub_config_reg(TXTCR_DPR);
+        uint64_t dpr_bottom = ((uint64_t)dpr.top << 20) - (dpr.size * 1024*1024);
+        /* round up to 2MB so that we don't have to truncate memory for VT-d
+           (this will still be within DPR, so no problems) */
+        dpr_bottom = (dpr_bottom + 0x200000ULL - 1) & ~0x1fffffULL;
+        /* we need to ensure that there are no RAM regions above max lo */
+        get_highest_sized_ram(1, 0x100000000ULL, &above_base, &above_size);
+        if ( above_base + above_size > dpr_bottom ) {
+            printk("e820 has RAM region above DPR (0x%Lx): 0x%Lx - 0x%Lx\n",
+                   dpr_bottom, above_base, above_base+above_size);
+            return false;
+        }
+        *min_lo_ram = 0;
+        *max_lo_ram = dpr_bottom;
+
+        /* get hi memory from e820 map */
+        get_highest_sized_ram(1, ~0ULL, &above_base, &above_size);
+        if ( above_base + above_size > 0x100000000ULL ) {
+            *min_hi_ram = 0x100000000ULL;
+            *max_hi_ram = above_base + above_size;
+        }
+        else
+            *min_hi_ram = *max_hi_ram = 0;
+    }
+    else {
+        *min_lo_ram = *min_hi_ram = ~0ULL;
+        *max_lo_ram = *max_hi_ram = 0;
+        bool found_reserved_region = false;
+
+        for ( unsigned int i = 0; i < g_nr_map; i++ ) {
+            memory_map_t *entry = &g_copy_e820_map[i];
+            uint64_t base = e820_base_64(entry);
+            uint64_t limit = base + e820_length_64(entry);
+
+            if ( entry->type == E820_RAM ) {
+                /* if range straddles 4GB boundary, that is an error */
+                if ( base < 0x100000000ULL && limit > 0x100000000ULL ) {
+                    printk("e820 memory range straddles 4GB boundary\n");
+                    return false;
+                }
+
+                /*
+                 * we support three options for how to DMA protect low (<4GB)
+                 * memory:
+                 * all   : protect all physical memory regardless of e820 type
+                 * type1 : protect from 0 to end of last type 1 memory region;
+                 *         this may cover reserved regions
+                 * nores : protect from 0 to end of last type 1 region before
+                 *         first non-type 1 region (after 1MB); i.e. don't
+                 *         protect any type 2-4 regions above 1MB
+                 *         this will also mark any type 1 regions found above
+                 *         the reserved regions as reserved (so that they do
+                 *         not get used by the kernel/VMM)
+                 *
+                 * Note: some BIOSes put legacy USB buffers in reserved regions
+                 * <4GB, which if DMA protected may cause SMM to hang or cause
+                 * VT-d to register errors
+                 */
+                if ( (!found_reserved_region && g_prot_mem == nores ) ||
+                     g_prot_mem == type1 ) {
+                    if ( base < 0x100000000ULL && base < *min_lo_ram )
+                        *min_lo_ram = base;
+                    if ( limit <= 0x100000000ULL && limit > *max_lo_ram )
+                        *max_lo_ram = limit;
+                }
+                else {     /* need to reserve low RAM above reserved regions */
+                    if ( base < 0x100000000ULL ) {
+                        printk("discarding RAM above reserved regions: 0x%Lx - 0x%Lx\n", base, limit);
+                        if ( !e820_reserve_ram(base, limit - base) )
+                            return false;
+                    }
+                }
+
+                if ( base >= 0x100000000ULL && base < *min_hi_ram )
+                    *min_hi_ram = base;
+                if ( limit > 0x100000000ULL && limit > *max_hi_ram )
+                    *max_hi_ram = limit;
             }
-
-            /*
-             * some BIOSes put legacy USB buffers in reserved regions <4GB,
-             * which if DMA protected cause SMM to hang, so make sure that
-             * we don't overlap any of these even if that wastes RAM
-             */
-            if ( !found_reserved_region ) {
-                if ( base < 0x100000000ULL && base < *min_lo_ram )
-                    *min_lo_ram = base;
-                if ( limit <= 0x100000000ULL && limit > *max_lo_ram )
-                    *max_lo_ram = limit;
+            else {
+                /* parts of low memory may be reserved for cseg, ISA hole,
+                   etc. but these seem OK to DMA protect, so ignore reserved
+                   regions <0x100000 */
+                if ( *min_lo_ram != ~0ULL && limit > 0x100000ULL )
+                    found_reserved_region = true;
             }
-            else {     /* need to reserve low RAM above reserved regions */
-                if ( base < 0x100000000ULL ) {
-                    printk("discarding RAM above reserved regions: 0x%Lx - 0x%Lx\n", base, limit);
-                    if ( !e820_reserve_ram(base, limit - base) )
-                        return false;
-                }
-            }
-
-            if ( base >= 0x100000000ULL && base < *min_hi_ram )
-                *min_hi_ram = base;
-            if ( limit > 0x100000000ULL && limit > *max_hi_ram )
-                *max_hi_ram = limit;
-        }
-        else {
-            /* parts of low memory may be reserved for cseg, ISA hole,
-               etc. but these seem OK to DMA protect, so ignore reserved
-               regions <0x100000 */
-            if ( *min_lo_ram != ~0ULL && limit > 0x100000ULL )
-                found_reserved_region = true;
         }
     }
 
diff -r 950fec11ef90 tboot/include/cmdline.h
--- a/tboot/include/cmdline.h	Sun Jan 15 23:21:20 2012 +0800
+++ b/tboot/include/cmdline.h	Wed Jan 25 16:41:09 2012 -0800
@@ -1,7 +1,7 @@
 /*
  * cmdline.h: support functions for command line parsing
  *
- * Copyright (c) 2006-2010, Intel Corporation
+ * Copyright (c) 2006-2011, Intel Corporation
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -39,7 +39,6 @@
 #define CMDLINE_SIZE   512
 extern char g_cmdline[CMDLINE_SIZE];
 
-
 extern void tboot_parse_cmdline(void);
 extern void get_tboot_loglvl(void);
 extern void get_tboot_log_targets(void);
@@ -49,6 +48,7 @@
 extern void get_tboot_vga_delay(void);
 extern bool get_tboot_mwait(void);
 extern bool get_tboot_prefer_da(void);
+extern void get_tboot_prot_mem(void);
 
 /* for parse cmdline of linux kernel, say vga and mem */
 extern void linux_parse_cmdline(const char *cmdline);
diff -r 950fec11ef90 tboot/include/e820.h
--- a/tboot/include/e820.h	Sun Jan 15 23:21:20 2012 +0800
+++ b/tboot/include/e820.h	Wed Jan 25 16:41:09 2012 -0800
@@ -1,7 +1,7 @@
 /*
  * e820.h: support functions for manipulating the e820 table
  *
- * Copyright (c) 2006-2009, Intel Corporation
+ * Copyright (c) 2006-2011, Intel Corporation
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -68,6 +68,8 @@
     uint32_t type;    /* type of memory segment */
 } e820entry_t;
 
+typedef enum { all, nores, type1 } prot_mem_t;
+
 extern bool copy_e820_map(const multiboot_info_t *mbi);
 extern bool e820_protect_region(uint64_t addr, uint64_t size, uint32_t type);
 extern bool e820_reserve_ram(uint64_t base, uint64_t length);
