VOGONS


First post, by superfury

User metadata
Rank l33t++
Rank
l33t++

I'm trying to create a little program for use with my emulator to execute:
- A cold reboot (flush caches, set 40:72 to 0, try and execute hard reset using 8042 chip, try reset by calling interrupt 19h. Error out on fail.). Parameter is /hard.
- A MS-DOS reboot (flush caches, load boot sector into address 7C00, jump to boot sector, error out on fail.). Parameter = /soft.
- A default reboot handler (flush caches, set 40:72 to 0, jump to F000:0).

Although my emulator doesn't handle floppy disk writes correctly atm for some reason (worked perfectly earlier), I already made a program that does that. Cold reboots and default reboot works. Soft reboot fails for some reason? Anyone knows why this happens? It flushes cache by using the assembler method specified in:
https://support.microsoft.com/en-us/kb/67929

It only executes the jump to the BIOS using an inline statement (it jumps to the loaded boot sector data with the /soft flag instead using "inline($EA,$00,$7C,$00,$00);" after having read the sector using interrupt 13h, function 02h. This should work, but instead it's hanging? ).

My source code:

Program reboot;
uses dos;
var
regs: registers;
currentdisk: byte;
disklist: array[0..3] of byte;
currentdisk2: byte;
oldmem: word;

procedure preparereboot;
begin
asm
mov ah,$0D
int $21
mov ax,$40
mov ds,ax
or byte ptr ds:[$17],$0C
mov ax,$4F53
int $15
mov word ptr ds:[$72],$1234
end;
end;

Begin
oldmem := memw[$40:$72];
disklist[0]:=$80;
disklist[1]:=$81;
disklist[2]:=$0;
disklist[3]:=$1;
if (ParamStr(1)='/?') then
begin
writeln;
writeln('Reboot: performs a reboot.');
writeln('Usage: reboot [/hard]');
writeln('/hard: tries to perform a hard reboot, default is soft boot');
writeln('/soft: tries to perform a soft reboot from floppy, then hdd');
exit;
end;
if (ParamStr(1)='/hard') then
begin
fillchar(regs,sizeof(regs),0);
preparereboot;
memw[$40:$72] := 0; (* Hard reboot *)
port[$64] := $FE; (* Try hard reset *)
intr($19,regs); (* Second option: BIOS *)
memw[$40:$72] := oldmem; (* Hard reset instead *)
writeln('Hard reboot failed.');
exit;
end;
if (ParamStr(1)='/soft') then
begin
for currentdisk := 0 to sizeof(disklist)-1 do
begin
fillchar(regs,sizeof(regs),0);
currentdisk2 := disklist[currentdisk]; (* The disk to boot *)
regs.ah := 0;
regs.dl := currentdisk2;
intr($13,regs);
if ((regs.flags and FCarry)=0) then (* Reset? *)
begin
Show last 34 lines
        regs.ah := 2;
regs.al := 1;
regs.ch := 0;
regs.cl := 1;
regs.dh := 0;
regs.dl := currentdisk2;
regs.es := 0;
regs.bx := $7C00;
intr($13,regs);
if ((regs.flags and FCarry)=0) then (* Read sector? *)
if ((memw[0:$7dfe]=$aa55) or (disklist[currentdisk]<$80)) then (* Valid to boot? *)
begin
preparereboot;
asm
mov dl,currentdisk2
db $EA
dw $7C00
dw 0
end;
end;
end;
end;
memw[$40:$72] := oldmem; (* Hard reset instead *)
writeln('Soft reboot failed: no bootable disks have been found.');
exit;
end;

preparereboot;
memw[$40:$72] := 0; (* Hard reset instead *)
inline($EA/$00/$00/$FF/$FF); (* Perform hard reset manually. *)

memw[$40:$72] := oldmem; (* Hard reset instead *)
writeln('Hard BIOS reset failed.');
End.

- Reboot.exe without parameters reboots using a cold reboot.
- Reboot.exe with /soft hangs executing (simply blinking cursor on the next row after the command line).
- Reboot /hard executes, waits a bit (emulator resetting it's system), then restarts the BIOS (working correctly).

Anyone knows why the /soft parameter makes the system hang? The sector should be correctly loaded at 0000:7C00 and jumped to? The assembly executes until the jump to 0:7C00 then crashes (doesn't seem to do anything anymore). Anyone knows what I'm doing wrong here?

I'm using the latest x86EMU build to test this program.
Edit: After doing some research: do I need to replace "mov dl,currentdisk2" with "mov dl,[currentdisk2]"?

Author of the UniPCemu emulator.
UniPCemu Git repository
UniPCemu for Android, Windows, PSP, Vita and Switch on itch.io

Reply 1 of 14, by superfury

User metadata
Rank l33t++
Rank
l33t++

I've replaced the code prepping and booting the boot sector(the prepareboot and following assembly as follows:

preparereboot;
mem[0:$7f00] := currentdisk2;
memw[0:$7efc] := $7c00;
memw[0:$7efe] := 0;
asm
mov bx,0
mov es,bx
mov ss,bx
mov sp,$7efc
mov bx,$7f00
mov dl,[es:bx]
retf
end;

This should ensure that memory is cleaned up (preparereboot function), dl is loaded with the driver number (in my environment 80h, aka HDD #0, which is the first bootable device found), SS:SP is set to 0:7f00(512 bytes past the boot sector) and execution is transferred to 0000:7c00 for the boot sector. Anyone can verify this? Or is there an error in my code? When I try to run this in my x86EMU emulator, the CPU stops for some reason?

I've based my preparereboot function on the code at https://support.microsoft.com/en-us/kb/67929
Is this correct?

After I call the program with the /soft parameter, my emulator still runs, but won't respond to the debugger. This is only the case when either the debugger is running, but not showing due to an error(not likely, since it runs fine during other times)) or the CPU is in a HALT state (the debugger won't be executed, since it needs an CPU instruction to step, which it doesn't have during the HALT state. It's only called when the CPU has executed an instruction). Is there a reason the HLT instruction is called during booting?

Author of the UniPCemu emulator.
UniPCemu Git repository
UniPCemu for Android, Windows, PSP, Vita and Switch on itch.io

Reply 2 of 14, by Jepael

User metadata
Rank Oldbie
Rank
Oldbie

Well, the first version of prepareboot failed most likely because you trashed DS segment and did not restore it. It needs to be pointing to Pascal's data segment for variables to work.

The second version assumes there is nothing running at 0:$7c00, but in reality DOS or some programs could be loaded there and it might be timer interrupt code, mouse interrupt code or whatever. There might be something already enabled that wants to execute something there. Blindly reloading boot sector to 0:$7c00 is really not a safe way to restart DOS, because DOS and drivers assume things are the way they are after BIOS has initialized them.

Same thing with calling int 19h. It's OK for a boot sector to call it to retry booting, but after DOS is running, it is not safe. It does not reinitialize hardware devices the way they should be (e.g. COM port interrupts disabled) and it does not reinitialize interrupt vectors (timer interrupt could point to code running under DOS).

Reply 3 of 14, by Davros

User metadata
Rank l33t
Rank
l33t

How about
sNObXKb.jpg

Guardian of the Sacred Five Terabyte's of Gaming Goodness

Reply 4 of 14, by superfury

User metadata
Rank l33t++
Rank
l33t++

The problem is that I want the program to reboot MS-DOS only (soft reboot, so only reboot DOS, not run the entire BIOS again. Afaik using 1234h with int19h should do it, but the BIOS will fully reset anyway (the same as the normal CPU reset pin) when I try that. Is this an error in the BIOS?). Also running device drivers etc. should have been terminated by the int 21h function 0D combined with the Ctrl+Alt+Del simulation according to Microsoft's specs of their code (EMM386 terminated)?

I'm using the Generic Super PC/Turbo XT BIOS v2.5 to test.

Author of the UniPCemu emulator.
UniPCemu Git repository
UniPCemu for Android, Windows, PSP, Vita and Switch on itch.io

Reply 5 of 14, by Jepael

User metadata
Rank Oldbie
Rank
Oldbie
Davros wrote:
How about http://i.imgur.com/sNObXKb.jpg […]
Show full quote

How about
sNObXKb.jpg

Well, that does not create a standalone program, it needs debug.com from DOS and the commands instruct the debug program to go execute code from $FFFF:$0000, which is exactly same thing as JMP $FFFF:$0000 in superfury's code here:

inline($EA/$00/$00/$FF/$FF);

Another thing is it does not set the magic word at $40:$72 to perform either cold or warm reboot.

And it's better to notify memory managers and disk caches to shut down first. Otherwise you might lose data not written to disk yet, or hang the machine if there is a memory manager and for instance a 80386 CPU is in V86 mode so the BIOS ROM is also virtualized.

Reply 6 of 14, by vladstamate

User metadata
Rank Oldbie
Rank
Oldbie

Just to continue Jepael's post (and I know this is not impacting Superfury, as his x86emu emulates real 8086) but I think it also won't work in Protected Mode (not only not in V86) on a 286+ as the FFFF segment might not be mapped in the GDT.

YouTube channel: https://www.youtube.com/channel/UC7HbC_nq8t1S9l7qGYL0mTA
Collection: http://www.digiloguemuseum.com/index.html
Emulator: https://sites.google.com/site/capex86/
Raytracer: https://sites.google.com/site/opaqueraytracer/

Reply 7 of 14, by Jepael

User metadata
Rank Oldbie
Rank
Oldbie
superfury wrote:

The problem is that I want the program to reboot MS-DOS only (soft reboot, so only reboot DOS, not run the entire BIOS again. Afaik using 1234h with int19h should do it, but the BIOS will fully reset anyway (the same as the normal CPU reset pin) when I try that. Is this an error in the BIOS?). Also running device drivers etc. should have been terminated by the int 21h function 0D combined with the Ctrl+Alt+Del simulation according to Microsoft's specs of their code (EMM386 terminated)?

I'm using the Generic Super PC/Turbo XT BIOS v2.5 to test.

I still think it's impossible, reloading DOS again from DOS. Most likely calling int 19h in your program just crashes the system so bad it reboots. The word at $40:$72 just selects if full cold boot sequence is run, or can it skip some initial tests and just do a warm boot, but it is read when jumping to $FFFF:$0, not when calling INT 19H.

INT 21H function 0D is a disk reset, it does not shut down peripherals, mouse drivers, other hooked interrupts or other DOS programs, like TSRs playing music (which could have hooked timer interrupts and/or sound card interrupts and using memory at $0:$7c00 for interrupt routines or DMA buffer for the soundcard). Calling INT 19H also does not stop ongoing interrupt/DMA systems. Jumping to $FFFF:$0 will, because it disables interrupts and reinitializes all motherboard peripherals and interrupt vectors to their default state before calling INT 19H to bootstrap DOS from disk.

Few links about int 19h:
http://members.tripod.com/vitaly_filatov/ng/a … asm_001.12.html
http://stanislavs.org/helppc/int_19.html

Reply 8 of 14, by superfury

User metadata
Rank l33t++
Rank
l33t++

So I must replace the /soft option with calling preparereboot, setting $40:$72 to $1234, then jump to $FFFF:$0000 using the inline statement. Also preparereboot must execute push ds before and pop ds before returning? And the /hard option must execute the bottom option(catch-all) instead of calling interrupt 19h? Then all options should work? (The ds problem might explain why debugging using Turbo Pascal 6.0 failed (keyboard not fully working and couldn't step/resume execution. I just assumed DS would be loaded again during execution past the assembly, when trying to use the variables))
Would the /soft option just clear the screen and reboot dos(not executing the first screen of the Turbo XT BIOS v2.5 when implemented as described above?

Author of the UniPCemu emulator.
UniPCemu Git repository
UniPCemu for Android, Windows, PSP, Vita and Switch on itch.io

Reply 9 of 14, by Jepael

User metadata
Rank Oldbie
Rank
Oldbie
superfury wrote:

So I must replace the /soft option with calling preparereboot, setting $40:$72 to $1234, then jump to $FFFF:$0000 using the inline statement. Also preparereboot must execute push ds before and pop ds before returning? And the /hard option must execute the bottom option(catch-all) instead of calling interrupt 19h? Then all options should work? (The ds problem might explain why debugging using Turbo Pascal 6.0 failed (keyboard not fully working and couldn't step/resume execution. I just assumed DS would be loaded again during execution past the assembly, when trying to use the variables))
Would the /soft option just clear the screen and reboot dos(not executing the first screen of the Turbo XT BIOS v2.5 when implemented as described above?

The prepareboot could use ES instead of DS, so you don't have to do anything (ES does not need to be preserved).

Yes, call prepareboot to notify disk caches and memory managers (as if either is in use on a 808x anyway), then decide between warm boot or cold boot by writing $1234 or $0000 to $40:$72. Never invoke INT 19H, never load anything directly to $0:$7C00 as it could overwrite the currently executing reboot program.

The effect of cold boot is same as turning on the power switch, and the effect of warm boot is same as using CTRL-ALT-DEL keyboard sequence. Some initial memory checking is skipped, so it's somewhat faster, but all motherboard peripherals are reinitialized similarly before bootstrap. I don't think you can have faster DOS reload unless you somehow take a snapshot of the emulator and save it (memory contents, CPU registers, peripheral states..), but even then it requires that if disks are detected before that, the disks must also be identical to match the saved state.

Maybe the emulator could have a fast restart button so it resets and runs at maximum speed without video/audio rendering until INT 19H is hit?

Reply 10 of 14, by superfury

User metadata
Rank l33t++
Rank
l33t++

I've removed the if clause content of the /soft flag. I've also removed the interrupt 19h call.
I've moved the if clause itself to the bottom part of the script, where it will either set $40:$72 to 0(without /soft) or $1234(with /soft).

I tried running the newly compiled executable with /soft, but it results in a full reboot (The Super PC/Turbo XT BIOS still shows refreshes VGA(screen update), Shows blue bar with header, show hardware connected and starts counting memory, just like a normal hard reset (or closing and opening the emulator again). Is there an error in the BIOS I use? Does it check for the $1234 at all?
So there's no visible difference between $1234 and 0 being set with jumping to FFFF:0000? Shouldn't the whole first screen of the BIOS need to be skipped with $1234 set (and instead just start booting again with an empty screen, from the user perspective)?

When I look at the source code of the BIOS, I notice something strange:

;--------------------------------------------------------------------------------------------------
; Power-On Entry Point
;--------------------------------------------------------------------------------------------------
entry 0FFF0h ; Hardware power reset entry
proc power far ; CPU begins here on power up

jmpf 0F000h, cold_boot

endp power

Then at cold_boot:

;---------------------------------------------------------------------------------------------------
; BIOS Power-On Self Test (POST)
;---------------------------------------------------------------------------------------------------
entry 0E05Bh ; IBM restart entry point
proc post near

cold_boot:
mov ax, 40h ; Entered by POWER_ON/RESET
mov ds, ax
mov [word ds:72h], 0 ; Show data areas not init

warm_boot:

So it will never perform a warm reboot using FFFF:0000 (always reset the 1234h value). It does seem to correctly call warm_boot with CTRL-ALT-DEL with ENHANCED_KEYB defined. So the only way to reliably perform a warm reboot is either jumping to the direct address of warm_boot from my program, or simulating a CTRL+ALT+DEL through the keyboard controller(set 40:17 to 0xC, finally add key code 0x53 to the keyboard input buffer to trigger the BIOS's warm reboot. Finally, if still running display an error message.)?

Edit: I've tested above changes too: The $1234 flag is simply ignored by the BIOS. Anyone? (I'm using this BIOS: http://www.phatcode.net/downloads.php?id=101 ) I'm using v2.5's PCXTBIOS.BIN file as the BIOS.

Author of the UniPCemu emulator.
UniPCemu Git repository
UniPCemu for Android, Windows, PSP, Vita and Switch on itch.io

Reply 11 of 14, by Jepael

User metadata
Rank Oldbie
Rank
Oldbie

It appears that bios jumps to warm boot label from the keyboard interrupt after detecting CTRL-ALT-DEL.

However, real IBM bios jumps to $FFFF:$0000, and later determines if this was a cold or warm boot.

So yes, the generic turbo XT bios does ignore it when jumping to $FFFF:$0000. That's bad, but good thing is there's source code and you can still patch the bios to work differently.

Reply 12 of 14, by superfury

User metadata
Rank l33t++
Rank
l33t++

But unfortunately when I try to execute a CTRL-ALT-DEL key combination on my keyboard, in Direct Input mode Windows catches it instead of my emulator and when I try to execute it using the OSK in the emulator it has no effect. Apparently it's function(ENHANCHED_KEYBOARD thing according to the comments) disabled in the ROM that's distributed with the source code? Although the source code itself has it enabled? Or maybe the key has the wrong scancode mapped (it's using the scancode set #1 I believe, since it checks for the E0 prefix.)? Ctrl and Alt work fine afaik.

Author of the UniPCemu emulator.
UniPCemu Git repository
UniPCemu for Android, Windows, PSP, Vita and Switch on itch.io

Reply 13 of 14, by Jepael

User metadata
Rank Oldbie
Rank
Oldbie

Yes, in Windows, user programs won't get CTRL-ALT-DEL combination.

That's why emulators have a menu to send CTRL-ALT-DEL or they remap some other key combination to be CTRL-ALT-DEL, CTRL-ALT-INS or CTRL-ALT-END seem to be popular in some virtual machines.

(I don't know why emulator OSK does not work here).

Reply 14 of 14, by superfury

User metadata
Rank l33t++
Rank
l33t++

After looking at the scancode set 1 page (http://www.computer-engineering.org/ps2keyboa … scancodes1.html) I notice that E0 53 is the make code of delete. So it's indeed using scancode set 1.

Left control is 1D(make) and 9D(break).
Left alt is 38(make) and B8(break)
Right control is E0 1D(make) and E0 9D(break)
Right alt is E0 38(make) and E0 B8(break)
Delete is E0 53(make) and E0 D3(break)

Now comparing it to my emulation of scancode set 1 (Contained in a big array in hardware/keyboard_data.c)...
Left control is correct.
Left alt is correct.
Right control is correct.
Right alt is correct.
Delete is also correct.

So the input is actually correct according to the documentation.

Now looking at the actual source code of the Super PC/Turbo XT BIOS v2.5...

Edit: Currently checked Control and Alt key updating. The code seems OK(if my emulated CPU works correctly, which I think it does). So the ctrl and alt flags should be correctly updated. Now to check the del key...

It looks that when ctrl and alt are pressed and delete is pressed, below quote should be executed:

reboot:
mov [word ds:72h], 1234h ; Ctrl-Alt-Del, set init flag
jmp warm_boot ; do a warm reboot

Next question: Since it seems that entering a Ctrl-Alt-Del through Direct Input won't work because of Windows and Ctrl-Alt-Del using seperate keys during keyboard mode (k+l for selecting the correct input block, holding left for ctrl, next also holding right for alt and finally numpad 6 to actually press the del key. So for some reason, the emulator won't receive the Ctrl-Alt-Del input because having k, l, left, right and numpad 6 pressed will be ignored for some reason (real keyboard buffer overflow because pressing 5 keys at the same time(which isn't supported by the Dell SK-8185 keyboard I'm typing with now?) (generating too many input doesn't seem to be the case, since the PC isn't producing beeps) or limitations on the amount of keys pressed in that area (don't know if the keyboard still uses those electrical wires limiting simulaneous input with that key combination?)? In any case, the emulator isn't receiving the key combination. Anyone knows anything about this?'

Also, if the ctrl-alt-del make codes aren't sent in the right order, the del won't trigger a reboot (using up instead of left+right is mapped to trigger both ctrl and alt at the same time in x86EMU during keyboard and mouse modes(indicated by the flag disappearing and a capital M in the bottom right corner of the window/screen(at fullscreen))).

I look at my input emulation and I notice two errors in both keyboard and gaming mode (gaming mode is entered by pressing down while in either mouse or keyboard mode, and exited using select(PSP) or backspace(PC). The errors are exactly the same in both cases: It checks for release of keys first, then handles keypresses, but instead of requesting release of keys it presses the keys(at the keyboard file, which handles all timing used by the CPU, but in realtime instead of direct CPU time (the CPU speed might be faster or (way) slower than it's supposed to be running (when running at 100% emulation speed). With slower PCs (less than 3-4GHz CPU), it's usually between 0% speed and 90% speed with current optimization). This shouldn't affect input given by the user, which types in realtime. So in order to fix that I've locked the keyboard input rate to real time (gotten from a high percision timer) instead of being synchronized with the CPU clock (which varies with machines running the CPU faster or slower).

I'm patching this bug right now. That should at least fix being able to use Control and Alt within those two modes, thus able to actually execute a Ctrl-Alt-Del (and any other Control and/or Alt combined with another normal key).

Edit: Now that the bug is fixed, Ctrl-Alt-Del using the emulator's OSK works. I do notice that after the XT-IDE BIOS trying to boot C, fails because of a missing OS, Ctrl-Alt-Del soft reboots. After that the soft reboot Ctrl-Alt-Del has no effect anymore?

Author of the UniPCemu emulator.
UniPCemu Git repository
UniPCemu for Android, Windows, PSP, Vita and Switch on itch.io