 So, after Kevin's introduction about the microcontroller that we choose on the OXM, I'm going to talk a bit more about the coming from the top layer, not from the hardware side, but from the software and firmware side, and about some things that I thought I would do differently this time compared to other microcontroller projects that I did in the past. I don't have slides. I think there is a pattern that the further the day in Osmo Defcon, the lesser slides I have, guess why. So, yeah, as I said, there's a couple of things that I wanted to differently this time, especially since the last couple of years we did a lot of test-driven development now in the Osmo ComCNI projects, and I was thinking how can we benefit from this kind of approach even when doing microcontroller firmware, where of course we have lots of hardware related bits, which makes it more difficult to test things. So, fundamentally, the task is we want to write a firmware on the device that drives these 8 SIM card slots, and that speaks CCID on USB, so that's actually rather simple if you think about it, but then I said the constraints regarding testability and so on, so one idea was to start write the actual CCID code and make that independent of the hardware and be able to test it using the normal host stack, so using the LibCCID and the PCSC driver and all the stuff that you normally use on the Linux machine to talk to a smart card, and then I remember that there is this function FS, which allows you to create a USB gadget on Linux. So, basically, you can implement your actual device in user space and make it expose a USB device, and that's, I mean, you can do that in Android devices with some other Android specific dialect of the gadget FS or function FS. You can do it with lots of microcontroller boards where Linux runs on the board itself and has a physical USB device port or an on-the-go port that you can switch into device mode, but what also exists, which is, I think, less known or at least less used as far as I could find, is there's a virtual host controller driver on Linux, so basically, you can have a virtual host controller driver which creates a virtual USB bus and then you can attach your USB gadget devices that you implement in Linux to that virtual host controller driver, so you basically have a user space program that implements a USB device that appears normally and you can use USB to talk to it and you can, or your normal drivers, even, let's say, you create a mass storage device or something, then the normal kernel mass storage driver will bind to it or HID device or CDC ACM or something, so you can do a complete USB device firmware development in a user space program and make that appear on your PC without any hacks. Before I actually discovered that, I also found that because I was looking on which kind of board could I do the development that actually has a gadget device that's supported by the kernel and then I discovered that actually some years ago there was a company making a PCIe USB gadget device. It's, I think, a PLX, whatever chip and you can still find them on eBay. I think I bought two for $20 or something, so it's like a PCI card that you can plug into a PC which then exposes a USB 2 device port and then there's a mainline kernel gadget driver for that USB device and then, basically, like on a microcontroller board on your normal PC on x86, you can also create an actual USB device that you can plug into another host or even the same host, but yeah, with a virtual controller that, of course, works easier. So let's look at how this actually looks, how do you create such a device from your Linux system? So this is the shell script that I used to do this and I hope I remember what I was doing when I wrote it. So you have to load a couple of kernel modules. In this case, since I want to have a full speed device, we're developing a full speed device, I have to load this module with is high speed equals zero and is super speed equals zero, otherwise I would create a USB 2 or USB 3 high or super speed device. And then in the end, you have to go to this gadget directory, which is basically here, this kernel and config USB gadget and in there then you have some magic files where you echo in your vendor ID, your product ID, basically the string descriptors. So here is the sysmo comms, sysmo octsum and so on. So you have string descriptors and then you basically do make their commands to create configurations on that virtual device. And then inside the configurations, you actually, again, can set your string descriptors and things like that. And then you can actually create functions in that configuration. Here is I call it ffs.usb0 where ffs is for function fs. And then actually you mount endpoints or you mount the function into a separate directory in your file system. And in there you have one file descriptor for each endpoint that your interface exposes. So in the end, you have a couple of, not just EP0 of course, but initially you only have an endpoint zero in there. And then you write a user space program that opens this EP0 file and it will receive control transfers and so on on endpoint zero that go beyond, actually you open it first and then you write all the descriptors to it. So you open the endpoint zero file and you write all the USB descriptors to it. At which point then it will enumerate on the bus and the host control and the normal USB stack will start issuing all the get device descriptor, read configuration descriptor, all the control transfers. And anything that is not handled by the kernel, which is not the normal configuration interface on the descriptors, you get the basically the control transfer and user space, you build the response, you send it back. And once you have also pushed all your descriptors in the kernel, so the first write you make to this EP0 file makes all the other EP files appear because in your descriptors you say what kind of other like bulk endpoints, isochronous endpoints and so on you have and they all will also make files appear in user space that represent those descriptors. So actually it's rather nice, yet there's one part that you still need to do is to echo this to UDC, but that you have to do after your program. So basically you run the script which creates everything up to the EP0 file, then you run the program which writes the descriptors and after that has happened, you have to do this echo whatever, not like that. You have to do this echo to make it actually appear on the stack. And then you see your normal DMS, you see oh there's a new USB device and a new USB and UDEV and whatever that happens. USB device controller. So yeah, the question was what is UDC? Yeah, so let's look at the program that's actually opening this EP0 file. Basically we define some structures which are our normal descriptors, USB descriptors, there's just one header here in front, the USB function FS descriptors header version two, which is a structure that's defined in an include file that the kernel provides this USB function FS header. And then you have your interface class whatever endpoint descriptors and I'm basically just defining all these descriptors like you would do normally in a firm where it's just you have this additional header in front. And there's also for string descriptors, you can have additional string descriptors that go beyond the strings for ID vendor ID product that you set in in the function FS interface with from the shell script. And if we look at actually the code, there's this EP0 init function. And if we look at that, it will open this EP0 file registered with Osmo file descriptors, and we've write this entire descriptors array that we define. That's basically all that we do. So we write that descriptors array. And as I said, at this point, the kernel will then create all the other endpoint files for the other endpoints like EP120 and so on that you can see here. And subsequently, we can open these endpoint files and we also register them with the live Osmo core file descriptor magic so we can use select on them and so on. And I was okay, this is great, you know, I got to this point where I had basically device enumerate and it looked great and it was a CCID device because all the right descriptors were in there. And then I struggled a lot making the non endpoint zero descriptors work. And the problem is, and that I had to discover only by reading source code of the kernel side. They only implement blocking IO. They are not, you can mark them as non blocking and the kernel will acknowledge, yes, I marked it as non blocking, but actually it's not non blocking. So basically, the kernel driver is so broken in that it, I mean, normally, if you don't implement non blocking behavior, you would just expect the set or non block to just say E-inval or whatever. But it doesn't. So all your code assumes that it's not blocking and I can do select and poll on it, but it doesn't work. And the only asynchronous mechanism that's implemented is AIO and not POSIX AIO, but the Linux specific AIO. So I had to study how AIO works, which I never used before. And this is why they have these if defs. So this if def function FS supports EPOL, that's basically if a hypothetical future version of function FS would support POL, then we would do this. But unfortunately, we don't. So we have this if and def where we then basically hack AIO and event FD together to simulate what Osmo FD, whatever abstraction needs in order to select on it. So you can AIO is asynchronous IO as the name implies, and you can basically submit IO transfers read and write. And you can tell it, well, if you complete this transfer mark that event FD is readable. And basically, I'm using that mechanism. And then I have the event FD and the event FD, I can again register with the Osmo com select abstraction. And this way I basically get normal select poll semantics on these endpoints. But that took me quite some time. Yeah, and yeah, for some absurdly weird reason, it doesn't support the standard of non blocking. Yeah, so yeah, I wrote to the USB Linux USB made in this, and there was exactly zero comment on any of that. And that was like, I don't know, half a year ago, or I don't know how many months ago. Yeah, so anyway, but now this is working. And we basically have file descriptors for endpoints and all the higher level logic can just read and write to it like you would and do usb transfers using these endpoints. So that's nice done. So now we can focus on the actual implementation of the CCID code. Any questions on function fs before I continue? No, okay. Yeah, then the next step is, well, now assume that we have a USB device, whether it's physical or whether it's virtual using function fs that we want to test somehow over USB, how do we do the actual testing? Now, of course, you can run the normal PC SC demon and you can, you know, open the car read the ATR into some APDU exchange. But that's rather high level testing. So I really, I mean, the device implements usb CCID and I want to test usb CCID and not like five layers up the stack with all kinds of rather complex software in between. So how do we do that? And then I thought, well, since we are quite happy with using TTC and three for all the testing of our Osmo com core stuff, why not write a test port for usb for Titan? And that now basically means I wrote some code, which uses lib usb, which runs on the usb host, which allows a TTC and three test case to read and write things on usb endpoints, using lib usb. So it's like a lib usb binding to TTC and three. And using that, then we can have the normal templates for usb descriptors, but the entire template logic and so on. We have a test port and we can exchange data. So that also took some time to implement. And it's at some points, it's not as low level as I would actually want it to be. So I mean, I guess you have some idea about the level of abstraction that lib usb offers. Sometimes it would be nicer to do even lower level testing, but that's of course not possible if you have the entire Linux kernel host usb stack there and the lib usb. So you will not be able to test low level usb transactions, but you're basically bound at the level of abstraction that lib usb provides. So let's have a quick look at that. So yeah, let's look a bit at the Titan code. I'm not going to look at the C code much, the C++ code, but I had to define the usb types there. So basically the request types, the, well, the request type type, the, and so on and so on. And we did the individual control requests, the codes, the descriptors and so on. So we have templates for all the normal things that happen on usb control endpoints. And I try to like really define this as verbose as possible according to the usb spec chapter nine. So we get a meaningful decode of usb control transfers in Titan. And then in the end, of course, we have encode decode functions for encoding those descriptors. And yeah, you can see here all the descriptor types that are supported by the descriptor encoder decoders. And from there, I then created templates for all the different control transactions like here clear feature get configuration, get descriptors, get interface, set configuration and so on, which then use these types. So we can write tests against all those different for these different usb commands using the templates. And I did the same also for CCIDs and that's the usb profile that we will implement. So if we look at CCID types, there we define all the CCID related descriptors. Well, not all. I think there's some stuff that I commented out here, which are just basically a 32 bit value here and not further decode these fields. And again, there we have templates for the CCID headers and for all the different CCID commands. So transfer block, get parameters, reset parameters, notify slot change and all the CCID commands. And those we can then exchange over the usb port. And if you look at the actual usb code, that's basically a bit of C++ code that I had to write to interface the the Titan test port with lib usb. Yeah, so in terms of actual tests, I don't think I have many tests yet. But just I think there's a small demo here. It's already too long to remember all the details. But yeah, there is like a function where you can say, well, get the standard descriptor for configuration and then it would just log it. So there's no actual tests that would really do protocol ever tests, but all the infrastructure is there. So yeah, and now the actual work can start now that we have the ability to run the firmware on the function fs and we have the testing side. On the other hand side, we can actually do low level testing. And I think when I did this, already, some things didn't work in the usb stack that Atmel provided. So yeah, as usual, whenever you write tests, immediately something falls apart. So oh yeah, like, oh, unless I mess it, but how did you connect like the Atmel USB stack to this like you have to patch the stack to know so if like the TTC and three test is just using lib usb on the host. So you can either run it against the physical device with the Atmel USB stack and so on attached to a physical USB port, or you can run, basically combine those two parts. So first I was talking about the virtual USB device. Yeah, but since this is just using lib usb talking to the normal kernel host drivers, you can of course run the test against physical devices and against virtual devices, but you can also run like compile a special version of the firmware that appears as a USB gadget, but then you don't use the Atmel USB. Yes, correct. Then you don't use the stack. So the CC ID code that I wrote at the moment, actually, it only supports that's where I'm right now. It only supports the virtual code. But then there basically needs to be some glue code to glue the CC ID core against the Atmel driver stack in the firmware or to glue it against these file descriptors of the usb function fs when you run in the virtual environment. So of course, you're not testing the Atmel stack on the host. I mean, once you go that, that's when you go to the device. But at least you should be able to run, you know, test all the, you know, normal CC ID commands and that kind of stuff in in and do development there easily in a virtual environment on the host. And then the next step then is to test the actual device. So the there I probably put some, you know, define SIM cards in the slot of one board attached to one Jenkins slave or something. And then we can actually test, well, do we get the ATR that we expect from the slot? Similar to what Philip has already been doing for the PySIM automatic testing, where basically we have one Jenkins slave that has a couple of SIM card readers and sysmo and other SIM cards inside. And then we run PySIM against the real hardware and Jenkins gets the results back about whether or not given PySIM commit still can talk to all the cards, all the cards we have at least. Yeah. So once all that is done, and we have this also the virtual device that can again be used as a component to test the REMSIM, of course, without hardware. So if we have the virtual CC ID reader and we implement a very minimal pseudo SIM card, that basically just answers to give some basic responses, then we can run tests for the REMSIM bank demon, which talks PCSC over the virtual USB bus to the CC ID firmware on function FS. So we can run basically tests against the REMSIM bank demon on on any build slave without any hardware dependency. Yeah, so I hope that this USB test port will be useful for other devices as well. Maybe we once once the E1 protocol exists, we can probably also write some tests there. So let's say, for example, you could plug in a loopback plug in your RJ45 and then you can test basically some whether you get the data loopback or something like that. Yeah, so that's why I put it in a separate repository because it's generally useful to other people. Yeah. So there is the food if somebody could help them to the doors already unlocked. Okay, good. Then further questions on this? No? Okay, thanks.