|< << 3 of 3 >> >|

Sending network packets

A little sidetrack into the world of PCI probing and NE2000 network card emulation.

Wanted to have a taste of sending and receiving network packets inside my little OS, so I went and implemented PCI scanning (extremely simple) and NE2000 card driver (fairly simple too, their doc is quite good although misses some crucial points).

So, after some fiddling I was able to send a packet and receive it through the bochs virtual network card. I've then connected bochs to the host network card and stared at network packets for a while. Cool stuff.

Here's the screen dump of the sent and then received broadcast packet.

IRQ11 enabled.
Finished initializing NE2000 with MAC b0:c4:20:00:00:00.
Received irq: 0x0000000b
Packet transmitted.
Packet received.
Received packet with status 33 of length 68, next packet at 82

0x004f0064  ff ff ff ff ff ff 28 cf  da 00 99 f5 00 10 48 65  ......(.......He
0x004f0074  6c 6c 6f 20 6e 65 74 20  77 6f 72 6c 64 21 00 00  llo net world!..
0x004f0094  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  ................

sjlj and exception handling

Of course, the clang's implementation of setjmp is very generic and uses quite an abstraction of program state, which makes it hardly suitable for the ad-hoc local exception support I'm using. Since my requirements for setjmp were quite simple (just give me back my damn registers and stack frame), I went and implemented a very custom-tailored versions __sjljeh_setjmp and __sjljeh_longjmp which do just what I need.

With that stuff out of the way, my entire boot sequence now works and I can finally fiddle with more interesting stuff. Type system and introspection, here we go.

Bret Victor's Kill Math

Bret Victors Kill Math

How to stop worrying and love your visualization tools.


The reason for not booting was simple - Clang, seeing that target is Pentium 4 and above, optimized some memmoves into SSE operations. Bochs didn't expect that.

Now everything boots up until exceptions, at which point I believe the __builtin_longjmp primitive fails. Debugging it.

Clanged now

Anyway, I've done doing the craziest port of recent times - at the same time GCC to Clang and from waf 1.5 to 1.6.

Quite a bit of quirks to work around.

waf has changed a lot internally, and from occasional backtraces I still see that I'm using compatibility mode somewhere. Oh well, one day when I'm bored…

Clang is also full of quirks. First, I had to build a cross-gcc for it anyway, because otherwise it totally refuses to link or assemble anything. Second, the freestanding standard C headers are not quite finished it seems - stdint.h for example spits out about 20-30 warnings about redefined macros, so I had to disable -Werror for now just to get it to compile. Third, the generated code, obviously, doesn't run. I got only first couple functions of kickstart bootloader to work in bochs, after that it just GPFs. Now if it keeps raining tomorrow like today, I'll certainly will go and look what happens there, otherwise it might have to wait until next weekend (actually, in two weeks).

Magic Ink

Magic Ink

Highly recommend this read to all programmers and designers. Very inspirational.

It intersects with Metta's ideas of supporting creativity freedom, and is written a lot better than I could ever dream to write myself.

Font rasterization theory and techniques

Font rasterization theory and techniques

Metta MMU module init

MMU initialisation

First off, we start by loading the needed modules - mmu_mod, frames_mod and heap_mod.

mmu_mod will allocate and map the first chunk of memory to use. It does so without knowing much about memory allocation - just takes a first fit chunk from the physical memory map, passed to us by the bootloader. Parts of this memory will be used by frames_mod and heap_mod as well, so we need a way to know how much memory they would need.

Read more →

A historical moment

OMAP3 beagleboard.org # mmcinit
OMAP3 beagleboard.org # fatload mmc 0 0x82000000 kernel.bin
reading kernel.bin
640 bytes read
OMAP3 beagleboard.org # go 0x8200024c
## Starting application at 0x8200024C ...
hello, world!
## Application terminated, rc = 0x0

Metta progress report one

I have cleaned up the booting mess more or less and now my loader is able to enter the root domain - the startup component, which initialises all other components in order and passes control on to userspace loader component, which is supposed to finish system initialisation by starting up all user interface services.

Now there are pretty many loaders here already - there's a first stage loader which is either GRUB or some other kind of boot loader, next there is second stage loader which understands boot protocol, be it multiboot or Linux-style boot or something else and converts all information to format understood by kernel startup, which in turn parses the info from bootinfo page and sets necessary flags, configures necessary platform hardware, prepares memory structures like IDT and GDT and then launches the root domain, which in turn loads all startup modules, initialises them and passes control on to userspace startup component. This is 5 startup stages in all.

Now the design decision in modular system with C++ implementation is separation of component architecture and OO implementation. In component system, nothing is known about component implementation outside of the component and C++ implementation details break at component interface boundary - we want to confine implementation details inside component and expose only a C++ representation of public interface.

Therefore, C++ implementation breaks down to 3 essential parts: C++ implementation, in whatever level of detail we want, from very simple to complex elaborate designs, this is invisible to client code. Second is a thin C-style component interface layer. It is so thin, that I do not want to mess with it manually and it is generated by the IDL stub compiler, meddler. It is also able to generate the third piece - C++ wrapper around C interface that can be used in appropriate way by C++ clients.

Since meddler is still in the works, I generated some C interfaces manually for testing and now implement the memory management components behind those interfaces. Seems to be fairly interesting, since in pre-component design the C++ interfaces were directly exposed to client code and it was fairly easy to change public interface by simply declaring new methods public or private. It was also fairly easy to screw things up, because C++ exposes way too much to clients by default. This is different in component world, you have to be careful with how much of API you expose to clients - what is exposed once remains with this version of interface and has to be supported. Thankfully, I have versioned interfaces and this liability is not forever. On the bright side, only what you exposed will be seen - this makes client interface much thinner and cleaner.

Now on to MMU, frame allocator and stretch allocator implementations.

To remain the web weavers

To remain the web’s weavers and not its ensnared victims, we must merge with our electronic exocortex, wiring greater memory, thought processing and communication abilities directly into our brains.

James Hughen

|< << 3 of 3 >> >|