arch/x86: Fix undefined behavior

Fixes report found by undefined behavior sanitizer. Dereferencing a
pointer that is not aligned to the size of access is undefined behavior.
Switch to memcpy() for unaligned write to EBDA_LOWMEM. Change other
write16()s in setup_ebda() to memcpy() for consistency.

Change-Id: I79814bd47a14ec59d84068b11d094dc2531995d9
Signed-off-by: Ryan Salsamendi <rsalsamendi@hotmail.com>
Reviewed-on: https://review.coreboot.org/20132
Tested-by: build bot (Jenkins) <no-reply@coreboot.org>
Reviewed-by: Aaron Durbin <adurbin@chromium.org>
Reviewed-by: Philippe Mathieu-Daudé <philippe.mathieu.daude@gmail.com>
diff --git a/src/arch/x86/ebda.c b/src/arch/x86/ebda.c
index 284b5be..b5dfb41 100644
--- a/src/arch/x86/ebda.c
+++ b/src/arch/x86/ebda.c
@@ -22,6 +22,10 @@
 
 void setup_ebda(u32 low_memory_size, u16 ebda_segment, u16 ebda_size)
 {
+	u16 low_memory_kb;
+	u16 ebda_kb;
+	void *ebda;
+
 	/* Skip in S3 resume path */
 	if (acpi_is_wakeup_s3())
 		return;
@@ -29,15 +33,20 @@
 	if (!low_memory_size || !ebda_segment || !ebda_size)
 		return;
 
-	/* clear BIOS DATA AREA */
-	memset((void *)X86_BDA_BASE, 0, X86_BDA_SIZE);
+	low_memory_kb = low_memory_size >> 10;
+	ebda_kb = ebda_size >> 10;
+	ebda = (void *)((uintptr_t)ebda_segment << 4);
 
-	write16(X86_EBDA_LOWMEM, (low_memory_size >> 10));
-	write16(X86_EBDA_SEGMENT, ebda_segment);
+	/* clear BIOS DATA AREA */
+	memset(X86_BDA_BASE, 0, X86_BDA_SIZE);
+
+	/* Avoid unaligned write16() since it's undefined behavior */
+	memcpy(X86_EBDA_LOWMEM, &low_memory_kb, sizeof(low_memory_kb));
+	memcpy(X86_EBDA_SEGMENT, &ebda_segment, sizeof(ebda_segment));
 
 	/* Set up EBDA */
-	memset((void *)((uintptr_t)ebda_segment << 4), 0, ebda_size);
-	write16((void *)((uintptr_t)ebda_segment << 4), (ebda_size >> 10));
+	memset(ebda, 0, ebda_size);
+	memcpy(ebda, &ebda_kb, sizeof(ebda_kb));
 }
 
 void setup_default_ebda(void)