Back to home page

DOS ain't dead

Forum index page

Log in | Register

Back to index page
Thread view  Board view
rosegondon

C:\DOS,
14.01.2022, 22:39
 

How to detect FreeDOS kernel from Turbo Pascal program? (Developers)

Hello,

I am looking for a method of detection of running FreeDOS kernel from Turbo Pascal compiled program. Because under FreeDOS various shells can be loaded (for example FreeCOM can be replaced by 4DOS) this cannot be a method referring to simple shell call. What I need is to find if my Pascal program runs under FreeDOS kernel, regardless of the command interpreter used.

For now I use ugly and dirty code of type "if exist {boot drive}\kernel.sys then RunningUnderFreeDOS" but this ugliness fails miserably when multiboot (and multikernel) configuration is working because while kernel.sys is present, it doesn't mean it is loaded.

---
echo g=ffff:0|debug>nul

mceric

Germany,
15.01.2022, 00:22

@ rosegondon
 

How to detect FreeDOS kernel from Turbo Pascal program?

> I am looking for a method of detection of running FreeDOS kernel

set ax=0x3000 and call int 0x21, check whether the returned bh is 0xfd.

if yes, set ax=0x33ff and call int 0x21, it returns a pointer dx:ax to a version string.

how to express this in the programming language of your choice is up to you, please share an example implementation code snippet here :-)

---
FreeDOS / DOSEMU2 / ...

rosegondon

C:\DOS,
15.01.2022, 16:20
(edited by rosegondon, 15.01.2022, 16:39)

@ mceric
 

How to detect FreeDOS kernel from Turbo Pascal program?

> > I am looking for a method of detection of running FreeDOS kernel
>
> set ax=0x3000 and call int 0x21, check whether the returned bh is 0xfd.
>
> if yes, set ax=0x33ff and call int 0x21, it returns a pointer dx:ax to a
> version string.
>
> how to express this in the programming language of your choice is up to
> you, please share an example implementation code snippet here :-)

Success! It works even when FreeCOM is not used at all.

Uses Dos;

Function IsFreeDos : Boolean;
        VAR Regs : Registers;
        begin
           With Regs do
              begin
                 ax := $3000;
                 bx := $00;
              end;
           Intr ($21, Regs);
           if Regs.bh = $FD then IsFreeDOS := TRUE else IsFreeDOS := FALSE
        end;


Begin
WriteLn(IsFreeDos);
End.

---
echo g=ffff:0|debug>nul

Rugxulo

Homepage

Usono,
19.01.2022, 01:05

@ rosegondon
 

How to detect FreeDOS kernel from Turbo Pascal program?

> Success! It works even when FreeCOM is not used at all.

Minor improvements:


program whatfdos;
uses DOS;

function IsFreeDOS: boolean;
  var reg: registers;
begin
  reg.ax := $3000; reg.bx := 0;
  msdos(reg);
  IsFreeDOS := reg.bh = $FD
end;

begin
  writeln('FreeDOS = ',IsFreeDOS)
end.

ecm

Homepage E-mail

Düsseldorf, Germany,
15.01.2022, 17:32

@ mceric
 

21.33FF kernel version string interface

> > I am looking for a method of detection of running FreeDOS kernel
>
> set ax=0x3000 and call int 0x21, check whether the returned bh is 0xfd.
>
> if yes, set ax=0x33ff and call int 0x21, it returns a pointer dx:ax to a
> version string.
>
> how to express this in the programming language of your choice is up to
> you, please share an example implementation code snippet here :-)

Here's an example for the latter call in 8086 NASM assembly: callver.asm


        mov ax,33ffh    ; get FreeDOS version string pointer
        xor dx, dx
        int 21h         ; returns DX AX
        test dx, dx
        jnz gotname
        mov dx, ds
        mov ax, msgnoname


The returned pointer is an ASCIZ string that may have trailing whitespace (such as CR or LF). There is some code following the quoted part that will ignore trailing whitespace.

Here's an addition I made to comcom32, a DPMI client shell written in C. It does essentially the same as my callver code: Preset dx to zero, check for a nonzero return in dx, and ignore trailing whitespace. (It also ignores leading whitespace and copies the entire string to a 256-byte buffer allocated by malloc.)

Here's the same function in RxCMD, 8086 assembly too.

Crucially this doesn't depend on the 21.3000 OEM number (like a prior version of callver) to detect support for the 21.33FF function. Instead, it presets dx to zero and checks for a non-zero segment return. This function is also supported by my more recent RxDOS kernels (which have OEM number 5Eh).

Here's the string in RxDOS's DOS code segment: https://hg.pushbx.org/ecm/rxdos-7.2x/file/38ec35f277df/RxDOS/doscode.asm#l58

Here's what it looks like in the file: (from the uncompressed RxDOS.COM file of RxDOS version 7.24)

001B90 0C 0C 0C 0C 0C 0C 0C 04-04 52 78 44 4F 53 20 76  >.........RxDOS v<
001BA0 65 72 73 69 6F 6E 20 37-2E 32 34 20 5B 68 67 20  >ersion 7.24 [hg <
001BB0 62 30 30 34 65 61 38 30-65 32 32 32 5D 20 5B 32  >b004ea80e222] [2<
001BC0 30 31 38 2D 31 30 2D 30-39 5D 00 5E 43 0D 0A 00  >018-10-09].^C...<


This is the result of using the call on my current FreeDOS in dosemu2 setup:

C:\>ldebug
-a
1E8E:0100 mov ax, 33ff
1E8E:0103 int 21
1E8E:0105 nop
1E8E:0106
-r
AX=0000 BX=0000 CX=0000 DX=0000 SP=FFFE BP=0000 SI=0000 DI=0000
DS=1E8E ES=1E8E SS=1E8E CS=1E8E IP=0100 NV UP EI PL ZR NA PE NC
1E8E:0100 B8FF33            mov     ax, 33FF
-t
AX=33FF BX=0000 CX=0000 DX=0000 SP=FFFE BP=0000 SI=0000 DI=0000
DS=1E8E ES=1E8E SS=1E8E CS=1E8E IP=0103 NV UP EI PL ZR NA PE NC
1E8E:0103 CD21              int     21
-
AX=17E4 BX=0000 CX=0000 DX=00D9 SP=FFFE BP=0000 SI=0000 DI=0000
DS=1E8E ES=1E8E SS=1E8E CS=1E8E IP=0105 NV UP EI PL ZR NA PE NC
1E8E:0105 90                nop
-d dx:ax
00D9:17E0              46 72 65 65-44 4F 53 20 6B 65 72 6E     FreeDOS kern
00D9:17F0  65 6C 20 2D 20 47 49 54-20 28 62 75 69 6C 64 20 el - GIT (build
00D9:1800  32 30 34 33 20 4F 45 4D-3A 30 78 66 64 29 20 5B 2043 OEM:0xfd) [
00D9:1810  63 6F 6D 70 69 6C 65 64-20 4F 63 74 20 32 38 20 compiled Oct 28
00D9:1820  32 30 32 31 5D 0A 00 00-68 93 68 93 68 93 68 93 2021]...h.h.h.h.
00D9:1830  BD 94 BD 94 68 93 68 93-BD 94 BD 94 68 93 51 93 ....h.h.....h.Q.
00D9:1840  68 93 BD 94 BD 94 BD 94-68 93 00 00 03 0C 03 0C h.......h.......
00D9:1850  06 0A 0F 00 00 00 13 13-17 18 19 19 22 5B 5D 3A ............"[]:
00D9:1860  7C 3C 3E 2B            -                        |<>+
-


Note the trailing 0Ah byte (Line Feed).

---
l

rosegondon

C:\DOS,
17.01.2022, 20:06

@ ecm
 

21.33FF kernel version string interface

> > > I am looking for a method of detection of running FreeDOS kernel
> >
> > set ax=0x3000 and call int 0x21, check whether the returned bh is 0xfd.
> >
> > if yes, set ax=0x33ff and call int 0x21, it returns a pointer dx:ax to a
> > version string.
> >
> > how to express this in the programming language of your choice is up to
> > you, please share an example implementation code snippet here :-)
>
> Here's an example for the latter call in 8086 NASM assembly:
> callver.asm
>
>
> mov ax,33ffh    ; get FreeDOS version string pointer
> xor dx, dx
> int 21h               ; returns DX AX
> test dx, dx
> jnz gotname
> mov dx, ds
> mov ax, msgnoname
>

>
> The returned pointer is an ASCIZ string that may have trailing whitespace
> (such as CR or LF). There is some code following the quoted part that will
> ignore trailing whitespace.

How to get this version string in Pascal?

---
echo g=ffff:0|debug>nul

DosWorld

18.01.2022, 02:54

@ rosegondon
 

21.33FF kernel version string interface

> How to get this version string in Pascal?

:)

function GetFreeDosVer : pchar; assembler;
asm
> > mov ax,$33ff ; get FreeDOS version string pointer
> > xor dx, dx
> > int $21 ; returns DX AX
> > test dx, dx
> > jnz @gotname
xor ax, ax
mov dx, ax
@gotname:
end;

---
Make DOS great again!

Carthago delenda est, Ceterum censeo Carthaginem delendam esse.

rosegondon

C:\DOS,
18.01.2022, 09:06

@ DosWorld
 

21.33FF kernel version string interface

> > How to get this version string in Pascal?
>
> :)
>
> function GetFreeDosVer : pchar; assembler;
> asm
> > > mov ax,$33ff ; get FreeDOS version string pointer
> > > xor dx, dx
> > > int $21 ; returns DX AX
> > > test dx, dx
> > > jnz @gotname
> xor ax, ax
> mov dx, ax
> @gotname:
> end;

Uses Strings;
Begin
Writeln(StrPas(GetFreeDosVer));
End.

Under MS-DOS this function returns a string of random characters. Shouldn't it return empty result under DOS other than FreeDOS?

---
echo g=ffff:0|debug>nul

Laaca

Homepage

Czech republic,
18.01.2022, 14:25

@ rosegondon
 

21.33FF kernel version string interface

Or this dualistic implementation (Turbopascal / Freepascal)
(compatible with both FPC calling modes: oldfpccall and fastcall)

Procedure Get_FreeDOS_version_string_asm(var s,o:word);assembler;
asm
{$IFDEF FPC}
   push esi
   push edi
   mov esi,s
   mov edi,o
   mov ax,33ffh
   mov dx,0
   int 21h
   mov [esi],dx
   mov [edi],ax
   pop edi
   pop esi
{$ELSE}
push si
push ds
mov ax,33ffh
mov dx,0
int 21h
lds si,s
mov [si],dx
lds si,o
mov [si],ax
pop ds
pop si
{$ENDIF}
end;


Function Get_FreeDOS_version_string:string;
var t:string;
    s,o:word;
    a,b:byte;
begin
Get_FreeDOS_version_string_asm(s,o);
t:='';
if s<>0 then
   for a:=0 to 254 do
       begin
       b:=Mem[s:o+a];
       if b=0 then break else
       if b>=32 then t:=t+char(b);
       end;
Get_FreeDOS_version_string:=t;
end;


begin
writeln(Get_freedos_version_string);
end.

---
DOS-u-akbar!

tkchia

Homepage

18.01.2022, 15:30

@ rosegondon
 

21.33FF kernel version string interface

Hello rosegondon,

> > function GetFreeDosVer : pchar; assembler;
> > asm
> > > > mov ax,$33ff ; get FreeDOS version string pointer
> > > > xor dx, dx
> > > > int $21 ; returns DX AX
> > > > test dx, dx
> > > > jnz @gotname
> > xor ax, ax
> > mov dx, ax
> > @gotname:
> > end;
>
> Uses Strings;
> Begin
> Writeln(StrPas(GetFreeDosVer));
> End.
>
> Under MS-DOS this function returns a string of random characters. Shouldn't
> it return empty result under DOS other than FreeDOS?

The above implementation under MS-DOS will return a null pointer (0:0) — which in general may not point to an empty string. You probably want to check that the returned pointer is not a null pointer.

Thank you!

---
https://gitlab.com/tkchia · https://codeberg.org/tkchia · 😴 "MOV AX,0D500H+CMOS_REG_D+NMI"

DosWorld

18.01.2022, 16:44

@ rosegondon
 

21.33FF kernel version string interface

> Writeln(StrPas(GetFreeDosVer));

(TP's) "Writeln" can write content from pchar.

PS: (To rosegondon)
var str :pchar;
begin
str := GetFreeDosVer;
if str <> nil then Writeln(str);
end.

---
Make DOS great again!

Carthago delenda est, Ceterum censeo Carthaginem delendam esse.

rosegondon

C:\DOS,
18.01.2022, 19:14

@ DosWorld
 

21.33FF kernel version string interface

> > Writeln(StrPas(GetFreeDosVer));
>
> (TP's) "Writeln" can write content from pchar.
>
> PS: (To rosegondon)
> var str :pchar;
> begin
> str := GetFreeDosVer;
> if str <> nil then Writeln(str);
> end.

@Laaca, @DosWorld - thank you!
I acquired your code and it works perfectly. Thank you for FreePascal version!

---
echo g=ffff:0|debug>nul

Laaca

Homepage

Czech republic,
18.01.2022, 19:06

@ mceric
 

How to detect FreeDOS kernel from Turbo Pascal program?

By the way, where is documented the INT21h/AX=33FFh?
I am looking at the Ralf Brown's interrupt list and don't see it there...

It is even not mentioned nowhere on the FreeDOS site, what is shame...

---
DOS-u-akbar!

Rugxulo

Homepage

Usono,
19.01.2022, 00:57

@ Laaca
 

How to detect FreeDOS kernel from Turbo Pascal program?

> By the way, where is documented the INT21h/AX=33FFh?
> I am looking at the Ralf Brown's interrupt list and don't see it there...
>
> It is even not mentioned nowhere on the FreeDOS site, what is shame...

It's mentioned (at least by Eric) as far back as 2005:

"[Freedos-devel] re: re: VER /R" (2005-07-29)


So see the kernel sources:
VOID ASMCFUNC int21_syscall(iregs FAR * irp)
...
  switch (irp->AH)
...
    case 0x33:
      switch (irp->AL)
...
          /* set FreeDOS returned version for int 21.30 from BX */
        case 0xfc:             /* 0xfc ... 0xff are FreeDOS extensions */
          os_setver_major = irp->BL;
          os_setver_minor = irp->BH;
          break;
...
          /* Get DOS-C release string pointer                     */
        case 0xff:
          irp->DX = FP_SEG(os_release);
          irp->AX = FP_OFF(os_release);
      }
      break;
...


I had my own wimpy code from 2007, so clearly I learned it from somebody:


LANG OCTASM,0.1
org 100h use16 file_out \whatfdos.com
VER=33FFh
#Komenco   ax=VER int 21h jc Fino cmp ax,VER jz Fino
           ds=dx si=ax ax=1225h int 2Fh # lodsb int 29h loop <1
#Fino      ret

Laaca

Homepage

Czech republic,
19.01.2022, 10:33

@ Rugxulo
 

How to detect FreeDOS kernel from Turbo Pascal program?

I would not consider a code snippet mentioned a year ago in some email conversation as a properly documented FreeDOS function

The all FreeDOS webpage is awful but it would be for an another topic. Anyway, there is nowhere mentioned this function call.
I know - in the main menu is "Links", and there a section "technical documentation". There are about 3 copies of RBIL and some other stuff.
But INT21h/AX=33FFh? Nowhere.

---
DOS-u-akbar!

Oso2k

15.01.2022, 00:24

@ rosegondon
 

How to detect FreeDOS kernel from Turbo Pascal program?

> Hello,
>
> I am looking for a method of detection of running FreeDOS kernel from Turbo
> Pascal compiled program. Because under FreeDOS various shells can be loaded
> (for example FreeCOM can be replaced by 4DOS) this cannot be a method
> referring to simple shell call. What I need is to find if my Pascal program
> runs under FreeDOS kernel, regardless of the command interpreter used.
>
> For now I use ugly and dirty code of type "if exist {boot
> drive}\kernel.sys then RunningUnderFreeDOS" but this ugliness fails
> miserably when multiboot (and multikernel) configuration is working because
> while kernel.sys is present, it doesn't mean it is loaded.


http://www.ctyme.com/intr/rb-2711.htm

http://www.ctyme.com/intr/rb-2730.htm

Laaca

Homepage

Czech republic,
15.01.2022, 11:09
(edited by Laaca, 15.01.2022, 11:23)

@ rosegondon
 

How to detect FreeDOS kernel from Turbo Pascal program?

The DOS call proposed by McEric certainly works but I recommend to use a shell call. The "ver" command is reliable and the format should be standardised even through various alternate command interpretters.

Firstly call simply "ver".
Then, if it contains string "FREECOM" (after capitalization) call "ver /r" and analyse the output.

---
DOS-u-akbar!

mceric

Germany,
15.01.2022, 12:29

@ Laaca
 

How to detect FreeDOS kernel from Turbo Pascal program?

> The DOS call proposed by McEric certainly works but I recommend to use a
> shell call. The "ver" command is reliable and the format should be
> standardised even through various alternate command interpretters.

I disagree. I am not aware of any standard format for the text returned by a VER shell command in the DOS wild west.

Also, calling the shell and interpreting the results is a lot more overhead than calling a well-documented int 21.30 kernel interface or even a less documentet FreeDOS kernel version string interface. Also note that only FreeCOM, but not non-FreeDOS shells, is able to include the kernel version string in the VER /R output. The normal VER output only shows the version of FreeCOM, not the version of FreeDOS, and you can use FreeCOM with any version of DOS, possibly not FreeDOS at all.

By the way, I am curious why the Turbo Pascal program wants to know whether a FreeDOS kernel is active, does it need any special workarounds? Or does it provide extra features that you want to detect to be present?

---
FreeDOS / DOSEMU2 / ...

Back to index page
Thread view  Board view
22049 Postings in 2034 Threads, 396 registered users, 119 users online (0 registered, 119 guests)
DOS ain't dead | Admin contact
RSS Feed
powered by my little forum