 Let's write an operating system or at least port an operating system that someone has already written Because writing our own sounds like work So what I've got here is a copy of Alan Cox's physics operating system which is a very small Unix alike operating system for platforms like the Z80 the 8080 and so on it provides most of a Reasonable Unix like operating environment with multiple processors normal file system binaries etc except it will run on tiny platforms and Also here I have One of these or at least a gray market clone of one of these this is a ESP 8266 Wi-Fi module they are absurdly cheap I Think I spent a little bit more for mine which turned out not to be real But seems to work anyway They are based around a 32-bit microcontroller with 96 K of data RAM 64 K of Instruction RAM and a decent chunk of flash. I don't actually know how much flash mine has They're mostly intended to be used as turnkey Internet of things devices where you write your program blow it onto the flash and Run it from there. However, because it's got instruction RAM Which can be used to run code out of we should be able to run a real operating system on it And I'm going to give a decent try at porting physics To the ESP 8266 Now this is actually going to be a series I Doubt very much whether I'm going to finish this in one chunk of work and in fact, I'm not intending to so Rather than the epic nine-hour videos. I'm going to producing some short videos Working through porting this thing. It's a fairly large job So we'll see how it goes. I have done this before I've ported physics to both the Raspberry Pi and the MSP 430 another tiny microcontroller But various issues meant that it never got upstreamed. I'm hoping this one will actually get upstreamed Now I did do some pre-work Where I got a basic hello world running on the platform So it's built. I can use this command line to burn it onto the device Which is connected via USB connect up a TTY and I'm in the wrong directory again And it works. I need to hit the reset button to make it actually run There we go. I Don't know what the garbage is. It seems to be something produced by the device's bootrom It then takes a little bit of time for the you are to get into working orders. So the Hello fails But It does work. So we have us. We have it actually running code So from here We're going to expand this into a complete kernel port Okay, about the ESP 8266 It's based around a extensor LX 6 Processor which is kind of weird The extensor architecture is designed to be expanded by end users So the CPU it's actually got is a thing called the LX 106 For which there is practically no documentation. So what I've got here is the base documentation for the extensor Instruction set which should work. I shouldn't have to write actual machine code very much for this a little bit but not much It's a 32-bit CPU with 26-bit instructions, which is interesting It's got 16 registers. There's a There's a register window system that I believe the LX 106 doesn't have it's an optional extra It's a little bit weird, but seems to work pretty well I can Use this disassembler. It's well covered by GCC and bin utils. I Just installed this toolchain off Debian, which is nice So this is the program here that I wrote to it so Let me find some actual code and not some data Not that it's the main Here we go. Here is the main program, which is this A1 is the stack pointer. So this is allocating stack frame This doors a 12 onto the stack frame this loads of value via the Program counter relative addressing and so on there's nothing particularly exciting about it You notice here are the 24-bit instructions However, the LX 106 has the option where some instructions can be represented in 16 bits for increased code density now over here I have a Disassembly of the entire boot ROM which is on the device. This is not the flash This is mask ROM, which is part of the The module I've got this because it provides a very useful reference for things like memory areas and I will need to know how some of the ROM works You see the thing about the ESP 8266 is the ROM is always in control. There's quite a lot of code in it It things like the interrupt vectors are always rooted through the ROM So we have to use the ROM's Functionality to do things like register interrupts. It's actually got some pretty useful stuff in it So we're going to use that as well, but we have to have it We can't simply load our operating system and ignore it now here is the memory map of the device and Just like the rest of the ESP 8266 the memory map is kind of weird now the useful bits for us are These blocks this is the RAM it's got 96 K divided into two contiguous areas The first area is not used at all by the system The second area this one is Used by the ROM for things like interrupt vector tables and it also has the default stack in it The usage of this is not very well known It's a whole 16 K. So it's actually been rather nice to be able to use some of that But we'll see I'm going to ignore it for the time being Here is the 64 K boot ROM. This is the thing that's in this file and here Is the 64 K of instruction RAM? Instruction RAM is weird. It can be read and written using normal data operations But only 32-bit ones. It doesn't support reading bytes or shorts at all its primary purpose is for actually executing code and The thing is that because this is RAM Then if you power it down or your code gets lost, which is where this comes in This is where the flash chip is mapped Unfortunately The flash chip is a SPI serial flash device, which means the CPU cannot actually run code from it So what it's got instead is a rather odd system where it will essentially demand page code from the flash Which will show up to use a code as being in this memory block However, the code is actually executed from these two instruction RAM cache blocks So what happens is that once it's set up you? Jump to an address here The CPU will then intercept the load the instruction load It will look to see if that instruction is somewhere in the cache if it's not it will load a chunk from the SPI flash into the cache and Then execute it using some kind of hidden memory management system to make it look as if it's coming from here this is pretty cunning as it allows you to have like a complete megabyte of flash code Which is just like code you can execute Although I do notice that this number here is wrong Without actually having to either memory map a real nor flash device which are expensive or To copy code into RAM it's done automatically here so because there's actually a reasonable chunk of complexity here this means that We have to use the bootloader to Load our code out of flash Because when the systems turned on none of this stuff is set up yet So the only code that couldn't execute is here in the boot ROM So when you start up the system what it will do is it will copy a chunk of data from the flash Are you seeing normal? SPI load and save routines none of the memory map stuff into this 32k block and And You then get 32k worth of code to play with in order to set up the rest of your system Which normally involves initializing this stuff Once that's done you can then use this block of instruction RAM for anything you like so Let's go back to this disassembly There are our very small operating system image starts at this address Which of course corresponds to the instruction RAM because this is code that the bootloader has copied into the instruction RAM and After initialization the bootloader will then jump to the entry point routine, which is here This code actually belongs in boot.c, which is this So what we do is We set the system clock. We're using the default value of 52 megahertz because that's easily fast enough You can run these things up to 350 which is kind of impressive And then we set up the UART to allow us to Actually send text to the system We then Enable the SPI flash memory mapping stuff once this is done. We can then execute code from flash following from that We have a simple loop that just initializes the bss Memory in the kernel to zeros bss memory is variables to look like that See defines these have to be initialized to zero. So this is the code that does it if It looks like that Then this is actually initialized in a different way what happens here is the Compiler will generate a chunk of data that lives in the flash that the bootloader then copies into RAM But that's done for us. I Hope we'll find out that later. So we shouldn't have to worry about it. And once that's done we then call main which lives at Lives at the flash address. So here Nope This is the bss initialization stuff Here is where we call main so this loads the address of the main function and This calls it and then we have some unused code to Terminate the subroutine now main itself lives here 402 1 0 0 8 which if we go back to the memory map is In the flash block it's 64 K advance from the beginning of the flash because that's 64 K contains both the 32 K of initial code and Various fields like headers addresses where the entry point is the Data the initial the initial data Etc. Etc. So Once we get to here, we should have a full running execution environment Now I should add that most people who program the ESP 8266 don't do this. This is bare metal programming. What they usually do is use one of These SDKs which are provided by Espressif Espressif Espressif The people who make the module These contain huge libraries of useful routines including things like Wi-Fi TCP IP stack timers File system etc. Etc. We're going to be using none of that. We're doing it all from scratch All right then So where do we start well The first thing is to go look at another port. This is the Atari ST port and In here We should find The initial piece of code that gets executed. It's back not there. Okay. Let's go look at a different one This is the one I'm more familiar with Sadly this particular port got bit rotted and no longer works Okay, I am familiar with the source code, but it has been a while so Somewhere in here should be the routine that actually gets executed I thought it was going to be in main dot C, but apparently it's not So this has got stuff to initialize. This is the Atari ST So it initializes things like the memory map the memory management unit Okay So let's just do this the old-fashioned way right CRT zero s this is The initial piece of code that gets executed on system startup on the Atari ST So we can actually see Yes, I've forgotten this right physics main is the Kernel's main entry point, but it doesn't belong in the platform directory. It's part of the the general physics source code That's one of these files Probably start dot C This stuff is all platform independent I've already got the here we go physics main I've already got the build system working So we this is all actually being built. It's just not linked into anything. So we don't have to worry about that So what we're gonna have to do first is call Well, turn the interrupts off In fact, we need to add some routines to turn interrupts on and off normally you do this stuff in Machine code, but it's easier to do it in C So let's do that that gets built up here. We have not to find a D. I There's also a set of directories containing CPU specific stuff and the EI and DI routines Were in here the last time I saw them, but they're not now Okay, so that has actually changed since the last time I Touched this So let's look so this has got some low-level stuff to do with process switching. I'm actually looking for No, let's try Yeah Right, this is ultra low-level machine code routines. That's a division routine Now this is all math stuff exception handler great Okay Interesting. Well, this is kind of less than impressive. I'll show you how it used to work This is the MSP 431 which is bit rotted and hasn't been updated. So you used to provide II DI and IRQ restore functions which turned interrupts on turn them off and return the old interrupt state and restored the state so Let's actually look for IRQ door Okay, that still exists So IRQ door right that seems to be what it's called now and there's a Configuration options soft IRQ. That's a new one on me. What does this do? Okay, so it sounds like we don't want Soft IRQ to be enabled. This is our physics configuration file Okay, that's added the prototype, but we still need the definition of Hard DI now where does that live? hard to DI goes in Find a platform that actually is probably up to date Hmm Or maybe it's in a low-level Yes, it is. Okay So we need to create a low-level routine a low-level file Apparently I already did and we need to add our interrupt routines to this and then hook that up to the build system So let's find This one which I understand but which doesn't use hard DI. Let's try This one which I understand Okay, and let's just set these to be I think that's the right The right instruction and return from interrupt Yep I The way Rhett works on the LX6 is it actually jumps to a Zero which I believe is the link register The dot n just means it's the small form with luck the assembly will take care of this for us Let me try and find a reason a routine that actually uses a stack frame. Yeah, here we go So Rand The first thing we do on entry well, we'd be load some constants and to registers We allocate a stack frame. We save the old link register a zero onto the stack frame At the end what we do is we load a zero out of the stack frame Retract over the stack frame and call Rhett So that should work. I mean you won't do anything, but it should work Save that why isn't my build thing triggered because I need to capital S assembly files Okay, that should be global gas assembler syntax is Weirdly variable Here is the make file for our kernel Let me see how those worked. This does not refer to the low-level routine which makes me think that It belongs somewhere else about the make file here Yeah, okay, we should get that automatically So the top-level kernel make file seems to include the relevant File for us, but it does need to get added to the Link list. So where does that happen? Let's try a Different one. Let's try the Atari ST port again. Oh, I bet it you see this is changing a sources and a object which are the variables for Object files and things But this is actually assigning it and so is our make file here so One of them is going to win. Ah Yeah, I don't know how the Z80 pack one worked, but this one is obviously just we refer to the file in the link list and it does it Yeah, I I'm not a fan of the physics build system, which is Lots of nested make files. However, I did actually try at one point to fix it and it was a complete utter disaster Which I still feel embarrassed about so I'm not going to complain just stick with it so we want x106.0 and That has not worked Why has that not worked? probably due to Too many underscores So some C compilers Some platforms rather Traditionally add an underscore into the front of symbols when they pass through the C compiler Some don't right and it appears that the LX 106 is one of the ones that doesn't so We now actually need to figure out how to turn interrupts on and off and You know do it so Here we are in the boot ROM now There are routines here for doing things like turning interrupts on and off I'm wondering if we can actually get away with using them We are going to need to use the the boot ROMs Interrupt vector table so the way you do this is you load a value into a register and you use the WSR command to actually do stuff to Special registers So let me just find RSR is read special register, and I don't know the difference in interrupt internable. So Let's just go and have a look at this Enable special register. There are no hyperlink so H2 3 1 Yeah So nice if you could actually type in a page number and have it go there right into enable That's a hyperlink right this. Yeah, this is an interrupt mask The LX-6 has support for multiple different interrupts in different priorities that can be turned on and off well, I know therefore that when turning interrupts off we are going to want to read the internable register into A zero is the link register a one is the stack pointer. So a two is a General-purpose register. I'll have to go look up the ABI actually I Need to look up which register is Alt-going arguments turn address and stack pointer a to an ace day two to a seven of the incoming arguments So our return values R2 to our five okay, so a two is the return value which is correct we want to Return the old interrupt state in a two so here we then going to load zero into a three and write that and Set that as the current interrupt status and it even built So Restoring This passes in a interrupt status that we've had from here In a two so all we need to do is do Enable a to ret That will set the interrupt status to Whatever it was in To whatever got it will set the interrupt state to whatever it was before the user called di Now enabling the interrupts is going to be interesting Because I think we need to know What the Value we need to write to set all the to enable all the interrupts We could just write minus one that would probably work. This is the boot ROMs routine to Actually turn interrupts on so we can see here it's setting the value in a five A five is anded a six is storing a five I Don't know what our seal does right this is to do with register windows which I Think we are not supporting. I think we're not supporting If we are supporting it then that's going to make doing things like process switching tricky But there's a lot of stuff in the boot ROM that's not used. All right Let's Just set Let's see if that works. So that should enable everything Here is where we are calling our di routine Yeah, we should be able to do it cleverer than that. But anyway Di is That's interesting. Oh Right So what I'm seeing here is that all these routines are in the image even though we're only calling one of them This is because I actually need to do Need to do this put them into separate sections This then allows the linker to only include the sections that Are actually used The align for is because all entry points must be for aligned on the LX 106 so Yeah, I seem to have somehow told it to disassemble all the debug sections. Let's do that instead Really what I expected to be honest thing is what we're seeing here is that the source code Doesn't match the disassembly That implies that this has not actually assembled anything Right, that's a dependency bug in my make file Yeah Okay, I'm gonna have to do this the make file didn't know that I wanted it to Relink the kernel because I didn't give it enough information. Okay, right that's now working And to find reference to hard DI Should be defined in here, okay right now it's complaining about the things I did wrong in the machine code Of which there's quite a lot of it. Well for a start. It's just tried to compile that with CC which is somewhat wrong So it should have used cross CC to assemble it Yeah, the way porting operating systems works is you spend ages on tiny minutiae at the beginning and Then you start making huge steps forward as big chunks of stuff start working and Then you spend ages on tiny minutiae at the end in order to try and fix the last few bugs So if it seems like I'm spending a lot of time just trying to set interrupts on and off, you're right So in the CPU directory There should be some rules that allow that tell it how to build things. I know what's happened. I Know what's happened. It's nested make files. This make file is trying to assemble the This file, but I haven't told it how So why isn't the kernel make file? Trying to do it. So what's it doing with a obj that goes to Obs It's only trying to assemble this because there is it hasn't assembled The file in the kernel make file. There should be a dot-o file there. I have defined cross AS So that should be Right, we've got cross a scene cross SS cross CC and cross AS this is the C compiler for the LX 106 you've got these set correctly. This is the full list of object files Unfortunately, I don't think they're sorted So when we when we build everything it does not in fact so what it should be doing is building all the top-level stuff All the generic kernel stuff Then it should be executing the make file in here to actually link it all together So I've done that right So it is calling platform ESP 66 This looks So this is saying that it needs to build the platform before it builds any of the objects files, which seems wrong Okay, I think this is another case where Things now work differently than they did last time. So you see here is the rule that builds the The image and it is referring to files to find in at a higher level So like that syscall croc, it's not to find anywhere in there Let's just try building that need to install The tool chain if I if it's in Debian It's not there are several sixty eight K tool chains in Debian. Just not that one So what platforms can I try? the 8080 Needs the ACK which I actually have installed It needs a patched ACK which I don't have installed Let's try the Sam Coupe That uses SDCC which I've got it's now building up to a point and then it fails It could be that the Atari ST platforms bit rotted. It does kind of tend to Hmm, I did just update from the master branch. So It should be up to date. This is another Z80 platform SDCC is a painfully slow compiler. The Z80 is a pig to compile for due to its Extremely unorthogonal and rather weird Rather weird instruction set, but I'm a bit surprised to be honest This is another of my ports. It's been a while since I've touched this interesting is My SDCC out of date. You see this is why I'm not a particular fan of the build system. It's just difficult to Get that one also needs UC Linux 68k x2 the MSX is a fairly high spec Z80 machine that was pretty popular So should be people using this this one should be up to date Also, the build system doesn't do parallel builds So my 8 core computer is not at its best. Great Okay, so Something's not right Let's see if we can work around that by putting this in here, okay Right that works What happened here is My make file built this This allowed the Okay, right and now I slightly understand how this works This make file gets executed twice. The first time is to build the object The second time is to build the image so Do not like multi-pass make files. So if we do a clean write so the first Yeah, yeah The first time through it's trying to build everything in this list But it doesn't know how to build this so it defaults to the old CC rule the second time through and All the object files have been built So we don't need to add it to the dependency list Except that if we don't add it to the dependency list this rule will not get invoked at all because The make file doesn't know that it needs to Okay, so we would find a variable for Colonel objects which contains So Okay, clean build Okay, that starts you to work. Let's take a look at the file again and Here we see it has actually linked in well, it has correctly assembled our Enable and disable routines But has not actually done anything It's it's it's not omitted the unused files. Okay Think that's right Bill okay, I don't know what's going on there. There's a particular option you have to pass to the linker to tell it to Discard unused sections, but apparently I'm not getting it right. Anyway, this doesn't actually matter Let's Burn and run it and see what happens so Okay Calling DI has apparently, you know done a thing That's Taking us a little bit further So we were looking at this file this calls in it early in its hardware and then fusics main This fusics main defined in the headers. It's not because it's normally called from the From machine code. Yeah, lots and lots of machine code. We could do this from machine code but I'm not going to we just prototype it there and That now It fails to link because Are we didn't do not have? prototypes for In it early or in its hardware Think we may not need an in it early Now we don't need an in it early That's a platform specific thing in its hardware is Also platform specific Yeah, let's just limit that for the time being So now this is failing to link because it doesn't know about fusics main and we can solve that by just adding that to our list of files And now that fails because it's actually trying to link a whole bunch of other stuff. It doesn't know how to do right Let's start at the bottom. Where does I open live file sys? C where does K printf live? Dev. I go where does K put char live right that's actually One of ours that should live in dev TTY So let's just take a look at one We're actually going to need one of these now the thing is that the boot rom Provides routines for doing stuff like put char So we're going to use that instead Or are we? So it's got ETS put C This is a blocking routine that writes one character to the serial port There's also got Get C Which is a blocking routine that reads one character from the serial port? however We don't want our get C to be blocking because physics is a multitasking operating system so what we want to do is to detect whether there's Anything in the serial port and then either return it or Return nothing, so we've got you are rx one char See I bet this is the blocking version and This is the non blocking version And one what I'm wondering is whether I should be using the rom routine or just duplicating it in machine code I'd rather use the rom routine to be honest You can see here This is loading Out of a system variable Which lives at that address which is somewhere in that mysterious system RAM block so By changing you are today if you get to change where the system you art is from the rom routines um Okay, so let's add a Let's add a dev TTY Add it to our list of files actually Well, we'll just steal the one from this other platform there's Actually quite a lot of this All right, that's because it's a that's a video terminal. I Want the I want a pure serial one, so a Video terminal is a It's displaced text on a screen where we just want to chuck it at serial port. So let's use the msp431 which is simpler Okay, you want to get rid of some of the msp430 junk main. See so this is the rom routine for putting a character So all k put Charles going to do is to call that We could actually be cleverer we could alias k put char to ETS put C so that every time Something Calls k put char it gets linked to this instead, which would be a few instructions cheaper This is the this is the low-level kernel put character routine this is the blocking Well, this is the real TTY routine Now I look at this this is blocking But it's relying on the kernel preemption to preempt the process and page something else in so we may actually be able to use ETS put char for this this returns whether the TTY is Whether there's a character waiting We're just gonna do that for now Chunk chunk chunk chunk This is the routine that's called when a interrupt happens Which we're just going to ignore for the time being is there a there is a dead TTY dot H Okay, my routine has a bit rotted since the last time I looked at it. All right, let's have a look at the different one and this Okay, this structure here defines the list of TTY devices and their buffers This is now a fast TTY carrier is yeah, that's also a fast But this is too The difference between you and 80 and you in fast 80 is that you went 80 is defined to be 8 bits wide Why you went fast 80 is a fast int that can store eight bits or more I Think in fast 80 Minor flags Yeah, the the MSP 430 port is hugely broken at this point I need to revisit it and from scratch I was sensible I would have done a global search and replace Okay Right now these are routines for doing things like Division well modulus and division and They're normally part of the compiler support library However, we're in luck here Because they're in the ROM so Find out where they are you mod si 3 equals And the other one was div Here yep e2 1c Memset likewise memset except without the underscores So what's the difference in ETS memset and memset this allocates a stack frame saves the value calls memset and Returns that's just a complete waste so Where is memset? Okay panic where does panic live? a It's a platform level routine. No, it's not it's in process Device in it that is a platform routine, and I think that goes in devices to see Yeah, this is where all the The character and block devices are Defined so what we're just going to copy this We will we will have an ID device Currently disabled. We will not have a floppy disk device We've got a tcy. We don't have a printer. We don't have memory Okay, that should work block devs not there. Yeah, I need to Think that is right. It does seem to be right. Okay Device in it. Oh, it's not actually there So where is it that is in? Main what does it do? Right, this is this actually initializes all the block devices, which we currently don't have any so that does nothing page map in it is the same This This initializes the banking system We will eventually be swapping to disk But we don't have any for now platform copyright displays a banner which is Disabled because we just don't care. That's a clean Because the build system doesn't do dependencies very well set CPU type that sounds like a platform thing Or not That's a low-level thing So what does it do? This detects what kind of CPU it is don't really care about Yep, okay, so Mem copy is a another ROM routine that address luckily so many people are using the ROM routines that Espresse for probably not going to change them. They've migrated these days to the ESP 32, which is a Similar kind of device except its dual core with two LX 106 cores three-quarters of a megabyte of RAM vastly improved everything and is The default software stack is open source, which is nice and defined reference to pause Cisco proc to see Val adder user mem Hang on a second. So the reason why I'm just I'm not just adding everything is Yep Various config features require different source files Yeah, so in fact flat mem has got The one we want that should have worked. Why isn't that not working? physics was originally of physics inherits from a very old Z80 Unix alike called Uzi It then got adopted by Alan Cox and updated and generally made a thing back in 2014 It's really intended for Z80 systems with banked memory So it doesn't work quite as well as it should on flat memory systems like like this one You can't use the MMU to swap between processors. You have to like physically copy Data in and out of RAM However, as there's only space for one process in memory at once. That's fine Now we're always going to have to hit disk to swap processors but it does a pretty good job of keeping processors in Memory for as long as possible. So it's actually surprisingly efficient and effective. I think I want the MMU Yeah, let's just go for flat. I think That's better Okay Where does K malloc live? What do you know? Malloc swap blocks that's going to be a platform thing No, it's not Is it a dev thing? There's a lot more stuff in dev. No, that's not there either. Oh, no, it's a low-level thing. I do notice that Only the 68,000 has a swap blocks while the NS 32,000 does not Interesting. So what does it do? I'm not quite sure It's a big loop that Right, I am beginning to think that this isn't that flat is not the configuration I want I think I need I think that what this is for is for systems with lots of memory and No MMU such as the Atari ST What this is about is it's moving Process memory into the place where the process executes and then out again elsewhere So we want a single tasking system Of which the MSP 430 is the only one I know of So I think we just need to turn this off And clean Okay. Yeah, I think so And we also need to find some variables to tell it where things are going to be in memory. Okay So this file is the kernel linker scripts This defines how our kernel image is being made and the bit we particularly care about is This chunk up here which defines all the memory regions It's not sure anymore so we have DRAM 1 is the system memory area DRAM 0 is the 80k user memory area. So what I'm going to do is Split DRAM 0 into user memory which is going to Start at the beginning and be 64k long and Then DRAM 0 seg can be 16k so also IRAM 1 here is going to be It's actually changed this to user data and this is going to become user code now this means that This is going to become user code seg So we then need to define Some symbols like so Note that this gives us 64k of data and 32k of code we are actually going to have to Chop this down a little bit because we're going to need some code that lives there 32k of code is not a lot but I'm hoping that we'll be able to get most programs in there and the fact that there's lots of Data available should make the system useful So we now need to define prog base is base base and We do need to declare that What's that complaining about? line for Tell me that colon's not required. Apparently that colon is required Yeah, this is the new linker syntax is very strange Okay, all right. This is actually supposed to be called user base right We now need page map free Where does that live? Is that a platform thing? It's a platform thing So I think that here we go We're all but one memory of area is These bank routines are the various different banking strategies. I think bank fix Is the one we want? Let me just check the I think that doesn't I Think this that may Think bank fix may post date my MSP 430 work. Let's try and find Platforms that don't have That don't do multitasking So Let's look at the dragon. Okay So let's just set this up We're not flat We're not multi Once we get I Think we're gonna need to configure swap I was hoping to I was hoping to put off touching swap until after we got the The disk system working right now is actually already defined there. We don't want that. Oh, yeah This this stuff the swap configuration Here in the config file actually defines where Where the program is swapped in not where it's swapped to so So swap base So we're going to swap the entire 64k of user space area We're going to have 32 swap slots The way this works is there's a partition on the disc Which in our case is going to be an SD card with 30 of size 32 times 64k and When you swap for bank it just Slams the whole lot out to that area. It's going to be more complicated for us because we also have to copy out the The instruction Space we may have to do some modifications to the physics kernel to make this work You data blocks Okay, I don't know what this one is This one is new on me. So the you data is the Is the structure that defines a process it's got all the information in it about file descriptors Signal states Save registers everything we need to store that along with the rest of the Process so I'm going to do this in the hope that It's less than 512 bytes and it occupies one block of disk and I need to define a swap device Whatever that does. Oh swap size This is the size of a swap block in pages So this is actually going to be 64 plus 32 Because we have to include the instruction RAM as well. What is this simple file? System and no user banking. This is what we have. This is what we actually want All tasks which can occurs by swapping existing process out to storage and reading it back in again Config swap only we actually we are going to have to link this are we we are probably going to have to write one of our own Yeah, we are But I am just going to But I'm just going to crudely fill this stuff out with what might be the right numbers just so that we can get things working Okay swap read. I mean the first stage is to actually get it executing some code That's going to be swap dot see swap map probably a platform thing platform thing trying to remember Okay, this is the swap only system So what does this do for swap map, right swap map is if I remember correctly It takes a page number and returns No, I don't know what that does But we're going to put it in anyway to see what happens and because dependencies don't work properly we clean and rebuild right page map base That's interesting We're not flat anymore. What does this do? Right, this has got to do with user paging. I believe okay There are multiple different strategies of memory allocation supported flat dot see from these Restrictions this looks like binaries are loaded at a random place in memory and Then they have to stay there Until the process exits You can't swap or fork because you can't move it around in memory because it's contained and bettered pointers Now we don't have one of these we have a fixed system where processors always exist at a particular location So what was that dragon doing? So I don't don't want flat. That's the wrong one, but it does look like the dragon does not have a Page map base does it that doesn't want simple? It does okay, so it's got to be somewhere and it looks like sometimes it's a function and sometimes it's a pointer Which is a little bit weird So because it's not actually to find anywhere. I wonder if this is actually simple at C61 our Prog load has set it That will be coming through here. That's come through this Okay Right, this is because we set 32 bit mode, which is this Because this is a 32 bit system, but that's not what it means. It means the 32 bit flattest memory flat memory map clean build Actually put a j8 and see if it works Kinda right struck you data. This is the the big you data structure which is defined in Colonel H. I believe here so It can't find you code base because We haven't defined config 32 bit So why is this referring to it? I don't think we should be trying to compile that file Yeah, I think something's gone something's wrong with the configuration here See Cisco xx 32 You should only apply for 32 bit systems Because it relies on these fields which only exist in If you have config 32 bit so Why is it being added to the R? Something is setting bits to 32. This is in fact the CPU This is this not this Bit Seals 32 that's causing it to Pull in Cisco xx 32 Things where a 32 bit system with doesn't really have a proper 32 bit memory map. Okay, what does the MSP for 32? for that Does not define rules because that uses My other build my other now obsolete and broken build system so So this is the routine that loads binaries I think that we're going to have to write our own one of these due to the split data instruction memory issue Now where else is bits used? It seems not to be So we could If you set it to 16 you would get the other loader the one that loads 16 bit binaries Yeah, let's try that and see what happens and clean build Okay, that's got somewhere else Where is types.h? That's a cpu thing Which we do actually have one So that suggests that We're not setting up something cpu lx 106 Right. This line indicates that it's trying to compile the wrong thing Let's do that again without the parallel build to get some better idea of what it's actually doing That's just tried to compile kernel.sh Is that because I have a comment after there? Yeah, apparently it is Okay Do fork where does do fork live? syscall proc No, that's where it's that's where it's referred to Okay, this lives in tricks.s Which we don't have yet tricks.s Contains the low-level machine code routines for doing Various cunning things including Forking So there's our dragon so global do fork section text do fork line 4 What this does is The user process has called fork We need to Copy the current process into We swap the current process out The this then becomes the old process the parent The current process becomes the child we then update various things And return there's actually not a lot to it But it is very subtle So let's just put a ret in there To make it crash in the most obscure way possible when things actually happen when we actually run the code you put l This is the routine that Copies from kernel memory to user memory Should be in user mem Um Which is here You put l We only get is if we do config 32 bit That's a That is actually a bug in the kernel. You should be able to do config 32 bit and Get this stuff. We're going to have to define that We're going to have to modify the other things That's interesting Config 32 bit is defined. So why and we are We have included user mem, but you put l is not there We also need to define this to get the c version of the routines in fact We could just turn all these into mem copies to be honest Still don't get you get l We're not flat We don't have a virtual mmu You get you get c you get w You put blah blah blah Fdf config 32 bit Have I spilt? Spilt this incorrectly No though This is conflicting with user mem direct Aha So this is actually just calling mem copy So it is behaving as if config 32 bit is not set I can see that it is only defined Get get c get w and friends And in fact, if I disassemble those See what the code produces is I can see References to mem sets. It's done the it's done user mem c But it hasn't done config 32 bit Why? So if we put an error here That errors out if we put an error here Does not config 32 bit is not set But this has included config dot h. Okay to clean for that Okay So something undefining config 32 bit I am very confused by this Okay, so If not defined conflict Bit That has not erred out Interesting What does kernel 32 do It's Yeah, there is something Funny going on here That errors that does not So somewhere in here Just trying to find where it's where it's compiling user mem Yeah Incidentally these two compiler configuration options The first one tells the compiler to generate long jumps this long calls This is where it loads the address into a register and then calls the register You saw it earlier in the disassemblies Um, yeah, I can't show you that again until it compiles The reason for that is the standard call routine has a fairly short range And we can't call the rom from code without it Uh, this one Tells it to never use byte or word memory accesses This allows us to put data in the flash Uh, the flash is always execute is always accessed via the instruction ram Which doesn't support doesn't support non integer accesses The this increases code size by apparently 3% so it's worth doing Otherwise you have to copy all your data into the into data ram, which is which is pretty precious But i'm still confused about what's going on here I feel like this is this file is being Uh Included multiple times Also Not very happy with these It's about you put i Hmm, so that would be to be defined in kernel 32.h Yeah, I think that there's something I mean This is because we are setting a prog load here So But then why aren't we getting duplicates? Hang on a second I have a feeling That different files are being compiled with different sets of flags and that's why these odd things are happening So there should be a config.h In each platform And nowhere else Which looks correct so Let's find user mem dot c So these if you run that manually We get a thing Which doesn't have the stuff we want in it So let's do That And we do not get our warning That has managed to pick up the wrong config.h That isn't helpful But I see the warning there What what even what minus e does here is it tells it to pre-process the result So if I do that I get the warnings If I do that I don't Okay, well CPU platform kernel include No, this is strange. This is strange Okay, that errors That errors That does not error. So that's not loading that config file So where is it loading it from? So somewhere in this ghastly mess this is this is what the gcc program is actually doing It's It's somewhere this will be listing the actual command lines Our gcc runs multiple commands to do all the various things, which is Pre-processor compilation and then assembly Except that in an attempt to be faster Some stages are combined So for example This command line Actually does the Compilation In a single unit. So it does the the pre-processing and the compilation together So I bet what's happening is that when we use a command line option to tell it Not to do combined pre-processing and assembly then odd things happen So Here is the machine code being generated by user mem and it is referring to The right config file. Let's put that error back again and try that again You suddenly remember seeing this This is a pre-compiled header I have no idea where that came from I should have looked at the timestamp to see whether it was new or not. I'm all too late now Okay, so What is happening is When I use a command line flag On the compiler which forces it to actually pre-process things itself Everything works correctly If I don't It picks up this pre-compiled header that has been pre-compiled for an old version of the headers and is now stale That is why Very strange things have been happening. But now it's gone Right, that's better. Now we get lots of errors, but they're errors. I expect Okay So, let's take a look at user mem Remember I said that this probably wasn't going to be done in one session I think I was right Okay, user mem direct and user mem see you mutually exclusive. Let's get rid of that This keep forgetting to put the kernel on the front of that Is Problem solved. This was copied from the msp430. So the Uh cpu but these user memory access functions have changed signatures since then Right, so what's happening here is I You get w which is used here in the 68,000 Has a got a different signature from you get l So we need to do that to adapt things Or not Oh So what's The reason for that is if I can find where that was you get l Uh, you get l takes the address to read and an address to put an error value in While You get w and friends do not I am not sure why because You get w returns a You went 16 Well, I was going to say it returns an unsigned in 32 so we can tell the difference in the failure and the non-failure by The value here, but that's not right Well, it's probably mysterious and could be due to bit rot Good we are actually Progressing a little page map base again so because because this is defining page map base as a Function Actually a function Hopefully that should sort that out Okay, where are these colonel.h Yeah, we can't use syscourt xx 16 because all the parameter types are wrong We are actually going to have to define our own Okay, let's call xx So we're going to change this to We're going to change this to lx 106 right, so Because this file has to live in the In the root Okay It's currently empty. So we're going to run into missing symbol routines, but Routine Lives in timer.c Udata, I'm going to skip for the time being Sturln is Okay, that Sturln needs is part of the compiler support library Do we get that in the? Yep, we get that in the ROM which is nice Map init is a platform thing So let's take a look at the dragon Does that live anywhere here? Yes, so what does it Do Nothing That is what I like to see Okay, this Unvine reference to xxv e is part of Uh I didn't want to do that So I loaded that file in the wrong window Never quite figured out how to switch back to the the nerd tree pane here. So let's have to restart it And syscall exec Okay So we're going to copy this And here we define the system call Which is just going to For the time being, okay, I think we're going to have to do udata now. So I think the udata is to find in assembly somewhere I can't quite remember where It can also move around depending on how you configure your system So sometimes it's referred to here we go common mem dot s Sometimes it's referred to via a pointer in In a register a global register the udata block contains both the process udata and also the kernel stack The The lx106 is a little bit profitably good with its With its stack use so hopefully that will be enough So we're actually going to put this At the top of user memory Are we We could put it at the bottom I don't think that adds any value No, we are going to put it at the bottom because that means that We can load and save we can swap in and out a complete process Uh While ignoring everything above the s break value We start at the we start at the bottom and keep saving until we reach the top of the application's workspace If we put it at the top then we would need to Save two chunks so Yes, this is where we want to put it and that's going to be The user base Undefined reference to udata does that want to be eq instead? No Hmm Apparently that didn't do what I thought it did I'm trying to define a symbol called this that is the same value as this But it's not letting me It appears to be defining a local symbol, but I have actually like told it that It does want to be global I suspect that they haven't updated the man page Oh, there it is. It's denser There's not actually a lot of information there Okay, uh See that's defined a value But that hasn't So is Do I need to tell it to import that symbol? Or I can Just do This which I don't like doing See now it's defining Udata, but when it's done like this So I can see here. This is trying to import the user base symbol, but it's not exporting udata Right, that's trying to import udata because I've declared it extern I do not understand what's going on there at all. It'll it'll be a quirk in gas possibly even a bug Gas is pretty quirky For example, whether it uses semicolon or hash to be a Uh comment character or sometimes a backslash Fantastic, okay undefined reference to xxve It's right here Though has it actually assembled it? Ah, we haven't added it to the make file. So let's call lxxxlx1060 Let's sort that into a sensible order okay Undefined reference to platform param That's a platform thing Which does nothing I don't think it likes that const Yeah Okay, Todd Where is Todd? I actually have no memory at all of what Todd is Oh, it's in kdata Right lots of stuff's in kdata Kdata is the file that contains all the variables And things like syscall tables Does it contain new data? No Anyway, we are getting there Mem free and mem alloc are system calls that do Out of process memory allocation and freeing Is to say it says 32-bit system only Uh, which in this situation includes us. So You just do that Right act is a system call That's in syscall fs2 The kernel is structured to allow the various system calls to be banked in and out this allows Uh Your kernel to be bigger than will actually fit in the address space for an 8-bit system But we have lots of space available in our megabytes of flash. So We're just going to link everything in together Uh, we want fs We want other platform reboot sounds like a platform thing. Yes, it is Yeah Eventually we'll call the rom routine to actually restart everything restart the system Platform monitor I do not know what that does Probably exits back to the system monitor if there is one Yeah, just as a reboot syncs the file systems it's in file sys.c which contains the bulk of the Unix file system stuff should be in No, it's not in file sys. What was I thinking? It's in inode In fact, we already had file sys up the top tty posts termiosmas That needs to live in our platform This looks like it's Something To do with Which ioc tools the device supports So let's go with Plus one equals I have no idea what this is. I'm just copying it Once things start executing things will be clearer Can't be const can't be const and that's not a pointer Let's take a look at that msnx Yeah, well Yeah, I am not really sure about some of this can't be const either Because you can't put this stuff in ROM. It's all going to get copied into precious precious ram I hope we're going to have enough Okay, well you put block mm, this is memory manager stuff We are getting there slowly This belongs in low level to do with cpu detection um I think we actually can't ignore this. I think we're going to have to set it to something so e2,0 and Yeah, try to remember how to write bytes s8i Now the problem is that we can't actually write directly to an address. We have to Load the address via l32 r So that's going to be l32 r e3 comma. I hope that works become a zero So write the value a2 to add the address a3 plus zero so we want to Wait a minute. What am I doing? I think we can just do this Just say we want one byte of common memory Is that going to work? Apparently it will and okay sysinfo I think is also going to be A low-level thing No, it's not and that looks like it's kdata Ah, no, it's in version.c Which is generated at build time. So we just need to add that Oh ram top is Not sure what ram top is It'll be one of the many variables. You know, here we go Yeah, it'll be one of the many variables that Tell the system where the top of memory is and I think that we can just do That maybe No, it's that has to actually be a value ram top Okay platform discard is a Is a platform specific routine That is called after system initialization Which throws away uh Any code that is not needed at runtime And in our case Yeah Oh So what this is doing is it's going through discarding all um It's discarding the The stray code and it's turning them into buffers Which I use for caching or everything really Because our system is running out of flash We don't need to do that Platform switch out Is a tricks thing Yes, uh, this is the routine that does a task switch it saves Uh, the state of the current process in the u data Which you can see happening here It calls a routine to switch to another runnable task, which could be the same one And it calls switch in to Uh, make the new process live There's actually not a lot to it And likewise we have switch in that does the reverse This is all part of the task switching functionality Actually, I don't need to put these stupid things in different sections because I know That I'm going to need them all. Okay, apparently that does not align And I thought it did better Uh platform switch out Hang on a second I'm getting switch out and platform switch out mixed up. So what does platform switch out do? Well, it's not there has this been renamed I think it has yes So this is now platform switch out But switch in does still seem to be switch in platform idle Is the routine which is called when there's nothing to do typically this Put the cpu into a low power state where it waits for the next interrupt Which will be an io event or a timer which point it wakes up again and does more stuff so I don't actually know how power management works in this machine but It is perfectly acceptable just to call red. I mean your machine will Spin madly and use up battery power can get hot but it'll work Program vectors That does not sound familiar. Oh, yeah, I remember what this does So this is intended for the z80 and on the z80 uh all your interrupt Uh vectors live down at the bottom of memory, which is actually owned by the process so Every process has its own copy of the vectors the interrupt handlers in there and what program vectors does Is it ensures that they're written into? user space So that when you switch in the new process the vectors will be present And you can turn interrupts on without bad things happening But because all our vectors are in ROM we don't use it Need resched that's another tricks thing Oh, that's a single byte variable, which presumably is a flag to say whether Uh the current process needs to be swapped out. Yep So that can live in here sys ioctl Dev sys sys cpu That's in low level Right that didn't do what I thought it did Can we do that? Page map in it multiple definitions Right because we're using simple. We don't need the one in here. Whoa. We have an image Okay, let's see how big it is first msp866 image elf It's 37 k of code 320 bytes of data Uh About 10 k of bss. That's quite a lot. I wonder where that's going However, if you remember our memory map All this stuff it has to fit in d ram zero here, which is 16 k So we're actually within our limit Which is nice 37 k of code is Not a lot this machine is nice and dense Let's have a look at that Disassembly all the code does seem to be showing up in the right course sort of place Let's take a look at our low level routine I want to look at set cpu type and see what it's assembled into Uh compiled into even Okay, good Movi is The root is an instruction that loads a value into a register And I was uncertain as to whether it supported loading 32 bit constants, but it has it's done exactly the right thing, which is nice Okay, well I suppose the next thing is to try and burn it and see what happens So that's written into the flash and When you run it it instantly crashes So if I hit the reset button And then quickly pause it I can see that it's died at Actually, there might been some tracing showing up before the um Before it actually started to crash. So let's just Yes, it's getting quite late now. I'm and my mind is going We burn it reset and pause quickly Okay, we're not getting any tracing It's an instantly dying somewhere in physics main so Something along here will have gone wrong Uh, I'm actually going to disassemble the Image To disassembly So that I can then load it into the editor so 4021 That is a flash address df2f here that is a rom address. So what's at df2f? We're inside memcump interesting Okay, so let's go look for 218 e22 That's tty default Why aren't we seeing disassembly? This looks like data Oh, I know what's happened Ouch This is really annoying Okay, remember I said that the Uh, where did I put it? Here's our memory map Remember, I said that the instruction ram And therefore the flash don't support non 32 bit accesses And that I had to use that flag to the compiler to tell it to use 32 bit accesses for all memory access Well, we're calling rom routines for things like memcump And the rom hasn't been built with those flags therefore As soon as we try to use one of those routines on something in the flash It'll do an unlined access and die Not an unlined access an unsupported access. It only supports 32 bit accesses. It doesn't support Uh anything else So what that means is I'm not quite sure why it's inside memcump Because we're not calling that What that means is that we can't use these We're going to have to write our own Which is a little annoying. Okay We're going to do this the simple way Add a simple Library file See what the formal definition of memset is returns. Yeah, okay Okay Memcupy des And this returns point to the destination Stirlen So I think that's right Um, this will read s and increment it So it will always when it reads the terminator it will always increment s afterwards So we need a minus one here to compensate Right, let's try this again Woohoo We've actually got somewhere. Uh, let me just Fix this So that we can read the text So we can see it start to boot It these are all wrong. It's it's hung trying to enable interrupts. Um, I don't know where it's got to Um, I'll have to put tracing through in order to figure that out But I think that this is probably a good place to stop for this first session We have successfully Hacked the kernel into Uh running it as I started it's like Obviously incredibly unfinished and lots of stuff is stubbed out like nearly everything But it is a good first step The next session I will try and figure out Uh What is going on here? Probably I it may be that that code to enable the interrupts we put in tricks.s No, we didn't we put it in low level Is wrong It could be that it has actually succeeded, but then something else is going wrong because These are dummy doubts So these should probably be replaced with calls to panic But let's do that next time So I hope you enjoyed this video the first of probably many hopefully And do let me know what you think in the comments