This is a popular discussion, that I know all of us probably want to put our
two-cents in for. So I thought I'd bring it up here, before any of us wander
off into tangents that we'll have to back out of later. (At least if we are
going to wander into a tangent, we need to do it as a group.)
Honestly, the biggest decision we have to make right now, is not the design
itself - but how anally-retentive we want to be about it. We don't have the
resources to sit down, and learn the ins and outs, of every architecture, to
do cross-comparisons. So in the end, we need to agree more on our process
than our approach - because we will probably end up completely refactoring a
few times. (And there are design decisions that in-and-of themselves, can
make this easier - like interface versioning.)
- As I understand it, some things work the same everywhere - like PCI.
And some things don't - like writing to I/O ports. So we need an abstraction
that can handle at least most kinds of allocatable/reservable hardware
resources. The abstraction needs to address which devices have which
resources, which devices *need* which resources, how to resolve them both,
and how to gracefully handle a failed attempt at such.
- Another issue, is device discovery and driver inter-dependencies. A
possible approach is having drivers designate, either through an interface,
or more likely through driver-type metadata (attributes), what kinds of
devices they can handle.
- On-board system devices, if exposed, need to be exposed abstractly -
including the PIT, the interrupt table, and any other motherboard/CPU
capability that is detectable programmatically.
- And last but foremost, we need to make everything "safe". That means
drivers will not be using pointers, nor I/O ports, directly. My best
suggestion is to wrap anything with an inherent write or read paradigm, as a
stream. An I/O port stream wraps ADC I/O port functionality. A memory buffer
stream (akin or maybe identical to, or replacing, a MemoryStream) wraps a
pointer and any ADC/Assembler functions available for fast memory writing.
This is where our power, yet safety, comes from. An example benefit
is, when we start talking about distributed usage of hardware - we could
literally run a driver on one machine against the raw hardware of another -
by marshalling the stream operations. (Would it not be good for debugging?)
Other "safe"ty issues involve using things like delegates,
exceptions, etc., to fully leverage the runtime's power.
Some other miscellaneous food for thought:
- ADC is not hardware. ADC should be dumbed down as much as possible
- and the namespaces should be completely seperate. SharpOS.Kernel.ADC&
SharpOS.Kernel.Hardware , or something along those lines.
Examples of ADC:
- Copying chunks of memory using Assembler instructions
- Reading CPUID and returning bitmasks (represented by masked
enum values) of its features (or a nicer abstraction of boolean
properties)
- Reading and writing to I/O ports
- Assigning/changing interrupt handlers
- Determining the cursor location on the text-mode screen
- Writing color codes and ASCII characters to the text-mode
screen
- Retrieving multiboot information
- Context switching
- Halting the processor
Examples of "Hardware" or kernel functions that are otherwise
*not* ADC:
- Interrupt handling (because they are being handled by objects
designed to do so)
- Providing and tracking output to the screen
- Writing to the serial port
- Task scheduling
- Enumerating PCI devices
A good example of "not ADC" is memory allocation. This is more
of a runtime issue. Sure, it has to figure out how much RAM is
available -
which is architecture-dependent. But the actual allocation, and
tracking of
allocations, is as generic as it gets.
- Basically, its only ADC if it is a static function. And ADC
should *only* be static functions, for performance reasons. My assumption
is, if for some reason, you need local context information to handle an
incoming function call, then you are doing something that *in general* is
not architecture-specific. And since static method calls are quicker than
VTable lookups, we need to keep our abstractions in check. Constant
vigilance!
- Another miscellaneous food for thought is pointer usage. If you are
writing code against the architecture, or against memory, that requires the
representation of a memory address: we need to stop using 'uint' just
because we are assuming we are working on 32-bit x86. " void* " exists for a
reason...
- Just because we want to use IPC for drivers doesn't mean we *should*
anytime soon. Any good marshalling IPC scheme should be pretty seamless
anyway, and it is more important for us to get hardware stuff of the ground.
- And no matter what, for debugging purposes, we need to retain
static-buffer-based string operations and screen/serial I/O - so that if
something gets horribly screwed up, we can figure out what's going on.
These are my ramblings. Amend, comment on, and dispute them as you like. The
more talk, the better the results!
-------------------------------------------------------------------------
This SF.net email is sponsored by: Microsoft
Defy all challenges. Microsoft(R) Visual Studio 2008.
http://clk.atdmt.com/MRT/go/vse0120000070mrt/direct/01/
_______________________________________________
SharpOS-Developers mailing list
SharpOS-Developers@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/sharpos-developers