VOGONS


Writing DOS device drivers in C

Topic actions

Reply 20 of 54, by lolo799

User metadata
Rank Oldbie
Rank
Oldbie
pan069 wrote on 2021-08-16, 22:07:

In the 90's there was a very popular book going around in Europe called "PC Intern". It was originally by a German author called Michael Tischer and was translated into various languages (I still have a Dutch translation sitting here on my bookshelf). It might be worth hunting down a copy of this, it has an incredible amount of information in it, including DOS device drivers. Looking through the ToC, it doesn't seem to have a DOS driver in C examples (only assembler), which is probably more suitable for this kind of thing.

In any case, maybe something to look into.

I remember seeing the french editions in bookstores in the mid 90's, it was selling well.
Many years later I bought the french 4th edition which is the same as the 3rd but with 50 or so extra pages covering Dos 6.2 and the Pentium.

PCMCIA Sound, Storage & Graphics

Reply 21 of 54, by cyclone3d

User metadata
Rank l33t++
Rank
l33t++

C is pretty sweet though. You can do just about anything in it.

You can also do inline assembly and if you really need to do any crazy optimizations, you can edit the resulting assembly code before you compile the code to an executable or whatever.

If you are good, you can actually optimize some of the C code better than the compiler could ever hope to. I've always just done the optimization in C and not even bothered with looking at the resulting assembly code.

I've got a primes number program I wrote from scratch that can handle up to a theoretical 2^32-1 threads.. all without any locks except for the thread that waits for the other threads to be finished before it starts spitting out the results.

It does start to get sketchy performance-wise when using a huge number of threads on a 6-core, 12-thread CPU though that is expected. I would love to have access to some super-computer so I could see what it would perform like in a scenario with thousands of CPU cores.

I would shudder to think about trying anything like that in assembler.

Yamaha modified setupds and drivers
Yamaha XG repository
YMF7x4 Guide
Aopen AW744L II SB-LINK

Reply 23 of 54, by Jo22

User metadata
Rank l33t++
Rank
l33t++
cyclone3d wrote on 2021-08-17, 21:21:

C is pretty sweet though. You can do just about anything in it.

I kind of miss K&R C, though. It was easier to remember/understand, I think.
ANSI C needed 40 lines of code, whereas K&R C needed 5.
Okay, that's a little over exaggerated, maybe. 😉
But it often felt that way nevertheless.

PS: There were some Peter Norton books in the 1980s.
They covered the IBM PC/DOS architecture, too.
The focus was on assembly language I think, but maybe some portions of it were in C, too.

"Time, it seems, doesn't flow. For some it's fast, for some it's slow.
In what to one race is no time at all, another race can rise and fall..." - The Minstrel

//My video channel//

Reply 24 of 54, by Oerg866

User metadata
Rank Member
Rank
Member

OK, so I think I've reached a dead end here.

Referring to MSC8.00 as an alias for Microsoft Visual C++ 1.52's DOS compiler.

Using the DOS Internals book's floppy disk, I have set up MS C/C++ 7.00 with 8.00's linker because 7.00's crashes on my K6 with a DPMI host installed.

While in principle this does work, I can compile and link an executable file that I can load both as a .SYS and as a .EXE, I'm shocked to find out that this compiler, released 5 years after the processor's introduction, does not support 386 code generation -- so that's out.

Then I tried MSC8.00's compiler and while it does have 386 code generation, the inline assembler (which I need for a few specific pentium+ things) does not support 386 instructions, which is mentioned in the help files.

Was that ever fixed? Was there a later version that can produce DOS code and maybe can inline 386 instructions?

Best regards,
Eric

Reply 25 of 54, by kjliew

User metadata
Rank Oldbie
Rank
Oldbie

Microsoft 16-bit C inline assembler wasn't that great, but Watcom 32-bit C was horrible using #pragma. Microsoft 32-bit C after MSVC4.0 would have better inline assembly but it no longer support DOS programming without 3rd-party DOS extender stubs.

Are you not familiar with mixed language programming with C and ASM? You can just write small ASM routines in 16-bit C ABI using 386 instructions and 32-bit registers. Just remember to save/restore properly the upper 16-bit of any 32-bit registers used. This is how I would code in 16-bit C, with 4GB "unreal" mode, RDMSR/RDTSC with 32-bit registers and 32-bit memory/IO accesses.

Reply 26 of 54, by Oerg866

User metadata
Rank Member
Rank
Member
kjliew wrote on 2021-08-19, 00:20:

Microsoft 16-bit C inline assembler wasn't that great, but Watcom 32-bit C was horrible using #pragma. Microsoft 32-bit C after MSVC4.0 would have better inline assembly but it no longer support DOS programming without 3rd-party DOS extender stubs.

Are you not familiar with mixed language programming with C and ASM? You can just write small ASM routines in 16-bit C ABI using 386 instructions and 32-bit registers. Just remember to save/restore properly the upper 16-bit of any 32-bit registers used. This is how I would code in 16-bit C, with 4GB "unreal" mode, RDMSR/RDTSC with 32-bit registers and 32-bit memory/IO accesses.

This is my first time touching both x86 assembly (writing it at least) and writing something for DOS in something that's actually as old as the OS, so excuse my short sightedness x)

You're right, that concept I do know but it completely slipped my mind. I will try to do this 😀

Best regards,
Eric

Reply 27 of 54, by amadeus777999

User metadata
Rank Oldbie
Rank
Oldbie

Watcom's inline assembler is, once you got acquainted to it, a bit above the usual "asm { ... }" solutions. You can produce some elegant code thanks to the parm/modify/value options... much better than gcc's AT&T brain-ache.

Why not use (Open)Watcom's dev tools instead of the "Mirkosoft" ones? You got a flat memory model, register based parameter passing and easy access to the fist megabyte - way better than in DJGPP's gcc port for example.

There's also wcc with which you can generate 16bit "software".

Paul Hsieh's guide is a good starting point on various issues if one's interested - http://www.azillionmonkeys.com/qed/watfaq.shtml

Last edited by amadeus777999 on 2021-08-19, 15:08. Edited 1 time in total.

Reply 28 of 54, by hyoenmadan

User metadata
Rank Member
Rank
Member

WTF...
A DOS driver (i suppose a sys file, or an EXE installable via device= directive) with 386 instructions on it? What's this black sorcery you're trying to do?!
I can't avoid to feel like you are doing all this wrong pal.

Reply 32 of 54, by Oerg866

User metadata
Rank Member
Rank
Member

I want to write a more flexible replacement for K6DOS.SYS that also works with CXT K6-IIs, which rquires rdmsr, wrmsr and cpuid instructions. I'm okay with those missing, I can manually insert them with macros, but the code around those require messing with 32 bit instructions and registers.

Reply 33 of 54, by BloodyCactus

User metadata
Rank Oldbie
Rank
Oldbie

should be super simple with nasm. its only a couple of MSR's.

--/\-[ Stu : Bloody Cactus :: [ https://bloodycactus.com :: http://kråketær.com ]-/\--

Reply 35 of 54, by BloodyCactus

User metadata
Rank Oldbie
Rank
Oldbie
Oerg866 wrote on 2021-08-20, 14:20:

more flexible

ok, I dont think you understand at all the complexity then.

when you use C, it has a lot of runtime initialisation, a lot of code is run before main() is called and the c libraries it expects certain things to be setup. SYS driver entry points does not call main(), so all the init code a C runtime does, does not trigger. Which means a lot of functions in the c stdlib etc wont have proper setup, want to do a printf? yeah, its not gonna work right.

Also, when a SYS is loaded, most of DOS is not there, so alot of C's stdlib cant interface with dos (again going back to printf, it uses a CON interface which is tied to the DOS file IO and buffering, a lot of those functions are not setup yet. sys files must be careful what portions of DOS they call). The sys parameter string is not list of strings like main(argc,*argv[]) etc. its also not zero termianted, its crlf terminated etc).

I knocked out a framework for openwatcom + nasm (cpuid,rdmsr,wrmsr) to jump from the sys interface into the C code, and its all working fine. would only need to call the MSR's with the correct values.. and determine the system memory (which is no trivial task because bios supports different levels of interface to get this information, some better some worse).

Since I'm quite happy with setmul I dont think I'll spend anymore time on it, but I proved to myself what I needed to know.

Last edited by BloodyCactus on 2021-08-21, 18:18. Edited 1 time in total.

--/\-[ Stu : Bloody Cactus :: [ https://bloodycactus.com :: http://kråketær.com ]-/\--

Reply 36 of 54, by Oerg866

User metadata
Rank Member
Rank
Member

Please stop being so condescending, I'm an embedded software engineer (got my own office and everything!) and I'm a reasonably capable programmer trying to learn a new (old) thing - the attitude in these types of threads make that very hard so I usually don't bother posting here.

I'm well aware that there's challenges involved but the bottom line is it can be done, else there wouldn't have been books about them. I've managed to solve all my compiler and assembler issues and have started development using the DOS internals driver framework (which does what you posted except in MSC/MASM).

I am already able to detect the CPU type and find VESA modes in a VBE 2.x capable card. It's not so hard if you actually read the docs properly. I will tackle the LFB stuff next.

Of course there already exist programs such as setk6 that do what I set out to do, but they all do not work with EMM386 (privileged instructions) or in case of k6dos, does not actually really do what it says on the box (and is incompatible with the k6-2 CXT, I patched out that check though and got nowhere) .

Elaborating on what I was saying at the beginning:

The problem is that when I started programming, DOS and its many concepts, interfaces and structures were already a thing of the past. Never learned them, never learned about memory models and segmentation and all that legacy goodness, never learned x86 assembly. My retro gaming hobbies were what made me learn 68k, z80 and later I learned ARM assembly in university; none of these platforms bore any similarity to this here architecture 😅

Perhaps that's why to people such as yourself I may look like an idiot - you can of course believe that, it's a free world after all, but even professionals have knowledge gaps 😀

Reply 37 of 54, by maxtherabbit

User metadata
Rank l33t
Rank
l33t

I think you're getting bent out of shape without justification. No one is really being condescending, just saying that it's better to use real mode assembly for installable dos device drivers, which is true

Reply 38 of 54, by Jo22

User metadata
Rank l33t++
Rank
l33t++
maxtherabbit wrote on 2021-08-21, 13:03:

I think you're getting bent out of shape without justification. No one is really being condescending, just saying that it's better to use real mode assembly for installable dos device drivers, which is true

My father thinks the same and he had been programming in machine language and assembly (macro assembler) since the 1970s.
Device drivers require certain tasks to be done in specific order, which I believe is tricky to accomplish with high-level languages (compilers try to optimize, among doing other things).

Except with, say FORTRAN or BASIC etc. They allow for efficient and infamous spaghetti code, but also structured programming, if needed.

On Windows, by the way, Delphi was used for quite some time to write DLLs (which could be used as drivers) , because Visual Basic wasn't up to the task.
Delphi (Object Pascal) was a friendly high-level language for all those people that didn't like C/C++ all too much. 😉

PS: For those of you looking for a real challenge, use the registers only.
Programs that store data on the registers only need no RAM.
Generally speaking only, of course. BIOS can do that during POST, but x86 architecture wasn't designed for that in first place. 😉

https://superuser.com/questions/857465/run-a- … ter-without-ram

Attachments

  • macro_z80.jpg
    Filename
    macro_z80.jpg
    File size
    108.57 KiB
    Views
    1281 views
    File license
    Fair use/fair dealing exception

"Time, it seems, doesn't flow. For some it's fast, for some it's slow.
In what to one race is no time at all, another race can rise and fall..." - The Minstrel

//My video channel//

Reply 39 of 54, by Oerg866

User metadata
Rank Member
Rank
Member
maxtherabbit wrote on 2021-08-21, 13:03:

I think you're getting bent out of shape without justification.

Yeah, fair point. I was rubbed wrongly mostly by the first two paragraphs of BloodyCactus' post and this gem. It's not needed and rude (and far from the first time I've seen unwelcoming behavior on this site...).

To clarify (maybe I was unclear) I set out to do what I explained, writing a replacement for the inadequate K6DOS.SYS. I had done research and according to the few book excerpts I had found, doing this in C seemed entirely possible. I also wanted to have the flexibility and functionality of some other utilities, like automatic detection of system memory and LFBs and such.

So I had two choices: Spend what little free time I have inbetween work days writing all of this in assembly, or I could do things in C and get a result in a reasonable amount of time. 😜

TL;DR: I have a working framework for this from DOS internals, and I am making progress. And doing this in C is NOT up for debate 😜

ANYWAY. I'll report back my results once I have more things implemented.

Best,
Eric