Mailing List Archive

reboot from com32
Q: Is there a way to do a reboot (either warm or cold) from a com32 program?

I have a com32 program that sometimes (based upon conditions) needs to
reboot the system.

I would prefer to do a warm reboot (40:72 = 0x1234), but at this point
cold would be OK too.

grepping through syslinux-3.51 I only found one reference, in
iso/pxelinux.asm at the tail end of 'kaboom' ... but presumably that only
happens after things go wrong.

It isn't clear to me how to do this since the com32 program is running in
32-bit mode.

Q: Can I just make a pointer to a function, set the value to 0x000FFFF0
and make a call into the BIOS ROM, even though I am running in 32-bit mode?


Miguel

_______________________________________________
SYSLINUX mailing list
Submissions to SYSLINUX@zytor.com
Unsubscribe or set options at:
http://www.zytor.com/mailman/listinfo/syslinux
Please do not send private replies to mailing list traffic.
Re: reboot from com32 [ In reply to ]
Miguel wrote:
> Q: Is there a way to do a reboot (either warm or cold) from a com32 program?
>
> I have a com32 program that sometimes (based upon conditions) needs to
> reboot the system.
>
> I would prefer to do a warm reboot (40:72 = 0x1234), but at this point
> cold would be OK too.
>
> grepping through syslinux-3.51 I only found one reference, in
> iso/pxelinux.asm at the tail end of 'kaboom' ... but presumably that only
> happens after things go wrong.
>
> It isn't clear to me how to do this since the com32 program is running in
> 32-bit mode.
>
> Q: Can I just make a pointer to a function, set the value to 0x000FFFF0
> and make a call into the BIOS ROM, even though I am running in 32-bit mode?
>

Not really.

The easiest way is to use __farcall() to call to 0xf000:0xfff0:

__noreturn syslinux_reboot(int warm)
{
static com32sys_t dummy_regs;
uint16_t * const reboot_flag = (uint16_t *)0x472;

*reboot_flag = warm ? 0x1234 : 0;
__farcall(0xf000, 0xfff0, &dummy_regs, NULL);
}

I just added syslinux_reboot() to the git tree.

-hpa

_______________________________________________
SYSLINUX mailing list
Submissions to SYSLINUX@zytor.com
Unsubscribe or set options at:
http://www.zytor.com/mailman/listinfo/syslinux
Please do not send private replies to mailing list traffic.
Re: reboot from com32 [ In reply to ]
>> Q: Is there a way to do a reboot (either warm or cold) from
>> a com32 program?
[snip]
> Not really.
>
> The easiest way is to use __farcall() to call to 0xf000:0xfff0:
>
> __noreturn syslinux_reboot(int warm)
> {
> static com32sys_t dummy_regs;
> uint16_t * const reboot_flag = (uint16_t *)0x472;
>
> *reboot_flag = warm ? 0x1234 : 0;
> __farcall(0xf000, 0xfff0, &dummy_regs, NULL);
> }
>
> I just added syslinux_reboot() to the git tree.

Looks great to me.


*** 5 minutes later ***

Hmm ... it isn't working ... and I'm puzzled.

I pasted this exact code into my com32 source file. When I compiled I got
a warning from gcc saying:

foo.c: In function ‘syslinux_reboot’:
foo.c:127: warning: ‘noreturn’ function does return

I shut this up by turning the __noreturn into a void.

At runtime, it returns. I put in printf statements before and after the
reboot:

void reboot()
{
printf("getting ready to call syslinux_reboot(1)\n");
syslinux_reboot(1);
printf("hmm ... why am I here?\n");
}

Both print messages come out. And I get back to the pxelinux boot: prompt

*** 5 minutes later ***

I made 2 changes
* made it say __noreturn instead of 'void'
* zeroed out the dummy_registers

Behavior is slightly different ... execution seems to be continuing at
some other place in my com32 program.

*** 15 minutes later ***

I'm stumped.


Miguel

_______________________________________________
SYSLINUX mailing list
Submissions to SYSLINUX@zytor.com
Unsubscribe or set options at:
http://www.zytor.com/mailman/listinfo/syslinux
Please do not send private replies to mailing list traffic.
Re: reboot from com32 [ In reply to ]
HPA wrote:
>
> The easiest way is to use __farcall() to call to 0xf000:0xfff0:
>
> __noreturn syslinux_reboot(int warm)
> {
> static com32sys_t dummy_regs;
> uint16_t * const reboot_flag = (uint16_t *)0x472;
>
> *reboot_flag = warm ? 0x1234 : 0;
> __farcall(0xf000, 0xfff0, &dummy_regs, NULL);
> }
>
> I just added syslinux_reboot() to the git tree.
>
> -hpa

I have been unable to get this to work properly.

On an HP DL360G2 it returns from syslinux_reboot, independent of whether
it is warm or cold.

On a Dell PE850 it hangs (but will respond to Ctl-Alt-Del), independent of
whether it is warm or cold.

The code that I am using is below in its entirety. It is a tweaked version
of samples/hello.c that responds to 'warm' or 'cold'.

My only thought is:

Q: Does __farcall switch out of 32 bit mode and back into 16 bit mode?

The standard BIOS reset entry point probably is expecting the processor to
be in 16 bit mode.

If that is not the problem, then I have no idea.


Miguel

----

/*
* com32 hello.c modified to test syslinux_reboot
*/

#include <string.h>
#include <stdio.h>
#include <console.h>
#include <com32.h>

__noreturn syslinux_reboot(int warm)
{
static com32sys_t dummy_regs;
printf("syslinux_reboot(%d)\n", warm);
memset(&dummy_regs, 0, sizeof dummy_regs);

uint16_t * const reboot_flag = (uint16_t *)0x472;

*reboot_flag = warm ? 0x1234 : 0;
__farcall(0xf000, 0xfff0, &dummy_regs, &dummy_regs);
printf("Why am I still here?\n");
}

int main(void)
{
char buffer[1024];

openconsole(&dev_stdcon_r, &dev_stdcon_w);

printf("Hello, World!\n");

for (;;) {
printf("> ");
fgets(buffer, sizeof buffer, stdin);
if ( !strncmp(buffer, "exit", 4) )
break;
elseif ( !strncmp(buffer, "cold", 4))
syslinux_reboot(0);
else if (! strncmp(buffer, "warm", 4))
syslinux_reboot(1);
printf(": %s", buffer);
}

return 0;
}

----

_______________________________________________
SYSLINUX mailing list
Submissions to SYSLINUX@zytor.com
Unsubscribe or set options at:
http://www.zytor.com/mailman/listinfo/syslinux
Please do not send private replies to mailing list traffic.
Re: reboot from com32 [ In reply to ]
Miguel wrote:
> HPA wrote:
>> The easiest way is to use __farcall() to call to 0xf000:0xfff0:
>>
>> __noreturn syslinux_reboot(int warm)
>> {
>> static com32sys_t dummy_regs;
>> uint16_t * const reboot_flag = (uint16_t *)0x472;
>>
>> *reboot_flag = warm ? 0x1234 : 0;
>> __farcall(0xf000, 0xfff0, &dummy_regs, NULL);
>> }
>>
>> I just added syslinux_reboot() to the git tree.
>>
>> -hpa
>
> I have been unable to get this to work properly.
>
> On an HP DL360G2 it returns from syslinux_reboot, independent of whether
> it is warm or cold.

That's utterly weird. Hanging I could have seen, but returning is just
weirder than weird.

> On a Dell PE850 it hangs (but will respond to Ctl-Alt-Del), independent of
> whether it is warm or cold.
>
> The code that I am using is below in its entirety. It is a tweaked version
> of samples/hello.c that responds to 'warm' or 'cold'.
>
> My only thought is:
>
> Q: Does __farcall switch out of 32 bit mode and back into 16 bit mode?

Yes, it does.

The most likely explanation IMO is that there is a bug in __farcall.
Unlike __intcall it hasn't been extensively used. They do, however,
share almost all the code.

-hpa

_______________________________________________
SYSLINUX mailing list
Submissions to SYSLINUX@zytor.com
Unsubscribe or set options at:
http://www.zytor.com/mailman/listinfo/syslinux
Please do not send private replies to mailing list traffic.
Re: reboot from com32 [ In reply to ]
hpa ... Thank you for your prompt response!

>> On an HP DL360G2 it returns from syslinux_reboot, independent of whether
>> it is warm or cold.
>
> That's utterly weird. Hanging I could have seen, but returning is just
> weirder than weird.

It returns and successfully does printfs.
I can then execute other pxelinux commands ... like boot kernels.
So, it seems that the system isn't too damaged.

>> On a Dell PE850 it hangs (but will respond to Ctl-Alt-Del), independent
>> of
>> whether it is warm or cold.

Once it failed on two different types of machines I stopped looking.

>> Q: Does __farcall switch out of 32 bit mode and back into 16 bit mode?
>
> Yes, it does.
>
> The most likely explanation IMO is that there is a bug in __farcall.
> Unlike __intcall it hasn't been extensively used. They do, however,
> share almost all the code.

I'll try to take a look at __farcall.


Miguel




_______________________________________________
SYSLINUX mailing list
Submissions to SYSLINUX@zytor.com
Unsubscribe or set options at:
http://www.zytor.com/mailman/listinfo/syslinux
Please do not send private replies to mailing list traffic.
Re: reboot from com32 [ In reply to ]
> The most likely explanation IMO is that there is a bug in __farcall.
> Unlike __intcall it hasn't been extensively used. They do, however,
> share almost all the code.
>
> -hpa

com32.inc
---------

com32_farcall:
pushfd ; Save IF among other things...
pushad ; We only need to save some, but...
mov eax,[esp+10*4] ; CS:IP
jmp com32_syscall


com32_intcall:
pushfd ; Save IF among other things...
pushad ; We only need to save some, but...

movzx eax,byte [esp+10*4] ; INT number
mov eax,[eax*4] ; Get CS:IP from low memory

com32_syscall:
cld
...

--------

Theory #1:

I am incapable of following the details of com32_syscall, but here is what
jumps out at me ...

both _farcall and _intcall load up the target address into eax.

That means that the _intcall version is going to have to push the flags
onto the stack because the interrupt handler will do an 'iret'.

But the code that is generally called by _farcall is going to do a 'ret',
not an 'iret'.

Therefore, I am concerned that there is going to be an extra set of flags
pushed on to the stack at some point ... which would interfere with
_farcall behavior.

BUT ... this call to F000:FFF0 should not be returning anyway, so I don't
see how that could affect what is going on here.


Theory #2

Confirm that the stack location of the target address is correct:

mov eax,[esp+10*4] ; CS:IP

BUT ... if that wasn't correct then _farcall would never have worked.



Hope this helps,
Miguel

_______________________________________________
SYSLINUX mailing list
Submissions to SYSLINUX@zytor.com
Unsubscribe or set options at:
http://www.zytor.com/mailman/listinfo/syslinux
Please do not send private replies to mailing list traffic.
Re: reboot from com32 [ In reply to ]
Miguel wrote:
>
> Theory #2
>
> Confirm that the stack location of the target address is correct:
>
> mov eax,[esp+10*4] ; CS:IP
>
> BUT ... if that wasn't correct then _farcall would never have worked.
>

It's not a given that it ever has worked.

-hpa

_______________________________________________
SYSLINUX mailing list
Submissions to SYSLINUX@zytor.com
Unsubscribe or set options at:
http://www.zytor.com/mailman/listinfo/syslinux
Please do not send private replies to mailing list traffic.
Re: reboot from com32 [ In reply to ]
H. Peter Anvin wrote:
> Miguel wrote:
>> Theory #2
>>
>> Confirm that the stack location of the target address is correct:
>>
>> mov eax,[esp+10*4] ; CS:IP
>>
>> BUT ... if that wasn't correct then _farcall would never have worked.
>
> It's not a given that it ever has worked.
>

In fact, the an off-by-one error in the library code meant it pretty
much hadn't.

I have fixed it and pushed it out as 3.52-pre6.

-hpa

_______________________________________________
SYSLINUX mailing list
Submissions to SYSLINUX@zytor.com
Unsubscribe or set options at:
http://www.zytor.com/mailman/listinfo/syslinux
Please do not send private replies to mailing list traffic.
Re: reboot from com32 [ In reply to ]
H. Peter Anvin wrote:
> In fact, the an off-by-one error in the library code meant it pretty
> much hadn't.
>
> I have fixed it and pushed it out as 3.52-pre6.

Tested on several different systems.
Works like a charm.
!Gracias!


Miguel

_______________________________________________
SYSLINUX mailing list
Submissions to SYSLINUX@zytor.com
Unsubscribe or set options at:
http://www.zytor.com/mailman/listinfo/syslinux
Please do not send private replies to mailing list traffic.