• Please review our updated Terms and Rules here

"Fun with BIOS" Programming Thread

Excuse me if this subject has been discussed before on this deep thread, but, have you taken a look at the Award Bios 1999 source code ?

I've never been able to find a complete torrent of it (people need to SEED), but yes I'm aware of its existence.
 
The Source Code has been floating on the net for a long time with different variants. It is Chipset dependent.

Here is a link for example. Source Code

The problem isn't really getting the source code. It is understanding it and getting it to assemble and link, (which was the original problem the thread was addressing).

If there is interest I will post the solution for assembling and linking the A***dBios Source Code.
 
Very interesting (but a bit long) thread. Having done it myself, I could say that writing BIOS is an interesting and very educating adventure. Not too difficult one, but it requires a lot of patience and time.

Some recommendations:
  • Entry points are important. Some things (e.g. VGA BIOS, and DOS) call BIOS subroutines, or mess with BIOS data area directly. There is a list of BIOS entry points here (starting at page 167).
  • Ralf Brown's Interrupt List and TECH Help! are good references. Ralf Brown's Interrupt List is especially useful since it explains differences in behavior of different BIOS implementations. It should be noted that neither one of these references are complete or error-free. I've got AMIBIOS Programmer's Guide too, but I can't say that it is more helpful than Ralf Brown's documentation.
  • In cases where documentation is not complete enough it helps to do black box type of experiments on some PC-compatibles.
  • I wrote my BIOS incrementally, implementing more essential functions first, and using stubs with some debug output for not yet implemented BIOS interrupts. Serial port would help here for debugging, but in my case a VGA display was enough. Having a working VGA card (with VGA BIOS) and XT-IDE BIOS helped a lot - Int 10h and Int 13h are more difficult parts of BIOS code. But with VGA/XT-IDE BIOS extensions it is possible to use fairly simple stubs on Int 10h and Int 13h (just to keep system happy).
  • You can "cheat" and copy BIOS fragments from existing implementations, and gradually replace them with your own code.
 
And let's not forget the Phoenix books on BIOS construction. A very good, but by no means complete, level of detail, including key entry point locations.
 
Writing a BIOS for an old IBM-PC/AT or compatible is not trivial, but it can be done. However, writing a BIOS for modern motherboards is a completely different matter.
 
Why would one want to do that, given the very short lifetime of modern systems?

^This. Additionally, modern BIOSes are probably written using some sort of support libraries which satisfy the entry-point/IBM compatibilities in their "startup routines".

Erm, sergey... I appreciate your input, but... you just only found this thread now? Spoiler alert: Nothing resembling a complete BIOS is anywhere in the thread. I wish I could delete most of this thread or at least start a new one.

Sergey, the real problem is the following: IBM compatible entry points make it exceptionally difficult to split up the source files into modules without requiring a large number of external tools (m4 being one of them if we did it my way). MASM does NOT have a facility to define the distance between segments between translation units- the .ORG directive will always be relative to the start of the current translation unit, and will have no knowledge about where it starts relative to another segment (other than being one after another).

So if I split up my source files to make a modular BIOS, I cannot have IBM-compatible entry points. The same issue would happen if I did the BIOS in C. (J)WLINK is the only linker which permits me to absolutely position segments, but the minute I decide to mix and match features/code for a modular BIOS, I will then have to use external tools to make sure that code sections (for instance, adding boot from floppy B: as well as A:, or a menu interface) do not overlap and overwrite IBM compatible entry points. It doesn't help that at least one entry point- the NMI vector, is placed RIGHT in the middle of the POST routine.

Organizing this project is more of a damn mess than just writing the code without any care for modularity, edge cases, or extra features. But I have to do it right from the beginning- going back to add modularity later won't work. I'll see if I can get an example showing the issue, but the last few pages of the thread explain the problem.

EDIT: Just read this post... it explains everything. Although Chuck(G) saw potential issues as early as the first reply to this thread :p.
 
Last edited:
Modern modular BIOSes are a whole 'nother story. I have a module for a VIA SATA card that I picked up and merged that into an Award BIOS on one of my machines. Worked just fine. The SATA card does not have its own BIOS. It's a great idea, made possible by big EEPROMs in current systems. Would that we had that in 1985...
 
Modern modular BIOSes are a whole 'nother story. I have a module for a VIA SATA card that I picked up and merged that into an Award BIOS on one of my machines. Worked just fine. The SATA card does not have its own BIOS. It's a great idea, made possible by big EEPROMs in current systems. Would that we had that in 1985...

Well that's not going to work with EPROM based systems, though UNIFLASH might be able to solve some of those issues on really-old flash based systems :p.

My idea is to autogenerate the final source file to be compiled... it would be three passes- the basic BIOS layout based on desired features would be created first (in m4 or pyexpander syntax). Platform-specific (PC, XT class for now) sections would be generated from the base layout generated in part one. Finally, chipset-specific features sections would be generated based upon the sections generated in the previous two steps.

After 3 passes, m4 or pyexpand will have enough defined sections/macros to "know" what source files to include and what to put where. In between each section, there should be checks that the BIOS will fit into the desired space.

Not that elegance matters anymore coming into year two of this project, but... to me, autogenerating source is something of a hack, even when it's simply including other files. It also prevents programming directly on a DOS system, but I think I can live without that (unless I write a macro expander in C, which isn't in my plans

EDIT: So, this thread passed 10,000 views I see. I'd like to thank everyone for their advice and input while I've very little in terms of results to show for it :p.
 
Last edited:
Erm, sergey... I appreciate your input, but... you just only found this thread now?

Yeah, just found it...

Sergey, the real problem is the following: IBM compatible entry points make it exceptionally difficult to split up the source files into modules without requiring a large number of external tools

Original IBM PC BIOS was only 8K (0FE000h-0FFFFFh) and that's where all entry points are. If you can afford more space for your BIOS, you can have some dispatch code in these 8 KiB, and the real code elsewhere below 0FE000h. Optionally you can fill the gaps with some useful routines. By the way most likely you will want to implement many of simple PC/XT BIOS routines anyway (e.g. INT 11h, INT 12h, INT 14h, INT 16h, INT17h services) and they might fit just nicely there. INT 10h, INT 13h, INT 15h are possible candidates for being modular - INT 10h can be configured to support various types of video adapters, or serial redirect; INT 13h can support HD disks or not, or have IDE support; INT 15h can have AT-specific functions or not.

I'd not complicate things with multiple segments... have one code segment starting at 0F0000h

Also, any specific reason you're restricting yourself to MASM? Why not to use a more modern assembler, e.g. NASM or FASM?
 
Last edited:
Also, any specific reason you're restricting yourself to MASM? Why not to use a more modern assembler, e.g. NASM or FASM?
Because MASM is what I was used to, and it's the most common dialect of x86. I also wanted the ability to assemble on DOS to make incremental changes prior to re-burning or re-flashing (E)EPROMs without using an intermediate machine. However, NASM by itself can run on DOS, and it is also written in ANSI C, so basically any platform with an ANSI C compiler/C library will run it, increasing portability. I'll just have to suck it up and learn its idiosyncrasies (Trixter, this is an apology to you for blowing off your suggestion some months back :p).

I decided to scrap the build system I have in place and start with a clean slate. The new build system still requires python, and either pyexpander or m4- preferably the former if I can get it to work. But, this time, it is used to construct the final source file from various source code modules. No need for ifdefs all over the place with this method. NASM can generate a raw binary file without requiring an OMF linker, which is sufficient for BIOS development.
 
Just noticed something peculiar about the Generic XT BIOS... I have included the relevant snippets:


Code:
kosher: POP	DS				; Setup special low vectors
	MOV	Word ptr ES:8,offset int_2	;  ...NMI interrupt
	MOV	Word ptr ES:14h,offset int_5	;  ...print screen interrupt
	MOV	Word ptr ES:7Ch,0		; No special graphics chars.
	MOV	Word ptr ES:7Eh,0		;  ...so zero vector 1Fh
	MOV	DX,61h
	IN	AL,DX				; Read machine flags
	OR	AL,30h				;  ...clear old parity error
	OUT	DX,AL				; Write them back to reset
	AND	AL,0CFh 			;  ...enable parity
	OUT	DX,AL				; Write back, parity enabled
	MOV	AL,80h				;  ...allow NMI interrupts
	OUT	0A0h,AL
	MOV	AX,30h				; Load monochrome
	MOV	DS:10h,AX			;  ...say found
	INT	10h				;  ...initialize
	MOV	AX,20h				; Load CGA 80 x 25
	MOV	DS:10h,AX			;  ...say found
	INT	10h				;  ...initialize
	IN	AL,62h
	AND	AL,0Fh
	MOV	AH,AL
	MOV	AL,0ADh
	OUT	61h,AL
	IN	AL,62h
	MOV	CL,4
	SHL	AL,CL
	OR	AL,AH
	MOV	AH,0
	MOV	DS:10h,AX
	AND	AL,30h				; Test for Video
	JNZ	LE232				;  ...present
	MOV	AX,offset DUMMY 		; No CRT found, dummy INT_10
	MOV	ES:40h,AX			;  ...save offset
	JMP	short	LE235

LE232:	CALL	V_INIT				; Setup video

The first snippet initializes the video by calling int 0x10, ah=0x00 directly, and then reads the XT switches to determine the video mode. First off, isn't that the reverse of what should be done? Next, the equipment word is then checked, and if there is a display detected, the XT BIOS... goes and initializes the display again, but instead by calling V_INIT, which in turn calls int 0x10, ah=0x00! Isn't that redundant?

V_INIT is called twice more later in the code... once during a Parity Check, and again after the keyboard/Video RAM test and before the LPT/Serial port test. The former I can understand the need to init video (parity check can happen when video is disabled/indeterminate), and the latter seems like the CORRECT place to initialize the video... after VRAM is checked, and there's no chance a user will see random garbage due to test patterns.
 
https://github.com/cr1901/pcbios

Not even close to being bootable, but... I think I can actually do it now. DMA refresh works, verified using a logic probe. Next I want to get some video. None of the hardware self-tests are implemented, though I have some commented out. Hardest one so far is checking the flags, since CMP won't work (and I'd STILL like to avoid copying IBM's version).

Trixter, if you are reading this: you were right. I should've used NASM/kept it simple, but I let my ego and desire for too many conflicting goals get in the way. For now, I just want to get a PC version running. Then I'll worry about expanding it to be modular. As of right now, the valuable data is in biosdesc.md. When I complete this document, I'll put away the Tech Ref, and use my own notes to build my own BIOS.

In a sense, building a new BIOS is harder than building the original thanks to all the compatibility stuff that must be done, especially wrt to Entry Points and the Data Area (Example: I have to use the data area how it's used by convention. If I were actually building the original BIOS myself, I think I'd probably store some of the Data Area as stack locals- things local to specific routines, like the last NEC floppy command inputs).
 
Last edited:
Back
Top