flat assembler
Message board for the users of flat assembler.

Index > OS Construction > Mathis Operating System

Author
Thread Post new topic Reply to topic
BAiC



Joined: 22 Mar 2011
Posts: 272
Location: California
BAiC
This is my OS work as of yet.

it's an x64 integrated bootloader + kernal founded on the combination of Ordered Ring Buffers, Interrupts and Callbacks to intelligently execute Software without some wannabe dictator playing around with our code. All processor functions which exist for "protection" are effectively disabled. The only protection against bad code is to not allow it to be executed in the first place.

it includes:
Red: A Generalized Interrupt Redirection Table
... which allows the interrupt handler to be modified with little more effort than updating a quadword variable. it also provides the interrupt handler with the Vector Number (in the Accumulator). The first 7 registers are pushed -- and later popped -- onto the stack automatically freeing the handler from that error-prone task.

Intimidation: A Massive 65,536 entry Ordered Ring Buffer for executing blocks of code.
... Each entry has 64 bytes of data available for passing to the code once the processor reaches it. This queue system allows interrupts to continue the primary chunk of their work at a later point once the processor is available for full-force execution.

it includes all of the user-targetted handlers like Mouse and Keyboard drivers. it also includes a basic layering system: when testing in VirtualBox just click the screen and move the mouse to see the text follow the cursor.

A PCI Enumerator is included with a collection of functions needed to access PCI Configuration Space. The Opening Screen shows PCI Config Space data, simply press the down arrow (on the number pad) to scroll through the devices.

rand: a Random Number Generator that I've tied to the Interrupt Redirection Table allowing every interrupt to assist in the generation of that random number.

Instigator: a Generalized Memory Allocator which works on multiples of 64k. The Instant Allocator is founded on a Stack architecture to provide the resource "instantly".

ATAQ: a Hard Disk Ring Buffer for commands to an ATA drive. It uses PIO and Interrupts to process the entries.

GUIL: the 'basic' layering system I referred to earlier. This allows each layer, from bottom to top to draw its' data to the screen each frame (each Real Time Clock interrupt)

Other Drivers:
Classic DMA Code (only used by SB16)
Real Time Clock
Sound Blaster 16 ... uses DMA AutoInit only!
Heartbeat Timer (8253)
Mouse and Keyboard Driver (both PS/2)


BAiC


Last edited by BAiC on 11 Aug 2011, 14:07; edited 6 times in total
Post 08 May 2011, 13:51
View user's profile Send private message Visit poster's website Reply with quote
BAiC



Joined: 22 Mar 2011
Posts: 272
Location: California
BAiC
in VMware Player the Page Up and Page Down keys will scroll the screen more than one line at a time. This doesn't work in VirtualBox.

the counter at the center-bottom of the screen (it's yellow) is the number of cycles burnt by the queue.

the light blue text on the bottom left are the bits of the 3 mouse packets. moving the mouse will update them.

The stuff on the bottom right is a text input area. The keys you press get printed there.
Post 08 May 2011, 13:57
View user's profile Send private message Visit poster's website Reply with quote
BAiC



Joined: 22 Mar 2011
Posts: 272
Location: California
BAiC
The software also includes


Khron: a Timeout Queue.
... the primary loop is invoked every few iterations of the Heartbeat Timer Interrupt. it's role is to iterate through a list of "sleeping" programs and if any of their timer values have been exceeded by RDTSC the code shall wake that program up. it enques the code within the Intimidation Queue allowing the program to wake up with full control of the processor.

There is a library of functions for tasks such as converting a number to an ASCII string (printing it to the screen), a function for printing a block of memory to the screen in a structured format (Hex codes on the left, Ascii codes on the right). it also has functions for printing text to the screen.

each device driver has a complement of functions for dealing with its' respective hardware.
Post 08 May 2011, 15:35
View user's profile Send private message Visit poster's website Reply with quote
BAiC



Joined: 22 Mar 2011
Posts: 272
Location: California
BAiC
Should an exception occur, the code prints the exception number as well as a screenful of the code that caused the exception to the screen using a Red highlight to show the first byte of the instruction that caused the exception. the Queue then moves onto the next entry.

Whatever the flags between the boot procedure and starting the queue are restored when an exception occurs. ensuring the processor state is restored.

BAiC
Post 08 May 2011, 16:02
View user's profile Send private message Visit poster's website Reply with quote
BAiC



Joined: 22 Mar 2011
Posts: 272
Location: California
BAiC
The OS attempts to retrieve an ATA Disks' first block of data during the ATAQ (AT Attachment Queue) activation sequence.

if it finds both the Constant (string) marker, as well as the hash of the labels (and, of course, they agree with the local copy) then it executes it. otherwise it frees the memory and moves on. I would like to eventually add a hash of the actual code to that boot marker.

the "Mathis" Directory is the OS Project Directory (Floppy), using RadAsm, while the Aegis directory is (also with RadAsm) the Boot Disk Image.

Mathis.img is the Floppy Disk image which it boots from. the fasm.ini file is the RadAsm Configuration that I use to highlight custom macros.

while some people prefer to make a file system before a driver I like to "actively develop" so I've left the filesystem on the back burner until recently. The Aegis project assembles to a Hard Disk Image that can be mounted in VirtualBox.
Post 11 May 2011, 13:15
View user's profile Send private message Visit poster's website Reply with quote
BAiC



Joined: 22 Mar 2011
Posts: 272
Location: California
BAiC
Those familiar with the x86-64 architecture will know that the architecture does not directly support any direct "absolute" pointers embedded within the code. What I'm referring to is represented by things like far calls/jumps and the "normal" constant memory references inside instructions like:
Code:
mov [label only], eax    

and
Code:
jmp far Seg:Offset    

the simplest way to get around this is (mostly, far jumps aren't compatible with the example register jumps)
Code:
mov reg, label
mov [reg], eax;eax probably shouldn't be equal to reg.    

Code:
mov reg, label
jmp reg    

the way that most get around this, from what I've read, employs local memory which can be targetted with relative pointers:
Code:
call qword [label]
;.
;.
;.
label: dq Address Of Code    

now, considering the fact that labels are constant (unless you like SMC) the need for such complexity is curious to say the least.

that said, there is some support for absolute pointers even though they may, or may not, be intended: if there is a single GPR register referenced within a memory operand then any constant becomes an absolute value (rather than relative).

if you know what a registers' value is, it can be "piggybacked" upon to retrieve a global value without wasting a register. the simplest case is a loop counter:
Code:
mov ecx, count
mov rax, [rcx-count+AbsoluteLabel]    

by subtracting out the known value in the register the "absolute" pointer remains. I use this method within the 'enQ' macro:
Code:
mov edi, (Intimidation.Q shr line.log) + 1
xadd word [rdi-((Intimidation.Q shr line.log) + 1)+Intimidation.Public], di
shl edi, line.log    

line is an EQU for 64, a cache 'line'. while line.log is the number of bits (6). The full enQ macro is on line 276 of 'struc.asm' inside the Mathis project Directory. it allows for both Position-Dependent code (system functions) as well as Position independent code to allocate entries in the work list without seperating each case into special functions nor including any other special code in the macro.

btw, Intimidation.Public is a ring buffer control variable. every user increments it with xadd and stores their data within the 64byte block of data which gets allocated. when the ring rolls over, it exploits the hardwares "automatic ignorance" of the carry-out to cause rollover.

edit: it should be noted that the Segment Registers mostly don't apply any longer.

BAiC

edit: pardon me, the 0xA1 implicit instruction allows for absolute addressing. it's slightly a moot point however since the implicit register (the Accumulator) needs to be worked around.


Last edited by BAiC on 03 Jul 2011, 01:19; edited 1 time in total
Post 11 May 2011, 14:03
View user's profile Send private message Visit poster's website Reply with quote
BAiC



Joined: 22 Mar 2011
Posts: 272
Location: California
BAiC
In order to provide a general, reliable method of executing code I use the following Structure for my Ring Buffers:

RSI: Points to a region of memory, usually 64bytes, which stores data that needs to be processed while the processor is fully available to do so.

^--The structure of this "packet" always has the 64bit address of the callback in the first 8bytes. The rest of the data is determined by what Ring Buffer it's used by.

RAX: Points to the address. While this is technically unnecssary with position independant pointers it's quite convenient for reducing code density, particularly sign extended byte offsets.

Code:
    .:
        
        mov esi, [.Private]
        cmp esi, [.Public]
        je .Sleep
            
            @@:
                
                shl esi, line.log
                
                readtsc
                psh rax
                
                mov rax, [rsi];rsi is pointing to the data.
                cal rax       ;rax is pointing to the code.
                
               .Circumstances:
                mov esp, StackTop-8
                
                readtsc
                pop rdx
                sub rax,rdx
                add [.Cycles], rax
                
                ;don't trust the registers to be in any specific state after return so reload the pointer.
                mov esi, [.Private]
                inc  si
                
                mov [.Private], esi  ;update the internal work pointer.
                cmp [.Public ], esi  ;compare with the external work pointer. if they're equal then terminate.
                
            jne @b
            
       .Sleep:
        hlt
        
    jmp .    

'trickery' is emplyed in the queue so understanding it may take a second read of the source.

.Private : This is the pointer to the current entry which needs to be worked on. As long as it's not equal to the Public variable there are more entries to work on. This is only written by the loop code (each iteration) it is never written by any other code.

.Public : This is the "public" side of the ring buffer. Every time an entry is allocated the low word of this DWORD is incremented...

The Address of the working region is aligned to 4mb(!), or 64x64kb, which allows the low word of the pointers to "roll over" safely forming the ring buffer. The pointer was pre-normalized to remove the factor of 64 so that a simple shift-left of the register would make it point to the block of memory.

I record timing information for each queue entry:

readtsc : Macro for calculating rdtsc into RAX.
psh rax : simple abbreviation for push. I prefer the 3-letter mnemonics, thats all.

by storing it on the stack, once the call is made the stack becomes aligned to a multiple of 16 which allows code to use the XMM registers on the stack.

for Advanced Functionality, the stack is re-initialized to a fixed location at the end of each entry: the same value it "should" return to by itself. Khron.Sleep uses this to wake up a queue entry at some later point.

Since it's at the root of the CPU-loop, once it runs out of entries it enters the halt (hlt) state to be awoken by an external interrupt such as the Heartbeat Timer. if the interrupt which woke the processor up doesn't add any work to the queue it simply goes to sleep again.

ORB, a FASM struc within the file 'struc.asm' is the generalized form of Intimidation. it eliminates the base address (the pointer) from the value stored in the Public/Private values (requiring a post-retrieval addition operation). The index into the Ring is normalized (shifted left) as close to the end of the DWORD as it needs to be (2^32/(entries in buffer)). unless you want a ring buffer with upwards of 8billion entries I don't suggest changing the code to use qwords Twisted Evil .. Now that's a massive Ring Buffer.

Finally, I must say that these Advanced Ring Buffers are founded on what some programmers consider to be a negative: the rollover effect. obviously, I don't consider it a negative at all Smile

BAiC
Post 11 May 2011, 17:03
View user's profile Send private message Visit poster's website Reply with quote
BAiC



Joined: 22 Mar 2011
Posts: 272
Location: California
BAiC
This new version implements a native x86-64 Floppy Driver. it's an 82077AA. it works in VirtualBox. VirtualBox emulates the hardware at an unrealistic rate (it appears to approach 1megabyte/second) so don't expect the transfer rate to hold in real hardware.

The true transfer rate should be roughly 50kb-100kb.

The Driver is binded with a Queue that orders the transfers to ensure the floppy is properly synchronized with the driver.

the file is 'FloppyQ.asm'

on another note: ATAQ (which the floppy code was derived from) has been disabled until I finish the PCI Bus Mastering DMA. The version of ATAQ in this file is the newest version: the IO Data copying code is gone and won't be returning as it's FAR too costly.
Post 01 Jun 2011, 03:28
View user's profile Send private message Visit poster's website Reply with quote
BAiC



Joined: 22 Mar 2011
Posts: 272
Location: California
BAiC
I made significant improvements to the reliability of the Floppy Driver/Queue. not only does it work in my physical machine and VirtualBox+VMware Player but it also survives significant errors including disk removal .... just don't put in a different disk while it's retrying the command because that's something else entirely.

The PCI Enumerator has been improved.

A new keyboard shortcut scrolls to the current output when you press the letter 'e'. The Page Up / Down keys still scroll at 12 lines per key.
Post 02 Jul 2011, 23:29
View user's profile Send private message Visit poster's website Reply with quote
BAiC



Joined: 22 Mar 2011
Posts: 272
Location: California
BAiC
as anyone who has studied Random Numbers knows, there is no way to ever calculate a True Random Number in a programmatic sequence: therefore, it must be removed from the programmatic sequence.

In order to provide Random Numbers to Applications I bind a small hashing program to the Interrupt Redirection Table handler. Everytime, and I mean everytime, an interrupt occurs this small program reads in the local-most state the processor was in at the time of the interrupt (or near, in the case of time). whether the User moves the mouse, presses a key, or uses some other device with interrupts, the Random Number gets re-hashed. the small, indeterminate differences in Time during Interval interrupts such as the Heartbeat Timer, Real Time Clock, etc even help the random number however it's still the code which was interrupted that provides the most significant chaos in the generator.

Code:
        ;use time to help the random number.
        readtsc
        rol rcx,  cl
        add rcx, rax
        
        ;use the current value of two other registers.
        lea rdx, [rsi+rdi]
        xor rcx, rdx
        ror rcx,  cl
        xor rax, rcx
        
        ;use the stack pointer.
        xor rcx, rsp
        ror rcx,  cl
        xor rax, rsp
        
        ;use the return address.
        xor rcx, [rsp+jack]
        ror rcx,  cl
        ror rax,  cl
        
        ;use the current value of two other registers.
        lea rdx, [r8+r9]
        xor rcx, rdx
        ror rcx,  cl
        xor rax, rcx
        
        xor [rand+8], rcx
        xor [rand+0], rax
    

The function uses the classic 'seed' time -- in the form of RDTSC -- but it also uses the state of some of the registers at the moment of the interrupt (rsi,rdi,r8,r9,rcx,rax,rdx). Also, it uses the location of the Stack and the Address of the interrupted code.

According to Intels' Documentation the precise boundary point for the Instruction Sequence -- and therefore the Stack* -- is subject to runtime considerations which itself is influenced by interrupts. The method of hashing I've chosen is actually very simple: rotate the random data according to the Random Data and blend with the new Source of seed data via xor.

*) When an interrupt fires in Long Mode (Interrupt Gate) the processor internally aligns the stack to 16bytes so the low 4 bits of the Stack are determined.

BAiC
Post 03 Jul 2011, 00:15
View user's profile Send private message Visit poster's website Reply with quote
BAiC



Joined: 22 Mar 2011
Posts: 272
Location: California
BAiC
the file 'fasm.ini' is for RadASM: it includes all of the text-coloring information to help identify special functions/macros/etc.

also, if you're limited on memory -- for example -- and can't assemble the code (it requires upto 300megs) the file 'Mathis.Img' in the Mathis folder is the last-built version.

if you assemble inside RadASM (by opening the project file) the settings are already there. however, if you assemble using a command line you may want to specify memory usage explicitly:

Code:
FASM -m 300000 "Mathis.asm" "Mathis.img"    

my laptop, for example, will fail to assemble the code without this.
Post 03 Jul 2011, 01:11
View user's profile Send private message Visit poster's website Reply with quote
Display posts from previous:
Post new topic Reply to topic

Jump to:  


< Last Thread | Next Thread >
Forum Rules:
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum
You cannot attach files in this forum
You can download files in this forum


Copyright © 1999-2020, Tomasz Grysztar. Also on GitHub, YouTube, Twitter.

Website powered by rwasa.