x86: Support a chained-boot development flow

Sometimes it is useful to jump into U-Boot directly from coreboot or UEFI
without any 16-bit init. This can help during development by allowing U-Boot
to avoid doing all the init required by the platform.

U-Boot expects its GDT to be set up correctly by its 16-bit code. If
coreboot doesn't do this (because it hasn't run the payload setup code yet)
then this won't happen.

In this case we cannot rely on the GDT settings. U-Boot will hang or crash
if these are wrong. Provide a development-only option to set up the GDT
correctly. This is just a hack so you can jump to U-Boot from any stage of
coreboot, not just at the end.

Signed-off-by: Simon Glass <sjg@chromium.org>
Reviewed-by: Bin Meng <bmeng.cn@gmail.com>
diff --git a/arch/x86/cpu/start.S b/arch/x86/cpu/start.S
index 485868f..a5cba1c 100644
--- a/arch/x86/cpu/start.S
+++ b/arch/x86/cpu/start.S
@@ -18,6 +18,14 @@
 #include <generated/generic-asm-offsets.h>
 #include <generated/asm-offsets.h>
 
+/*
+ * Define this to boot U-Boot from a 32-bit program which sets the GDT
+ * differently. This can be used to boot directly from any stage of coreboot,
+ * for example, bypassing the normal payload-loading feature.
+ * This is only useful for development.
+ */
+#undef LOAD_FROM_32_BIT
+
 .section .text
 .code32
 .globl _start
@@ -68,6 +76,10 @@
 	/* Save table pointer */
 	movl	%ecx, %esi
 
+#ifdef LOAD_FROM_32_BIT
+	lgdt	gdt_ptr2
+#endif
+
 	/* Load the segement registers to match the GDT loaded in start16.S */
 	movl	$(X86_GDT_ENTRY_32BIT_DS * X86_GDT_ENTRY_SIZE), %eax
 	movw	%ax, %fs
@@ -220,3 +232,71 @@
 	.long	0
 	/* entry addr */
 	.long	CONFIG_SYS_TEXT_BASE
+
+#ifdef LOAD_FROM_32_BIT
+	/*
+	 * The following Global Descriptor Table is just enough to get us into
+	 * 'Flat Protected Mode' - It will be discarded as soon as the final
+	 * GDT is setup in a safe location in RAM
+	 */
+gdt_ptr2:
+	.word	0x1f		/* limit (31 bytes = 4 GDT entries - 1) */
+	.long	gdt_rom2	/* base */
+
+	/* Some CPUs are picky about GDT alignment... */
+	.align	16
+.globl gdt_rom2
+gdt_rom2:
+	/*
+	 * The GDT table ...
+	 *
+	 *	 Selector	Type
+	 *	 0x00		NULL
+	 *	 0x08		Unused
+	 *	 0x10		32bit code
+	 *	 0x18		32bit data/stack
+	 */
+	/* The NULL Desciptor - Mandatory */
+	.word	0x0000		/* limit_low */
+	.word	0x0000		/* base_low */
+	.byte	0x00		/* base_middle */
+	.byte	0x00		/* access */
+	.byte	0x00		/* flags + limit_high */
+	.byte	0x00		/* base_high */
+
+	/* Unused Desciptor - (matches Linux) */
+	.word	0x0000		/* limit_low */
+	.word	0x0000		/* base_low */
+	.byte	0x00		/* base_middle */
+	.byte	0x00		/* access */
+	.byte	0x00		/* flags + limit_high */
+	.byte	0x00		/* base_high */
+
+	/*
+	 * The Code Segment Descriptor:
+	 * - Base   = 0x00000000
+	 * - Size   = 4GB
+	 * - Access = Present, Ring 0, Exec (Code), Readable
+	 * - Flags  = 4kB Granularity, 32-bit
+	 */
+	.word	0xffff		/* limit_low */
+	.word	0x0000		/* base_low */
+	.byte	0x00		/* base_middle */
+	.byte	0x9b		/* access */
+	.byte	0xcf		/* flags + limit_high */
+	.byte	0x00		/* base_high */
+
+	/*
+	 * The Data Segment Descriptor:
+	 * - Base   = 0x00000000
+	 * - Size   = 4GB
+	 * - Access = Present, Ring 0, Non-Exec (Data), Writable
+	 * - Flags  = 4kB Granularity, 32-bit
+	 */
+	.word	0xffff		/* limit_low */
+	.word	0x0000		/* base_low */
+	.byte	0x00		/* base_middle */
+	.byte	0x93		/* access */
+	.byte	0xcf		/* flags + limit_high */
+	.byte	0x00		/* base_high */
+#endif