[Skiboot] [RFC PATCH] initial little endian support

Nicholas Piggin npiggin at gmail.com
Wed Sep 18 13:46:12 AEST 2019


Building with LITTLE_ENDIAN=1 now gives something that can boot Linux
on mambo. It's going to still need more work on real hardware mostly
interacting with other firmware components, and the existing OPAL call
ABI is horrible when OPAL runs LE, so at the moment this is a novelty.

But LE/ELFv2 is much nicer, smaller image and less stack usage. So in
the longer term this will be the way to go. We can do a nicer calling
convention and move kernels to it, then switch skiboot some time after
that, still keeping the old convention for back compatibility.

This patch isn't for merge just yet because of the spira initialiser
hacks I haven't fixed up, but it's pretty trivial so I'll submit it
before long.

Thanks,
Nick
---
 Makefile.main                            | 38 ++++++++++++--
 asm/head.S                               | 65 ++++++++++++++++++++----
 core/cpu.c                               | 25 +++++++--
 core/init.c                              |  2 +
 hdata/spira.c                            | 12 ++---
 include/asm-utils.h                      | 17 +++++++
 include/cpu.h                            |  3 ++
 include/elf.h                            |  4 ++
 libpore/p9_cpu_reg_restore_instruction.H | 23 +++++----
 9 files changed, 155 insertions(+), 34 deletions(-)

diff --git a/Makefile.main b/Makefile.main
index 2d60bbbf5..1d834e81b 100644
--- a/Makefile.main
+++ b/Makefile.main
@@ -65,21 +65,35 @@ CPPFLAGS += -I$(SRC)/libfdt -I$(SRC)/libflash -I$(SRC)/libxz -I$(SRC)/libc/inclu
 CPPFLAGS += -I$(SRC)/libpore
 CPPFLAGS += -D__SKIBOOT__ -nostdinc
 CPPFLAGS += -isystem $(shell $(CC) -print-file-name=include)
-CPPFLAGS += -DBITS_PER_LONG=64 -DHAVE_BIG_ENDIAN
+CPPFLAGS += -DBITS_PER_LONG=64
+
 # We might want to remove our copy of stdint.h
 # but that means uint64_t becomes an ulong instead of an ullong
 # causing all our printf's to warn
 CPPFLAGS += -ffreestanding
 
+ifeq ($(LITTLE_ENDIAN),1)
+CPPFLAGS += -DHAVE_LITTLE_ENDIAN
+else
+CPPFLAGS += -DHAVE_BIG_ENDIAN
+endif
+
 ifeq ($(DEBUG),1)
 CPPFLAGS += -DDEBUG -DCCAN_LIST_DEBUG
 endif
 
-CFLAGS := -fno-strict-aliasing -pie -fpie -fno-pic -mbig-endian -m64 -fno-asynchronous-unwind-tables
+CFLAGS := -fno-strict-aliasing -pie -fpie -fno-pic -m64 -fno-asynchronous-unwind-tables
 CFLAGS += -mcpu=power8
 CFLAGS += -Wl,--oformat,elf64-powerpc -ggdb
 CFLAGS += $(call try-cflag,$(CC),-ffixed-r13)
 CFLAGS += $(call try-cflag,$(CC),-std=gnu11)
+
+ifeq ($(LITTLE_ENDIAN),1)
+CFLAGS += -mlittle-endian
+else
+CFLAGS += -mbig-endian
+endif
+
 ifeq ($(ELF_ABI_v2),1)
 CFLAGS += $(call try-cflag,$(CC),-mabi=elfv2)
 else
@@ -135,8 +149,8 @@ LDFLAGS := -m64 -static -nostdlib -pie
 LDFLAGS += -Wl,-pie
 LDFLAGS += -Wl,-Ttext-segment,$(LD_TEXT) -Wl,-N -Wl,--build-id=none
 LDFLAGS += -Wl,--no-multi-toc
-LDFLAGS += -mcpu=power8 -mbig-endian -Wl,--oformat,elf64-powerpc
-LDFLAGS_FINAL = -EB -m elf64ppc --no-multi-toc -N --build-id=none --whole-archive
+LDFLAGS += -mcpu=power8 -Wl,--oformat,elf64-powerpc
+LDFLAGS_FINAL = -m elf64lppc --no-multi-toc -N --build-id=none --whole-archive
 LDFLAGS_FINAL += -static -nostdlib -pie -Ttext-segment=$(LD_TEXT) --oformat=elf64-powerpc
 LDFLAGS_FINAL += --orphan-handling=warn
 
@@ -144,11 +158,25 @@ LDRFLAGS=-melf64ppc
 # Debug stuff
 #LDFLAGS += -Wl,-v -Wl,-Map,foomap 
 
+ifeq ($(LITTLE_ENDIAN),1)
+LDFLAGS += -mlittle-endian
+LDFLAGS_FINAL += -EL
+else
+LDFLAGS += -mbig-endian
+LDFLAGS_FINAL += -EB
+endif
+
 ifeq ($(DEAD_CODE_ELIMINATION),1)
 LDFLAGS += -Wl,--gc-sections
 endif
 
-AFLAGS := -D__ASSEMBLY__ -mbig-endian -m64
+AFLAGS := -D__ASSEMBLY__ -m64
+ifeq ($(LITTLE_ENDIAN),1)
+AFLAGS += -mlittle-endian
+else
+AFLAGS += -mbig-endian
+endif
+
 ifeq ($(ELF_ABI_v2),1)
 AFLAGS += $(call try-cflag,$(CC),-mabi=elfv2)
 else
diff --git a/asm/head.S b/asm/head.S
index e78dc520a..327fa4001 100644
--- a/asm/head.S
+++ b/asm/head.S
@@ -41,6 +41,8 @@ __head:
 	. = 0x10
 .global fdt_entry
 fdt_entry:
+	OPAL_ENTRY_TO_SKIBOOT_ENDIAN
+
 	mr	%r27,%r3
 	b	boot_entry
 
@@ -362,7 +364,11 @@ boot_entry:
 	add	%r2,%r2,%r29
 
 	/* Fixup our MSR (remove TA) */
+#ifdef __BIG_ENDIAN
 	LOAD_IMM64(%r3, (MSR_HV | MSR_SF))
+#else
+	LOAD_IMM64(%r3, (MSR_HV | MSR_SF | MSR_LE))
+#endif
 	mtmsrd	%r3,0
 
 	/* Check our PIR, avoid threads */
@@ -696,14 +702,18 @@ init_shared_sprs:
 	mtspr	SPR_TSCR, %r3
 
 	/* HID0: Clear bit 13 (enable core recovery)
-	 *       Clear bit 19 (HILE)
+	 *       Set/clear bit 19 (HILE) depending on skiboot endian
 	 */
 	mfspr	%r3,SPR_HID0
 	li	%r0,1
 	sldi	%r4,%r0,(63-13)
-	sldi	%r5,%r0,(63-19)
-	or	%r0,%r4,%r5
-	andc	%r3,%r3,%r0
+	andc	%r3,%r3,%r4
+	sldi	%r4,%r0,(63-19)
+#ifdef __BIG_ENDIAN
+	andc	%r3,%r3,%r4
+#else
+	or	%r3,%r3,%r4
+#endif
 	sync
 	mtspr	SPR_HID0,%r3
 	mfspr	%r3,SPR_HID0
@@ -730,17 +740,21 @@ init_shared_sprs:
 	LOAD_IMM32(%r3,0x80287880)
 	mtspr	SPR_TSCR, %r3
 	/* HID0: Clear bit 5 (enable core recovery)
-	 *       Clear bit 4 (HILE)
+	 *       Set/clear bit 4 (HILE) depending on skiboot endian
 	 *       Set bit 8 (radix)
 	 */
 	mfspr	%r3,SPR_HID0
 	li	%r0,1
-	sldi	%r4,%r0,(63-8)
+	sldi	%r4,%r0,(63-4)
+#ifdef __BIG_ENDIAN
+	andc	%r3,%r3,%r4
+#else
 	or	%r3,%r3,%r4
+#endif
 	sldi	%r4,%r0,(63-5)
-	sldi	%r5,%r0,(63-4)
-	or	%r0,%r4,%r5
-	andc	%r3,%r3,%r0
+	andc	%r3,%r3,%r4
+	sldi	%r4,%r0,(63-8)
+	or	%r3,%r3,%r4
 	sync
 	mtspr	SPR_HID0,%r3
 	isync
@@ -880,6 +894,8 @@ opal_boot_trampoline:
 	.balign	0x10
 .global opal_entry
 opal_entry:
+	OPAL_ENTRY_TO_SKIBOOT_ENDIAN
+
 	/* Get our per CPU pointer in r12 to check for quiesce */
 	mfspr	%r12,SPR_PIR
 	GET_STACK(%r12,%r12)
@@ -1025,12 +1041,22 @@ opal_entry:
 	lwz	%r11,CPUTHREAD_IN_OPAL_CALL(%r12)
 	subi	%r11,%r11,1
 	stw	%r11,CPUTHREAD_IN_OPAL_CALL(%r12)
+#ifdef __BIG_ENDIAN
 	/*
 	 * blr with BH=01b means it's not a function return, OPAL was entered
 	 * via (h)rfid not bl, so we don't have a corresponding link stack
 	 * prediction to return to here.
 	 */
 	bclr	20,0,1
+#else
+	mflr	%r12
+	mtspr	SPR_HSRR0,%r12
+	mfmsr	%r11
+	li	%r12,MSR_LE
+	andc	%r11,%r11,%r12
+	mtspr	SPR_HSRR1,%r11
+	hrfid
+#endif
 
 .global start_kernel
 start_kernel:
@@ -1038,7 +1064,14 @@ start_kernel:
 	icbi	0,%r3
 	sync
 	isync
+#ifdef __BIG_ENDIAN
 	mtctr	%r3
+#else
+	mtspr	SPR_HSRR0,%r3
+	LOAD_IMM64(%r3,MSR_HV|MSR_SF)
+	mtspr	SPR_HSRR1,%r3
+#endif
+
 	mr	%r3,%r4
 	LOAD_IMM64(%r8,SKIBOOT_BASE);
 	LOAD_IMM32(%r10, opal_entry - __head)
@@ -1047,7 +1080,11 @@ start_kernel:
 	addi	%r7,%r5,1
 	li	%r4,0
 	li	%r5,0
+#ifdef __BIG_ENDIAN
 	bctr
+#else
+	hrfid
+#endif
 
 	.global start_kernel32
 start_kernel32:
@@ -1062,6 +1099,16 @@ start_kernel32:
 start_kernel_secondary:
 	sync
 	isync
+#ifdef __BIG_ENDIAN
 	mtctr	%r3
+#else
+	mtspr	SPR_HSRR0,%r3
+	LOAD_IMM64(%r3,MSR_HV|MSR_SF)
+	mtspr	SPR_HSRR1,%r3
+#endif
 	mfspr	%r3,SPR_PIR
+#ifdef __BIG_ENDIAN
 	bctr
+#else
+	hrfid
+#endif
diff --git a/core/cpu.c b/core/cpu.c
index 8e0b0650d..9dfe72cf2 100644
--- a/core/cpu.c
+++ b/core/cpu.c
@@ -42,7 +42,7 @@ static unsigned long hid0_attn;
 static bool sreset_enabled;
 static bool ipi_enabled;
 static bool pm_enabled;
-static bool current_hile_mode;
+static bool current_hile_mode = true;
 static bool current_radix_mode;
 static bool tm_suspend_enabled;
 
@@ -1278,6 +1278,7 @@ static void opal_start_thread_job(void *data)
 	/* We do not return, so let's mark the job as
 	 * complete
 	 */
+
 	start_kernel_secondary((uint64_t)data);
 }
 
@@ -1415,6 +1416,24 @@ static int64_t cpu_change_all_hid0(struct hid0_change_req *req)
 	return OPAL_SUCCESS;
 }
 
+void cpu_set_hile_mode(bool hile)
+{
+	struct hid0_change_req req;
+
+	if (hile == current_hile_mode)
+		return;
+
+	if (hile) {
+		req.clr_bits = 0;
+		req.set_bits = hid0_hile;
+	} else {
+		req.clr_bits = hid0_hile;
+		req.set_bits = 0;
+	}
+	cpu_change_all_hid0(&req);
+	current_hile_mode = hile;
+}
+
 static void cpu_cleanup_one(void *param __unused)
 {
 	mtspr(SPR_AMR, 0);
@@ -1453,8 +1472,8 @@ static int64_t cpu_cleanup_all(void)
 
 void cpu_fast_reboot_complete(void)
 {
-	/* Fast reboot will have cleared HID0:HILE */
-	current_hile_mode = false;
+	/* Fast reboot will have set HID0:HILE */
+	current_hile_mode = true;
 
 	/* and set HID0:RADIX */
 	current_radix_mode = true;
diff --git a/core/init.c b/core/init.c
index cd333dcbd..f04204ee1 100644
--- a/core/init.c
+++ b/core/init.c
@@ -622,6 +622,8 @@ void __noreturn load_and_boot_kernel(bool is_reboot)
 
 	cpu_give_self_os();
 
+	cpu_set_hile_mode(false); /* Clear HILE on all CPUs */
+
 	if (kernel_32bit)
 		start_kernel32(kernel_entry, fdt, mem_top);
 	start_kernel(kernel_entry, fdt, mem_top);
diff --git a/hdata/spira.c b/hdata/spira.c
index e118e229f..4566c4909 100644
--- a/hdata/spira.c
+++ b/hdata/spira.c
@@ -51,19 +51,19 @@ __section(".cpuctrl.data") struct cpu_ctl_init_data cpu_ctl_init_data = {
 #if !defined(TEST)
 	.cpu_ctl_lt = {
 		.spat = {
-			.addr = CPU_TO_BE64((unsigned long)&(cpu_ctl_spat_area) + SKIBOOT_BASE),
+//			.addr = CPU_TO_BE64((unsigned long)&(cpu_ctl_spat_area) + SKIBOOT_BASE),
 			.size = CPU_TO_BE64(sizeof(struct sp_addr_table)),
 		},
 		.sp_attn_area1 = {
-			.addr = CPU_TO_BE64((unsigned long)&(cpu_ctl_sp_attn_area1) + SKIBOOT_BASE),
+//			.addr = CPU_TO_BE64((unsigned long)&(cpu_ctl_sp_attn_area1) + SKIBOOT_BASE),
 			.size = CPU_TO_BE64(sizeof(struct sp_attn_area)),
 		},
 		.sp_attn_area2 = {
-			.addr = CPU_TO_BE64((unsigned long)&(cpu_ctl_sp_attn_area2) + SKIBOOT_BASE),
+//			.addr = CPU_TO_BE64((unsigned long)&(cpu_ctl_sp_attn_area2) + SKIBOOT_BASE),
 			.size = CPU_TO_BE64(sizeof(struct sp_attn_area)),
 		},
 		.hsr_area = {
-			.addr = CPU_TO_BE64((unsigned long)&(cpu_ctl_hsr_area) + SKIBOOT_BASE),
+//			.addr = CPU_TO_BE64((unsigned long)&(cpu_ctl_hsr_area) + SKIBOOT_BASE),
 			.size = CPU_TO_BE64(sizeof(struct hsr_data_area)),
 		},
 	},
@@ -133,7 +133,7 @@ __section(".spira.data") struct spira spira = {
 		},
 #if !defined(TEST)
 		.cpu_ctrl = {
-			.addr		= CPU_TO_BE64((unsigned long)&cpu_ctl_init_data),
+//			.addr		= CPU_TO_BE64((unsigned long)&cpu_ctl_init_data),
 			.alloc_cnt	= CPU_TO_BE16(1),
 			.act_cnt	= CPU_TO_BE16(1),
 			.alloc_len	=
@@ -172,7 +172,7 @@ __section(".spirah.data") struct spirah spirah = {
 		},
 #if !defined(TEST)
 		.cpu_ctrl = {
-			.addr		= CPU_TO_BE64((unsigned long)&cpu_ctl_init_data),
+//			.addr		= CPU_TO_BE64((unsigned long)&cpu_ctl_init_data),
 			.alloc_cnt	= CPU_TO_BE16(1),
 			.act_cnt	= CPU_TO_BE16(1),
 			.alloc_len	=
diff --git a/include/asm-utils.h b/include/asm-utils.h
index 2d26545e7..72cc53f5e 100644
--- a/include/asm-utils.h
+++ b/include/asm-utils.h
@@ -28,6 +28,23 @@
 /* Load an address via the TOC */
 #define LOAD_ADDR_FROM_TOC(r, e)	ld r,e at got(%r2)
 
+#ifdef __BIG_ENDIAN
+#define OPAL_ENTRY_TO_SKIBOOT_ENDIAN
+#else
+/* This must preserve LR, so can't use FIXUP_ENDIAN */
+#define OPAL_ENTRY_TO_SKIBOOT_ENDIAN				   \
+	.long 0xa600607d; /* mfmsr r11				*/ \
+	.long 0x01006b69; /* xori r11,r11,1			*/ \
+	.long 0xa64b7b7d; /* mthsrr1 r11			*/ \
+	.long 0xa602687d; /* mflr r11				*/ \
+	.long 0x05009f42; /* bcl 20,31,$+4			*/ \
+	.long 0xa602487d; /* mflr r10				*/ \
+	.long 0x14004a39; /* addi r10,r10,20			*/ \
+	.long 0xa64b5a7d; /* mthsrr0 r10			*/ \
+	.long 0xa603687d; /* mtlr r11				*/ \
+	.long 0x2402004c  /* hrfid				*/
+#endif
+
 #define FIXUP_ENDIAN						   \
 	tdi   0,0,0x48;	  /* Reverse endian of b . + 8		*/ \
 	b     191f;	  /* Skip trampoline if endian is good	*/ \
diff --git a/include/cpu.h b/include/cpu.h
index cda78644d..008f08a68 100644
--- a/include/cpu.h
+++ b/include/cpu.h
@@ -282,6 +282,9 @@ extern void cpu_process_local_jobs(void);
 /* Check if there's any job pending */
 bool cpu_check_jobs(struct cpu_thread *cpu);
 
+/* Set/clear HILE on all CPUs */
+void cpu_set_hile_mode(bool hile);
+
 /* OPAL sreset vector in place at 0x100 */
 void cpu_set_sreset_enable(bool sreset_enabled);
 
diff --git a/include/elf.h b/include/elf.h
index 93524bb99..8ce37fad4 100644
--- a/include/elf.h
+++ b/include/elf.h
@@ -9,7 +9,11 @@
 /* Generic ELF header */
 struct elf_hdr {
 	uint32_t ei_ident;
+#ifdef _BIG_ENDIAN
 #define ELF_IDENT	0x7F454C46
+#else
+#define ELF_IDENT	0x464C457F
+#endif
 	uint8_t ei_class;
 #define ELF_CLASS_32	1
 #define ELF_CLASS_64	2
diff --git a/libpore/p9_cpu_reg_restore_instruction.H b/libpore/p9_cpu_reg_restore_instruction.H
index dd4358a82..cf00ff5e5 100644
--- a/libpore/p9_cpu_reg_restore_instruction.H
+++ b/libpore/p9_cpu_reg_restore_instruction.H
@@ -61,23 +61,24 @@ enum
     RLDICR_CONST        =   1,
     MTSPR_CONST1        =   467,
     MTMSRD_CONST1       =   178,
-    MR_R0_TO_R10        =   0x7c0a0378, //mr r10, r0
-    MR_R0_TO_R21        =   0x7c150378, //mr r21, r0
-    MR_R0_TO_R9         =   0x7c090378, //mr r9, r0
-    URMOR_CORRECTION    =   0x7d397ba6,
     MFSPR_CONST         =   339,
-    BLR_INST            =   0x4e800020,
-    MTSPR_BASE_OPCODE   =   0x7c0003a6,
-    ATTN_OPCODE         =   0x00000200,
     OPCODE_18           =   18,
     SELF_SAVE_FUNC_ADD  =   0x2300,
     SELF_SAVE_OFFSET    =   0x180,
-    SKIP_SPR_REST_INST  =   0x4800001c, //b . +0x01c
-    MFLR_R30            =   0x7fc802a6,
-    SKIP_SPR_SELF_SAVE  =   0x3bff0020, //addi r31 r31, 0x20
-    MTLR_INST           =   0x7fc803a6  //mtlr r30
 };
 
+#define MR_R0_TO_R10            0x7c0a0378UL //mr r10 r0
+#define MR_R0_TO_R21            0x7c150378UL //mr r21 r0
+#define MR_R0_TO_R9             0x7c090378UL //mr r9 r0
+#define URMOR_CORRECTION        0x7d397ba6UL
+#define BLR_INST                0x4e800020UL
+#define MTSPR_BASE_OPCODE       0x7c0003a6UL
+#define ATTN_OPCODE             0x00000200UL
+#define SKIP_SPR_REST_INST      0x4800001cUL //b . +0x01c
+#define MFLR_R30                0x7fc802a6UL
+#define SKIP_SPR_SELF_SAVE      0x3bff0020UL //addi r31 r31 0x20
+#define MTLR_INST               0x7fc803a6UL //mtlr r30
+
 #ifdef __cplusplus
 } // namespace stopImageSection ends
 
-- 
2.23.0



More information about the Skiboot mailing list