Skip to contentSkip to conversation

IP32 prom crashes due to __pa() funkiness

PATCH New Kumba 6 participants 22 messages Feb 18, 2007 – Mar 23, 2007 1 message not in the archive MIPS

lore
Share & tools
lore

Kumba

author
#0 lore raw

Initially, booting a straight git checkout on an IP32 will cause it to prom crash, usually somewhere in between init_bootmem() and init_bootmem_core(). I bisected git to trace this back to one of the inital __pa() introduction patches from commit d4df6d4 (get ride of CPHYSADDR()). It actually appears that the actual commit that broke things was 620a480 (Make __pa() aware of XKPHYS/CKSEG0 address mix for 64 bit kernels).

The [short-term] fix highlighted by Ilya is to make __pa() unconditionally be defined to "((unsigned long)(x) < CKSEG0 ? PAGE_OFFSET : CKSEG0)"; Discovered by building IP32 with CONFIG_BUILD_ELF64=n.

Normally, this shouldn't be possible, as CONFIG_BUILD_ELF64=n was originally only allowed by using the old o64 hack, which has subsequently died and been replaced with the newer -msym32 form. As far as I know, CONFIG_BUILD_ELF64 is apparently supposed to be removed at some point in the future, since I believe it existed only for quirky 64bit-in-32bit kernels for IP22 and more commonly, IP32. From 2.6.17 onwards, I've been building IP32 kernels with CONFIG_BUILD_ELF64=y and using gcc-4, and haven't had problems up until now.

Anyways, I'm not sure if this is an IP32-specific oddity or not (probably is), but it needs the define highlighted above to work properly. Plain PAGE_OFFSET won't work for these machines. Given the same trick os -msym32 is used for the rare IP22 64bit kernel, I would not be surprised if the same problem and fix both occur and work for those machines as well. Something to maybe test later, I suppose.

But for now, anyone got thoughts as to a sane workaround for this? Perhaps some conditional tweaks in mach-ip32/*.h files somewheres, would it be simpler to just switch to:

#if defined(CONFIG_64BIT) && (!defined(CONFIG_BUILD_ELF64) || defined(CONFIG_SGI_IP32))

(assuming that IP22 doesn't need it; I'll find out later)

--Kumba

Signature · 3 lines
Gentoo/MIPS Team Lead

"Such is oft the course of deeds that move the wheels of the world: small hands do them because they must, while the eyes of the great are elsewhere."  --Elrond
author
#1 lore raw
Quoted 7 lines · Kumba

Initially, booting a straight git checkout on an IP32 will cause it to prom crash, usually somewhere in between init_bootmem() and init_bootmem_core(). I bisected git to trace this back to one of the inital __pa() introduction patches from commit d4df6d4 (get ride of CPHYSADDR()). It actually appears that the actual commit that broke things was 620a480 (Make __pa() aware of XKPHYS/CKSEG0 address mix for 64 bit kernels).

The [short-term] fix highlighted by Ilya is to make __pa() unconditionally be defined to "((unsigned long)(x) < CKSEG0 ? PAGE_OFFSET : CKSEG0)"; Discovered by building IP32 with CONFIG_BUILD_ELF64=n.

Normally, this shouldn't be possible, as CONFIG_BUILD_ELF64=n was originally only allowed by using the old o64 hack, which has subsequently died and been replaced with the newer -msym32 form. As far as I know, CONFIG_BUILD_ELF64 is apparently supposed to be removed at some point in the future, since I believe it existed only for quirky 64bit-in-32bit kernels for IP22 and more commonly, IP32. From 2.6.17 onwards, I've been building IP32 kernels with CONFIG_BUILD_ELF64=y and using gcc-4, and haven't had problems up until now.

Quoted 7 lines

Anyways, I'm not sure if this is an IP32-specific oddity or not (probably is), but it needs the define highlighted above to work properly. Plain PAGE_OFFSET won't work for these machines. Given the same trick os -msym32 is used for the rare IP22 64bit kernel, I would not be surprised if the same problem and fix both occur and work for those machines as well. Something to maybe test later, I suppose.

But for now, anyone got thoughts as to a sane workaround for this? Perhaps some conditional tweaks in mach-ip32/*.h files somewheres, would it be simpler to just switch to:

#if defined(CONFIG_64BIT) && (!defined(CONFIG_BUILD_ELF64) || defined(CONFIG_SGI_IP32))

(assuming that IP22 doesn't need it; I'll find out later)

"Re-verify range to target, One ping only."

So, anyone got thoughts on this?

I've actually built and booted an SGI IP32 kernel using this logic in include/asm-mips/page.h, Line 135:

#if defined(CONFIG_64BIT) && (!defined(CONFIG_BUILD_ELF64) || (defined(CONFIG_SGI_IP32) || defined(CONFIG_SGI_IP22)))

--Kumba

Signature · 3 lines
Gentoo/MIPS Team Lead

"Such is oft the course of deeds that move the wheels of the world: small hands do them because they must, while the eyes of the great are elsewhere."  --Elrond
#2 lore raw
In reply to Kumba

Hi,

Quoted 9 lines · Kumba

Initially, booting a straight git checkout on an IP32 will cause it to prom crash, usually somewhere in between init_bootmem() and init_bootmem_core(). I bisected git to trace this back to one of the inital __pa() introduction patches from commit d4df6d4 (get ride of CPHYSADDR()). It actually appears that the actual commit that broke things was 620a480 (Make __pa() aware of XKPHYS/CKSEG0 address mix for 64 bit kernels).

Quoted 5 lines

The [short-term] fix highlighted by Ilya is to make __pa() unconditionally be defined to "((unsigned long)(x) < CKSEG0 ? PAGE_OFFSET : CKSEG0)"; Discovered by building IP32 with CONFIG_BUILD_ELF64=n.

Well, it means that you previously used CONFIG_BUILD_ELF64=y (this implied that PAGE_OFFSET is in XKPHYS) whereas your kernel has CKSEG load address (symbols need PAGE_OFFSET in CKSEG for address translation).

So the question is why can't you use CONFIG_BUILD_ELF64=n (and reagarding the current definition of CONFIG_BUILD_ELF64).

Quoted 5 lines

Normally, this shouldn't be possible, as CONFIG_BUILD_ELF64=n was originally only allowed by using the old o64 hack, which has subsequently died and been replaced with the newer -msym32 form. As far as I know, CONFIG_BUILD_ELF64 is apparently supposed to be removed at some point in the future, since I believe it existed only for quirky

It makes me think that I posted a patch for that a couple of weeks ago:

http://marc.theaimsgroup.com/?l=linux-mips&m=117154480225936&w=2
http://marc.theaimsgroup.com/?l=linux-mips&m=117154480126802&w=2
http://marc.theaimsgroup.com/?l=linux-mips&m=117154587014827&w=2

Basically this patch removes CONFIG_BUILD_ELF64 and makes Kbuild to use '-msym32' switch if you really need it. Kbuild makes its choice according the load address of your kernel image.

Could you give it a try ? This patch was based on 2.6.20 but it should apply fine on a 2.6.21-rc[12].

Signature · 1 line
              Franck
#3 lore raw

PATCH 1/1 , Re: IP32 prom crashes due to __pa() funkiness

Hi !

Watching the discussion about __pa(), CPHYSADDR and related stuff, with about a hundred e-mails last October, and rising again several times recently (see below), i wonder why we must cling so firmly to the "x - page_offset" algorithm, the least capable one. AFAIK this method is taken over unaltered from the i386 arch (yes, i know, the majority of archs did this), where we have a situation quite different from MIPS:
A (preferably simple) mapping must be invented for kernel-memory with some, more or less deliberately chosen, "page-offset". There exist no addresses beside this mapping, no hardware "kernel-mappings" with (un)cached regions, cached-attributes, unmapped spaces, etc. and "x - page_offset" is necessary and sufficient to handle all addresses.

On the MIPS-side there isn't really something like "the" page-offset, and the processor architecture already defines kernel spaces with respective address-syntax. In other words, the definitions in asm-mips/addrspace.h properly describe the virtual/physical conversions and masking, not some subtracting, is the natural way to go.

Since __pa() and virt_to_phys() are currently "under construction" anyway, i think it's time to submit robust versions (with kernel_physaddr() stolen from the IP30 patch) for both, that handle any pitfall in one place and may be used without pain throughout the kernel. I don't know, which one to prefer, 29 drivers are using __pa(), 60 are using virt_to_phys(), the uses in arch/mips files are about equal.

Having a robust __pa()/virt_to_phys() avoids the need for local fixes, like in sgiwd93.c and sgiseeq.c, which have to cope with at least one uncached (usu. 0x9000...) address-type and at least one cached type (usu. 0xa800...) in xkphys, and where virt_to_phys() blew up nicely. In some situation there may be need to handle a ckseg0/1 address additionaly.

Quoted 24 lines · Franck Bui-Huu

Date: Thu, 1 Mar 2007 10:39:08 +0100
From: Franck Bui-Huu <[email protected]>
To: Kumba <[email protected]>
Cc: Linux MIPS List <[email protected]>
Subject: Re: IP32 prom crashes due to __pa() funkiness

Hi,

Quoted 9 lines · Kumba

Initially, booting a straight git checkout on an IP32 will cause it to prom crash, usually somewhere in between init_bootmem() and init_bootmem_core(). I bisected git to trace this back to one of the inital __pa() introduction patches from commit d4df6d4 (get ride of CPHYSADDR()). It actually appears that the actual commit that broke things was 620a480 (Make __pa() aware of XKPHYS/CKSEG0 address mix for 64 bit kernels).

Quoted 5 lines

The [short-term] fix highlighted by Ilya is to make __pa() unconditionally be defined to "((unsigned long)(x) < CKSEG0 ? PAGE_OFFSET : CKSEG0)"; Discovered by building IP32 with CONFIG_BUILD_ELF64=n.

Quoted 6 lines

Well, it means that you previously used CONFIG_BUILD_ELF64=y (this implied that PAGE_OFFSET is in XKPHYS) whereas your kernel has CKSEG load address (symbols need PAGE_OFFSET in CKSEG for address translation).

...

========================================================================

include/asm-mips/addrspace.h +11 -0
@@ -54,6 +54,17 @@
 #define XPHYSADDR(a)            ((_ACAST64_(a)) &			\
 				 _CONST64_(0x000000ffffffffff))
 
+static inline unsigned long kernel_physaddr(unsigned long kva)
+{
+#ifdef CONFIG_64BIT
+	if((kva & 0xffffffff80000000UL) == 0xffffffff80000000UL)
+		return CPHYSADDR(kva);
+	return XPHYSADDR(kva);
+#else
+	return CPHYSADDR(kva);
+#endif
+}
+
 #ifdef CONFIG_64BIT
 
 /*
include/asm-mips/io.h +1 -1
@@ -116,7 +116,7 @@ static inline void set_io_port_base(unsi
  */
 static inline unsigned long virt_to_phys(volatile const void *address)
 {
-	return (unsigned long)address - PAGE_OFFSET + PHYS_OFFSET;
+	return kernel_physaddr((unsigned long)address);
 }
 
 /*
include/asm-mips/page.h +1 -1
@@ -154,7 +154,7 @@ typedef struct { unsigned long pgprot; }
 #else
 #define __pa_page_offset(x)	PAGE_OFFSET
 #endif
-#define __pa(x)		((unsigned long)(x) - __pa_page_offset(x) + PHYS_OFFSET)
+#define __pa(x)		kernel_physaddr((unsigned long)(x))
 #define __va(x)		((void *)((unsigned long)(x) + PAGE_OFFSET - PHYS_OFFSET))
 #define __pa_symbol(x)	__pa(RELOC_HIDE((unsigned long)(x),0))

========================================================================

author
#4 lore raw
In reply to Franck Bui-Huu

(whoops, reply didn't send to the ML, sorry Frank!)

Quoted 2 lines · Franck Bui-Huu

Hi,

[snip]

Quoted 9 lines

Well, it means that you previously used CONFIG_BUILD_ELF64=y (this implied that PAGE_OFFSET is in XKPHYS) whereas your kernel has CKSEG load address (symbols need PAGE_OFFSET in CKSEG for address translation).

So the question is why can't you use CONFIG_BUILD_ELF64=n (and reagarding the current definition of CONFIG_BUILD_ELF64).

[snip]

Quoted 7 lines

It makes me think that I posted a patch for that a couple of weeks ago:

http://marc.theaimsgroup.com/?l=linux-mips&m=117154480225936&w=2
http://marc.theaimsgroup.com/?l=linux-mips&m=117154480126802&w=2
http://marc.theaimsgroup.com/?l=linux-mips&m=117154587014827&w=2

Quoted 6 lines

Basically this patch removes CONFIG_BUILD_ELF64 and makes Kbuild to use '-msym32' switch if you really need it. Kbuild makes its choice according the load address of your kernel image.

Could you give it a try ? This patch was based on 2.6.20 but it should apply fine on a 2.6.21-rc[12].

Tested, and it still failed.

And I didn't always use CONFIG_BUILD_ELF64. In fact, for the longest time (up until 2.6.17) I built IP32 and 64bit IP22 kernels without CONFIG_BUILD_eLF64, passing -mabi=o64 (a.k.a., the binutils hack). This let me use the plain 'vmlinux' target w/o the need for an objcopy to boot these systems. After 2.6.17, the nature of o64 was mostly neutered, so I switched to using CONFIG_BUILD_ELF64 and the 'vmlinux.32' target, as this is apparently the way Debian builds their IP32 kernels (and was the way geoman/spbecker said I should've been using all along).

So with the changes brought in by __pa(), I suppose a new, RightWay(TM) to build IP32 (and conversely, 64bit IP22) kernels needs to be found. These two systems are particularly wacky, hence why they need a bit more special care than more traditional, proper, 64bit systems like Origin and Octane.

Also, Peter raises a good point in this case. It sounds like a re-thinking of how all this address stuff is handled will fix not only special cases like IP32/IP22, but the really weird systems, like IP28, as well. Which would be a big plus in my opinion.

--Kumba

Signature · 3 lines
Gentoo/MIPS Team Lead

"Such is oft the course of deeds that move the wheels of the world: small hands do them because they must, while the eyes of the great are elsewhere."  --Elrond
#5 lore raw
Quoted 3 lines · Kumba

So with the changes brought in by __pa(), I suppose a new, RightWay(TM) to build IP32 (and conversely, 64bit IP22) kernels needs to be found.

I don't know if it is the RightWay(TM), but I am running here a fresh IP32 kernel (l.m.o git updated yesterday). It was compiled with CONFIG_BUILD_ELF64=n, and I am using vmlinux.

$ file /boot/vmlinux-2.6.21-rc3-g839fd555 
/boot/vmlinux-2.6.21-rc3-g839fd555: ELF 64-bit MSB executable, MIPS, MIPS-IV version 1 (SYSV), statically linked, not stripped

If it makes a difference, I am using arcboot.

Arnaud

author
#6 lore raw
Quoted 8 lines · Arnaud Giersch

I don't know if it is the RightWay(TM), but I am running here a fresh IP32 kernel (l.m.o git updated yesterday). It was compiled with CONFIG_BUILD_ELF64=n, and I am using vmlinux.

$ file /boot/vmlinux-2.6.21-rc3-g839fd555 /boot/vmlinux-2.6.21-rc3-g839fd555: ELF 64-bit MSB executable, MIPS, MIPS-IV version 1 (SYSV), statically linked, not stripped

If it makes a difference, I am using arcboot.

I suppose then the question is, which is better for IP32? CONFIG_BUILD_ELF64=y or CONFIG_BUILD_ELF64=n. The reason the o64 hack used to exist, if my memory serves me correctly, was that someone once said that when built and run as a pure 64bit binary converted to 32bit via objcopy, 6 extra insns were run every cycle (I think), introducing unneeded slowdown. This changed to 2 insns by going the o64 route, which involved CONFIG_BUILD_ELF64=n. So 4 less insns technically resulted in a quicker kernel, though the layman might not notice such. I believe that all changed at some point, which is why CONFIG_BUILD_ELF64=y was an A-OK thing prior to the __pa() introduction.

Now I guess we're back to CONFIG_BUILD_ELF64=n? I guess the real question is, which way is the OneWay(TM), RightWay(TM) and OnlyWay(TM)?

Cheers,

--Kumba

Signature · 3 lines
Gentoo/MIPS Team Lead

"Such is oft the course of deeds that move the wheels of the world: small hands do them because they must, while the eyes of the great are elsewhere."  --Elrond
#7 lore raw
Quoted 6 lines · Kumba
Quoted 5 lines · Arnaud Giersch

I don't know if it is the RightWay(TM), but I am running here a fresh IP32 kernel (l.m.o git updated yesterday). It was compiled with CONFIG_BUILD_ELF64=n, and I am using vmlinux.

Quoted 7 lines
Quoted 5 lines
$ file /boot/vmlinux-2.6.21-rc3-g839fd555
/boot/vmlinux-2.6.21-rc3-g839fd555: ELF 64-bit MSB executable, MIPS,
MIPS-IV version 1 (SYSV), statically linked, not stripped

If it makes a difference, I am using arcboot.

I suppose then the question is, which is better for IP32?

That's the question I was wondering during my first reply to your initial post...

Quoted 5 lines

CONFIG_BUILD_ELF64=y or CONFIG_BUILD_ELF64=n. The reason the o64 hack used to exist, if my memory serves me correctly, was that someone once said that when built and run as a pure 64bit binary converted to 32bit via objcopy, 6 extra insns were run every cycle (I think), introducing unneeded slowdown. This changed to 2 insns by going the o64 route,

OK that's the reason why the last patch you applied has no effect. If you're using 'objcopy' your kernel can still be miss configured.

BTW, does your gcc support '-sym32' switch ?

Quoted 5 lines

which involved CONFIG_BUILD_ELF64=n. So 4 less insns technically resulted in a quicker kernel, though the layman might not notice such. I believe that all changed at some point, which is why CONFIG_BUILD_ELF64=y was an A-OK thing prior to the __pa() introduction.

My current feeling is that __pa() introduction now breaks configs which were initialy _broken_, IMHO. CPHYSADDR() hide them because it can happily convert any virutal address form both CKSEG0 or XKPHYS.

It may be a good thing to crash at this point. CONFIG_BUILD_ELF64 is used in some others places, where it can introduce some others bugs harder to find (if miss configured of course). The sad thing is that the kernel does not report any useful messages. That's why I think adding some specific sanity checks for 64 bit kernels in boot mem init code may be usefull.

Quoted 3 lines

Now I guess we're back to CONFIG_BUILD_ELF64=n? I guess the real question is, which way is the OneWay(TM), RightWay(TM) and OnlyWay(TM)?

Now it's clear that CONFIG_BUILD_ELF64 is really confusing. I would say that whatever the value of CONFIG_BUILD_ELF64, your kernel should run fine. BUT it really depends on your kernel load address:

if CONFIG_BUILD_ELF64=y then kernel load address must be in XKPHYS if CONFIG_BUILD_ELF64=n then kernel load address must be in CKSEG0

All others configs (I think) are buggy...

That's said, it seems that IPxx kernels are really special beasts. Take from MIPS makefile:

"""
Some machines like the Indy need 32-bit ELF binaries for booting purposes.
"""

So I dunno if this statement is still correct but it sounds that you have no other choice thatn CONFIG_BUILD_ELF64=n and load address in CKSEG0.

I'm sorry but my IPxx background is 0 ;)

Franck

#8 lore raw

Franck Bui-Huu wrote:
[snip]

Quoted 11 lines
Quoted 2 lines

Now I guess we're back to CONFIG_BUILD_ELF64=n? I guess the real question is, which way is the OneWay(TM), RightWay(TM) and OnlyWay(TM)?

Now it's clear that CONFIG_BUILD_ELF64 is really confusing. I would say that whatever the value of CONFIG_BUILD_ELF64, your kernel should run fine. BUT it really depends on your kernel load address:

if CONFIG_BUILD_ELF64=y then kernel load address must be in XKPHYS if CONFIG_BUILD_ELF64=n then kernel load address must be in CKSEG0

All others configs (I think) are buggy...

Why? A ELF64 kernel for CKSEG0 should be fine, at least in principle, even if it doesn't work wih the current codebase.

Quoted 7 lines

That's said, it seems that IPxx kernels are really special beasts. Take from MIPS makefile:

"""
Some machines like the Indy need 32-bit ELF binaries for booting purposes.
"""

This is true for netbooting via firmware. For booting from disk the bootloaders support AFAIR ELF64-for-CKSEG0.

Thiemo

#9 lore raw
Quoted 4 lines · Thiemo Seufer

Why? A ELF64 kernel for CKSEG0 should be fine, at least in principle, even if it doesn't work wih the current codebase.

Yes you're right. I just replied to my self to say that.

Thanks

Signature · 1 line
              Franck
#10 lore raw
In reply to Franck Bui-Huu
Quoted 6 lines · Franck Bui-Huu

Now it's clear that CONFIG_BUILD_ELF64 is really confusing. I would say that whatever the value of CONFIG_BUILD_ELF64, your kernel should run fine. BUT it really depends on your kernel load address:

if CONFIG_BUILD_ELF64=y then kernel load address must be in XKPHYS if CONFIG_BUILD_ELF64=n then kernel load address must be in CKSEG0

to be more accurate, the following other config:

CONFIG_BUILD_ELF64=y and kernel load address in CKSEG0

should theoretically work but currently doesn't because of __pa() introduction.

This config should not be used because it's normally not interesting for normal user. It's only interesting for testing purpose if I recall correctly. And the patch that automatically set CONFIG_BUILD_ELF64 should fix this.

BTW, you should take a look at:

http://marc.info/?l=linux-mips&m=117019833420946&w=2

this thread clearly state that current config of IP32 kernel is broken. Sorry for remembering so lately...

Signature · 1 line
              Franck
author
#11 lore raw
In reply to Franck Bui-Huu
Quoted 4 lines · Franck Bui-Huu

OK that's the reason why the last patch you applied has no effect. If you're using 'objcopy' your kernel can still be miss configured.

BTW, does your gcc support '-sym32' switch ?

I'll have to re-try some runs w/ the straight 64bit vmlinux later on then, but AFAICT, __pa() braks IP32 because of the assumption I highlighted. This, cobalt, and IP22 are a bit "special" in their needs, I guess. Anyone got a short yellow bus?

Quoted 10 lines

My current feeling is that __pa() introduction now breaks configs which were initialy _broken_, IMHO. CPHYSADDR() hide them because it can happily convert any virutal address form both CKSEG0 or XKPHYS.

It may be a good thing to crash at this point. CONFIG_BUILD_ELF64 is used in some others places, where it can introduce some others bugs harder to find (if miss configured of course). The sad thing is that the kernel does not report any useful messages. That's why I think adding some specific sanity checks for 64 bit kernels in boot mem init code may be usefull.

A good idea to crash at this point? Not for users. Up until this point, I've never really seen any bugs produced by CONFIG_BUILD_ELF64, granted I avoided using it until ~2.6.17 (when o64 died). If there were bugs, they were subtle and didn't appear to affect the day-to-day running of the system. At minimum, __pa() should recreate this effect, and then we can trace down the bugs and hammer them to death later.

Quoted 12 lines

Now it's clear that CONFIG_BUILD_ELF64 is really confusing. I would say that whatever the value of CONFIG_BUILD_ELF64, your kernel should run fine. BUT it really depends on your kernel load address:

if CONFIG_BUILD_ELF64=y then kernel load address must be in XKPHYS if CONFIG_BUILD_ELF64=n then kernel load address must be in CKSEG0

All others configs (I think) are buggy...

That's said, it seems that IPxx kernels are really special beasts. Take from MIPS makefile:

Quoted 8 lines

"""
Some machines like the Indy need 32-bit ELF binaries for booting purposes.
"""

So I dunno if this statement is still correct but it sounds that you have no other choice thatn CONFIG_BUILD_ELF64=n and load address in CKSEG0.

Most of this is because IP22 (Indy/Idigo2 R4xx) and IP32 (O2 R5xxx), while supporting 64bit kernels (same for cobalt, since it's a mips4-level CPU), we had to "trick" them into accepting 64bit code. IP32 at one point ran 32bit kernels only, but it was later converted to supporting only 64bit kernels, hence the hackery involved. We describe it as wrapping 64bit code into a 32bit object, because their proms will only recognize 32bit objects (specifically, IP22 will only boot 32bit objects; crash on 64bit; IP32 will take both, but likes 32bit better).

So really, CONFIG_BUILD_ELF64 was probably part of this "magic" to stuff 64bit code into a candy-coated 32bit wrapper for the Indy (And later the O2) to suck down w/o complaint. Hence, __pa() probably needs to replicate this support, or we all need to brainstorm a proper way to get these systems to boot.

Octane, Origin, IP28 (Indigo2 R10000). et al, don't complain, and don't need this hacker, because their proms boot proper 64bit binaries only (they reject all else).

So probably the following is true (someone correct me if not)

if (CONFIG_BUILD_ELF64=y and (!CONFIG_SGI_IP22 or !CONFIG_SGI_IP32 or !CONFIG_COBALT)) then kernel load address must be in XKPHYS else load address must be in CKSEG0
if CONFIG_BUILD_ELF64=n then kernel load address must be in CKSEG0

Quoted 1 line

I'm sorry but my IPxx background is 0 ;)

Time to buy an O2 :)

--Kumba

Signature · 3 lines
Gentoo/MIPS Team Lead

"Such is oft the course of deeds that move the wheels of the world: small hands do them because they must, while the eyes of the great are elsewhere."  --Elrond
#12 lore raw
Quoted 10 lines · Kumba

Most of this is because IP22 (Indy/Idigo2 R4xx) and IP32 (O2 R5xxx), while supporting 64bit kernels (same for cobalt, since it's a mips4-level CPU), we had to "trick" them into accepting 64bit code. IP32 at one point ran 32bit kernels only, but it was later converted to supporting only 64bit kernels, hence the hackery involved. We describe it as wrapping 64bit code into a 32bit object, because their proms will only recognize 32bit objects (specifically, IP22 will only boot 32bit objects; crash on 64bit; IP32 will take both, but likes 32bit better).

Quoted 5 lines

So really, CONFIG_BUILD_ELF64 was probably part of this "magic" to stuff 64bit code into a candy-coated 32bit wrapper for the Indy (And later the O2) to suck down w/o complaint. Hence, __pa() probably needs to replicate this support, or we all need to brainstorm a proper way to get these systems to boot.

The "magic" is CONFIG_BOOT_ELF32 and CONFIG_BOOT_ELF64, isn't it? CONFIG_BUILD_ELF64 is not irrelevant to ELF format.

I feel there are some confusions about this issue on this discussion...
---
Atsushi Nemoto

#13 lore raw
In reply to Kumba

Kumba wrote:
[snip]

Quoted 9 lines

Most of this is because IP22 (Indy/Idigo2 R4xx) and IP32 (O2 R5xxx), while supporting 64bit kernels (same for cobalt, since it's a mips4-level CPU), we had to "trick" them into accepting 64bit code. IP32 at one point ran 32bit kernels only, but it was later converted to supporting only 64bit kernels, hence the hackery involved. We describe it as wrapping 64bit code into a 32bit object, because their proms will only recognize 32bit objects (specifically, IP22 will only boot 32bit objects; crash on 64bit; IP32 will take both, but likes 32bit better).

Quoted 5 lines

So really, CONFIG_BUILD_ELF64 was probably part of this "magic" to stuff 64bit code into a candy-coated 32bit wrapper for the Indy (And later the O2) to suck down w/o complaint. Hence, __pa() probably needs to replicate this support, or we all need to brainstorm a proper way to get these systems to boot.

BUILD_ELF64 + -sym32 + objcopy into a ELF32 file is supposed to be the full replacement for the old o64-in-o32 hack.

Quoted 10 lines

Octane, Origin, IP28 (Indigo2 R10000). et al, don't complain, and don't need this hacker, because their proms boot proper 64bit binaries only (they reject all else).

So probably the following is true (someone correct me if not)

if (CONFIG_BUILD_ELF64=y and (!CONFIG_SGI_IP22 or !CONFIG_SGI_IP32 or !CONFIG_COBALT)) then kernel load address must be in XKPHYS else load address must be in CKSEG0
if CONFIG_BUILD_ELF64=n then kernel load address must be in CKSEG0

The 64/64 configs can do both:

                      |  BUILD_ELF64  | BUILD_ELF32
---------------------------------------------------
64bit firmware loader | CKSEG0/XKPHYS |   CKSEG0
32bit firmware loader |     CKSEG0    |   CKSEG0

Thiemo

#14 lore raw
In reply to Kumba
Quoted 10 lines · Kumba

Most of this is because IP22 (Indy/Idigo2 R4xx) and IP32 (O2 R5xxx), while supporting 64bit kernels (same for cobalt, since it's a mips4-level CPU), we had to "trick" them into accepting 64bit code. IP32 at one point ran 32bit kernels only, but it was later converted to supporting only 64bit kernels, hence the hackery involved. We describe it as wrapping 64bit code into a 32bit object, because their proms will only recognize 32bit objects (specifically, IP22 will only boot 32bit objects; crash on 64bit; IP32 will take both, but likes 32bit better).

Quoted 5 lines

So really, CONFIG_BUILD_ELF64 was probably part of this "magic" to stuff 64bit code into a candy-coated 32bit wrapper for the Indy (And later the O2) to suck down w/o complaint. Hence, __pa() probably needs to replicate this support, or we all need to brainstorm a proper way to get these systems to boot.

I'm really not confident with all your tricks you described. Maybe a config that I believed to be uninsteresting and useless should be supported still.

Can you try the attached patch with a plain linux-mips kernel ? This patch restore CPHYSADDR() for 64 bits kernels _only_. I guess it's ok because we won't need to support mapped kernels on 64 bits machines...

Could others give their opinions ?

Quoted 4 lines
Quoted 1 line

I'm sorry but my IPxx background is 0 ;)

Time to buy an O2 :)

As soon as it will work with a plain linux-mips without hackery ;)

Signature · 1 line
              Franck
include/asm-mips/page.h +4 -4
index d3fbd83..6461154 100644
@@ -149,12 +149,12 @@ typedef struct { unsigned long pgprot; } pgprot_t;
 /*
  * __pa()/__va() should be used only during mem init.
  */
-#if defined(CONFIG_64BIT) && !defined(CONFIG_BUILD_ELF64)
-#define __pa_page_offset(x)	((unsigned long)(x) < CKSEG0 ? PAGE_OFFSET : CKSEG0)
+#ifdef CONFIG_64BIT
+#define __pa(x)		((unsigned long)(x) < CKSEG0 ? XPHYSADDR((unsigned long)(x))\
+						     : CPHYSADDR((unsigned long)(x)))
 #else
-#define __pa_page_offset(x)	PAGE_OFFSET
+#define __pa(x)		((unsigned long)(x) - PAGE_OFFSET + PHYS_OFFSET)
 #endif
-#define __pa(x)		((unsigned long)(x) - __pa_page_offset(x) + PHYS_OFFSET)
 #define __va(x)		((void *)((unsigned long)(x) + PAGE_OFFSET - PHYS_OFFSET))
 #define __pa_symbol(x)	__pa(RELOC_HIDE((unsigned long)(x),0))
 
author
#15 lore raw
Quoted 10 lines · Franck Bui-Huu

I'm really not confident with all your tricks you described. Maybe a config that I believed to be uninsteresting and useless should be supported still.

Can you try the attached patch with a plain linux-mips kernel ? This patch restore CPHYSADDR() for 64 bits kernels _only_. I guess it's ok because we won't need to support mapped kernels on 64 bits machines...

Could others give their opinions ?

After going through all the fun to get rid of CPHYSADDR, I see no point really to bring it back. Plus that patch unnecessarily complicates those defines. As I highlighted in my original mail, O2 doesn't need CPHYSADDR added to __pa(), it just needs the conditional define for __pa_page_offset to be a little bit more flexible.

Since only three machines, O2 R5xx, Indy/Indigo2 R4xx, and Cobalt will exhibit similar issues (the latter two when booting 64bit kernels), a saner method in my opinion is to introduce a flag of sorts into the conditional for __pa_page_offset to determine whether to define it strictly to PAGE_OFFSET or to the other value listed in the code. The only thing is, I'm not sure which method of the two I've thought up is cleaner.

The first introduces a hidden Kconfig value, CONFIG_SYS_LOADS_IN_CKSEG0, that only turns on when BUILD_ELF64 && (SGI_IP22 || (SGI_IP32 && (CPU_R5000 || CPU_NEVADA || CPU_RM7000)) || MIPS_COBALT), and then we test for this flag in include/asm-mips/page.h when setting the value of __pa_page_offset.

The other way is to define a similar flag in a new header file, memmap.h, in include/asm-mips/mach-{ip22,ip32,cobalt}/* called MIPS_USES_CKSEG0, and similarly, test for that flag in the same spot as above. With this method, though, I'm not sure where exactly to pull in the memmap.h header, so the patch for it is incomplete (but included for reference).

I've tested the first patch (kconfig one), and it works fine. The second one will also work, provided I find a nice spot to pull in memmap.h, but from a semantics perspective, which one do you guys like better?

--Kumba

Signature · 3 lines
Gentoo/MIPS Team Lead

"Such is oft the course of deeds that move the wheels of the world: small hands do them because they must, while the eyes of the great are elsewhere."  --Elrond
arch/mips/Kconfig +5 -0
diff -Naurp mipslinux/arch/mips/Kconfig mipslinux.ckseg0-a/arch/mips/Kconfig
@@ -1659,6 +1659,11 @@ config SB1_PASS_2_1_WORKAROUNDS
 	depends on CPU_SB1 && CPU_SB1_PASS_2
 	default y
 
+config SYS_LOADS_IN_CKSEG0
+	bool
+	depends on BUILD_ELF64 && (SGI_IP22 || (SGI_IP32 && (CPU_R5000 || CPU_NEVADA || CPU_RM7000)) || MIPS_COBALT)
+	default y
+
 config 64BIT_PHYS_ADDR
 	bool "Support for 64-bit physical address space"
 	depends on (CPU_R4X00 || CPU_R5000 || CPU_RM7000 || CPU_RM9000 || CPU_R10000 || CPU_SB1 || CPU_MIPS32 || CPU_MIPS64) && 32BIT
include/asm-mips/page.h +1 -1
diff -Naurp mipslinux/include/asm-mips/page.h mipslinux.ckseg0-a/include/asm-mips/page.h
@@ -149,7 +149,7 @@ typedef struct { unsigned long pgprot; }
 /*
  * __pa()/__va() should be used only during mem init.
  */
-#if defined(CONFIG_64BIT) && !defined(CONFIG_BUILD_ELF64)
+#if defined(CONFIG_64BIT) && (!defined(CONFIG_BUILD_ELF64) || defined(CONFIG_SYS_LOADS_IN_CKSEG0))
 #define __pa_page_offset(x)	((unsigned long)(x) < CKSEG0 ? PAGE_OFFSET : CKSEG0)
 #else
 #define __pa_page_offset(x)	PAGE_OFFSET
include/asm-mips/mach-cobalt/memmap.h +9 -0
diff -Naurp mipslinux/include/asm-mips/mach-cobalt/memmap.h mipslinux.ckseg0-b/include/asm-mips/mach-cobalt/memmap.h
@@ -0,0 +1,9 @@
+#ifndef __ASM_MACH_IP32_MEMMAP_H
+#define __ASM_MACH_IP32_MEMMAP_H
+
+
+#ifdef CONFIG_64BIT
+#define MIPS_USES_CKSEG0	1
+#endif
+
+#endif /* __ASM_MACH_IP32_MEMMAP_H */
include/asm-mips/mach-ip22/memmap.h +9 -0
diff -Naurp mipslinux/include/asm-mips/mach-ip22/memmap.h mipslinux.ckseg0-b/include/asm-mips/mach-ip22/memmap.h
@@ -0,0 +1,9 @@
+#ifndef __ASM_MACH_IP32_MEMMAP_H
+#define __ASM_MACH_IP32_MEMMAP_H
+
+
+#ifdef CONFIG_64BIT
+#define MIPS_USES_CKSEG0	1
+#endif
+
+#endif /* __ASM_MACH_IP32_MEMMAP_H */
include/asm-mips/mach-ip32/memmap.h +9 -0
diff -Naurp mipslinux/include/asm-mips/mach-ip32/memmap.h mipslinux.ckseg0-b/include/asm-mips/mach-ip32/memmap.h
@@ -0,0 +1,9 @@
+#ifndef __ASM_MACH_IP32_MEMMAP_H
+#define __ASM_MACH_IP32_MEMMAP_H
+
+
+#if defined(CONFIG_CPU_R5000) || defined(CONFIG_CPU_NEVADA) || defined (CONFIG_CPU_RM7000)
+#define MIPS_USES_CKSEG0	1
+#endif
+
+#endif /* __ASM_MACH_IP32_MEMMAP_H */
include/asm-mips/page.h +1 -1
diff -Naurp mipslinux/include/asm-mips/page.h mipslinux.ckseg0-b/include/asm-mips/page.h
@@ -149,7 +149,7 @@ typedef struct { unsigned long pgprot; }
 /*
  * __pa()/__va() should be used only during mem init.
  */
-#if defined(CONFIG_64BIT) && !defined(CONFIG_BUILD_ELF64)
+#if defined(CONFIG_64BIT) && (!defined(CONFIG_BUILD_ELF64) || defined(MIPS_USES_CKSEG0))
 #define __pa_page_offset(x)	((unsigned long)(x) < CKSEG0 ? PAGE_OFFSET : CKSEG0)
 #else
 #define __pa_page_offset(x)	PAGE_OFFSET
#16 lore raw
Quoted 3 lines · Kumba

After going through all the fun to get rid of CPHYSADDR, I see no point really to bring it back.

The patch restores CPHYSADDR() but in __pa()'s _implementation_. It makes a huge difference.

I think CPHYSADDR() is not that bad for 64 bits kernels. With such beasts we need to handle two PAGE_OFFSET values if we stick with the current implementation of __pa(). Magically using CPHYSADDR() removes this need. OTOH, CPHYSADDR() is quite bad for mapped kernels.

But do we really care in 64 bits world ?

Quoted 5 lines

Plus that patch unnecessarily complicates those defines. As I
highlighted in my original mail, O2 doesn't need CPHYSADDR added to __pa(), it just needs the conditional define for __pa_page_offset to be a little bit more flexible.

I don't see why the patch complicates those defines. It actually gets rid of CONFIG_BUILD_ELF64 and __pa_page_offset(). OK I could have written it a little bit more readable:

#ifdef CONFIG_64BIT
#define __pa(x) \

({								\
	unsigned long __x = (unsigned long)(x);			\
	__x < CKSEG0 ? XPHYSADDR(__x) : CPHYSADDR(__x);		\
})

#else
#define __pa(x) \
((unsigned long)(x) - PAGE_OFFSET + PHYS_OFFSET)
#endif

Yes, it actually increases size code for CONFIG_64BIT because we always test if the virtual address is from XKPHYS or CKSEG0. But how much ? I would say not a lot, and it maybe worths it since we get rid of an obscure config option.

Franck

Signature · 1 line
              Franck

A message that is not in the archive (sent off-list or not yet received): [email protected]

#18 lore raw

Hi!

Did you try to use PHYS_OFFSET > 0 ? __pa() ist still (as of d3fbd83ff545e49e2a0a5ca0f00dda4eedaf8be7) defined as (casts omitted):

#define __pa(x) (x - (x < CKSEG0 ? PAGE_OFFSET:CKSEG0) + PHYS_OFFSET)

This gives __pa(CKSEG0) == PHYS_OFFSET, which will never work for PHYS_OFFSET > 0. A quick fix (assuming this was the cause for failure) could be:

========================================================================

include/asm-mips/page.h +1 -1
@@ -150,7 +150,7 @@ typedef struct { unsigned long pgprot; }
  * __pa()/__va() should be used only during mem init.
  */
 #if defined(CONFIG_64BIT) && !defined(CONFIG_BUILD_ELF64)
-#define __pa_page_offset(x)	((unsigned long)(x) < CKSEG0 ? PAGE_OFFSET : CKSEG0)
+#define __pa_page_offset(x)	((unsigned long)(x) < CKSEG0 ? PAGE_OFFSET : CKSEG0+PHYS_OFFSET)
 #else
 #define __pa_page_offset(x)	PAGE_OFFSET
 #endif

========================================================================

Of course, "#define PAGE_OFFSET (CAC_BASE + PHYS_OFFSET)" is also needed.

kind regards

peter

Quoted 65 lines · Kumba

Date: Sat, 17 Mar 2007 14:53:23 -0400
From: Kumba <[email protected]>
To: Franck Bui-Huu <[email protected]>
Cc: peter fuerst <[email protected]>
Subject: Re: IP32 prom crashes due to __pa() funkiness

Quoted 2 lines · Franck Bui-Huu

Hi,

[snip]

Quoted 9 lines

Well, it means that you previously used CONFIG_BUILD_ELF64=y (this implied that PAGE_OFFSET is in XKPHYS) whereas your kernel has CKSEG load address (symbols need PAGE_OFFSET in CKSEG for address translation).

So the question is why can't you use CONFIG_BUILD_ELF64=n (and reagarding the current definition of CONFIG_BUILD_ELF64).

[snip]

Quoted 7 lines

It makes me think that I posted a patch for that a couple of weeks ago:

http://marc.theaimsgroup.com/?l=linux-mips&m=117154480225936&w=2
http://marc.theaimsgroup.com/?l=linux-mips&m=117154480126802&w=2
http://marc.theaimsgroup.com/?l=linux-mips&m=117154587014827&w=2

Quoted 6 lines

Basically this patch removes CONFIG_BUILD_ELF64 and makes Kbuild to use '-msym32' switch if you really need it. Kbuild makes its choice according the load address of your kernel image.

Could you give it a try ? This patch was based on 2.6.20 but it should apply fine on a 2.6.21-rc[12].

Tested, and it still failed.

And I didn't always use CONFIG_BUILD_ELF64. In fact, for the longest time (up until 2.6.17) I built IP32 and 64bit IP22 kernels without CONFIG_BUILD_eLF64, passing -mabi=o64 (a.k.a., the binutils hack). This let me use the plain 'vmlinux' target w/o the need for an objcopy to boot these systems. After 2.6.17, the nature of o64 was mostly neutered, so I switched to using CONFIG_BUILD_ELF64 and the 'vmlinux.32' target, as this is apparently the way Debian builds their IP32 kernels (and was the way geoman/spbecker said I should've been using all along).

So with the changes brought in by __pa(), I suppose a new, RightWay(TM) to build IP32 (and conversely, 64bit IP22) kernels needs to be found. These two systems are particularly wacky, hence why they need a bit more special care than more traditional, proper, 64bit systems like Origin and Octane.

Also, Peter raises a good point in this case. It sounds like a re-thinking of how all this address stuff is handled will fix not only special cases like IP32/IP22, but the really weird systems, like IP28, as well. Which would be a big plus in my opinion.

--Kumba

--
Gentoo/MIPS Team Lead

"Such is oft the course of deeds that move the wheels of the world: small hands do them because they must, while the eyes of the great are elsewhere." --Elrond

author
#19 lore raw
Quoted 28 lines · peter fuerst

Hi!

Did you try to use PHYS_OFFSET > 0 ? __pa() ist still (as of d3fbd83ff545e49e2a0a5ca0f00dda4eedaf8be7) defined as (casts omitted):

#define __pa(x) (x - (x < CKSEG0 ? PAGE_OFFSET:CKSEG0) + PHYS_OFFSET)

This gives __pa(CKSEG0) == PHYS_OFFSET, which will never work for PHYS_OFFSET > 0. A quick fix (assuming this was the cause for failure) could be:

========================================================================

include/asm-mips/page.h +1 -1
@@ -150,7 +150,7 @@ typedef struct { unsigned long pgprot; }
  * __pa()/__va() should be used only during mem init.
  */
 #if defined(CONFIG_64BIT) && !defined(CONFIG_BUILD_ELF64)
-#define __pa_page_offset(x)	((unsigned long)(x) < CKSEG0 ? PAGE_OFFSET : CKSEG0)
+#define __pa_page_offset(x)	((unsigned long)(x) < CKSEG0 ? PAGE_OFFSET : CKSEG0+PHYS_OFFSET)
 #else
 #define __pa_page_offset(x)	PAGE_OFFSET
 #endif
Quoted 7 lines

========================================================================

Of course, "#define PAGE_OFFSET (CAC_BASE + PHYS_OFFSET)" is also needed.

kind regards

peter

Hmm, I can't find where PHYS_OFFSET is defined for mips. A grep shows it mostly existing for the arm arch. Is there an alternative macro available, or is this something that needs porting over?

--Kumba

Signature · 3 lines
Gentoo/MIPS Team Lead

"Such is oft the course of deeds that move the wheels of the world: small hands do them because they must, while the eyes of the great are elsewhere."  --Elrond
author
#20 lore raw
Quoted 36 lines · Kumba
Quoted 35 lines · peter fuerst

Hi!

Did you try to use PHYS_OFFSET > 0 ? __pa() ist still (as of d3fbd83ff545e49e2a0a5ca0f00dda4eedaf8be7) defined as (casts omitted):

#define __pa(x) (x - (x < CKSEG0 ? PAGE_OFFSET:CKSEG0) + PHYS_OFFSET)

This gives __pa(CKSEG0) == PHYS_OFFSET, which will never work for PHYS_OFFSET > 0. A quick fix (assuming this was the cause for failure) could be:

========================================================================
---
d3fbd83ff545e49e2a0a5ca0f00dda4eedaf8be7/include/asm-mips/page.h Sat Mar 10 08:43:17 2007
+++ quickfix/include/asm-mips/page.h Sun Mar 18 10:24:34 2007

include/asm-mips/page.h +1 -1
@@ -150,7 +150,7 @@ typedef struct { unsigned long pgprot; }
  * __pa()/__va() should be used only during mem init.
  */
 #if defined(CONFIG_64BIT) && !defined(CONFIG_BUILD_ELF64)
-#define __pa_page_offset(x)    ((unsigned long)(x) < CKSEG0 ? 
 PAGE_OFFSET : CKSEG0)
+#define __pa_page_offset(x)    ((unsigned long)(x) < CKSEG0 ? 
 PAGE_OFFSET : CKSEG0+PHYS_OFFSET)
 #else

#define __pa_page_offset(x) PAGE_OFFSET
#endif

========================================================================

Of course, "#define PAGE_OFFSET (CAC_BASE + PHYS_OFFSET)" is also needed.

Quoted 8 lines
Quoted 3 lines

kind regards

peter

Hmm, I can't find where PHYS_OFFSET is defined for mips. A grep shows it mostly existing for the arm arch. Is there an alternative macro available, or is this something that needs porting over?

--Kumba

Ah, duh. PHYS_OFFSET was introduced post-2.6.20, so I won't be able to leverage this w/o backporting.

--Kumba

Signature · 3 lines
Gentoo/MIPS Team Lead

"Such is oft the course of deeds that move the wheels of the world: small hands do them because they must, while the eyes of the great are elsewhere."  --Elrond
author
#21 lore raw
In reply to peter fuerst
Quoted 28 lines · peter fuerst

Hi!

Did you try to use PHYS_OFFSET > 0 ? __pa() ist still (as of d3fbd83ff545e49e2a0a5ca0f00dda4eedaf8be7) defined as (casts omitted):

#define __pa(x) (x - (x < CKSEG0 ? PAGE_OFFSET:CKSEG0) + PHYS_OFFSET)

This gives __pa(CKSEG0) == PHYS_OFFSET, which will never work for PHYS_OFFSET > 0. A quick fix (assuming this was the cause for failure) could be:

========================================================================

include/asm-mips/page.h +1 -1
@@ -150,7 +150,7 @@ typedef struct { unsigned long pgprot; }
  * __pa()/__va() should be used only during mem init.
  */
 #if defined(CONFIG_64BIT) && !defined(CONFIG_BUILD_ELF64)
-#define __pa_page_offset(x)	((unsigned long)(x) < CKSEG0 ? PAGE_OFFSET : CKSEG0)
+#define __pa_page_offset(x)	((unsigned long)(x) < CKSEG0 ? PAGE_OFFSET : CKSEG0+PHYS_OFFSET)
 #else
 #define __pa_page_offset(x)	PAGE_OFFSET
 #endif
Quoted 7 lines

========================================================================

Of course, "#define PAGE_OFFSET (CAC_BASE + PHYS_OFFSET)" is also needed.

kind regards

peter

Backported the patches that bring in PHYS_OFFSET and tried both with and without Frank's patches to remove CONFIG_BUILD_ELF64 from the Makefile, plus this change, and still no go. W/o CONFIG_BUILD_ELF64, both the vmlinux and vmlinux.32 targets just silently hang. With CONFIG_BUILD_ELF64 in the Makefile, the same Prom crash.

--Kumba

Signature · 3 lines
Gentoo/MIPS Team Lead

"Such is oft the course of deeds that move the wheels of the world: small hands do them because they must, while the eyes of the great are elsewhere."  --Elrond
#22 lore raw
Quoted 7 lines · Kumba

Backported the patches that bring in PHYS_OFFSET and tried both with and without Frank's patches to remove CONFIG_BUILD_ELF64 from the Makefile, plus this change, and still no go. W/o CONFIG_BUILD_ELF64, both the vmlinux and vmlinux.32 targets just silently hang. With CONFIG_BUILD_ELF64 in the Makefile, the same Prom crash.

wait wait wait. PHYS_OFFSET has nothing to do in this case. You are obvioulsy not using it by default.

Signature · 1 line
              Franck