qemu-devel.nongnu.org archive mirror
 help / color / mirror / Atom feed
* [PATCH] pc-bios/s390x: Pack ResetInfo struct
@ 2020-02-05 18:21 Jason J. Herne
  2020-02-06  9:55 ` Cornelia Huck
  2020-02-06 10:09 ` Christian Borntraeger
  0 siblings, 2 replies; 15+ messages in thread
From: Jason J. Herne @ 2020-02-05 18:21 UTC (permalink / raw)
  To: qemu-devel, qemu-s390x, cohuck, borntraeger

This fixes vfio-ccw when booting non-Linux operating systems. Without this
struct being packed, a few extra bytes of low core memory get overwritten when
we  assign a value to memory address 0 in jump_to_IPL_2. This is enough to
cause some non-Linux OSes of fail when booting.

The problem was introduced by:
5c6f0d5f46a77d77 "pc-bios/s390x: Fix reset psw mask".

The fix is to pack the struct thereby removing the 4 bytes of padding that get
added at the end, likely to allow an array of these structs to naturally align
on an 8-byte boundary.

Fixes: 5c6f0d5f46a7 ("pc-bios/s390x: Fix reset psw mask")
CC: Janosch Frank <frankja@linux.ibm.com>
Signed-off-by: Jason J. Herne <jjherne@linux.ibm.com>
---
 pc-bios/s390-ccw/jump2ipl.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/pc-bios/s390-ccw/jump2ipl.c b/pc-bios/s390-ccw/jump2ipl.c
index da13c43cc0..1e9eaa037f 100644
--- a/pc-bios/s390-ccw/jump2ipl.c
+++ b/pc-bios/s390-ccw/jump2ipl.c
@@ -18,7 +18,7 @@
 typedef struct ResetInfo {
     uint64_t ipl_psw;
     uint32_t ipl_continue;
-} ResetInfo;
+} __attribute__((packed)) ResetInfo;
 
 static ResetInfo save;
 
-- 
2.21.1



^ permalink raw reply related	[flat|nested] 15+ messages in thread

* Re: [PATCH] pc-bios/s390x: Pack ResetInfo struct
  2020-02-05 18:21 [PATCH] pc-bios/s390x: Pack ResetInfo struct Jason J. Herne
@ 2020-02-06  9:55 ` Cornelia Huck
  2020-02-06 10:09 ` Christian Borntraeger
  1 sibling, 0 replies; 15+ messages in thread
From: Cornelia Huck @ 2020-02-06  9:55 UTC (permalink / raw)
  To: Jason J. Herne; +Cc: Thomas Huth, borntraeger, qemu-s390x, qemu-devel

On Wed,  5 Feb 2020 13:21:26 -0500
"Jason J. Herne" <jjherne@linux.ibm.com> wrote:

> This fixes vfio-ccw when booting non-Linux operating systems. Without this
> struct being packed, a few extra bytes of low core memory get overwritten when
> we  assign a value to memory address 0 in jump_to_IPL_2. This is enough to
> cause some non-Linux OSes of fail when booting.

s/of/to/

> 
> The problem was introduced by:
> 5c6f0d5f46a77d77 "pc-bios/s390x: Fix reset psw mask".

So, what introduced the problem was turning two 32 bit values into a 64
bit value?

> 
> The fix is to pack the struct thereby removing the 4 bytes of padding that get
> added at the end, likely to allow an array of these structs to naturally align
> on an 8-byte boundary.
> 
> Fixes: 5c6f0d5f46a7 ("pc-bios/s390x: Fix reset psw mask")
> CC: Janosch Frank <frankja@linux.ibm.com>
> Signed-off-by: Jason J. Herne <jjherne@linux.ibm.com>
> ---
>  pc-bios/s390-ccw/jump2ipl.c | 2 +-
>  1 file changed, 1 insertion(+), 1 deletion(-)
> 
> diff --git a/pc-bios/s390-ccw/jump2ipl.c b/pc-bios/s390-ccw/jump2ipl.c
> index da13c43cc0..1e9eaa037f 100644
> --- a/pc-bios/s390-ccw/jump2ipl.c
> +++ b/pc-bios/s390-ccw/jump2ipl.c
> @@ -18,7 +18,7 @@
>  typedef struct ResetInfo {
>      uint64_t ipl_psw;
>      uint32_t ipl_continue;
> -} ResetInfo;
> +} __attribute__((packed)) ResetInfo;
>  
>  static ResetInfo save;
>  

I'm wondering if we have more stuff like that lurking in the bios.



^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [PATCH] pc-bios/s390x: Pack ResetInfo struct
  2020-02-05 18:21 [PATCH] pc-bios/s390x: Pack ResetInfo struct Jason J. Herne
  2020-02-06  9:55 ` Cornelia Huck
@ 2020-02-06 10:09 ` Christian Borntraeger
  2020-02-06 11:00   ` Thomas Huth
  2020-02-13 18:02   ` Jason J. Herne
  1 sibling, 2 replies; 15+ messages in thread
From: Christian Borntraeger @ 2020-02-06 10:09 UTC (permalink / raw)
  To: Jason J. Herne, qemu-devel, qemu-s390x, cohuck



On 05.02.20 19:21, Jason J. Herne wrote:
> This fixes vfio-ccw when booting non-Linux operating systems. Without this
> struct being packed, a few extra bytes of low core memory get overwritten when
> we  assign a value to memory address 0 in jump_to_IPL_2. This is enough to
> cause some non-Linux OSes of fail when booting.
> 
> The problem was introduced by:
> 5c6f0d5f46a77d77 "pc-bios/s390x: Fix reset psw mask".
> 
> The fix is to pack the struct thereby removing the 4 bytes of padding that get
> added at the end, likely to allow an array of these structs to naturally align
> on an 8-byte boundary.
> 
> Fixes: 5c6f0d5f46a7 ("pc-bios/s390x: Fix reset psw mask")
> CC: Janosch Frank <frankja@linux.ibm.com>
> Signed-off-by: Jason J. Herne <jjherne@linux.ibm.com>
> ---
>  pc-bios/s390-ccw/jump2ipl.c | 2 +-
>  1 file changed, 1 insertion(+), 1 deletion(-)
> 
> diff --git a/pc-bios/s390-ccw/jump2ipl.c b/pc-bios/s390-ccw/jump2ipl.c
> index da13c43cc0..1e9eaa037f 100644
> --- a/pc-bios/s390-ccw/jump2ipl.c
> +++ b/pc-bios/s390-ccw/jump2ipl.c
> @@ -18,7 +18,7 @@
>  typedef struct ResetInfo {
>      uint64_t ipl_psw;
>      uint32_t ipl_continue;
> -} ResetInfo;
> +} __attribute__((packed)) ResetInfo;
>  
>  static ResetInfo save;

Just looked into that.

We do save the old content in "save" and restore the old memory content.

static void jump_to_IPL_2(void)
{
    ResetInfo *current = 0;

    void (*ipl)(void) = (void *) (uint64_t) current->ipl_continue;
--->*current = save;
    ipl(); /* should not return */
}

void jump_to_IPL_code(uint64_t address)
{
    /* store the subsystem information _after_ the bootmap was loaded */
    write_subsystem_identification();

    /* prevent unknown IPL types in the guest */
    if (iplb.pbt == S390_IPL_TYPE_QEMU_SCSI) {
        iplb.pbt = S390_IPL_TYPE_CCW;
        set_iplb(&iplb);
    }

    /*
     * The IPL PSW is at address 0. We also must not overwrite the
     * content of non-BIOS memory after we loaded the guest, so we
     * save the original content and restore it in jump_to_IPL_2.
     */
    ResetInfo *current = 0;

--->save = *current;



does something like


diff --git a/pc-bios/s390-ccw/jump2ipl.c b/pc-bios/s390-ccw/jump2ipl.c
index da13c43cc0..8839226803 100644
--- a/pc-bios/s390-ccw/jump2ipl.c
+++ b/pc-bios/s390-ccw/jump2ipl.c
@@ -18,6 +18,7 @@
 typedef struct ResetInfo {
     uint64_t ipl_psw;
     uint32_t ipl_continue;
+    uint32_t pad;
 } ResetInfo;
 
 static ResetInfo save;


also work? If yes, both variants are valid. Either packed or explicit padding.



^ permalink raw reply related	[flat|nested] 15+ messages in thread

* Re: [PATCH] pc-bios/s390x: Pack ResetInfo struct
  2020-02-06 10:09 ` Christian Borntraeger
@ 2020-02-06 11:00   ` Thomas Huth
  2020-02-07 11:28     ` Christian Borntraeger
  2020-02-13 18:02   ` Jason J. Herne
  1 sibling, 1 reply; 15+ messages in thread
From: Thomas Huth @ 2020-02-06 11:00 UTC (permalink / raw)
  To: Christian Borntraeger, Jason J. Herne, qemu-devel, qemu-s390x, cohuck

On 06/02/2020 11.09, Christian Borntraeger wrote:
> 
> 
> On 05.02.20 19:21, Jason J. Herne wrote:
>> This fixes vfio-ccw when booting non-Linux operating systems. Without this
>> struct being packed, a few extra bytes of low core memory get overwritten when
>> we  assign a value to memory address 0 in jump_to_IPL_2. This is enough to
>> cause some non-Linux OSes of fail when booting.
>>
>> The problem was introduced by:
>> 5c6f0d5f46a77d77 "pc-bios/s390x: Fix reset psw mask".
>>
>> The fix is to pack the struct thereby removing the 4 bytes of padding that get
>> added at the end, likely to allow an array of these structs to naturally align
>> on an 8-byte boundary.
>>
>> Fixes: 5c6f0d5f46a7 ("pc-bios/s390x: Fix reset psw mask")
>> CC: Janosch Frank <frankja@linux.ibm.com>
>> Signed-off-by: Jason J. Herne <jjherne@linux.ibm.com>
>> ---
>>  pc-bios/s390-ccw/jump2ipl.c | 2 +-
>>  1 file changed, 1 insertion(+), 1 deletion(-)
>>
>> diff --git a/pc-bios/s390-ccw/jump2ipl.c b/pc-bios/s390-ccw/jump2ipl.c
>> index da13c43cc0..1e9eaa037f 100644
>> --- a/pc-bios/s390-ccw/jump2ipl.c
>> +++ b/pc-bios/s390-ccw/jump2ipl.c
>> @@ -18,7 +18,7 @@
>>  typedef struct ResetInfo {
>>      uint64_t ipl_psw;
>>      uint32_t ipl_continue;
>> -} ResetInfo;
>> +} __attribute__((packed)) ResetInfo;
>>  
>>  static ResetInfo save;
> 
> Just looked into that.
> 
> We do save the old content in "save" and restore the old memory content.
> 
> static void jump_to_IPL_2(void)
> {
>     ResetInfo *current = 0;
> 
>     void (*ipl)(void) = (void *) (uint64_t) current->ipl_continue;
> --->*current = save;
>     ipl(); /* should not return */
> }
> 
> void jump_to_IPL_code(uint64_t address)
> {
>     /* store the subsystem information _after_ the bootmap was loaded */
>     write_subsystem_identification();
> 
>     /* prevent unknown IPL types in the guest */
>     if (iplb.pbt == S390_IPL_TYPE_QEMU_SCSI) {
>         iplb.pbt = S390_IPL_TYPE_CCW;
>         set_iplb(&iplb);
>     }
> 
>     /*
>      * The IPL PSW is at address 0. We also must not overwrite the
>      * content of non-BIOS memory after we loaded the guest, so we
>      * save the original content and restore it in jump_to_IPL_2.
>      */
>     ResetInfo *current = 0;
> 
> --->save = *current;

Right, and this should also work without your modification. I've stared
at the code a couple of weeks ago, looking for a very similar issue:

 https://lists.gnu.org/archive/html/qemu-devel/2019-12/msg03484.html

... but in the end, the problem was something else:

 https://lists.gnu.org/archive/html/qemu-devel/2019-12/msg03520.html

and the fix had been done in the startup code of the test:

 https://lists.gnu.org/archive/html/qemu-devel/2019-12/msg04225.html

So I'd guess that you face the very same problem here. That means, you
either have to convince the non-Linux OS to check their startup code
whether they depend on zeroed registers somewhere, or we fix this issue
for good in jump_to_IPL_2() by clearing the registers there before
jumping into the OS code (which we likely should do anyway since the OS
may expect a clean state).

 Thomas



^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [PATCH] pc-bios/s390x: Pack ResetInfo struct
  2020-02-06 11:00   ` Thomas Huth
@ 2020-02-07 11:28     ` Christian Borntraeger
  2020-02-07 14:02       ` Jason J. Herne
  0 siblings, 1 reply; 15+ messages in thread
From: Christian Borntraeger @ 2020-02-07 11:28 UTC (permalink / raw)
  To: Thomas Huth, Jason J. Herne, qemu-devel, qemu-s390x, cohuck

Jason,

can you run objdump -Sdr on jump2ipl.o on a broken variant?


On 06.02.20 12:00, Thomas Huth wrote:
> On 06/02/2020 11.09, Christian Borntraeger wrote:
>>
>>
>> On 05.02.20 19:21, Jason J. Herne wrote:
>>> This fixes vfio-ccw when booting non-Linux operating systems. Without this
>>> struct being packed, a few extra bytes of low core memory get overwritten when
>>> we  assign a value to memory address 0 in jump_to_IPL_2. This is enough to
>>> cause some non-Linux OSes of fail when booting.
>>>
>>> The problem was introduced by:
>>> 5c6f0d5f46a77d77 "pc-bios/s390x: Fix reset psw mask".
>>>
>>> The fix is to pack the struct thereby removing the 4 bytes of padding that get
>>> added at the end, likely to allow an array of these structs to naturally align
>>> on an 8-byte boundary.
>>>
>>> Fixes: 5c6f0d5f46a7 ("pc-bios/s390x: Fix reset psw mask")
>>> CC: Janosch Frank <frankja@linux.ibm.com>
>>> Signed-off-by: Jason J. Herne <jjherne@linux.ibm.com>
>>> ---
>>>  pc-bios/s390-ccw/jump2ipl.c | 2 +-
>>>  1 file changed, 1 insertion(+), 1 deletion(-)
>>>
>>> diff --git a/pc-bios/s390-ccw/jump2ipl.c b/pc-bios/s390-ccw/jump2ipl.c
>>> index da13c43cc0..1e9eaa037f 100644
>>> --- a/pc-bios/s390-ccw/jump2ipl.c
>>> +++ b/pc-bios/s390-ccw/jump2ipl.c
>>> @@ -18,7 +18,7 @@
>>>  typedef struct ResetInfo {
>>>      uint64_t ipl_psw;
>>>      uint32_t ipl_continue;
>>> -} ResetInfo;
>>> +} __attribute__((packed)) ResetInfo;
>>>  
>>>  static ResetInfo save;
>>
>> Just looked into that.
>>
>> We do save the old content in "save" and restore the old memory content.
>>
>> static void jump_to_IPL_2(void)
>> {
>>     ResetInfo *current = 0;
>>
>>     void (*ipl)(void) = (void *) (uint64_t) current->ipl_continue;
>> --->*current = save;
>>     ipl(); /* should not return */
>> }
>>
>> void jump_to_IPL_code(uint64_t address)
>> {
>>     /* store the subsystem information _after_ the bootmap was loaded */
>>     write_subsystem_identification();
>>
>>     /* prevent unknown IPL types in the guest */
>>     if (iplb.pbt == S390_IPL_TYPE_QEMU_SCSI) {
>>         iplb.pbt = S390_IPL_TYPE_CCW;
>>         set_iplb(&iplb);
>>     }
>>
>>     /*
>>      * The IPL PSW is at address 0. We also must not overwrite the
>>      * content of non-BIOS memory after we loaded the guest, so we
>>      * save the original content and restore it in jump_to_IPL_2.
>>      */
>>     ResetInfo *current = 0;
>>
>> --->save = *current;
> 
> Right, and this should also work without your modification. I've stared
> at the code a couple of weeks ago, looking for a very similar issue:
> 
>  https://lists.gnu.org/archive/html/qemu-devel/2019-12/msg03484.html
> 
> ... but in the end, the problem was something else:
> 
>  https://lists.gnu.org/archive/html/qemu-devel/2019-12/msg03520.html
> 
> and the fix had been done in the startup code of the test:
> 
>  https://lists.gnu.org/archive/html/qemu-devel/2019-12/msg04225.html
> 
> So I'd guess that you face the very same problem here. That means, you
> either have to convince the non-Linux OS to check their startup code
> whether they depend on zeroed registers somewhere, or we fix this issue
> for good in jump_to_IPL_2() by clearing the registers there before
> jumping into the OS code (which we likely should do anyway since the OS
> may expect a clean state).
> 
>  Thomas
> 
> 



^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [PATCH] pc-bios/s390x: Pack ResetInfo struct
  2020-02-07 11:28     ` Christian Borntraeger
@ 2020-02-07 14:02       ` Jason J. Herne
  2020-08-27 10:07         ` Thomas Huth
  0 siblings, 1 reply; 15+ messages in thread
From: Jason J. Herne @ 2020-02-07 14:02 UTC (permalink / raw)
  To: Christian Borntraeger, Thomas Huth, qemu-devel, qemu-s390x, cohuck

On 2/7/20 6:28 AM, Christian Borntraeger wrote:
> Jason,
> 
> can you run objdump -Sdr on jump2ipl.o on a broken variant?
> 
> 
To keep the volume lower, I've only pasted the output that I think you're interested in. 
If you want to see the entire thing just let me know.

static void jump_to_IPL_2(void)
{
  1d0:	eb bf f0 58 00 24 	stmg	%r11,%r15,88(%r15)
  1d6:	a7 fb ff 50       	aghi	%r15,-176
  1da:	b9 04 00 bf       	lgr	%r11,%r15
     ResetInfo *current = 0;
  1de:	a7 19 00 00       	lghi	%r1,0
  1e2:	e3 10 b0 a8 00 24 	stg	%r1,168(%r11)

     void (*ipl)(void) = (void *) (uint64_t) current->ipl_continue;
  1e8:	e3 10 b0 a8 00 04 	lg	%r1,168(%r11)
  1ee:	58 10 10 08       	l	%r1,8(%r1)
  1f2:	b9 16 00 11       	llgfr	%r1,%r1
  1f6:	e3 10 b0 a0 00 24 	stg	%r1,160(%r11)
     *current = save;
  1fc:	e3 10 b0 a8 00 04 	lg	%r1,168(%r11)
  202:	c0 20 00 00 00 00 	larl	%r2,202 <jump_to_IPL_2+0x32>
			204: R_390_PC32DBL	.bss+0x2
  208:	eb 23 20 00 00 04 	lmg	%r2,%r3,0(%r2)
  20e:	eb 23 10 00 00 24 	stmg	%r2,%r3,0(%r1)
     ipl(); /* should not return */
  214:	e3 10 b0 a0 00 04 	lg	%r1,160(%r11)
  21a:	0d e1             	basr	%r14,%r1
}
  21c:	18 00             	lr	%r0,%r0
  21e:	eb bf b1 08 00 04 	lmg	%r11,%r15,264(%r11)
  224:	07 fe             	br	%r14
  226:	07 07             	nopr	%r7

0000000000000228 <jump_to_IPL_code>:

void jump_to_IPL_code(uint64_t address)
{
  228:	eb bf f0 58 00 24 	stmg	%r11,%r15,88(%r15)
  22e:	c0 d0 00 00 00 00 	larl	%r13,22e <jump_to_IPL_code+0x6>
			230: R_390_PC32DBL	.rodata+0x2a
  234:	a7 fb ff 50       	aghi	%r15,-176
  238:	b9 04 00 bf       	lgr	%r11,%r15
  23c:	e3 20 b0 a0 00 24 	stg	%r2,160(%r11)
     /* store the subsystem information _after_ the bootmap was loaded */
     write_subsystem_identification();
  242:	c0 e5 00 00 00 00 	brasl	%r14,242 <jump_to_IPL_code+0x1a>
			244: R_390_PLT32DBL	write_subsystem_identification+0x2

     /* prevent unknown IPL types in the guest */
     if (iplb.pbt == S390_IPL_TYPE_QEMU_SCSI) {
  248:	c0 10 00 00 00 00 	larl	%r1,248 <jump_to_IPL_code+0x20>
			24a: R_390_GOTENT	iplb+0x2
  24e:	e3 10 10 00 00 04 	lg	%r1,0(%r1)
  254:	43 10 10 0c       	ic	%r1,12(%r1)
  258:	a7 28 00 ff       	lhi	%r2,255
  25c:	14 12             	nr	%r1,%r2
  25e:	a7 1e 00 ff       	chi	%r1,255
  262:	a7 74 00 15       	jne	28c <jump_to_IPL_code+0x64>
         iplb.pbt = S390_IPL_TYPE_CCW;
  266:	c0 10 00 00 00 00 	larl	%r1,266 <jump_to_IPL_code+0x3e>
			268: R_390_GOTENT	iplb+0x2
  26c:	e3 10 10 00 00 04 	lg	%r1,0(%r1)
  272:	92 02 10 0c       	mvi	12(%r1),2
         set_iplb(&iplb);
  276:	c0 10 00 00 00 00 	larl	%r1,276 <jump_to_IPL_code+0x4e>
			278: R_390_GOTENT	iplb+0x2
  27c:	e3 10 10 00 00 04 	lg	%r1,0(%r1)
  282:	b9 04 00 21       	lgr	%r2,%r1
  286:	c0 e5 ff ff ff 75 	brasl	%r14,170 <set_iplb>
     /*
      * The IPL PSW is at address 0. We also must not overwrite the
      * content of non-BIOS memory after we loaded the guest, so we
      * save the original content and restore it in jump_to_IPL_2.
      */
     ResetInfo *current = 0;
  28c:	a7 19 00 00       	lghi	%r1,0
  290:	e3 10 b0 a8 00 24 	stg	%r1,168(%r11)

     save = *current;
  296:	c0 10 00 00 00 00 	larl	%r1,296 <jump_to_IPL_code+0x6e>
			298: R_390_PC32DBL	.bss+0x2
  29c:	e3 20 b0 a8 00 04 	lg	%r2,168(%r11)
  2a2:	eb 23 20 00 00 04 	lmg	%r2,%r3,0(%r2)
  2a8:	eb 23 10 00 00 24 	stmg	%r2,%r3,0(%r1)

     current->ipl_psw = (uint64_t) &jump_to_IPL_2;
  2ae:	c0 20 ff ff ff 91 	larl	%r2,1d0 <jump_to_IPL_2>
  2b4:	e3 10 b0 a8 00 04 	lg	%r1,168(%r11)
  2ba:	e3 20 10 00 00 24 	stg	%r2,0(%r1)
     current->ipl_psw |= RESET_PSW_MASK;
  2c0:	e3 10 b0 a8 00 04 	lg	%r1,168(%r11)
  2c6:	e3 10 10 00 00 04 	lg	%r1,0(%r1)
  2cc:	e3 20 d0 00 00 04 	lg	%r2,0(%r13)
  2d2:	b9 81 00 21       	ogr	%r2,%r1
  2d6:	e3 10 b0 a8 00 04 	lg	%r1,168(%r11)
  2dc:	e3 20 10 00 00 24 	stg	%r2,0(%r1)
     current->ipl_continue = address & 0x7fffffff;
  2e2:	e3 10 b0 a0 00 04 	lg	%r1,160(%r11)
  2e8:	b9 17 00 21       	llgtr	%r2,%r1
  2ec:	e3 10 b0 a8 00 04 	lg	%r1,168(%r11)
  2f2:	50 20 10 08       	st	%r2,8(%r1)

     debug_print_int("set IPL addr to", current->ipl_continue);
  2f6:	e3 10 b0 a8 00 04 	lg	%r1,168(%r11)
  2fc:	58 10 10 08       	l	%r1,8(%r1)
  300:	b9 16 00 11       	llgfr	%r1,%r1
  304:	b9 04 00 31       	lgr	%r3,%r1
  308:	c0 20 00 00 00 00 	larl	%r2,308 <jump_to_IPL_code+0xe0>
			30a: R_390_PC32DBL	.rodata+0x2
  30e:	c0 e5 ff ff ff 4d 	brasl	%r14,1a8 <debug_print_int>

     /* Ensure the guest output starts fresh */
     sclp_print("\n");
  314:	c0 20 00 00 00 00 	larl	%r2,314 <jump_to_IPL_code+0xec>
			316: R_390_PC32DBL	.rodata+0x12
  31a:	c0 e5 00 00 00 00 	brasl	%r14,31a <jump_to_IPL_code+0xf2>
			31c: R_390_PLT32DBL	sclp_print+0x2
     /*
      * HACK ALERT.
      * We use the load normal reset to keep r15 unchanged. jump_to_IPL_2
      * can then use r15 as its stack pointer.
      */
     asm volatile("lghi 1,1\n\t"
  320:	a7 19 00 01       	lghi	%r1,1
  324:	83 11 03 08       	diag	%r1,%r1,776
                  "diag 1,1,0x308\n\t"
                  : : : "1", "memory");
     panic("\n! IPL returns !\n");
  328:	c0 20 00 00 00 00 	larl	%r2,328 <jump_to_IPL_code+0x100>
			32a: R_390_PC32DBL	.rodata+0x14
  32e:	c0 e5 00 00 00 00 	brasl	%r14,32e <jump_to_IPL_code+0x106>
			330: R_390_PLT32DBL	panic+0x2
}
  334:	18 00             	lr	%r0,%r0
  336:	eb bf b1 08 00 04 	lmg	%r11,%r15,264(%r11)
  33c:	07 fe             	br	%r14
  33e:	07 07             	nopr	%r7



-- 
-- Jason J. Herne (jjherne@linux.ibm.com)


^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [PATCH] pc-bios/s390x: Pack ResetInfo struct
  2020-02-06 10:09 ` Christian Borntraeger
  2020-02-06 11:00   ` Thomas Huth
@ 2020-02-13 18:02   ` Jason J. Herne
  2020-02-13 18:24     ` Christian Borntraeger
  1 sibling, 1 reply; 15+ messages in thread
From: Jason J. Herne @ 2020-02-13 18:02 UTC (permalink / raw)
  To: Christian Borntraeger, qemu-devel, qemu-s390x, cohuck

On 2/6/20 5:09 AM, Christian Borntraeger wrote:
> 
> 
> On 05.02.20 19:21, Jason J. Herne wrote:
>> This fixes vfio-ccw when booting non-Linux operating systems. Without this
>> struct being packed, a few extra bytes of low core memory get overwritten when
>> we  assign a value to memory address 0 in jump_to_IPL_2. This is enough to
>> cause some non-Linux OSes of fail when booting.
>>
>> The problem was introduced by:
>> 5c6f0d5f46a77d77 "pc-bios/s390x: Fix reset psw mask".
>>
>> The fix is to pack the struct thereby removing the 4 bytes of padding that get
>> added at the end, likely to allow an array of these structs to naturally align
>> on an 8-byte boundary.
>>
>> Fixes: 5c6f0d5f46a7 ("pc-bios/s390x: Fix reset psw mask")
>> CC: Janosch Frank <frankja@linux.ibm.com>
>> Signed-off-by: Jason J. Herne <jjherne@linux.ibm.com>
>> ---
>>   pc-bios/s390-ccw/jump2ipl.c | 2 +-
>>   1 file changed, 1 insertion(+), 1 deletion(-)
>>
>> diff --git a/pc-bios/s390-ccw/jump2ipl.c b/pc-bios/s390-ccw/jump2ipl.c
>> index da13c43cc0..1e9eaa037f 100644
>> --- a/pc-bios/s390-ccw/jump2ipl.c
>> +++ b/pc-bios/s390-ccw/jump2ipl.c
>> @@ -18,7 +18,7 @@
>>   typedef struct ResetInfo {
>>       uint64_t ipl_psw;
>>       uint32_t ipl_continue;
>> -} ResetInfo;
>> +} __attribute__((packed)) ResetInfo;
>>   
>>   static ResetInfo save;
> 
> Just looked into that.
> 
> We do save the old content in "save" and restore the old memory content.
> 
> static void jump_to_IPL_2(void)
> {
>      ResetInfo *current = 0;
> 
>      void (*ipl)(void) = (void *) (uint64_t) current->ipl_continue;
> --->*current = save;
>      ipl(); /* should not return */
> }
> 
> void jump_to_IPL_code(uint64_t address)
> {
>      /* store the subsystem information _after_ the bootmap was loaded */
>      write_subsystem_identification();
> 
>      /* prevent unknown IPL types in the guest */
>      if (iplb.pbt == S390_IPL_TYPE_QEMU_SCSI) {
>          iplb.pbt = S390_IPL_TYPE_CCW;
>          set_iplb(&iplb);
>      }
> 
>      /*
>       * The IPL PSW is at address 0. We also must not overwrite the
>       * content of non-BIOS memory after we loaded the guest, so we
>       * save the original content and restore it in jump_to_IPL_2.
>       */
>      ResetInfo *current = 0;
> 
> --->save = *current;
> 
> 
> 
> does something like
> 
> 
> diff --git a/pc-bios/s390-ccw/jump2ipl.c b/pc-bios/s390-ccw/jump2ipl.c
> index da13c43cc0..8839226803 100644
> --- a/pc-bios/s390-ccw/jump2ipl.c
> +++ b/pc-bios/s390-ccw/jump2ipl.c
> @@ -18,6 +18,7 @@
>   typedef struct ResetInfo {
>       uint64_t ipl_psw;
>       uint32_t ipl_continue;
> +    uint32_t pad;
>   } ResetInfo;
>   
>   static ResetInfo save;
> 
> 
> also work? If yes, both variants are valid. Either packed or explicit padding.
> 

I don't believe this will work. I think the problem is that we're overwriting too much 
memory when we cast address 0 as a ResetInfo and then overwrite it (*current = save). I 
think we need the struct to be sized at 12-bytes instead of 16.


-- 
-- Jason J. Herne (jjherne@linux.ibm.com)


^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [PATCH] pc-bios/s390x: Pack ResetInfo struct
  2020-02-13 18:02   ` Jason J. Herne
@ 2020-02-13 18:24     ` Christian Borntraeger
  2020-02-25 10:23       ` Jason J. Herne
  0 siblings, 1 reply; 15+ messages in thread
From: Christian Borntraeger @ 2020-02-13 18:24 UTC (permalink / raw)
  To: jjherne, qemu-devel, qemu-s390x, cohuck


On 13.02.20 19:02, Jason J. Herne wrote:
> On 2/6/20 5:09 AM, Christian Borntraeger wrote:
>>
>>
>> On 05.02.20 19:21, Jason J. Herne wrote:
>>> This fixes vfio-ccw when booting non-Linux operating systems. Without this
>>> struct being packed, a few extra bytes of low core memory get overwritten when
>>> we  assign a value to memory address 0 in jump_to_IPL_2. This is enough to
>>> cause some non-Linux OSes of fail when booting.
>>>
>>> The problem was introduced by:
>>> 5c6f0d5f46a77d77 "pc-bios/s390x: Fix reset psw mask".
>>>
>>> The fix is to pack the struct thereby removing the 4 bytes of padding that get
>>> added at the end, likely to allow an array of these structs to naturally align
>>> on an 8-byte boundary.
>>>
>>> Fixes: 5c6f0d5f46a7 ("pc-bios/s390x: Fix reset psw mask")
>>> CC: Janosch Frank <frankja@linux.ibm.com>
>>> Signed-off-by: Jason J. Herne <jjherne@linux.ibm.com>
>>> ---
>>>   pc-bios/s390-ccw/jump2ipl.c | 2 +-
>>>   1 file changed, 1 insertion(+), 1 deletion(-)
>>>
>>> diff --git a/pc-bios/s390-ccw/jump2ipl.c b/pc-bios/s390-ccw/jump2ipl.c
>>> index da13c43cc0..1e9eaa037f 100644
>>> --- a/pc-bios/s390-ccw/jump2ipl.c
>>> +++ b/pc-bios/s390-ccw/jump2ipl.c
>>> @@ -18,7 +18,7 @@
>>>   typedef struct ResetInfo {
>>>       uint64_t ipl_psw;
>>>       uint32_t ipl_continue;
>>> -} ResetInfo;
>>> +} __attribute__((packed)) ResetInfo;
>>>     static ResetInfo save;
>>
>> Just looked into that.
>>
>> We do save the old content in "save" and restore the old memory content.
>>
>> static void jump_to_IPL_2(void)
>> {
>>      ResetInfo *current = 0;
>>
>>      void (*ipl)(void) = (void *) (uint64_t) current->ipl_continue;
>> --->*current = save;
>>      ipl(); /* should not return */
>> }
>>
>> void jump_to_IPL_code(uint64_t address)
>> {
>>      /* store the subsystem information _after_ the bootmap was loaded */
>>      write_subsystem_identification();
>>
>>      /* prevent unknown IPL types in the guest */
>>      if (iplb.pbt == S390_IPL_TYPE_QEMU_SCSI) {
>>          iplb.pbt = S390_IPL_TYPE_CCW;
>>          set_iplb(&iplb);
>>      }
>>
>>      /*
>>       * The IPL PSW is at address 0. We also must not overwrite the
>>       * content of non-BIOS memory after we loaded the guest, so we
>>       * save the original content and restore it in jump_to_IPL_2.
>>       */
>>      ResetInfo *current = 0;
>>
>> --->save = *current;
>>
>>
>>
>> does something like
>>
>>
>> diff --git a/pc-bios/s390-ccw/jump2ipl.c b/pc-bios/s390-ccw/jump2ipl.c
>> index da13c43cc0..8839226803 100644
>> --- a/pc-bios/s390-ccw/jump2ipl.c
>> +++ b/pc-bios/s390-ccw/jump2ipl.c
>> @@ -18,6 +18,7 @@
>>   typedef struct ResetInfo {
>>       uint64_t ipl_psw;
>>       uint32_t ipl_continue;
>> +    uint32_t pad;
>>   } ResetInfo;
>>     static ResetInfo save;
>>
>>
>> also work? If yes, both variants are valid. Either packed or explicit padding.
>>
> 
> I don't believe this will work. I think the problem is that we're overwriting too much memory when we cast address 0 as a ResetInfo and then overwrite it (*current = save). I think we need the struct to be sized at 12-bytes instead of 16.
> 

The idea of the code is that we _save_ the original content from address 0 to save and _restore_ it before jumping into final code. I do not yet understand why this does not work.



^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [PATCH] pc-bios/s390x: Pack ResetInfo struct
  2020-02-13 18:24     ` Christian Borntraeger
@ 2020-02-25 10:23       ` Jason J. Herne
  2020-02-25 11:13         ` Christian Borntraeger
  0 siblings, 1 reply; 15+ messages in thread
From: Jason J. Herne @ 2020-02-25 10:23 UTC (permalink / raw)
  To: Christian Borntraeger, qemu-devel, qemu-s390x, cohuck

On 2/13/20 1:24 PM, Christian Borntraeger wrote:
...
>>> diff --git a/pc-bios/s390-ccw/jump2ipl.c b/pc-bios/s390-ccw/jump2ipl.c
>>> index da13c43cc0..8839226803 100644
>>> --- a/pc-bios/s390-ccw/jump2ipl.c
>>> +++ b/pc-bios/s390-ccw/jump2ipl.c
>>> @@ -18,6 +18,7 @@
>>>    typedef struct ResetInfo {
>>>        uint64_t ipl_psw;
>>>        uint32_t ipl_continue;
>>> +    uint32_t pad;
>>>    } ResetInfo;
>>>      static ResetInfo save;
>>>
>>>
>>> also work? If yes, both variants are valid. Either packed or explicit padding.
>>>
>>
>> I don't believe this will work. I think the problem is that we're overwriting too much memory when we cast address 0 as a ResetInfo and then overwrite it (*current = save). I think we need the struct to be sized at 12-bytes instead of 16.
>>
> 
> The idea of the code is that we _save_ the original content from address 0 to save and _restore_ it before jumping into final code. I do not yet understand why this does not work.
> 

I've found the real problem here. Legacy operating systems that expect to start
in 32-bit addressing mode can fail if we leave junk in the high halves of our
64-bit registers. This is because some instructions (LA for example) are
bi-modal and operate differently depending on the machine's current addressing
mode.

In the case where we pack the struct, the compiler happens to use the mvc
instruction to load/store the current/save memory areas.

       *current = save;
   1fc:	e3 10 b0 a8 00 04 	lg	%r1,168(%r11)
   202:	c0 20 00 00 00 00 	larl	%r2,202 <jump_to_IPL_2+0x32>
			204: R_390_PC32DBL	.bss+0x2
   208:	d2 0b 10 00 20 00 	mvc	0(12,%r1),0(%r2)

Everything works as expected here, our legacy OS boots without issue.
However, in the case where we've packed this struct the compiler optimizes the
code and uses lmg/stmg instead of mvc to copy the data:

       *current = save;
   1fc:	e3 10 b0 a8 00 04 	lg	%r1,168(%r11)
   202:	c0 20 00 00 00 00 	larl	%r2,202 <jump_to_IPL_2+0x32>
			204: R_390_PC32DBL	.bss+0x2
   208:	eb 23 20 00 00 04 	lmg	%r2,%r3,0(%r2)
   20e:	eb 23 10 00 00 24 	stmg	%r2,%r3,0(%r1)

Depending on the data being copied, the high halves of the registers may contain
non-zero values. Example:

     r2             0x108000080000780        74309395999098752
     r3             0x601001800004368        432627142283510632

So, by sheer luck of the generated assembler, the patch happens to "fix" the
problem.  A real fix might be to insert inline assembler that clears the high
halves of the registers before we call ipl() in jump_to_IPL_2(). Can we think of
a better way to do that than 15 LLGTR instructions? :) Let me know your
thoughts.

jump_to_IPL_2 for easy reference:
     static void jump_to_IPL_2(void)
     {
         ResetInfo *current = 0;

         void (*ipl)(void) = (void *) (uint64_t) current->ipl_continue;
         *current = save;
         ipl(); /* should not return */
     }


-- 
-- Jason J. Herne (jjherne@linux.ibm.com)


^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [PATCH] pc-bios/s390x: Pack ResetInfo struct
  2020-02-25 10:23       ` Jason J. Herne
@ 2020-02-25 11:13         ` Christian Borntraeger
  2020-02-25 12:58           ` Jason J. Herne
  0 siblings, 1 reply; 15+ messages in thread
From: Christian Borntraeger @ 2020-02-25 11:13 UTC (permalink / raw)
  To: jjherne, qemu-devel, qemu-s390x, cohuck



On 25.02.20 11:23, Jason J. Herne wrote:
> On 2/13/20 1:24 PM, Christian Borntraeger wrote:
> ...
>>>> diff --git a/pc-bios/s390-ccw/jump2ipl.c b/pc-bios/s390-ccw/jump2ipl.c
>>>> index da13c43cc0..8839226803 100644
>>>> --- a/pc-bios/s390-ccw/jump2ipl.c
>>>> +++ b/pc-bios/s390-ccw/jump2ipl.c
>>>> @@ -18,6 +18,7 @@
>>>>    typedef struct ResetInfo {
>>>>        uint64_t ipl_psw;
>>>>        uint32_t ipl_continue;
>>>> +    uint32_t pad;
>>>>    } ResetInfo;
>>>>      static ResetInfo save;
>>>>
>>>>
>>>> also work? If yes, both variants are valid. Either packed or explicit padding.
>>>>
>>>
>>> I don't believe this will work. I think the problem is that we're overwriting too much memory when we cast address 0 as a ResetInfo and then overwrite it (*current = save). I think we need the struct to be sized at 12-bytes instead of 16.
>>>
>>
>> The idea of the code is that we _save_ the original content from address 0 to save and _restore_ it before jumping into final code. I do not yet understand why this does not work.
>>
> 
> I've found the real problem here. Legacy operating systems that expect to start
> in 32-bit addressing mode can fail if we leave junk in the high halves of our
> 64-bit registers. This is because some instructions (LA for example) are
> bi-modal and operate differently depending on the machine's current addressing
> mode.
> 
> In the case where we pack the struct, the compiler happens to use the mvc
> instruction to load/store the current/save memory areas.
> 
>       *current = save;
>   1fc:    e3 10 b0 a8 00 04     lg    %r1,168(%r11)
>   202:    c0 20 00 00 00 00     larl    %r2,202 <jump_to_IPL_2+0x32>
>             204: R_390_PC32DBL    .bss+0x2
>   208:    d2 0b 10 00 20 00     mvc    0(12,%r1),0(%r2)
> 
> Everything works as expected here, our legacy OS boots without issue.
> However, in the case where we've packed this struct the compiler optimizes the
> code and uses lmg/stmg instead of mvc to copy the data:
> 
>       *current = save;
>   1fc:    e3 10 b0 a8 00 04     lg    %r1,168(%r11)
>   202:    c0 20 00 00 00 00     larl    %r2,202 <jump_to_IPL_2+0x32>
>             204: R_390_PC32DBL    .bss+0x2
>   208:    eb 23 20 00 00 04     lmg    %r2,%r3,0(%r2)
>   20e:    eb 23 10 00 00 24     stmg    %r2,%r3,0(%r1)
> 
> Depending on the data being copied, the high halves of the registers may contain
> non-zero values. Example:
> 
>     r2             0x108000080000780        74309395999098752
>     r3             0x601001800004368        432627142283510632
> 
> So, by sheer luck of the generated assembler, the patch happens to "fix" the
> problem.  A real fix might be to insert inline assembler that clears the high
> halves of the registers before we call ipl() in jump_to_IPL_2(). Can we think of
> a better way to do that than 15 LLGTR instructions? :) Let me know your
> thoughts

Does sam31 before the ipl() work?

> 
> jump_to_IPL_2 for easy reference:
>     static void jump_to_IPL_2(void)
>     {
>         ResetInfo *current = 0;
> 
>         void (*ipl)(void) = (void *) (uint64_t) current->ipl_continue;
>         *current = save;
>         ipl(); /* should not return */
>     }
> 
> 


^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [PATCH] pc-bios/s390x: Pack ResetInfo struct
  2020-02-25 11:13         ` Christian Borntraeger
@ 2020-02-25 12:58           ` Jason J. Herne
  2020-02-25 15:00             ` Christian Borntraeger
  0 siblings, 1 reply; 15+ messages in thread
From: Jason J. Herne @ 2020-02-25 12:58 UTC (permalink / raw)
  To: Christian Borntraeger, qemu-devel, qemu-s390x, cohuck

On 2/25/20 6:13 AM, Christian Borntraeger wrote:
> 
> 
> On 25.02.20 11:23, Jason J. Herne wrote:
>> On 2/13/20 1:24 PM, Christian Borntraeger wrote:
>> ...
>>>>> diff --git a/pc-bios/s390-ccw/jump2ipl.c b/pc-bios/s390-ccw/jump2ipl.c
>>>>> index da13c43cc0..8839226803 100644
>>>>> --- a/pc-bios/s390-ccw/jump2ipl.c
>>>>> +++ b/pc-bios/s390-ccw/jump2ipl.c
>>>>> @@ -18,6 +18,7 @@
>>>>>     typedef struct ResetInfo {
>>>>>         uint64_t ipl_psw;
>>>>>         uint32_t ipl_continue;
>>>>> +    uint32_t pad;
>>>>>     } ResetInfo;
>>>>>       static ResetInfo save;
>>>>>
>>>>>
>>>>> also work? If yes, both variants are valid. Either packed or explicit padding.
>>>>>
>>>>
>>>> I don't believe this will work. I think the problem is that we're overwriting too much memory when we cast address 0 as a ResetInfo and then overwrite it (*current = save). I think we need the struct to be sized at 12-bytes instead of 16.
>>>>
>>>
>>> The idea of the code is that we _save_ the original content from address 0 to save and _restore_ it before jumping into final code. I do not yet understand why this does not work.
>>>
>>
>> I've found the real problem here. Legacy operating systems that expect to start
>> in 32-bit addressing mode can fail if we leave junk in the high halves of our
>> 64-bit registers. This is because some instructions (LA for example) are
>> bi-modal and operate differently depending on the machine's current addressing
>> mode.
>>
>> In the case where we pack the struct, the compiler happens to use the mvc
>> instruction to load/store the current/save memory areas.
>>
>>        *current = save;
>>    1fc:    e3 10 b0 a8 00 04     lg    %r1,168(%r11)
>>    202:    c0 20 00 00 00 00     larl    %r2,202 <jump_to_IPL_2+0x32>
>>              204: R_390_PC32DBL    .bss+0x2
>>    208:    d2 0b 10 00 20 00     mvc    0(12,%r1),0(%r2)
>>
>> Everything works as expected here, our legacy OS boots without issue.
>> However, in the case where we've packed this struct the compiler optimizes the
>> code and uses lmg/stmg instead of mvc to copy the data:
>>
>>        *current = save;
>>    1fc:    e3 10 b0 a8 00 04     lg    %r1,168(%r11)
>>    202:    c0 20 00 00 00 00     larl    %r2,202 <jump_to_IPL_2+0x32>
>>              204: R_390_PC32DBL    .bss+0x2
>>    208:    eb 23 20 00 00 04     lmg    %r2,%r3,0(%r2)
>>    20e:    eb 23 10 00 00 24     stmg    %r2,%r3,0(%r1)
>>
>> Depending on the data being copied, the high halves of the registers may contain
>> non-zero values. Example:
>>
>>      r2             0x108000080000780        74309395999098752
>>      r3             0x601001800004368        432627142283510632
>>
>> So, by sheer luck of the generated assembler, the patch happens to "fix" the
>> problem.  A real fix might be to insert inline assembler that clears the high
>> halves of the registers before we call ipl() in jump_to_IPL_2(). Can we think of
>> a better way to do that than 15 LLGTR instructions? :) Let me know your
>> thoughts
> 
> Does sam31 before the ipl() work?
asm volatile ("sam31\n");

Inserting the above right before ipl(); does not change the outcome, the guest still fails.

This allows the guest to boot.

asm volatile ("llgtr %r2,%r2\n"
               "llgtr %r3,%r3\n");

My guess as to why sam31 does not work: The legacy OS is eventually doing a sam64 and the 
high halves of the registers are not subsequently cleared before use. I could be wrong 
about this though.


-- 
-- Jason J. Herne (jjherne@linux.ibm.com)


^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [PATCH] pc-bios/s390x: Pack ResetInfo struct
  2020-02-25 12:58           ` Jason J. Herne
@ 2020-02-25 15:00             ` Christian Borntraeger
  2020-02-25 15:05               ` Christian Borntraeger
  0 siblings, 1 reply; 15+ messages in thread
From: Christian Borntraeger @ 2020-02-25 15:00 UTC (permalink / raw)
  To: jjherne, qemu-devel, qemu-s390x, cohuck



On 25.02.20 13:58, Jason J. Herne wrote:
> On 2/25/20 6:13 AM, Christian Borntraeger wrote:
>>
>>
>> On 25.02.20 11:23, Jason J. Herne wrote:
>>> On 2/13/20 1:24 PM, Christian Borntraeger wrote:
>>> ...
>>>>>> diff --git a/pc-bios/s390-ccw/jump2ipl.c b/pc-bios/s390-ccw/jump2ipl.c
>>>>>> index da13c43cc0..8839226803 100644
>>>>>> --- a/pc-bios/s390-ccw/jump2ipl.c
>>>>>> +++ b/pc-bios/s390-ccw/jump2ipl.c
>>>>>> @@ -18,6 +18,7 @@
>>>>>>     typedef struct ResetInfo {
>>>>>>         uint64_t ipl_psw;
>>>>>>         uint32_t ipl_continue;
>>>>>> +    uint32_t pad;
>>>>>>     } ResetInfo;
>>>>>>       static ResetInfo save;
>>>>>>
>>>>>>
>>>>>> also work? If yes, both variants are valid. Either packed or explicit padding.
>>>>>>
>>>>>
>>>>> I don't believe this will work. I think the problem is that we're overwriting too much memory when we cast address 0 as a ResetInfo and then overwrite it (*current = save). I think we need the struct to be sized at 12-bytes instead of 16.
>>>>>
>>>>
>>>> The idea of the code is that we _save_ the original content from address 0 to save and _restore_ it before jumping into final code. I do not yet understand why this does not work.
>>>>
>>>
>>> I've found the real problem here. Legacy operating systems that expect to start
>>> in 32-bit addressing mode can fail if we leave junk in the high halves of our
>>> 64-bit registers. This is because some instructions (LA for example) are
>>> bi-modal and operate differently depending on the machine's current addressing
>>> mode.
>>>
>>> In the case where we pack the struct, the compiler happens to use the mvc
>>> instruction to load/store the current/save memory areas.
>>>
>>>        *current = save;
>>>    1fc:    e3 10 b0 a8 00 04     lg    %r1,168(%r11)
>>>    202:    c0 20 00 00 00 00     larl    %r2,202 <jump_to_IPL_2+0x32>
>>>              204: R_390_PC32DBL    .bss+0x2
>>>    208:    d2 0b 10 00 20 00     mvc    0(12,%r1),0(%r2)
>>>
>>> Everything works as expected here, our legacy OS boots without issue.
>>> However, in the case where we've packed this struct the compiler optimizes the
>>> code and uses lmg/stmg instead of mvc to copy the data:
>>>
>>>        *current = save;
>>>    1fc:    e3 10 b0 a8 00 04     lg    %r1,168(%r11)
>>>    202:    c0 20 00 00 00 00     larl    %r2,202 <jump_to_IPL_2+0x32>
>>>              204: R_390_PC32DBL    .bss+0x2
>>>    208:    eb 23 20 00 00 04     lmg    %r2,%r3,0(%r2)
>>>    20e:    eb 23 10 00 00 24     stmg    %r2,%r3,0(%r1)
>>>
>>> Depending on the data being copied, the high halves of the registers may contain
>>> non-zero values. Example:
>>>
>>>      r2             0x108000080000780        74309395999098752
>>>      r3             0x601001800004368        432627142283510632
>>>
>>> So, by sheer luck of the generated assembler, the patch happens to "fix" the
>>> problem.  A real fix might be to insert inline assembler that clears the high
>>> halves of the registers before we call ipl() in jump_to_IPL_2(). Can we think of
>>> a better way to do that than 15 LLGTR instructions? :) Let me know your
>>> thoughts
>>
>> Does sam31 before the ipl() work?
> asm volatile ("sam31\n");
> 
> Inserting the above right before ipl(); does not change the outcome, the guest still fails.
> 
> This allows the guest to boot.
> 
> asm volatile ("llgtr %r2,%r2\n"
>               "llgtr %r3,%r3\n");
> 
> My guess as to why sam31 does not work: The legacy OS is eventually doing a sam64 and the high halves of the registers are not subsequently cleared before use. I could be wrong about this though.

I think we should rewrite jump_to_IPL_2 is assembler as we cannot clear out all registers
with just inline assembly (we whould kill the stack and others that the compiler might still want).

Do the register clearing in there and then use something like

static void jump_to_IPL_2(void)
{
    asm volatile(	....clearing...
			"llgf 14,8\n"
                	"br 14\n");
}




^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [PATCH] pc-bios/s390x: Pack ResetInfo struct
  2020-02-25 15:00             ` Christian Borntraeger
@ 2020-02-25 15:05               ` Christian Borntraeger
  0 siblings, 0 replies; 15+ messages in thread
From: Christian Borntraeger @ 2020-02-25 15:05 UTC (permalink / raw)
  To: jjherne, qemu-devel, qemu-s390x, cohuck



On 25.02.20 16:00, Christian Borntraeger wrote:
> 
> 
> On 25.02.20 13:58, Jason J. Herne wrote:
>> On 2/25/20 6:13 AM, Christian Borntraeger wrote:
>>>
>>>
>>> On 25.02.20 11:23, Jason J. Herne wrote:
>>>> On 2/13/20 1:24 PM, Christian Borntraeger wrote:
>>>> ...
>>>>>>> diff --git a/pc-bios/s390-ccw/jump2ipl.c b/pc-bios/s390-ccw/jump2ipl.c
>>>>>>> index da13c43cc0..8839226803 100644
>>>>>>> --- a/pc-bios/s390-ccw/jump2ipl.c
>>>>>>> +++ b/pc-bios/s390-ccw/jump2ipl.c
>>>>>>> @@ -18,6 +18,7 @@
>>>>>>>     typedef struct ResetInfo {
>>>>>>>         uint64_t ipl_psw;
>>>>>>>         uint32_t ipl_continue;
>>>>>>> +    uint32_t pad;
>>>>>>>     } ResetInfo;
>>>>>>>       static ResetInfo save;
>>>>>>>
>>>>>>>
>>>>>>> also work? If yes, both variants are valid. Either packed or explicit padding.
>>>>>>>
>>>>>>
>>>>>> I don't believe this will work. I think the problem is that we're overwriting too much memory when we cast address 0 as a ResetInfo and then overwrite it (*current = save). I think we need the struct to be sized at 12-bytes instead of 16.
>>>>>>
>>>>>
>>>>> The idea of the code is that we _save_ the original content from address 0 to save and _restore_ it before jumping into final code. I do not yet understand why this does not work.
>>>>>
>>>>
>>>> I've found the real problem here. Legacy operating systems that expect to start
>>>> in 32-bit addressing mode can fail if we leave junk in the high halves of our
>>>> 64-bit registers. This is because some instructions (LA for example) are
>>>> bi-modal and operate differently depending on the machine's current addressing
>>>> mode.
>>>>
>>>> In the case where we pack the struct, the compiler happens to use the mvc
>>>> instruction to load/store the current/save memory areas.
>>>>
>>>>        *current = save;
>>>>    1fc:    e3 10 b0 a8 00 04     lg    %r1,168(%r11)
>>>>    202:    c0 20 00 00 00 00     larl    %r2,202 <jump_to_IPL_2+0x32>
>>>>              204: R_390_PC32DBL    .bss+0x2
>>>>    208:    d2 0b 10 00 20 00     mvc    0(12,%r1),0(%r2)
>>>>
>>>> Everything works as expected here, our legacy OS boots without issue.
>>>> However, in the case where we've packed this struct the compiler optimizes the
>>>> code and uses lmg/stmg instead of mvc to copy the data:
>>>>
>>>>        *current = save;
>>>>    1fc:    e3 10 b0 a8 00 04     lg    %r1,168(%r11)
>>>>    202:    c0 20 00 00 00 00     larl    %r2,202 <jump_to_IPL_2+0x32>
>>>>              204: R_390_PC32DBL    .bss+0x2
>>>>    208:    eb 23 20 00 00 04     lmg    %r2,%r3,0(%r2)
>>>>    20e:    eb 23 10 00 00 24     stmg    %r2,%r3,0(%r1)
>>>>
>>>> Depending on the data being copied, the high halves of the registers may contain
>>>> non-zero values. Example:
>>>>
>>>>      r2             0x108000080000780        74309395999098752
>>>>      r3             0x601001800004368        432627142283510632
>>>>
>>>> So, by sheer luck of the generated assembler, the patch happens to "fix" the
>>>> problem.  A real fix might be to insert inline assembler that clears the high
>>>> halves of the registers before we call ipl() in jump_to_IPL_2(). Can we think of
>>>> a better way to do that than 15 LLGTR instructions? :) Let me know your
>>>> thoughts
>>>
>>> Does sam31 before the ipl() work?
>> asm volatile ("sam31\n");
>>
>> Inserting the above right before ipl(); does not change the outcome, the guest still fails.
>>
>> This allows the guest to boot.
>>
>> asm volatile ("llgtr %r2,%r2\n"
>>               "llgtr %r3,%r3\n");
>>
>> My guess as to why sam31 does not work: The legacy OS is eventually doing a sam64 and the high halves of the registers are not subsequently cleared before use. I could be wrong about this though.
> 
> I think we should rewrite jump_to_IPL_2 is assembler as we cannot clear out all registers
> with just inline assembly (we whould kill the stack and others that the compiler might still want).
> 
> Do the register clearing in there and then use something like
> 
> static void jump_to_IPL_2(void)
> {
>     asm volatile(	....clearing...
> 			"llgf 14,8\n"
>                 	"br 14\n");
> }

maybe something like that instead.

    asm volatile(  ...clearing...
		    "llgf 14,%0\n"
                   "br 14\n"::"i" (__builtin_offsetof(ResetInfo, ipl_continue)));
 }
 



^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [PATCH] pc-bios/s390x: Pack ResetInfo struct
  2020-02-07 14:02       ` Jason J. Herne
@ 2020-08-27 10:07         ` Thomas Huth
  2020-09-01 13:02           ` Jason J. Herne
  0 siblings, 1 reply; 15+ messages in thread
From: Thomas Huth @ 2020-08-27 10:07 UTC (permalink / raw)
  To: jjherne, Christian Borntraeger, qemu-devel, qemu-s390x, cohuck

On 07/02/2020 15.02, Jason J. Herne wrote:
> On 2/7/20 6:28 AM, Christian Borntraeger wrote:
>> Jason,
>>
>> can you run objdump -Sdr on jump2ipl.o on a broken variant?
>>
>>
> To keep the volume lower, I've only pasted the output that I think
> you're interested in. If you want to see the entire thing just let me know.
> 
> static void jump_to_IPL_2(void)
> {
>  1d0:    eb bf f0 58 00 24     stmg    %r11,%r15,88(%r15)
>  1d6:    a7 fb ff 50           aghi    %r15,-176
>  1da:    b9 04 00 bf           lgr    %r11,%r15
>     ResetInfo *current = 0;
>  1de:    a7 19 00 00           lghi    %r1,0
>  1e2:    e3 10 b0 a8 00 24     stg    %r1,168(%r11)
> 
>     void (*ipl)(void) = (void *) (uint64_t) current->ipl_continue;
>  1e8:    e3 10 b0 a8 00 04     lg    %r1,168(%r11)
>  1ee:    58 10 10 08           l    %r1,8(%r1)
>  1f2:    b9 16 00 11           llgfr    %r1,%r1
>  1f6:    e3 10 b0 a0 00 24     stg    %r1,160(%r11)
>     *current = save;
>  1fc:    e3 10 b0 a8 00 04     lg    %r1,168(%r11)
>  202:    c0 20 00 00 00 00     larl    %r2,202 <jump_to_IPL_2+0x32>
>             204: R_390_PC32DBL    .bss+0x2
>  208:    eb 23 20 00 00 04     lmg    %r2,%r3,0(%r2)
>  20e:    eb 23 10 00 00 24     stmg    %r2,%r3,0(%r1)
>     ipl(); /* should not return */
>  214:    e3 10 b0 a0 00 04     lg    %r1,160(%r11)
>  21a:    0d e1                 basr    %r14,%r1
> }
>  21c:    18 00                 lr    %r0,%r0
>  21e:    eb bf b1 08 00 04     lmg    %r11,%r15,264(%r11)
>  224:    07 fe                 br    %r14
>  226:    07 07                 nopr    %r7

I'm currently looking through the past s390-ccw bios patches that still
might need attention ... was there ever a follow up on this discussion?
Do we need to clear the registers before jumping to the OS?
And looking at the disassembly, should we declar the ipl function
pointer with __attribute__((noreturn)) ?

 Thomas



^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [PATCH] pc-bios/s390x: Pack ResetInfo struct
  2020-08-27 10:07         ` Thomas Huth
@ 2020-09-01 13:02           ` Jason J. Herne
  0 siblings, 0 replies; 15+ messages in thread
From: Jason J. Herne @ 2020-09-01 13:02 UTC (permalink / raw)
  To: Thomas Huth, Christian Borntraeger, qemu-devel, qemu-s390x, cohuck

On 8/27/20 6:07 AM, Thomas Huth wrote:
> On 07/02/2020 15.02, Jason J. Herne wrote:
>> On 2/7/20 6:28 AM, Christian Borntraeger wrote:
>>> Jason,
>>>
>>> can you run objdump -Sdr on jump2ipl.o on a broken variant?
>>>
>>>
>> To keep the volume lower, I've only pasted the output that I think
>> you're interested in. If you want to see the entire thing just let me know.
>>
>> static void jump_to_IPL_2(void)
>> {
>>   1d0:    eb bf f0 58 00 24     stmg    %r11,%r15,88(%r15)
>>   1d6:    a7 fb ff 50           aghi    %r15,-176
>>   1da:    b9 04 00 bf           lgr    %r11,%r15
>>      ResetInfo *current = 0;
>>   1de:    a7 19 00 00           lghi    %r1,0
>>   1e2:    e3 10 b0 a8 00 24     stg    %r1,168(%r11)
>>
>>      void (*ipl)(void) = (void *) (uint64_t) current->ipl_continue;
>>   1e8:    e3 10 b0 a8 00 04     lg    %r1,168(%r11)
>>   1ee:    58 10 10 08           l    %r1,8(%r1)
>>   1f2:    b9 16 00 11           llgfr    %r1,%r1
>>   1f6:    e3 10 b0 a0 00 24     stg    %r1,160(%r11)
>>      *current = save;
>>   1fc:    e3 10 b0 a8 00 04     lg    %r1,168(%r11)
>>   202:    c0 20 00 00 00 00     larl    %r2,202 <jump_to_IPL_2+0x32>
>>              204: R_390_PC32DBL    .bss+0x2
>>   208:    eb 23 20 00 00 04     lmg    %r2,%r3,0(%r2)
>>   20e:    eb 23 10 00 00 24     stmg    %r2,%r3,0(%r1)
>>      ipl(); /* should not return */
>>   214:    e3 10 b0 a0 00 04     lg    %r1,160(%r11)
>>   21a:    0d e1                 basr    %r14,%r1
>> }
>>   21c:    18 00                 lr    %r0,%r0
>>   21e:    eb bf b1 08 00 04     lmg    %r11,%r15,264(%r11)
>>   224:    07 fe                 br    %r14
>>   226:    07 07                 nopr    %r7
> 
> I'm currently looking through the past s390-ccw bios patches that still
> might need attention ... was there ever a follow up on this discussion?
> Do we need to clear the registers before jumping to the OS?
> And looking at the disassembly, should we declar the ipl function
> pointer with __attribute__((noreturn)) ?
> 

Janosch has done some cleanup work that has not hit master yet. This work, if accepted, 
would fix this problem and eliminate the need for this patch. So I think we should wait to 
see how that plays out before we revisit this.

-- 
-- Jason J. Herne (jjherne@linux.ibm.com)


^ permalink raw reply	[flat|nested] 15+ messages in thread

end of thread, other threads:[~2020-09-01 13:06 UTC | newest]

Thread overview: 15+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2020-02-05 18:21 [PATCH] pc-bios/s390x: Pack ResetInfo struct Jason J. Herne
2020-02-06  9:55 ` Cornelia Huck
2020-02-06 10:09 ` Christian Borntraeger
2020-02-06 11:00   ` Thomas Huth
2020-02-07 11:28     ` Christian Borntraeger
2020-02-07 14:02       ` Jason J. Herne
2020-08-27 10:07         ` Thomas Huth
2020-09-01 13:02           ` Jason J. Herne
2020-02-13 18:02   ` Jason J. Herne
2020-02-13 18:24     ` Christian Borntraeger
2020-02-25 10:23       ` Jason J. Herne
2020-02-25 11:13         ` Christian Borntraeger
2020-02-25 12:58           ` Jason J. Herne
2020-02-25 15:00             ` Christian Borntraeger
2020-02-25 15:05               ` Christian Borntraeger

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).