flat assembler
Message board for the users of flat assembler.
Index
> OS Construction > Mathis Operating System |
Author |
|
BAiC 08 May 2011, 13:57
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. |
|||
08 May 2011, 13:57 |
|
BAiC 08 May 2011, 15:35
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. |
|||
08 May 2011, 15:35 |
|
BAiC 08 May 2011, 16:02
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 |
|||
08 May 2011, 16:02 |
|
BAiC 11 May 2011, 13:15
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. |
|||
11 May 2011, 13:15 |
|
BAiC 11 May 2011, 14:03
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 |
|||
11 May 2011, 14:03 |
|
BAiC 11 May 2011, 17:03
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 .. 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 BAiC |
|||
11 May 2011, 17:03 |
|
BAiC 01 Jun 2011, 03:28
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. |
|||
01 Jun 2011, 03:28 |
|
BAiC 02 Jul 2011, 23:29
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. |
|||
02 Jul 2011, 23:29 |
|
BAiC 03 Jul 2011, 00:15
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 |
|||
03 Jul 2011, 00:15 |
|
BAiC 03 Jul 2011, 01:11
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. |
|||
03 Jul 2011, 01:11 |
|
< Last Thread | Next Thread > |
Forum Rules:
|
Copyright © 1999-2024, Tomasz Grysztar. Also on GitHub, YouTube.
Website powered by rwasa.