Thread (7 messages) 7 messages, 3 authors, 2017-08-21

Re: [PATCH] MIPS: Set ISA bit in entry-y for microMIPS kernels

From: James Hogan <hidden>
Date: 2017-08-18 23:05:15

On 18 August 2017 23:13:39 BST, "Maciej W. Rozycki" [off-list ref] wrote:
quoted hunk ↗ jump to hunk
Hi Paul,
quoted
I originally did this [1], and wrote about it in the
post-three-dashes notes 
quoted
for this patch. To quote myself:
quoted
I originally tried using "objdump -f" to obtain the entry address,
which
quoted
quoted
works for microMIPS but it always outputs a 32 bit address for a 32
bit
quoted
quoted
ELF whilst nm will sign extend to 64 bit. That matters for systems
where
quoted
quoted
we might want to run a MIPS32 kernel on a MIPS64 CPU & load it with
a
quoted
quoted
MIPS64 bootloader, which would then jump to a non-canonical
(non-sign-extended) address.

This works in all cases as it only changes the behaviour for
microMIPS
quoted
quoted
kernels, but isn't the prettiest solution. A possible alternative
would
quoted
quoted
be to write a custom tool to just extract, sign extend & print the
entry
quoted
quoted
point of an ELF executable. I'm open to feedback if that would be
preferred.
So if we were to use objdump we'd need to handle sign extending 32
bit 
quoted
addresses to form a canonical address. Perhaps that'd be cleaner
though.

Hmm, your reasoning sounds right (and I was blind to miss it entirely, 
sorry), however reality seems to disagree.  As at 5fc9484f5e41^ I get:

make -f ./scripts/Makefile.build obj=arch/mips/boot VMLINUX=vmlinux \
	VMLINUX_LOAD_ADDRESS=0xffffffff80100000
VMLINUX_ENTRY_ADDRESS=0x804fca20 PLATFORM="generic/" ADDR_BITS=32
arch/mips/boot/vmlinux.srec

whereas at 5fc9484f5e41^ I get:

make -f ./scripts/Makefile.build obj=arch/mips/boot VMLINUX=vmlinux \
	VMLINUX_LOAD_ADDRESS=0xffffffff80100000
VMLINUX_ENTRY_ADDRESS=0x804fca21 PLATFORM="generic/" ADDR_BITS=32
arch/mips/boot/vmlinux.srec

so in both cases the entry address is 32-bit, which is why I didn't see

any disadvantage from using `objdump -f'.  Indeed:

$ mips-linux-gnu-nm vmlinux | grep kernel_entry
80100000 T __kernel_entry
804fca20 T kernel_entry
$ mips-mti-linux-gnu-nm vmlinux | grep kernel_entry
ffffffff80100000 T __kernel_entry
ffffffff804fca20 T kernel_entry
$ 

which means you can't rely on `nm' sign-extending addresses to 64 bits 
with 32-bit binaries.  And it looks like a bug to me indeed that some 
versions of `nm' do such sign-extension, unlike `objdump' and
`readelf'.  
I'll have to bisect it to see when it started happening and take it
with 
upstream binutils.

How about this version then?  It does the right thing for me:

make -f ./scripts/Makefile.build obj=arch/mips/boot VMLINUX=vmlinux \
	VMLINUX_LOAD_ADDRESS=0xffffffff80100000
VMLINUX_ENTRY_ADDRESS=0xffffffff804fca21 PLATFORM="generic/"
ADDR_BITS=32 arch/mips/boot/vmlinux.srec

and given than we need to sign-extend in either case I think retrieving

the canonical entry point rather than transforming the entry symbol is 
simpler and more reliable.

 Maciej

---
arch/mips/Makefile |   19 +++++--------------
1 file changed, 5 insertions(+), 14 deletions(-)

linux-mips-start-address.diff
Index: linux-sfr-usead/arch/mips/Makefile
===================================================================
--- linux-sfr-usead.orig/arch/mips/Makefile	2017-08-18
22:17:42.962681000 +0100
+++ linux-sfr-usead/arch/mips/Makefile	2017-08-18 23:01:00.997846000
+0100
@@ -244,20 +244,11 @@ ifdef CONFIG_PHYSICAL_START
load-y					= $(CONFIG_PHYSICAL_START)
endif

-entry-noisa-y				= 0x$(shell $(NM) vmlinux 2>/dev/null \
-					| grep "\bkernel_entry\b" | cut -f1 -d \ )
-ifdef CONFIG_CPU_MICROMIPS
-  #
-  # Set the ISA bit, since the kernel_entry symbol in the ELF will
have it
-  # clear which would lead to images containing addresses which
bootloaders may
-  # jump to as MIPS32 code.
-  #
-  entry-y = $(patsubst %0,%1,$(patsubst %2,%3,$(patsubst %4,%5, \
-              $(patsubst %6,%7,$(patsubst %8,%9,$(patsubst %a,%b, \
-              $(patsubst %c,%d,$(patsubst
%e,%f,$(entry-noisa-y)))))))))
-else
-  entry-y = $(entry-noisa-y)
-endif
+# Knowing that a 32-bit kernel will be linked at a KSEG address
thats not true with CONFIG_KVM_GUEST kernels, which use a separate set of emulated guest kernel segments in useg, i.e. at 0x40000000. I've also seen EVA kernels linked at low addresses like around 0x20000000, though entry gets a bit fiddly for EVA depending on whether bootloader already has the chosen segment configuration set up.

Cheers
James
+# sign-extend the entry point to 64 bits if retrieved as a 32-bit
+# number by stuffing `ffffffff' after the leading `0x'.
+entry-y	= $(shell $(OBJDUMP) -f vmlinux 2>/dev/null \
+	| sed -n 's/0x\(........\)$$/0xffffffff\1/;s/start address //p')

cflags-y			+= -I$(srctree)/arch/mips/include/asm/mach-generic
drivers-$(CONFIG_PCI)		+= arch/mips/pci/

--
James Hogan
Keyboard shortcuts
hback out one level
jnext message in thread
kprevious message in thread
ldrill in
Escclose help / fold thread tree
?toggle this help