Alcor BIOS is a program for AlcorPC (previously FizykPC), that makes using various high-speed components easier. I wrote it some time ago, giving it support for console screen, keyboard and some system functions, details are below. Recently, for a week or two I have been working on some new functions: ones, that add filesystem functionality. Now they are almost complete, so I decided to publish the changes.
You can download it from the attachments, or get it from GWCD SVN at https://svn.wireos.com:81/svn/gwcd_cpu/
What can it do?
Well, I created my BIOS to provide some functions to make writing programs using console screen and keyboard easier. It has system functions, like writing string on the screen, reading string from the keyboard; screen functions - outputting single characters, refreshing the screen, turning the screen on and off etc.; keyboard functions - reading one key from the keyboard, or checking if a key is pressed; FAT functions - create a file, open, read, write, delete. It also supports up to 1 MB of additional RAM and one extra slot for inserting cartridges with programs to boot. In my dupe file you can find a computer, that has 192kB of RAM (CPU + 128kB chip), slot for a cartridge (now called floppy) and 256kB wire EEPROM as a HDD.
Also there are now memory management functions available. They are functions 20-22 of interrupt 32. Use them when you need some memory to make sure that you don't overwrite some needed data.
How do I use it?
There was a guide here, describing how to build your own computer, but this became pretty complicated, so I'll just describe the dupe of the computer instead (available via GWCD SVN).
The computer consists of some circuits (
), the console screen, the keyboard, the HDD (Wire Flash), 1 floppy slot and 3 device slots.
I think the console screen and the keyboard don't need descriptions 
The floppy slot is used to launch programs/dump them to the HDD. It is the first place the BIOS will try to load a program from, only if there is no floppy inserted, it will try to boot from the HDD.
The device slots are a new thing. They allow to connect up to 3 devices, which can use up to 1 MB of memory each (like the digital screen does). There is a new function in interrupt 32, which returns the addresses of respective slots (in case I will change the memory layout again).
The freshly spawned PC with no floppy inserted will start, detect available memory, say that there is no floppy and try to boot from a HDD. Probably you have no boot program on the HDD from the start, so it will say "HDD is not bootable" and stop. If you want it to do something more, you will need to insert a floppy with a program.
To build a floppy, just wire a CPU to a Data Plug and it's ready. You can also download a dupe of an empty cartridge from here. Then upload a program to it.
How to write a program for my BIOS
It's pretty easy. In general, programs for my BIOS should look like that:
Code:
db programsize
//code
//code
//code
//...
This way the first byte of the program is the size of the program itself. My BIOS copies whole program on startup to the main RAM, so that it can use more than 64 kB of memory (though the program itself can't exceed this limit). In order to copy the whole program and only the program, it needs to know it's size.
After 'db programsize' you can write any code like you write for an empty CPU. But you can also use the functions provided by the BIOS! It's how you do it:
BIOS functions
The BIOS provides it's functions through interrupts. There are 5 interrupts at the moment:
1. int 32 - system interrupt
2. int 33 - screen interrupt
3. int 34 - keyboard interrupt
4. int 35 - FAT interrupt
5. int 37 - process/DLL interrupt (only DLL at the moment)
In order to use a function, you pass it's number in eax (and sometimes ebx), some parameters if needed and invoke an interrupt. Isn't it easy?
For example, if you want to display text, you use function 9 from interrupt 32, like this:
Code:
db programsize
jmp codestart
txt:
db 'Hello World!',0
codestart:
mov eax,9
mov esi,txt
int 32
Function 9 needs one parameter: ds:#esi pointing to a zero-terminated string. The DS register is initialized properly by the BIOS on startup, so you needn't worry about it. You only need to setup the esi register and it's ready.
How to write DLLs
Recently I added a new functionality to my BIOS, which is the ability to handle simple DLLs, or libraries of functions, whatever you want to call them. This short guide will show you how to write DLLs and how to use them.
A DLL should have the following format:
Code:
db programsize
db number_of_functions
db name_of_function1,function1
db name_of_function2,function2
...
name_of_function1:
db 'some_name',0
name_of_function2:
db 'some_other_name',0
...
function1:
push ebp
mov ebp,esp
add ebp,4
//function body
pop ebp
retf
function2:
...
retf
...
Ok, now what is what.
"db programsize" has the same function as in normal programs - it lets the BIOS know how long is the code. Nothing new here.
Now for the next lines. "db number_of_functions" means how many functions you are "exporting". This is mostly to determine the size of the function table, which goes next.
The function table connects the function offsets with their names. It should have number_of_functions entries, and each entry should consist of an offset of the name of a function, and an offset of the function body itself.
The names and functions have to be defined somewhere. In my example function names go first and then goes the actual code, but it doesn't matter. It could be mixed up in any way you desire, the important thing is the function table.
Now, as you probably noticed, the function bodies look a bit strange. That's because I suggest that the functions follow the C-style calling convention. The parameters are pushed on stack, and you use EBP to get to them. After adding 4 to EBP, like in the example, SS:#EBP will be the last parameter on the stack. To get to the earlier ones, you have to increase EBP.
DLL functions should end with "retf". They are called using far calls, so they have to return with "retf".
Calling the functions from the DLLs
How to call the functions? First, you need to load a library, using function 10 from int 37 (see docs below). The path to the library has to be a full path at the moment (that is, for example '/dlls/library.dll'). If the function succeeds, the segment of the library is returned in eax. Save it somewhere.
Then you need to get an offset of a function. You can do that using function 11, or function 13 if you intend to use multiple functions from the DLL.
Now you can call the function. To do that, you use code like this:
Code:
push argument1
push argument2
...
callf function_offset,library_segment
add esp,number_of_arguments
After you made all the calls you wanted to make, free the library using function 12.
BIOS function reference
Each function is described as number passed in eax, needed parameters and return values. Also in italics there is syntax for this function in bios_lib.c.
Int 32 - system interrupt
Function: eax = 8 - read string from keyboard
readln(buffer,size)
Parameters: ds:#esi - buffer, ecx - size of buffer
Function reads characters from keyboard until user presses enter or the buffer is full. It stores the characters in the buffer. It can recognize backspace.
Function: eax = 9 - write string to the screen
printf(text)
Parameters: ds:#esi - null-terminated string
Function writes a string to the screen. It can recognize characters with code 10 as new lines.
Function: eax = 10 - print a floating-point number on the screen
printnum(num,prec)
Parameters: edx - number, esi - decimal precision (of 10^esi)
Function writes a decimal number on the screen. The decimal precision tells how many digits it should write. esi = 0 makes it write the number as a whole number. esi = -1 makes it write a number up to 1 place after the decimal point etc.
Function: eax = 20 - allocate memory
Parameters: ecx = number of bytes
Returns: eax = absolute address of the allocated block or -1 if failed
Function allocates a block of memory and returns a pointer to it.
Function: eax = 21 - realloc()
Parameters: ebx = address of the block, ecx = desired size
Returns: eax = new block
Function changes size of the block pointed by ebx. If the block was moved somewhere else, all data is copied.
Function: eax = 22 - free allocated block
Parameters: ebx = address of the block
Function frees previously allocated memory.
Function: eax = 30 - get device address
Parameters: ebx = number of a device
Returns: eax = address of the device
Possible numbers of devices: 0 = floppy, 1 = HDD, 2 = device slot #1, 3 = device slot #2, 4 = device slot #3. The address returned is an absolute address.
Int 33 - screen interrupt
Function: eax = 0 - screen control
Subfunctions:
ebx = 0 - clear screen - scr_clrscr()
ebx = 1 - set Clk; Params: ecx = desired value of Clk - scr_setclk(clk)
Function: eax = 1 - GotoXY
scr_gotoxy(x,y)
Parameters: ecx = X, edx = Y
Function moves the cursor to the point (X,Y) on the screen.
Function: eax = 2 - Putchar
scr_putchar(c)
Parameters: edx - character
Function puts a character from edx on the screen and moves the cursor.
Function: eax = 3 - Setparam
scr_setparam(param)
Parameters: edx = parameter
Function sets current text parameter (text color and background color) to this in edx.
Function: eax = 4 - GetData
scr_getdata(x,y,param) (Important! x,y and param are of type int*, so the values are returned in places pointed by the parameters)
Parameters: none
Returns: ecx = X, edx = Y, ebx = parameter
Function returns current X and Y of the cursor and current text parameter.
Function eax = 255 - refresh the screen
scr_refresh()
Parameters: none
Function refreshes the screen. It is required to call this function every time you make a change on the screen using the screen interrupt - the system interrupt does it by itself.
Int 34 - keyboard interrupt
Function: eax = 0 - read a character
keyb_readkey()
Parameters: none
Returns: eax = character
Function reads one character from keyboard and returns it. If the keyboard buffer is empty, it waits until a key is pressed.
Function: eax = 1 - check if a key is pressed
keyb_keypressed()
Parameters: none
Returns: eax = {1 - key was pressed, 0 - no key was pressed}
Function checks if a key was pressed.
Function: eax = 2 - check if certain key is pressed
keyb_getkeystate(key)
Parameters: edx = key
Returns: eax = {1 - key is pressed, 0 - key is not pressed}
Function checks if a certain key is currently being pressed.
Int 35 - FAT interrupt
Function: eax = 0 - format the HDD
Parameters: none
Function writes an empty FAT filesystem to the wire HDD. Just like in a normal computer, you will lose all data stored before formatting.
Function: eax = 1 - create a file
file_create(name,attrib)
Parameters: ds:esi = path to file (for example '/folder1/folder2/file.txt'), edx - attributes (currently 0=file, 1=directory)
Returns: eax = handle of the file or -1 if failed
Function creates a file and returns its handle, which then can be used to perform read/write operations. If the file existed before, it zeroes its size.
Function: eax = 2 - open a file
file_open(name)
Parameters: ds:esi = path to file
Returns: eax = handle
Function opens an existing file and returns the handle.
Function: eax = 3 - close a file
file_close(handle)
Parameters: ebx = handle
Function closes an opened file. You should always use this after all work with the file is done.
Function: eax = 4 - read from a file
file_read(handle,buffer,start,count)
Parameters: ebx = handle, ecx = number of bytes, edx = starting position, es:edi = buffer
Function reads ecx bytes from a file and stores them in a buffer pointed by es:edi.
Function: eax = 5 - write to a file
file_write(handle,buffer,start,count)
Parameters: ebx = handle, ecx = number of bytes, edx = starting position, ds:esi = buffer
Function writes ecx bytes from buffer pointed by ds:esi to a file.
Function: eax = 6 - delete a file
file_delete(name)
Parameters: ds:esi = path to the file
Function deletes a file.
Int 37 - process/DLL interrupt
Function: eax = 10 - load library
Parameters: ds:esi = path to the library
Returns: eax = library handle (and segment at the same time)
Function loads a DLL library into the memory, and returns a segment that contains the library. It should be used later as a library handle, and in far calls to the library functions.
Function: eax = 11 - get function address
Parameters: gs = library handle/segment, ds:esi = function name
Returns: eax = offset of the function, or -1 if not found.
Function translates a function name to an offset, which is then used to call the DLL routine.
Function: eax = 12 - free library
Parameters: gs = library handle/segment
Returns: none
Function unloads a library from the memory. Call this function when you will no longer use a DLL.
Function: eax = 13 - get addresses of a table of functions
Parameters: gs = library handle/segment, ds:esi = function table
Returns: none
This function is there to make it easier to get offsets of multiple functions at once. Format of the table passed through ds:esi:
Code:
Offset 0 = number of functions
Offset 2N-1 = address of the name of N-th function
Offset 2N = address of a place for the offset of the N-th function - the interrupt will place the offset here
Example:
Code:
function_table:
db 2
db txt_function1,function1
db txt_function2,function2
txt_function1:
db 'function1',0
txt_function2:
db 'function2',0
alloc function1
alloc function2
This will load offsets of functions named "function1" and "function2" to variables "function1" and "function2".
Screenshots
You can see some screenshots in the attachment. They show a bit of my upcoming Alcyone OS. Currently it is only an installer, that puts a "Hello World"-type file named kernel.bin on the wire HDD, which can then be booted. Screens show the installer's functions "info" and "format" and also booted kernel.bin, showing "Starting Alcyone v0.01".
Attachments
alcorpc_test.txt - A dupe of a test computer. It is not the final version, this one is only for testing purposes.
cartridge.txt - A dupe of an empty cartridge, if you don't want to make one yourself or didn't understand how to do it. Ready to upload a program into it.
alcorbios.txt - The source of the BIOS (v0.83).
bios_lib.txt - A C library that provides wrappers for most of the BIOS functions. Rename it to bios_lib.c (vBulletin doesn't allow .c files) and enjoy!
Bookmarks