Coreboot and PC technical details
Stuge, Peter
A modern PC is quite different from the 1980s original, and while the BIOS still lingers after 30 years it must now solve many tricky problems. When the original PC with it's pre-ISA expansion bus was powered on, it was almost immediately ready to run an application. Today's PC can have several multicore CPUs interconnected by HyperTransport, Front Side Bus or QuickPath, DDR3 RAM on each CPU, and a large number of buses and peripherals. Many components require increasingly complex initialization to be implemented in software. This talk describes the technical challenges encountered by coreboot developers and their solutions.
 The second demo and please be quiet everyone. Some that we might be able to hear what's actually going on. No way to hear what's going on. I'll just have to sort of narrate. Again, serial console. This is one of the GLLX boards, an AMD CPU. The embedded, AMD embedded CPU with two six megabytes of RAM. And let's see when I reset. There we go. Four boot running. And there it's already starting the Linux kernel. And that's the final prompt of the Linux system, which is full up at that time. So this shows that if you disable all the debugging stuff and you have a really trimmed down kernel, you can get a very nice start up time. And talking about boot time measurements, I think it's important to be careful with the numbers here. Or just be careful about what the numbers actually are saying. Because different people will use different metrics for boot time measurements. And of course everyone wants their numbers to be the best, so they're going to use what is best for them. What is this time measurement actually saying? Is it saying from power supply connected to windows running with a full desktop, whatever login user or Linux or whatever you have? Or is it from after the mainboard power up sequence, which might make a difference? It sounds silly, but it might actually make a big difference. There are about 30 voltages in a PC system, so and these all need to start in a special sequence. And that takes time, of course. Or is it from the first instruction fetch, which might be a lot later? Then after all the voltages are up, who knows what's going on in the system? So the guy who's been developing CBIOS, his name is Kevin O'Connor, he did some optimizations for his particular board. He has an EPR board of the EPR-CN with a C7 CPU and the CN700 chipset. He put core boot and CBIOS in flash, used CBIOS as the payload, and he had a grub on a SATA SSD. And this is the results he got. He had to spend 350 milliseconds just waiting for what seems to be power sequencing. From the time he presses the button to some software actually running, it's almost half a second. Then he measured that it takes about 50 milliseconds to wait for a communications bus on the mainboard to stabilize. Another 20 milliseconds to configure the memory controller. 10 milliseconds running core boot. 200 milliseconds waiting for the VGA BIOS to initialize the graphics. And another 10 milliseconds in grub. And the grunt of who is that it takes 750 milliseconds from the time he presses the power button to when Linux is already starting. Security slide, I don't know. I think I'm going to skip this. Well, maybe just mention it quickly. Core boot attack, there was an attack made public, I guess, the year before last year, so 2008, even though you power down your computer, the RAM might not be completely empty. And if someone can steal your laptop or desktop for that matter, they can check out the RAM, the DIMM, and extract all the contents of the data. And it's really easy to find crypto keys and so on. So core boot can be used both in the attack and for defense here, because core boot has RAM initialization, it can start the memory controller and then have a special dump routine inside core boot to read out all the contents without changing anything in RAM. But you could also use it so that when you're shutting down, there's a part of core boot which runs and makes sure it's to clear all the memory before it powers off. Code injection into the operating system. And exploit published where part of the BIOS was changed to always rewrite permissions on a particular file in the root file system. So whenever you rebooted, this file became world executable with the plus s and everyone had a root shell on the system. That's not something you want in your firmware, so it might be worthwhile to look carefully at the firmware you're running. There's a lot of good stuff about core boot. You can get really fast startup times. It's open source, C code, DPL, you can audit, you can read it. You don't have to study assembly, assembly sources, a day on end to go through the code. We have one tree for all the boards, so there's a fair chance of reusability and extensibility there. There's still some challenges. We need more testing. That would be great. There's a testing infrastructure, but it's kind of difficult to hook up boards to be tested to this infrastructure. So even though we have really nice way in this infrastructure to test each commit on actual hardware, because the fact that it's too difficult to connect boards to this infrastructure means that there's little testing actually done. Everything is built on each commit, and that's a good start, of course, but it would be very nice also to see boot testing, because stuff can rig even though it compiles, it might not run. And it would be very nice to have all the boards really 100% supported. Most of the boards are implemented by one single developer or a small group of developers, and they were really happy when all the stuff they need is working, but that might not be enough for everyone else. So little things on the main board might still need some code to work. Most boards are not really far away. There's only very small, very small stuff missing. ACPI, we need to get better at ACPI, but we already have a lot of good progress there, thanks to Rudolph who's going to talk about it a bit later, and Ashlef and so on. And code is great fun. So come into the project, please. Thanks to Luke for organizing this dev room and some links for boot.org, and we have a mailing list and we're on our C, and the Wiki, you can just add anything after the URL, and you should get an informative page. Questions? What do you use for flashing your flash chip if it is completely screwed? What do you use for flashing your flash chip if it is completely screwed? Commercial flash chip. Sorry? Do you use some commercial flash chip? You can, yeah, sure, that's one way. You can have a flash programmer or flash writers down below. That helps, but you don't always have access to that. One thing you can do is to have a use another main board instead, and hot swap the flash chips. Flash chips, programmer. Good to have, but you can also use another main board. Yeah, hot swap, that's fine. I think Carl Daniel will talk more about that also in the flashroom talk. Another question, yeah? What are the implications of not fully supporting ACPI? What are the implications of not fully supporting ACPI? Yeah, sure. Rudolph wants to answer. I will enter the next talk on ACPI so that perhaps I can write that into a real question. But in support of it, to the moment that everything, the line of these is there, everything between those needs is there. So both is the news, all is there after everything, the software is everything. So what we did is somewhat minimalistic ACPI implementation. This was the standard prompt. It's there, nothing more. So we don't have much of the byte code stuff there. We are just only very basic routine, what is required by standard operating system. So in this case, everything which the real life operating system needs is probably there. But there is no consist of like the terminal zone and lake and so on, because it can be either on some platform level by some other drivers and so on. So we don't need to be full blown, let me say ACPI, so we just support what's really necessary. And there are, so I guess I could add there that one implication would be that there needs to be a driver to handle some tasks that might otherwise be handled using ACPI on another operating system or, sorry, another firmware. But again, if Linux has that driver and you want to run Linux, then it's fine. Thanks. No more, yeah, okay, another question? Your program, your first instruction that will be ever found is immediately copied. Yes. I presume that you have to configure portals, which serial port you are using? Yeah, things like that, yes, that's part of the build. And there are also some variables that are set or some settings that you can change runtime. Well, not runtime, but are read from NB RAM. So if you built up your operating system, you use NB RAM tool to change the settings. And the next time you reboot, they will take effect. For example, there's a new motherboard with, I don't know, a newer version or a higher clocked RAM version. How can you extract the exact parameters? So a new main board with higher clocked RAM or a different type of RAM would be small to medium effort. Rulof is also going to talk about porting coreboot to a new board. And it would really be like adding a new main board if it's, say, an upgrade from DDR2 to DDR3. Not all of the work needs to be done as if it was a completely new main board, but still some things have to be changed. And like for the RAM, in order to get your RAM stabilized to new weights, is it some sort of file? I'm sorry to talk about that in the next presentation of RAM initialization. If you're, are you staying for that as well? Then maybe, okay, all right. Well, if you have, then maybe we can come back to the question. All right. Yes, there's one laptop supported at the moment. Two if you count the OLPC. So the laptop that is supported is, I mentioned that in the presentation. The development was funded by the German BSI. And it's a rugged, rugged laptop, but the components in it are fairly standard. So that code and that effort can be reused for supporting other laptops as well. And I also have one board that I'm, I'm sort of working on a laptop. They call it a network, but I, it's a 12 inch, it has a 12 inch screen. So I don't know if I think it's a network, but this is, this is the board anyway. This is all that is really in the laptop except for the screen and the hard drive. It's a VIA based platform. It's the Samsung NC20. So hopefully that will, will work at some point as well. Does that answer your question? Please do, but it, it might be a lot of work. And especially it depends a lot on the, which components are in your laptop. Rudolph will, will talk about that more also in his presentation. It can be really difficult to find out all the information that is necessary. All right. So no more questions. Thank you very much for coming. Sorry, I, I went over time a bit, but yeah, I hope you thought it was, was interesting. Thank you. Do we need a few minutes of a break between presentations before I start the next one, or should I just go straight away? All right, I'll continue then. Okay, yeah. So, Pourgoot and PC Technical Details is the title of this presentation. This is what I hope to be able to talk about here. Yeah, who am I again? I guess that's the same as before. A look at the 30 years of PCs. The PC has been around for a long time and it's changed quite a lot. I would like to have a look at the ISO bus, the first, well, actually the second extension bus in the PC, but it worked the same way as the first one. So we're going to look at that in order to learn some things that are very important and still apply to a lot of other buses and devices in a modern PC. Some thing about hardware registers, various, on various buses, ISO, PCIe and MSR. I'm going to talk a bit about NVRAM, I'm going to talk a bit about interrupts. RAM initialization, cache as RAM is a trick that is used by many firmers today. GCC and ROMCC is something that came out of Pourgoot as well. The different x86 execution modes, real mode, protected mode, dimensions mode, maybe embedded controllers if there's time and the thanks. This is the same as the last slide I've been doing Pourgoot for a while. I started in Hamburg and I do stuff. The PC in the 1980s, it might have looked like this. There was a CPU and there was a boot ROM and there was some RAM connected and it was a cassette player and the keyboard and an expansion port. All of this was really connected to the same communications bus. We went from cassette to DDR3 and this is what the PC might look like today. There's a lot of stuff in here. We can have four or however many, eight, sixteen CPUs maybe. Every CPU might have its own memory controller and the RAM is connected to the memory controller and that's one bus and different CPUs might be connected together in one special bus. Then there's some connection to the North Bridge and some IO stuff. There's a whole graphics block which is either in the North Bridge or might be on a PCI Express bus off somewhere. There's another bus down here to something, South Bridge, which has a slower old PCI bus. There's some USB and IDE. PS2 may be there or might be over here in the Super IO. LPC is a replacement bus for the old ISA bus. I would say that it's really on every main board these days. There's an LPC bus somewhere. It can connect to a Super IO. It can also connect to a boot flash or there could be an SPI bus which connects from the South Bridge to the boot flash. Or there could be an SPI in the Super IO. So it could be LPC over to the Super IO to SPI and then to the boot flash. The Super IO has lots of other stuff also, floppy. It could be PS2 as I mentioned, serial, parallel, GPIOs, watchdog, thermal measuring lots of temperatures on the board. And there might also be microcontroller. So another CPU inside the IO chip down here. That's the embedded controller that I hope to rant a bit about also. Oh yeah, and there's the SM bus. I mentioned in the previous presentation that Kevin had some issues waiting for the SM bus to stabilize. We'll come back to that when we're talking about RAM initialization because it's connected to the RAM. So this is a look at how it might be. And it can of course be even more complex. You can have, this might not be a single core CPU, but it might be a four core CPU. So you have four CPU cores behind that one connected to one memory controller, but connected also to all the other CPUs. It can be pretty complicated. So HG is hyper-transport. That's AMD's bus for interconnect, or AMD's interconnect between CPUs. And IO nodes. Intel developed their own. It's both quick path interface, I think, is the abbreviation, the QPI. That's the same thing, connection between many CPUs in a system which has many CPUs. So what about this ISO bus? The way it looked back when? There's IO and memory access in the X86 CPU. There's an 8 or 16-bit data communication path. And depending on if you're doing IO access or you're doing memory access, the address space has a different size. So for IO, it's always 16-bit, so we have 64K addresses. These addresses, they're usually called ports. I'm not really sure why, but if you see port somewhere, it's about an IO. The CPU instructions used for IO is in-b, in-w, out-b, out-w. And in newer CPUs, you have the in-l and out-l instructions also. These also are available as function calls in Linux. You can do direct IO from Linux user space if you do some preparations first. I think my, Carl Daniel might talk about that also. Well, that knows. In the lighting talk, I guess. For the porting in the L-O-S room. Well, anyway, it's possible to do this direct, this IO communication, this IO accesses from Linux. And even if there's no I-sub bus in the system anymore, it's still possible to do these operations. And where are they going to end up? Well, they will end up on LPC usually, and there might be something listening there. Typically, the super IO is what you want to talk to in that case. If you're doing memory accesses, then you have 20 bits of address. And we'll have a look at how those 20-bit addresses are created in a bit. In execution mode, stuff. And the memory accesses, they all use move instructions. So it's just memory read and memory writes. If you're programming in C, you're reading from a variable. That's a memory read. In the really early PCs, that memory was external. The new PC, the memory is actually connected to the CPU itself. And of course, has a lot longer address space than 20 bits. There's a whole bunch of registers in all the hardware components that we looked at and in every add-on component that you can connect to a PC. And these register accesses, they will be either IO or the registers, they will either be IOMapped or they will be memory mapped. On ISAHearnware, it was kind of common on the really old, for example, really old networking cards. You had a whole bunch of jumpers. How many people remember those? Yeah? You had to choose the base IOPort, then you had to choose the interrupt, you had to make sure there were no conflicts and it never worked. They invented this plug-and-play stuff which was supposed to be clever, but I don't know. In theory, it was good, but I think the implementations weren't really that awesome. PCI is very different. There are no jumpers. There's no conflicts. It handles all the configuration. So Coreboot, that's all the long printouts that we saw from the first demo, is checking all the PCI devices connected to the system and making sure that they can coexist and be accessible at the same time. PCI devices, they have what's called configuration space, 256 bytes of registers. They are always reachable. I think the standard says that it's not necessarily always, but in practice it really is always. They are reachable on IOPort's CF8, hexadecimal, and CFC. This is an index data combination, so you first write the address of the register you want to access to CF8, and then you do the actual value access on CFC. So say you want to access... No, I'm not going to give you an example, because you have to encode the PCI device address and something that's called a function number and the register number into this access to CF8. I can do that in my head, so we'll have to skip that example. But anyway, first specify what you want to access and then do the actual access on a different IOPort. This is typically always available. If the system has PCI, then this is going to be there. This is called the Type 1 configuration interface, and maybe you've seen that in the Linux kernel sources. You can choose what type of configuration access method that's going to be used. This is also what CoreBoot uses. CoreBoot used to support another access method, but it was never used, so we threw that out. Configuration space can also be reached via memory mapped registers, and that's called MMConfig. Not every system supports it, but if they do, it's more convenient because you just access what could be a memory address. It looks just like any other address in memory, but there's no memory there. Instead, you're reading and writing, well, there is memory, but the memory is small registers on some PCI device, and it's not the dim, the main RAM in the system. So that's handy, and it's also faster. These IOP accesses tend to be pretty slow because they are so old and legacy compatibility stuff on the bus. The 16 first bytes of at least 256 are standardized by the PCI standard. So every single PCI device is going to have the first 16 bytes exactly the same. Well, not identical contents, but identical structure. The first four bytes show the vendor and the device ID. For example, there's also information about which interrupts is going to be used for this device and a couple of other things. Interruptible polarity detected errors on the PCI bus by this device. If this device is a busmaster and a whole bunch of other settings as well. And there are base address registers, or bars, as they're called. So maybe these 256 minus 16 bytes, these 240 bytes, maybe that's not enough for doing everything that this PCI device can do. Maybe you need a lot more if it's a graphics card. For example, you want access to the graphics memory. And 240 bytes isn't really a lot of graphics memory today. So you need some way to create a window into the graphics memory that is on the graphics card. So then you will configure a bar, or when the firmware will configure a bar, a base address register, saying to the PCI device that when the PCI bus sees an access to this particular address, then that is meant for you. So every PCI device looks at the traffic on the bus, and only the one that has been configured to access to this particular address is going to accept them and decode them and process them. So in case the firmware does a half-assed job and sets up base address registers which conflict, then you're going to have more than one device react to stuff going on on the PCI bus and nothing is going to be working. So in the example of a graphics card, the base address register would set up memory mapping because you want the graphics memory to be accessible as memory. But base address registers can also be used for IO mapping. In that case, you have some number of IO ports that you want to end up on this particular PCI device, and then you, the firmware, set a base address register in the same way which tells the PCI device to decode IO accesses to this particular port. This is really common for PCI devices to have one or both memory and IO bars. It could even be several. I think in the 200 and, sorry, in the 16 bytes, 16 standard bytes, I think there's room for four base address registers. I don't know. No, sorry, it's in the full 256. It's room for four or maybe even more base address registers. So you can have one PCI device that has several different memory regions or IO regions that it's decoding. There are also the MSRs. Yeah, almost can see. Model specific registers. That's low level registers in the CPU itself, in the North Bridge, in the IO controller, stuff like that. I'm going to come back to some of those. NV RAM, I mentioned that. It's also called CMOS. I don't know if, I probably doesn't use CMOS technology anymore, but the name has stuck. It's in its simplest form, with a basic form, it's 128 bytes of battery backed RAM, and it's stored in the real time clock chip. And the real time clock chip, in turn, is usually part of another chip in a modern PC. But in the original PC, that was one Motorola chip on its own. Now it's usually in the Super IO or maybe in the chipset. So these 100 odd bytes, they survive power down. You can have the system disconnected forever, well not forever, but for a long time, and the contents is still going to be the same. Also the clock keeps ticking, of course, when the system is shut down, that happens there. The standard way to access these registers is, again, one of these index value IO sequences. You write the address you want to access to port 70, and then you read or write port 71 hexadecimal to read or write that value. And this is where all the BIOS settings are stored, typically, and this is also what NVRAM tool messes with. So you give it the layout file of which bits are which setting, and it will do all the translation and make sure you don't overwrite any wrong bits. It accesses these ports 70 and 71, and it works out well. There are also extended registers, another 128 bytes, and there can also be another 256 bytes in other places, but that works just the same way. Ports 72 and 73 are really common. If you want to have a look at the driver for this in Linux, it's driver's car in VRAM. Somewhere in ART x86 there are a couple of macros which translate to the out-B and in-B, which will do the actual port accesses. Interrupts. How many recognize this picture? All right, excellent. How about 8, 9, 10 or so? So this is the legacy pick programmable interrupt controller. The way interrupts works in the beginning, single CPU systems, I guess all the way back to 8088, the original PC. There were 15 usable interrupt signals, interrupt inputs, to these two interrupt controllers that are connected together. And the chain of events is, as described here, a device. Well, typically one device would connect to each of these inputs 0 through 15. The device wants attention from the CPU because something has happened. There's a byte coming in from the modem or from the keyboard, or maybe it's possible now to send a byte out to the modem or to the keyboard or wherever. A network card for that matter. So the device signals an interrupt, pulls one of these strings. Now this is this, the interrupt controller, and if it's one of these high ones, it's going to trickle through to the master. And the only interrupt signal going to the CPU is the actual int. That one. Yeah, so the one interrupt signal from the master pick is all that is going to the CPU. The CPU only accepts one single interrupt signal. But what about all these devices? How does that work out? Well, so when there's an interrupt, the CPU will acknowledge that it received this interrupt signal by pulling on this int A signal to the interrupt controller. And then it's going to wiggle that interrupt acknowledge signal a little bit more, which causes then the program interrupt controller to write an address for the interrupt handler, or the interrupt vector to the data bus. So the CPU says, okay, I got the interrupt. The CPU says, okay, what should I do now? The interrupt controller has been programmed, hence programmable interrupt controller, has been programmed to know that interrupt this and that, should be handled by code running at this particular address in memory. So the CPU says, okay, what should I do now? The programmable interrupt controller replies, you should go to this address in memory where the interrupt handler lives. So it writes that out to the data bus. The CPU reads the address and jumps to the address. And there's an interrupt handler running in the CPU. So this was with just one CPU. Then there's only one interrupt signal, even though we can have many interrupt sources. And hopefully this explains all the interrupt problems that were with the old ESA cards a little bit. Okay, what about when there are multiple CPUs? Then it gets fun again. There's always one bootstrap processor. That's the first processor that comes up running when the system is starting. That is all arranged in hardware, which processor will be running when the power comes on. Then any other CPUs are going to be application processors. So there's always only one running in the beginning and it has to... Well, actually that's not true. That depends on if it's AMD or Intel, I think. But one of them, everyone comes up running and they have to agree to stop if they're not the BSP. But there has already been a decision made in hardware, so that there's only one which is designated the BSP. And it should check if it's the BSP and the other ones should stop, and the BSP will continue. Anyway, inside of these CPUs, there's a local APIC. APIC is, I guess, Advanced, Programmable Interrupt Controller. And the local APICs, there's one in each CPU, as I said, they communicate with each other. For example, this has a transport or it could be some front side bus or such, system bus, whatever. They also connect with this IO APIC, which is the one dealing with... Well, this looks familiar. This is the same, the legacy pick arrangement, which is still there, even if you have an APIC. It might not be used. If you... So the APIC situation, it needs to be configured before it's being used. And if it's not configured, then the system is still going to be using this legacy pick setup. But if you configure the full-on APIC situation, then you get the local APICs talking to each other and talking to the IO APIC, and you can do really flexible mapping of all the interrupts coming into the IO APIC, and all of the interrupts that can be generated by the local APICs also. Because by the time we have multiple CPUs, the CPUs also have a lot of more functionality included than maybe the older ones did. So for example, we have dimension-ready machine check exceptions, MCEs. If the CPU detects that it has broken, it can trigger an APIC interrupt, and that can call into an interrupt vector somewhere. So the interrupt vectoring part is still the same. The local APIC will make sure that the CPU runs... It will often run some configured interrupt handler. The difference from the legacy pick situation is that, well, first of all, the IO stuff which is connected to all the peripherals and the PCI bus down here, that's separated out. And the local APICs, they also have support for, I think, 256 interrupt sources instead of the 15. So there's plenty of interrupt signals available. They can come from... Interrupts can come from, as I mentioned, from within the APIC itself, from within the CPU itself. The APIC has also a timer which can generate interrupts. And yes. Yeah, of course, the APIC enabled there. It has to be enabled, as I mentioned. Here's also the system management interrupt signal, which goes into the CPU and not the APIC in this drawing, I think. So a lot more complicated, but basically still the same principle. You have programmed the pick, the interrupt controller, with all the interrupt vectors. And when the interrupt happens, it will send the CPU to run the code that it should. But there are a lot of possibilities with many different interrupts here. I think Rudolph will also come back to this. For RAM initialization, how are we doing on time? Okay. For RAM initialization, what do we have to do there? Well, our goal in RAM initialization is to configure this thick red connection over here. It could be DDR2, it could be DDR3. In any case, it's a lot of work. We need to know exactly what kind of RAM is connected here on this side. And the same for all of the CPUs and or memory controllers which have RAM connected. And well, since this communication link isn't working, what do we do? We then have to use this SM bus. So from the CPU, when we're doing memory configuration, we go through the North Bridge, South Bridge, out onto the SM bus and follow this green line and talk to this little green guy, which is an E squared prom on each dim. So a small serial E prom, it stores a couple of parameters. What size is this memory? How fast is it? Is it registered? Is it not registered? Et cetera, et cetera. All the parameters that, yeah, timing supported by this memory module, all the stuff that is needed to configure the memory controller correctly. And I'm not going to go into great detail with the memory controller configuration because it's so complicated. But I'm going to say that DDR2 at least requires some brute force searching for finding the correct tuning of the timing between the memory controller and the actual dim. So the firmware has to search through all possible settings or many possible settings for the tuning parameters in order to find the one that is working really well. And worst case, that parameter could actually change with the temperature in the room depending on how the board is laid out, the traces on the main board. So it's a long work. Cache's RAM is used in core boot. This RAM initialization stuff. So when the RAM initialization is running, there is no RAM available. That means it's not possible to run C code because C compilers, they assume that there is RAM available. And RAM is used for the stack, which is used to call functions. So we can't use C code when we're doing this RAM initialization. Back when memory technology was simpler, or the memory buses were simpler, it was kind of okay to do, I guess, the memory initialization, the RAM initialization in assembly. You could do it in assembly language. And it wasn't all that bad. It wasn't too long. It was okay. But with this, for example, with this brute force search stuff that is in DDR2, and which I can only assume is even more complex in DDR3, it's really not something that we want to do in assembly anymore. So one way around it is to use cache as RAM, which means that part of the CPU cache is used as memory. And in fact, it is memory. It's really fast memory. But normally it isn't addressable. But there's a way. It's documented by Intel, even. It doesn't exactly describe why you would do it, or I guess, well, they say how you do it, but not exactly that the result is cache as RAM, that you can run stuff without having RAM. You have to read between the lines a bit. But the information is there. You set up caching, and then you make sure that you load all the code that you want to run into the cache. And then you make sure that you don't run anything else, and that you don't access any code outside that. And if you do, it's possible to have ccode running without any RAM active. So that's used by Corbucci for many mainboards, but not for all, yet. Our ambition is to have this for every mainboard. We have the cache as RAM support for a lot of different CPUs and platforms for AMD64 and for GeoLX, and I think also for the VSC7, but all the boards aren't really using it yet. It can be tricky to do this in a general manner. We want cache as RAM support for everything, of course, but different platforms, different systems, they have restrictions on how big areas you can use for cache as RAM and where they need to live, in which addresses you can use for this. So it's not really easy to do this cache as RAM setup always. Another option. So that's GCC. If you have cache as RAM, you can use GCC compiled code. GCC assumes that there's memory. But before we started using cache as RAM, we had another thing, another solution. ROMCC was created by one of the Corbucci developers. It's a C compiler, custom-made, one big source file that's really long. It generates machine code which doesn't need any RAM. Of course, the X86 is sort of limited when it comes to the number of registers it has. So the C code cannot be infinitely complex because every time you call a function, the C compiler has to reserve one register. So eventually you run out of registers, and then the compiler will complain and it's not going to be able to compile the source code you have. But if you have simple source code, and if you write it in a certain way, in lines, for example, can help, then ROMCC does a fairly good job. There has been a couple of bugs in there which have been a bit difficult to track down. But I think the ROMCC code is pretty good by now. How can you make sure that you don't add up the nodes in the system? So how can the ROMCC compile nodes in any case that there's going to be not that much code? You basically cannot. So the question is, how does ROMCC know at compile time when it runs out of storage? Well, it has a model of the CPU that it's going to run on. And at compile time, it fills up that model, it fills up the registers, and eventually if it runs out of registers and it's impossible for the compiler to store the previous location, then it's going to fail. Then you can't do that function call at, I guess, level eight or nine. If the compiler knows about the CPU, but he probably doesn't know about the third-party kind of dynamic code on the front end. The compiler surely knows about the CPU on the desktop and he can cope with it, but he cannot know about somebody creating artificial calls. Artificial calls. Do you get dynamic calls or do you generate mistakes in your community? No dynamic calls. I think function pointers are much more... Yeah, for some reason. Well, it could be supported as long as there's a register free. But then you have to handle it on your own. Well, it would require one extra register, I guess, for saving the return or saving the function pointer somewhere. I think it's offline. Well, the sure explanation for this, basically every function call is inlined around CC. So if there is a function which calls itself around CC, it will try to inline and eventually detect that you have an infinite loop or something like that. So recursion or something like that, function pointers, forget it. But recursively you can't do it in a fully inlined assembly code with no calls at all. It can't be compiled by wrong CC. That's the thing. So I hope that... Basically working out to be unrolled. Yeah, right. It unrolls the source code completely. I think it should be possible to implement function pointers though, but it might not be in the current code. Excellent. Thank you. You can do it. Okay. Still, wrong CC is... Even though we're moving away from wrong CC code, I think it's still useful. For example, serialize, I believe, is the ROM shell for serialize is compiled with wrong CC. And it's really an amazing effort that went into it. Execution modes. In the X86, there's the good old real mode, the classic execution mode, that every modern CPU still starts up in. You have a bunch of 16-bit registers. The ones up there, I hope I don't forget one. The first four are segment registers, and the rest are... They have sort of intended purposes, but you can mix and match almost freely. Not quite, but you can mix and match a bit. And every memory address, as I said, in real mode is 20-bits. So two of these 16-bit registers need to be combined. And I've always seen that being called segmented addressing. And it's written in the form segment register colon offset register. They're both 16-bit, and the address ends up being... The segment register shifted left by four, or multiplied by 16, and then add on the offset register. So for an example, if ds equals f 000 hexadecimal, and si equals 6 000 hexadecimal, then the ds si segmented address would be a physical address of f 0006. So, yeah. That way you can reach a full megabyte of address space. And this was in 8086, 8088, 186 and 286. And then with the 386, there was the protected mode. Actually, there was one protected mode in the 286 as well, but it was so different that I'm not going to bother. I don't remember even all the details. But the protected mode, as we know it, and usually call it, is the one that came in 386. It has a concept of privilege levels, where you can specify that some parts of code is allowed to do some things and not some other things. And this is also... This is, of course, what every modern operating system relies on in order to do security properly. Otherwise, you wouldn't be able to do anything, even as a user in Linux, for example. But only the root user is really allowed, or the kernel is really allowed to do anything in the system. When one of these privilege instructions, or when you're trying to do, if you're trying to do something that you're not allowed to do, then the 386 or a protected mode CPU is going to throw an exception. And this can be handled by an interrupt handler and then all the APIC stuff comes into play. And you end up running some other piece of software which can sort of detect what happened. And then it goes all the way back and tells the user that, oops, you did something that you're not supposed to do instead of crashing or whatever. Also included in the protected mode is paging. This is a reference table, or a lookup table for addresses. So you're using an address, but it's not up here. If you say you want this address, it might actually be a completely different address. So there's a translation layer in between the address you're using, the virtual address, and the address that is actually seen on the bus, the physical address. The protected mode, not actually protected mode, this is more than 386. The 386 added 32-bit registers. So there are e versions of all the ones from AX out to HP. Then our 32-bit, the lower 16-bit are the same, and some of those can be divided into 8-bit registers. And then the segment registers, they change into what is called selectors. It's the same register name, it just has a different function. In protected mode, the selector will look up a data structure, which has information about paging and privileged instructions, and also base and limit. So this is all part of the translation. Depending on what you put in CS, if you say put, for example, 0, then you're going to get the first entry in this lookup table of selectors or descriptors. And that means if you access address 0, it's actually going to be somewhere completely different. But if you then change CS to be 8 instead, and you move one step forward in this table, the global descriptor table or the local descriptor table, as they're called, and then if you're accessing 0, it gets a completely different meaning. The limit specifies how big a memory block you can access, starting from the base address. So system management mode, I mentioned it's triggered by system management interrupt, when the processor enters system management mode, it's always running in real mode, but it's free to switch to protected mode if it wants to. Interrupts are always disabled, and the debug traps are always disabled, so when you're running in system management mode, you're really isolated. The machine is all yours. System management mode can be entered by, as I mentioned, IOTraps or even MMIOTraps, so the memory maps register accesses. Machine check exceptions, when the CPU detects that it's broken, and anything in the APIC can also generate or result in system management mode execution. Embedded controllers, I'm out of time, so unfortunately no RAM development embedded controllers, it's the 851 in the SuperIO. It can do a whole lot of stuff, which sort of messes up the system because it's transparent, and it might also be very difficult to detect. But, yeah, no. Thanks to Luke, and questions, if there's time. Yep. How does RonCC store loaded variables and variables passed to fantasy? In registers. So you can have only a few of those variables. Yes. How? In the SuperIO, the AD51, where does it get it's go from? Good question. So it depends on, sometimes the 851 there, it can be a standalone chip, and if it's a standalone chip, it can have a built-in firmware, but it could also be sharing the boot flash with the main firmware in the system. So, say the first 50, 56 kilobytes is the firmware for the microcontroller, the embedded controller. That's fairly common. Or it can have its own flash chip. Yep, it can definitely have its own flash chip as well. Yeah. Question? The build-run with the system management mode. System management mode? Does it also come from the boring? Yes. So you could actually disable some of our... Yes, definitely. Do you have a real-time system? Yes, definitely. Someone also earlier asked the question if... So the question was where the system management code that is run in Coreboot, where does it come from? And the answer is it is also in Coreboot. We have two separate implementations of system management code handlers in Coreboot. One is from AMD, that's the one for the Geo.LX, but they open-source that, and then there's the code that Stefan Reinhauer wrote for the Intel, Intel platforms. And I think, well, maybe a few of you also wrote some small system management code for the AMD64. Yeah. But it's all included in the Coreboot source, and there's full control, and it does really very little, because it wants to get out of the way. All right. Okay, thank you very much. Thank you.
 The second demo and please be quiet everyone.  Some that we might be able to hear what's actually going on.  No way to hear what's going on. I'll just have to sort of narrate.  Again, serial console. This is one of the GLLX boards, an AMD CPU.  The embedded, AMD embedded CPU with two six megabytes of RAM.  And let's see when I reset.  There we go. Four boot running.  And there it's already starting the Linux kernel.  And that's the final prompt of the Linux system, which is full up at that time.  So this shows that if you disable all the debugging stuff  and you have a really trimmed down kernel, you can get a very nice start up time.  And talking about boot time measurements, I think it's important to be careful with the numbers here.  Or just be careful about what the numbers actually are saying.  Because different people will use different metrics for boot time measurements.  And of course everyone wants their numbers to be the best, so they're going to use what is best for them.  What is this time measurement actually saying?  Is it saying from power supply connected to windows running with a full desktop, whatever login user or Linux or whatever you have?  Or is it from after the mainboard power up sequence, which might make a difference?  It sounds silly, but it might actually make a big difference.  There are about 30 voltages in a PC system, so and these all need to start in a special sequence.  And that takes time, of course.  Or is it from the first instruction fetch, which might be a lot later?  Then after all the voltages are up, who knows what's going on in the system?  So the guy who's been developing CBIOS, his name is Kevin O'Connor, he did some optimizations for his particular board.  He has an EPR board of the EPR-CN with a C7 CPU and the CN700 chipset.  He put core boot and CBIOS in flash, used CBIOS as the payload, and he had a grub on a SATA SSD.  And this is the results he got.  He had to spend 350 milliseconds just waiting for what seems to be power sequencing.  From the time he presses the button to some software actually running, it's almost half a second.  Then he measured that it takes about 50 milliseconds to wait for a communications bus on the mainboard to stabilize.  Another 20 milliseconds to configure the memory controller.  10 milliseconds running core boot.  200 milliseconds waiting for the VGA BIOS to initialize the graphics.  And another 10 milliseconds in grub.  And the grunt of who is that it takes 750 milliseconds from the time he presses the power button to when Linux is already starting.  Security slide, I don't know.  I think I'm going to skip this.  Well, maybe just mention it quickly.  Core boot attack, there was an attack made public, I guess, the year before last year, so 2008,  even though you power down your computer, the RAM might not be completely empty.  And if someone can steal your laptop or desktop for that matter, they can check out the RAM, the DIMM,  and extract all the contents of the data.  And it's really easy to find crypto keys and so on.  So core boot can be used both in the attack and for defense here,  because core boot has RAM initialization, it can start the memory controller and then have a special dump routine inside core boot  to read out all the contents without changing anything in RAM.  But you could also use it so that when you're shutting down, there's a part of core boot which runs  and makes sure it's to clear all the memory before it powers off.  Code injection into the operating system.  And exploit published where part of the BIOS was changed to always rewrite permissions on a particular file in the root file system.  So whenever you rebooted, this file became world executable with the plus s and everyone had a root shell on the system.  That's not something you want in your firmware, so it might be worthwhile to look carefully at the firmware you're running.  There's a lot of good stuff about core boot.  You can get really fast startup times.  It's open source, C code, DPL, you can audit, you can read it.  You don't have to study assembly, assembly sources, a day on end to go through the code.  We have one tree for all the boards, so there's a fair chance of reusability and extensibility there.  There's still some challenges.  We need more testing.  That would be great.  There's a testing infrastructure, but it's kind of difficult to hook up boards to be tested to this infrastructure.  So even though we have really nice way in this infrastructure to test each commit on actual hardware,  because the fact that it's too difficult to connect boards to this infrastructure means that there's little testing actually done.  Everything is built on each commit, and that's a good start, of course, but it would be very nice also to see boot testing,  because stuff can rig even though it compiles, it might not run.  And it would be very nice to have all the boards really 100% supported.  Most of the boards are implemented by one single developer or a small group of developers,  and they were really happy when all the stuff they need is working, but that might not be enough for everyone else.  So little things on the main board might still need some code to work.  Most boards are not really far away.  There's only very small, very small stuff missing.  ACPI, we need to get better at ACPI, but we already have a lot of good progress there,  thanks to Rudolph who's going to talk about it a bit later, and Ashlef and so on.  And code is great fun.  So come into the project, please.  Thanks to Luke for organizing this dev room and some links for boot.org,  and we have a mailing list and we're on our C, and the Wiki, you can just add anything after the URL,  and you should get an informative page.  Questions?  What do you use for flashing your flash chip if it is completely screwed?  What do you use for flashing your flash chip if it is completely screwed?  Commercial flash chip.  Sorry?  Do you use some commercial flash chip?  You can, yeah, sure, that's one way.  You can have a flash programmer or flash writers down below.  That helps, but you don't always have access to that.  One thing you can do is to have a use another main board instead,  and hot swap the flash chips.  Flash chips, programmer.  Good to have, but you can also use another main board.  Yeah, hot swap, that's fine.  I think Carl Daniel will talk more about that also in the flashroom talk.  Another question, yeah?  What are the implications of not fully supporting ACPI?  What are the implications of not fully supporting ACPI?  Yeah, sure.  Rudolph wants to answer.  I will enter the next talk on ACPI so that perhaps I can write that into a real question.  But in support of it, to the moment that everything, the line of these is there,  everything between those needs is there.  So both is the news, all is there after everything, the software is everything.  So what we did is somewhat minimalistic ACPI implementation.  This was the standard prompt.  It's there, nothing more.  So we don't have much of the byte code stuff there.  We are just only very basic routine, what is required by standard operating system.  So in this case, everything which the real life operating system needs is probably there.  But there is no consist of like the terminal zone and lake and so on,  because it can be either on some platform level by some other drivers and so on.  So we don't need to be full blown, let me say ACPI, so we just support what's really necessary.  And there are, so I guess I could add there that one implication would be that there needs to be a driver to handle some tasks  that might otherwise be handled using ACPI on another operating system or, sorry, another firmware.  But again, if Linux has that driver and you want to run Linux, then it's fine.  Thanks.  No more, yeah, okay, another question?  Your program, your first instruction that will be ever found is immediately copied.  Yes.  I presume that you have to configure portals, which serial port you are using?  Yeah, things like that, yes, that's part of the build.  And there are also some variables that are set or some settings that you can change runtime.  Well, not runtime, but are read from NB RAM.  So if you built up your operating system, you use NB RAM tool to change the settings.  And the next time you reboot, they will take effect.  For example, there's a new motherboard with, I don't know, a newer version or a higher clocked RAM version.  How can you extract the exact parameters?  So a new main board with higher clocked RAM or a different type of RAM would be small to medium effort.  Rulof is also going to talk about porting coreboot to a new board.  And it would really be like adding a new main board if it's, say, an upgrade from DDR2 to DDR3.  Not all of the work needs to be done as if it was a completely new main board, but still some things have to be changed.  And like for the RAM, in order to get your RAM stabilized to new weights, is it some sort of file?  I'm sorry to talk about that in the next presentation of RAM initialization.  If you're, are you staying for that as well?  Then maybe, okay, all right.  Well, if you have, then maybe we can come back to the question.  All right.  Yes, there's one laptop supported at the moment.  Two if you count the OLPC.  So the laptop that is supported is, I mentioned that in the presentation.  The development was funded by the German BSI.  And it's a rugged, rugged laptop, but the components in it are fairly standard.  So that code and that effort can be reused for supporting other laptops as well.  And I also have one board that I'm, I'm sort of working on a laptop.  They call it a network, but I, it's a 12 inch, it has a 12 inch screen.  So I don't know if I think it's a network, but this is, this is the board anyway.  This is all that is really in the laptop except for the screen and the hard drive.  It's a VIA based platform.  It's the Samsung NC20.  So hopefully that will, will work at some point as well.  Does that answer your question?  Please do, but it, it might be a lot of work.  And especially it depends a lot on the, which components are in your laptop.  Rudolph will, will talk about that more also in his presentation.  It can be really difficult to find out all the information that is necessary.  All right. So no more questions. Thank you very much for coming.  Sorry, I, I went over time a bit, but yeah, I hope you thought it was, was interesting.  Thank you.  Do we need a few minutes of a break between presentations before I start the next one,  or should I just go straight away?  All right, I'll continue then.  Okay, yeah.  So, Pourgoot and PC Technical Details is the title of this presentation.  This is what I hope to be able to talk about here.  Yeah, who am I again?  I guess that's the same as before.  A look at the 30 years of PCs.  The PC has been around for a long time and it's changed quite a lot.  I would like to have a look at the ISO bus, the first, well, actually the second extension bus in the PC,  but it worked the same way as the first one.  So we're going to look at that in order to learn some things that are very important  and still apply to a lot of other buses and devices in a modern PC.  Some thing about hardware registers, various, on various buses, ISO, PCIe and MSR.  I'm going to talk a bit about NVRAM, I'm going to talk a bit about interrupts.  RAM initialization, cache as RAM is a trick that is used by many firmers today.  GCC and ROMCC is something that came out of Pourgoot as well.  The different x86 execution modes, real mode, protected mode, dimensions mode,  maybe embedded controllers if there's time and the thanks.  This is the same as the last slide I've been doing Pourgoot for a while.  I started in Hamburg and I do stuff.  The PC in the 1980s, it might have looked like this.  There was a CPU and there was a boot ROM and there was some RAM connected  and it was a cassette player and the keyboard and an expansion port.  All of this was really connected to the same communications bus.  We went from cassette to DDR3 and this is what the PC might look like today.  There's a lot of stuff in here.  We can have four or however many, eight, sixteen CPUs maybe.  Every CPU might have its own memory controller and the RAM is connected to the memory controller  and that's one bus and different CPUs might be connected together in one special bus.  Then there's some connection to the North Bridge and some IO stuff.  There's a whole graphics block which is either in the North Bridge  or might be on a PCI Express bus off somewhere.  There's another bus down here to something, South Bridge, which has a slower old PCI bus.  There's some USB and IDE.  PS2 may be there or might be over here in the Super IO.  LPC is a replacement bus for the old ISA bus.  I would say that it's really on every main board these days.  There's an LPC bus somewhere.  It can connect to a Super IO.  It can also connect to a boot flash or there could be an SPI bus  which connects from the South Bridge to the boot flash.  Or there could be an SPI in the Super IO.  So it could be LPC over to the Super IO to SPI and then to the boot flash.  The Super IO has lots of other stuff also, floppy.  It could be PS2 as I mentioned, serial, parallel, GPIOs, watchdog,  thermal measuring lots of temperatures on the board.  And there might also be microcontroller.  So another CPU inside the IO chip down here.  That's the embedded controller that I hope to rant a bit about also.  Oh yeah, and there's the SM bus.  I mentioned in the previous presentation that Kevin had some issues waiting for the SM bus to stabilize.  We'll come back to that when we're talking about RAM initialization  because it's connected to the RAM.  So this is a look at how it might be.  And it can of course be even more complex.  You can have, this might not be a single core CPU, but it might be a four core CPU.  So you have four CPU cores behind that one connected to one memory controller,  but connected also to all the other CPUs.  It can be pretty complicated.  So HG is hyper-transport.  That's AMD's bus for interconnect, or AMD's interconnect between CPUs.  And IO nodes. Intel developed their own.  It's both quick path interface, I think, is the abbreviation, the QPI.  That's the same thing, connection between many CPUs in a system which has many CPUs.  So what about this ISO bus?  The way it looked back when?  There's IO and memory access in the X86 CPU.  There's an 8 or 16-bit data communication path.  And depending on if you're doing IO access or you're doing memory access,  the address space has a different size.  So for IO, it's always 16-bit, so we have 64K addresses.  These addresses, they're usually called ports.  I'm not really sure why, but if you see port somewhere, it's about an IO.  The CPU instructions used for IO is in-b, in-w, out-b, out-w.  And in newer CPUs, you have the in-l and out-l instructions also.  These also are available as function calls in Linux.  You can do direct IO from Linux user space if you do some preparations first.  I think my, Carl Daniel might talk about that also.  Well, that knows. In the lighting talk, I guess.  For the porting in the L-O-S room.  Well, anyway, it's possible to do this direct, this IO communication, this IO accesses from Linux.  And even if there's no I-sub bus in the system anymore, it's still possible to do these operations.  And where are they going to end up?  Well, they will end up on LPC usually, and there might be something listening there.  Typically, the super IO is what you want to talk to in that case.  If you're doing memory accesses, then you have 20 bits of address.  And we'll have a look at how those 20-bit addresses are created in a bit.  In execution mode, stuff.  And the memory accesses, they all use move instructions.  So it's just memory read and memory writes.  If you're programming in C, you're reading from a variable.  That's a memory read.  In the really early PCs, that memory was external.  The new PC, the memory is actually connected to the CPU itself.  And of course, has a lot longer address space than 20 bits.  There's a whole bunch of registers in all the hardware components that we looked at  and in every add-on component that you can connect to a PC.  And these register accesses, they will be either IO or the registers,  they will either be IOMapped or they will be memory mapped.  On ISAHearnware, it was kind of common on the really old, for example,  really old networking cards.  You had a whole bunch of jumpers.  How many people remember those?  Yeah?  You had to choose the base IOPort, then you had to choose the interrupt,  you had to make sure there were no conflicts and it never worked.  They invented this plug-and-play stuff which was supposed to be clever,  but I don't know.  In theory, it was good, but I think the implementations weren't really that awesome.  PCI is very different.  There are no jumpers.  There's no conflicts.  It handles all the configuration.  So Coreboot, that's all the long printouts that we saw from the first demo,  is checking all the PCI devices connected to the system  and making sure that they can coexist and be accessible at the same time.  PCI devices, they have what's called configuration space,  256 bytes of registers.  They are always reachable.  I think the standard says that it's not necessarily always,  but in practice it really is always.  They are reachable on IOPort's CF8, hexadecimal, and CFC.  This is an index data combination,  so you first write the address of the register you want to access to CF8,  and then you do the actual value access on CFC.  So say you want to access...  No, I'm not going to give you an example,  because you have to encode the PCI device address  and something that's called a function number and the register number into this access to CF8.  I can do that in my head, so we'll have to skip that example.  But anyway, first specify what you want to access  and then do the actual access on a different IOPort.  This is typically always available.  If the system has PCI, then this is going to be there.  This is called the Type 1 configuration interface,  and maybe you've seen that in the Linux kernel sources.  You can choose what type of configuration access method that's going to be used.  This is also what CoreBoot uses.  CoreBoot used to support another access method, but it was never used,  so we threw that out.  Configuration space can also be reached via memory mapped registers,  and that's called MMConfig.  Not every system supports it, but if they do, it's more convenient  because you just access what could be a memory address.  It looks just like any other address in memory,  but there's no memory there.  Instead, you're reading and writing, well, there is memory,  but the memory is small registers on some PCI device,  and it's not the dim, the main RAM in the system.  So that's handy, and it's also faster.  These IOP accesses tend to be pretty slow  because they are so old and legacy compatibility stuff  on the bus.  The 16 first bytes of at least 256 are standardized by the PCI standard.  So every single PCI device is going to have the first 16 bytes exactly the same.  Well, not identical contents, but identical structure.  The first four bytes show the vendor and the device ID.  For example, there's also information about which interrupts  is going to be used for this device and a couple of other things.  Interruptible polarity detected errors on the PCI bus by this device.  If this device is a busmaster and a whole bunch of other settings as well.  And there are base address registers, or bars, as they're called.  So maybe these 256 minus 16 bytes, these 240 bytes,  maybe that's not enough for doing everything that this PCI device can do.  Maybe you need a lot more if it's a graphics card.  For example, you want access to the graphics memory.  And 240 bytes isn't really a lot of graphics memory today.  So you need some way to create a window into the graphics memory that is on the graphics card.  So then you will configure a bar, or when the firmware will configure a bar,  a base address register, saying to the PCI device that when the PCI bus sees an access to this particular address,  then that is meant for you.  So every PCI device looks at the traffic on the bus,  and only the one that has been configured to access to this particular address  is going to accept them and decode them and process them.  So in case the firmware does a half-assed job and sets up base address registers which conflict,  then you're going to have more than one device react to stuff going on on the PCI bus  and nothing is going to be working.  So in the example of a graphics card, the base address register would set up memory mapping  because you want the graphics memory to be accessible as memory.  But base address registers can also be used for IO mapping.  In that case, you have some number of IO ports that you want to end up on this particular PCI device,  and then you, the firmware, set a base address register in the same way  which tells the PCI device to decode IO accesses to this particular port.  This is really common for PCI devices to have one or both memory and IO bars.  It could even be several.  I think in the 200 and, sorry, in the 16 bytes, 16 standard bytes,  I think there's room for four base address registers.  I don't know.  No, sorry, it's in the full 256.  It's room for four or maybe even more base address registers.  So you can have one PCI device that has several different memory regions or IO regions that it's decoding.  There are also the MSRs.  Yeah, almost can see.  Model specific registers.  That's low level registers in the CPU itself, in the North Bridge, in the IO controller, stuff like that.  I'm going to come back to some of those.  NV RAM, I mentioned that.  It's also called CMOS.  I don't know if, I probably doesn't use CMOS technology anymore, but the name has stuck.  It's in its simplest form, with a basic form, it's 128 bytes of battery backed RAM,  and it's stored in the real time clock chip.  And the real time clock chip, in turn, is usually part of another chip in a modern PC.  But in the original PC, that was one Motorola chip on its own.  Now it's usually in the Super IO or maybe in the chipset.  So these 100 odd bytes, they survive power down.  You can have the system disconnected forever, well not forever, but for a long time,  and the contents is still going to be the same.  Also the clock keeps ticking, of course, when the system is shut down, that happens there.  The standard way to access these registers is, again, one of these index value IO sequences.  You write the address you want to access to port 70,  and then you read or write port 71 hexadecimal to read or write that value.  And this is where all the BIOS settings are stored, typically,  and this is also what NVRAM tool messes with.  So you give it the layout file of which bits are which setting,  and it will do all the translation and make sure you don't overwrite any wrong bits.  It accesses these ports 70 and 71, and it works out well.  There are also extended registers, another 128 bytes,  and there can also be another 256 bytes in other places, but that works just the same way.  Ports 72 and 73 are really common.  If you want to have a look at the driver for this in Linux,  it's driver's car in VRAM.  Somewhere in ART x86 there are a couple of macros which translate to the out-B and in-B,  which will do the actual port accesses.  Interrupts.  How many recognize this picture?  All right, excellent. How about 8, 9, 10 or so?  So this is the legacy pick programmable interrupt controller.  The way interrupts works in the beginning, single CPU systems,  I guess all the way back to 8088, the original PC.  There were 15 usable interrupt signals, interrupt inputs,  to these two interrupt controllers that are connected together.  And the chain of events is, as described here, a device.  Well, typically one device would connect to each of these inputs 0 through 15.  The device wants attention from the CPU because something has happened.  There's a byte coming in from the modem or from the keyboard,  or maybe it's possible now to send a byte out to the modem or to the keyboard or wherever.  A network card for that matter.  So the device signals an interrupt, pulls one of these strings.  Now this is this, the interrupt controller, and if it's one of these high ones,  it's going to trickle through to the master.  And the only interrupt signal going to the CPU is the actual int.  That one.  Yeah, so the one interrupt signal from the master pick is all that is going to the CPU.  The CPU only accepts one single interrupt signal.  But what about all these devices? How does that work out?  Well, so when there's an interrupt, the CPU will acknowledge that it received this interrupt signal  by pulling on this int A signal to the interrupt controller.  And then it's going to wiggle that interrupt acknowledge signal a little bit more,  which causes then the program interrupt controller to write an address for the interrupt handler,  or the interrupt vector to the data bus.  So the CPU says, okay, I got the interrupt.  The CPU says, okay, what should I do now?  The interrupt controller has been programmed, hence programmable interrupt controller,  has been programmed to know that interrupt this and that,  should be handled by code running at this particular address in memory.  So the CPU says, okay, what should I do now?  The programmable interrupt controller replies, you should go to this address in memory  where the interrupt handler lives.  So it writes that out to the data bus.  The CPU reads the address and jumps to the address.  And there's an interrupt handler running in the CPU.  So this was with just one CPU.  Then there's only one interrupt signal,  even though we can have many interrupt sources.  And hopefully this explains all the interrupt problems that were with the old ESA cards a little bit.  Okay, what about when there are multiple CPUs?  Then it gets fun again.  There's always one bootstrap processor.  That's the first processor that comes up running when the system is starting.  That is all arranged in hardware, which processor will be running when the power comes on.  Then any other CPUs are going to be application processors.  So there's always only one running in the beginning and it has to...  Well, actually that's not true.  That depends on if it's AMD or Intel, I think.  But one of them, everyone comes up running and they have to agree to stop if they're not the BSP.  But there has already been a decision made in hardware,  so that there's only one which is designated the BSP.  And it should check if it's the BSP and the other ones should stop,  and the BSP will continue.  Anyway, inside of these CPUs, there's a local APIC.  APIC is, I guess, Advanced, Programmable Interrupt Controller.  And the local APICs, there's one in each CPU, as I said,  they communicate with each other.  For example, this has a transport or it could be some front side bus or such, system bus, whatever.  They also connect with this IO APIC, which is the one dealing with...  Well, this looks familiar.  This is the same, the legacy pick arrangement, which is still there, even if you have an APIC.  It might not be used.  If you...  So the APIC situation, it needs to be configured before it's being used.  And if it's not configured, then the system is still going to be using this legacy pick setup.  But if you configure the full-on APIC situation,  then you get the local APICs talking to each other and talking to the IO APIC,  and you can do really flexible mapping of all the interrupts coming into the IO APIC,  and all of the interrupts that can be generated by the local APICs also.  Because by the time we have multiple CPUs, the CPUs also have a lot of more functionality included  than maybe the older ones did.  So for example, we have dimension-ready machine check exceptions, MCEs.  If the CPU detects that it has broken, it can trigger an APIC interrupt,  and that can call into an interrupt vector somewhere.  So the interrupt vectoring part is still the same.  The local APIC will make sure that the CPU runs...  It will often run some configured interrupt handler.  The difference from the legacy pick situation is that, well, first of all,  the IO stuff which is connected to all the peripherals and the PCI bus down here,  that's separated out.  And the local APICs, they also have support for, I think, 256 interrupt sources instead of the 15.  So there's plenty of interrupt signals available.  They can come from...  Interrupts can come from, as I mentioned, from within the APIC itself,  from within the CPU itself.  The APIC has also a timer which can generate interrupts.  And yes.  Yeah, of course, the APIC enabled there.  It has to be enabled, as I mentioned.  Here's also the system management interrupt signal,  which goes into the CPU and not the APIC in this drawing, I think.  So a lot more complicated, but basically still the same principle.  You have programmed the pick, the interrupt controller,  with all the interrupt vectors.  And when the interrupt happens, it will send the CPU to run the code that it should.  But there are a lot of possibilities with many different interrupts here.  I think Rudolph will also come back to this.  For RAM initialization, how are we doing on time?  Okay.  For RAM initialization, what do we have to do there?  Well, our goal in RAM initialization is to configure this thick red connection over here.  It could be DDR2, it could be DDR3.  In any case, it's a lot of work.  We need to know exactly what kind of RAM is connected here on this side.  And the same for all of the CPUs and or memory controllers which have RAM connected.  And well, since this communication link isn't working, what do we do?  We then have to use this SM bus.  So from the CPU, when we're doing memory configuration, we go through the North Bridge, South Bridge,  out onto the SM bus and follow this green line and talk to this little green guy,  which is an E squared prom on each dim.  So a small serial E prom, it stores a couple of parameters.  What size is this memory?  How fast is it?  Is it registered?  Is it not registered?  Et cetera, et cetera.  All the parameters that, yeah, timing supported by this memory module,  all the stuff that is needed to configure the memory controller correctly.  And I'm not going to go into great detail with the memory controller configuration  because it's so complicated.  But I'm going to say that DDR2 at least requires some brute force searching  for finding the correct tuning of the timing between the memory controller and the actual dim.  So the firmware has to search through all possible settings or many possible settings  for the tuning parameters in order to find the one that is working really well.  And worst case, that parameter could actually change with the temperature in the room  depending on how the board is laid out, the traces on the main board.  So it's a long work.  Cache's RAM is used in core boot.  This RAM initialization stuff.  So when the RAM initialization is running, there is no RAM available.  That means it's not possible to run C code because C compilers,  they assume that there is RAM available.  And RAM is used for the stack, which is used to call functions.  So we can't use C code when we're doing this RAM initialization.  Back when memory technology was simpler, or the memory buses were simpler,  it was kind of okay to do, I guess, the memory initialization, the RAM initialization in assembly.  You could do it in assembly language.  And it wasn't all that bad. It wasn't too long. It was okay.  But with this, for example, with this brute force search stuff that is in DDR2,  and which I can only assume is even more complex in DDR3,  it's really not something that we want to do in assembly anymore.  So one way around it is to use cache as RAM,  which means that part of the CPU cache is used as memory.  And in fact, it is memory. It's really fast memory.  But normally it isn't addressable.  But there's a way. It's documented by Intel, even.  It doesn't exactly describe why you would do it,  or I guess, well, they say how you do it,  but not exactly that the result is cache as RAM,  that you can run stuff without having RAM.  You have to read between the lines a bit.  But the information is there. You set up caching,  and then you make sure that you load all the code that you want to run into the cache.  And then you make sure that you don't run anything else,  and that you don't access any code outside that.  And if you do, it's possible to have ccode running without any RAM active.  So that's used by Corbucci for many mainboards,  but not for all, yet.  Our ambition is to have this for every mainboard.  We have the cache as RAM support for a lot of different CPUs and platforms  for AMD64 and for GeoLX, and I think also for the VSC7,  but all the boards aren't really using it yet.  It can be tricky to do this in a general manner.  We want cache as RAM support for everything, of course,  but different platforms, different systems,  they have restrictions on how big areas you can use for cache as RAM  and where they need to live, in which addresses you can use for this.  So it's not really easy to do this cache as RAM setup always.  Another option.  So that's GCC.  If you have cache as RAM, you can use GCC compiled code.  GCC assumes that there's memory.  But before we started using cache as RAM,  we had another thing, another solution.  ROMCC was created by one of the Corbucci developers.  It's a C compiler, custom-made, one big source file that's really long.  It generates machine code which doesn't need any RAM.  Of course, the X86 is sort of limited when it comes to the number of registers it has.  So the C code cannot be infinitely complex  because every time you call a function,  the C compiler has to reserve one register.  So eventually you run out of registers,  and then the compiler will complain  and it's not going to be able to compile the source code you have.  But if you have simple source code,  and if you write it in a certain way,  in lines, for example, can help,  then ROMCC does a fairly good job.  There has been a couple of bugs in there  which have been a bit difficult to track down.  But I think the ROMCC code is pretty good by now.  How can you make sure that you don't add up the nodes in the system?  So how can the ROMCC compile nodes in any case  that there's going to be not that much code?  You basically cannot.  So the question is, how does ROMCC know at compile time  when it runs out of storage?  Well, it has a model of the CPU that it's going to run on.  And at compile time, it fills up that model,  it fills up the registers,  and eventually if it runs out of registers  and it's impossible for the compiler to store the previous location,  then it's going to fail.  Then you can't do that function call at, I guess, level eight or nine.  If the compiler knows about the CPU,  but he probably doesn't know about the third-party kind of dynamic code on the front end.  The compiler surely knows about the CPU on the desktop  and he can cope with it,  but he cannot know about somebody creating artificial calls.  Artificial calls.  Do you get dynamic calls or do you generate mistakes in your community?  No dynamic calls.  I think function pointers are much more...  Yeah, for some reason.  Well, it could be supported as long as there's a register free.  But then you have to handle it on your own.  Well, it would require one extra register, I guess,  for saving the return or saving the function pointer somewhere.  I think it's offline.  Well, the sure explanation for this,  basically every function call is inlined around CC.  So if there is a function which calls itself around CC,  it will try to inline and eventually detect that you have an infinite loop or something like that.  So recursion or something like that, function pointers, forget it.  But recursively you can't do it in a fully inlined assembly code with no calls at all.  It can't be compiled by wrong CC.  That's the thing.  So I hope that...  Basically working out to be unrolled.  Yeah, right. It unrolls the source code completely.  I think it should be possible to implement function pointers though,  but it might not be in the current code.  Excellent. Thank you. You can do it.  Okay.  Still, wrong CC is...  Even though we're moving away from wrong CC code,  I think it's still useful.  For example, serialize, I believe, is the ROM shell for serialize is compiled with wrong CC.  And it's really an amazing effort that went into it.  Execution modes.  In the X86, there's the good old real mode, the classic execution mode,  that every modern CPU still starts up in.  You have a bunch of 16-bit registers.  The ones up there, I hope I don't forget one.  The first four are segment registers,  and the rest are...  They have sort of intended purposes,  but you can mix and match almost freely.  Not quite, but you can mix and match a bit.  And every memory address, as I said, in real mode is 20-bits.  So two of these 16-bit registers need to be combined.  And I've always seen that being called segmented addressing.  And it's written in the form segment register colon offset register.  They're both 16-bit, and the address ends up being...  The segment register shifted left by four, or multiplied by 16,  and then add on the offset register.  So for an example, if ds equals f 000 hexadecimal,  and si equals 6 000 hexadecimal,  then the ds si segmented address would be a physical address of f 0006.  So, yeah.  That way you can reach a full megabyte of address space.  And this was in 8086, 8088, 186 and 286.  And then with the 386, there was the protected mode.  Actually, there was one protected mode in the 286 as well,  but it was so different that I'm not going to bother.  I don't remember even all the details.  But the protected mode, as we know it,  and usually call it, is the one that came in 386.  It has a concept of privilege levels,  where you can specify that some parts of code  is allowed to do some things and not some other things.  And this is also...  This is, of course, what every modern operating system relies on  in order to do security properly.  Otherwise, you wouldn't be able to do anything,  even as a user in Linux, for example.  But only the root user is really allowed,  or the kernel is really allowed to do anything in the system.  When one of these privilege instructions,  or when you're trying to do, if you're trying to do something  that you're not allowed to do,  then the 386 or a protected mode CPU is going to throw an exception.  And this can be handled by an interrupt handler  and then all the APIC stuff comes into play.  And you end up running some other piece of software  which can sort of detect what happened.  And then it goes all the way back  and tells the user that,  oops, you did something that you're not supposed to do  instead of crashing or whatever.  Also included in the protected mode is paging.  This is a reference table,  or a lookup table for addresses.  So you're using an address, but it's not up here.  If you say you want this address,  it might actually be a completely different address.  So there's a translation layer  in between the address you're using, the virtual address,  and the address that is actually seen on the bus, the physical address.  The protected mode, not actually protected mode,  this is more than 386.  The 386 added 32-bit registers.  So there are e versions of all the ones from AX out to HP.  Then our 32-bit, the lower 16-bit are the same,  and some of those can be divided into 8-bit registers.  And then the segment registers,  they change into what is called selectors.  It's the same register name, it just has a different function.  In protected mode, the selector will look up a data structure,  which has information about paging and privileged instructions,  and also base and limit.  So this is all part of the translation.  Depending on what you put in CS,  if you say put, for example, 0,  then you're going to get the first entry in this lookup table of selectors or descriptors.  And that means if you access address 0,  it's actually going to be somewhere completely different.  But if you then change CS to be 8 instead,  and you move one step forward in this table,  the global descriptor table or the local descriptor table, as they're called,  and then if you're accessing 0, it gets a completely different meaning.  The limit specifies how big a memory block you can access,  starting from the base address.  So system management mode, I mentioned it's triggered by system management interrupt,  when the processor enters system management mode,  it's always running in real mode,  but it's free to switch to protected mode if it wants to.  Interrupts are always disabled, and the debug traps are always disabled,  so when you're running in system management mode, you're really isolated.  The machine is all yours.  System management mode can be entered by, as I mentioned, IOTraps or even MMIOTraps,  so the memory maps register accesses.  Machine check exceptions, when the CPU detects that it's broken,  and anything in the APIC can also generate or result in system management mode execution.  Embedded controllers, I'm out of time,  so unfortunately no RAM development embedded controllers,  it's the 851 in the SuperIO.  It can do a whole lot of stuff, which sort of messes up the system  because it's transparent,  and it might also be very difficult to detect.  But, yeah, no.  Thanks to Luke, and questions, if there's time.  Yep.  How does RonCC store loaded variables and variables passed to fantasy?  In registers.  So you can have only a few of those variables.  Yes.  How?  In the SuperIO, the AD51, where does it get it's go from?  Good question.  So it depends on, sometimes the 851 there, it can be a standalone chip,  and if it's a standalone chip, it can have a built-in firmware,  but it could also be sharing the boot flash with the main firmware in the system.  So, say the first 50, 56 kilobytes is the firmware for the microcontroller,  the embedded controller.  That's fairly common.  Or it can have its own flash chip.  Yep, it can definitely have its own flash chip as well.  Yeah.  Question?  The build-run with the system management mode.  System management mode?  Does it also come from the boring?  Yes.  So you could actually disable some of our...  Yes, definitely.  Do you have a real-time system?  Yes, definitely.  Someone also earlier asked the question if...  So the question was where the system management code that is run in Coreboot,  where does it come from?  And the answer is it is also in Coreboot.  We have two separate implementations of system management code handlers in Coreboot.  One is from AMD, that's the one for the Geo.LX,  but they open-source that, and then there's the code that Stefan Reinhauer wrote  for the Intel, Intel platforms.  And I think, well, maybe a few of you also wrote some small system management code  for the AMD64.  Yeah.  But it's all included in the Coreboot source,  and there's full control, and it does really very little,  because it wants to get out of the way.  All right.  Okay, thank you very much.  Thank you.
Coreboot_and_PC_technical_details_gRwEZis7Z6A_0_2327.png Coreboot_and_PC_technical_details_gRwEZis7Z6A_2328_2423.png Coreboot_and_PC_technical_details_gRwEZis7Z6A_2424_3215.png Coreboot_and_PC_technical_details_gRwEZis7Z6A_3216_3299.png Coreboot_and_PC_technical_details_gRwEZis7Z6A_3300_13091.png Coreboot_and_PC_technical_details_gRwEZis7Z6A_13092_17567.png Coreboot_and_PC_technical_details_gRwEZis7Z6A_17568_25439.png Coreboot_and_PC_technical_details_gRwEZis7Z6A_25440_25595.png Coreboot_and_PC_technical_details_gRwEZis7Z6A_25596_26075.png Coreboot_and_PC_technical_details_gRwEZis7Z6A_26076_26135.png Coreboot_and_PC_technical_details_gRwEZis7Z6A_26136_26663.png Coreboot_and_PC_technical_details_gRwEZis7Z6A_26664_27047.png Coreboot_and_PC_technical_details_gRwEZis7Z6A_27048_27323.png Coreboot_and_PC_technical_details_gRwEZis7Z6A_27324_27551.png Coreboot_and_PC_technical_details_gRwEZis7Z6A_27552_28019.png Coreboot_and_PC_technical_details_gRwEZis7Z6A_28020_28187.png Coreboot_and_PC_technical_details_gRwEZis7Z6A_28188_28715.png Coreboot_and_PC_technical_details_gRwEZis7Z6A_28716_29087.png Coreboot_and_PC_technical_details_gRwEZis7Z6A_29088_29303.png Coreboot_and_PC_technical_details_gRwEZis7Z6A_29304_29927.png Coreboot_and_PC_technical_details_gRwEZis7Z6A_29928_32039.png Coreboot_and_PC_technical_details_gRwEZis7Z6A_32040_32291.png Coreboot_and_PC_technical_details_gRwEZis7Z6A_32292_32447.png Coreboot_and_PC_technical_details_gRwEZis7Z6A_32448_32603.png Coreboot_and_PC_technical_details_gRwEZis7Z6A_32604_32699.png Coreboot_and_PC_technical_details_gRwEZis7Z6A_32700_34151.png Coreboot_and_PC_technical_details_gRwEZis7Z6A_34152_34619.png Coreboot_and_PC_technical_details_gRwEZis7Z6A_34620_34751.png Coreboot_and_PC_technical_details_gRwEZis7Z6A_34752_36167.png Coreboot_and_PC_technical_details_gRwEZis7Z6A_36168_41207.png Coreboot_and_PC_technical_details_gRwEZis7Z6A_41208_47351.png Coreboot_and_PC_technical_details_gRwEZis7Z6A_47352_47567.png Coreboot_and_PC_technical_details_gRwEZis7Z6A_47568_48431.png Coreboot_and_PC_technical_details_gRwEZis7Z6A_48432_49151.png Coreboot_and_PC_technical_details_gRwEZis7Z6A_49152_50195.png Coreboot_and_PC_technical_details_gRwEZis7Z6A_50196_51599.png Coreboot_and_PC_technical_details_gRwEZis7Z6A_51600_56711.png Coreboot_and_PC_technical_details_gRwEZis7Z6A_56712_56879.png Coreboot_and_PC_technical_details_gRwEZis7Z6A_56880_57299.png Coreboot_and_PC_technical_details_gRwEZis7Z6A_57300_57443.png Coreboot_and_PC_technical_details_gRwEZis7Z6A_57444_57599.png Coreboot_and_PC_technical_details_gRwEZis7Z6A_57600_58355.png Coreboot_and_PC_technical_details_gRwEZis7Z6A_58356_58787.png Coreboot_and_PC_technical_details_gRwEZis7Z6A_58788_58991.png Coreboot_and_PC_technical_details_gRwEZis7Z6A_58992_59591.png Coreboot_and_PC_technical_details_gRwEZis7Z6A_59592_62003.png Coreboot_and_PC_technical_details_gRwEZis7Z6A_62004_62195.png Coreboot_and_PC_technical_details_gRwEZis7Z6A_62196_62591.png Coreboot_and_PC_technical_details_gRwEZis7Z6A_62592_63251.png Coreboot_and_PC_technical_details_gRwEZis7Z6A_63252_63311.png Coreboot_and_PC_technical_details_gRwEZis7Z6A_63312_65387.png Coreboot_and_PC_technical_details_gRwEZis7Z6A_65388_66659.png Coreboot_and_PC_technical_details_gRwEZis7Z6A_66660_67583.png Coreboot_and_PC_technical_details_gRwEZis7Z6A_67584_69491.png Coreboot_and_PC_technical_details_gRwEZis7Z6A_69492_70439.png Coreboot_and_PC_technical_details_gRwEZis7Z6A_70440_72875.png Coreboot_and_PC_technical_details_gRwEZis7Z6A_72876_79091.png Coreboot_and_PC_technical_details_gRwEZis7Z6A_79092_84335.png Coreboot_and_PC_technical_details_gRwEZis7Z6A_84336_88307.png Coreboot_and_PC_technical_details_gRwEZis7Z6A_88308_88607.png Coreboot_and_PC_technical_details_gRwEZis7Z6A_88608_89351.png Coreboot_and_PC_technical_details_gRwEZis7Z6A_89352_89663.png Coreboot_and_PC_technical_details_gRwEZis7Z6A_89664_91031.png
The second demo and please be quiet everyone. Some that we might be able to hear what's actually going on. No way to hear what's going on. I'll just have to sort of narrate. Again, serial console. This is one of the GLLX boards, an AMD CPU. The embedded, AMD embedded CPU with two six megabytes of RAM. And let's see when I reset. There we go. Four boot running. And there it's already starting the Linux kernel. And that's the final prompt of the Linux system, which is full up at that time. So this shows that if you disable all the debugging stuff and you have a really trimmed down kernel, you can get a very nice start up time. And talking about boot time measurements, I think it's important to be careful with the numbers here. Or just be careful about what the numbers actually are saying. Because different people will use different metrics for boot time measurements. And of course everyone wants their numbers to be the best, so they're going to use what is best for them. What is this time measurement actually saying? Is it saying from power supply connected to windows running with a full desktop, whatever login user or Linux or whatever you have? Or is it from after the mainboard power up sequence, which might make a difference? It sounds silly, but it might actually make a big difference. There are about 30 voltages in a PC system, so and these all need to start in a special sequence. And that takes time, of course. Or is it from the first instruction fetch, which might be a lot later? Then after all the voltages are up, who knows what's going on in the system? So the guy who's been developing CBIOS, his name is Kevin O'Connor, he did some optimizations for his particular board. He has an EPR board of the EPR-CN with a C7 CPU and the CN700 chipset. He put core boot and CBIOS in flash, used CBIOS as the payload, and he had a grub on a SATA SSD. And this is the results he got. He had to spend 350 milliseconds just waiting for what seems to be power sequencing. From the time he presses the button to some software actually running, it's almost half a second. Then he measured that it takes about 50 milliseconds to wait for a communications bus on the mainboard to stabilize. Another 20 milliseconds to configure the memory controller. 10 milliseconds running core boot. 200 milliseconds waiting for the VGA BIOS to initialize the graphics. And another 10 milliseconds in grub. And the grunt of who is that it takes 750 milliseconds from the time he presses the power button to when Linux is already starting. Security slide, I don't know. I think I'm going to skip this. Well, maybe just mention it quickly. Core boot attack, there was an attack made public, I guess, the year before last year, so 2008, even though you power down your computer, the RAM might not be completely empty. And if someone can steal your laptop or desktop for that matter, they can check out the RAM, the DIMM, and extract all the contents of the data. And it's really easy to find crypto keys and so on. So core boot can be used both in the attack and for defense here, because core boot has RAM initialization, it can start the memory controller and then have a special dump routine inside core boot to read out all the contents without changing anything in RAM. But you could also use it so that when you're shutting down, there's a part of core boot which runs and makes sure it's to clear all the memory before it powers off. Code injection into the operating system. And exploit published where part of the BIOS was changed to always rewrite permissions on a particular file in the root file system. So whenever you rebooted, this file became world executable with the plus s and everyone had a root shell on the system. That's not something you want in your firmware, so it might be worthwhile to look carefully at the firmware you're running. There's a lot of good stuff about core boot. You can get really fast startup times. It's open source, C code, DPL, you can audit, you can read it. You don't have to study assembly, assembly sources, a day on end to go through the code. We have one tree for all the boards, so there's a fair chance of reusability and extensibility there. There's still some challenges. We need more testing. That would be great. There's a testing infrastructure, but it's kind of difficult to hook up boards to be tested to this infrastructure. So even though we have really nice way in this infrastructure to test each commit on actual hardware, because the fact that it's too difficult to connect boards to this infrastructure means that there's little testing actually done. Everything is built on each commit, and that's a good start, of course, but it would be very nice also to see boot testing, because stuff can rig even though it compiles, it might not run. And it would be very nice to have all the boards really 100% supported. Most of the boards are implemented by one single developer or a small group of developers, and they were really happy when all the stuff they need is working, but that might not be enough for everyone else. So little things on the main board might still need some code to work. Most boards are not really far away. There's only very small, very small stuff missing. ACPI, we need to get better at ACPI, but we already have a lot of good progress there, thanks to Rudolph who's going to talk about it a bit later, and Ashlef and so on. And code is great fun. So come into the project, please. Thanks to Luke for organizing this dev room and some links for boot.org, and we have a mailing list and we're on our C, and the Wiki, you can just add anything after the URL, and you should get an informative page. Questions? What do you use for flashing your flash chip if it is completely screwed? What do you use for flashing your flash chip if it is completely screwed? Commercial flash chip. Sorry? Do you use some commercial flash chip? You can, yeah, sure, that's one way. You can have a flash programmer or flash writers down below. That helps, but you don't always have access to that. One thing you can do is to have a use another main board instead, and hot swap the flash chips. Flash chips, programmer. Good to have, but you can also use another main board. Yeah, hot swap, that's fine. I think Carl Daniel will talk more about that also in the flashroom talk. Another question, yeah? What are the implications of not fully supporting ACPI? What are the implications of not fully supporting ACPI? Yeah, sure. Rudolph wants to answer. I will enter the next talk on ACPI so that perhaps I can write that into a real question. But in support of it, to the moment that everything, the line of these is there, everything between those needs is there. So both is the news, all is there after everything, the software is everything. So what we did is somewhat minimalistic ACPI implementation. This was the standard prompt. It's there, nothing more. So we don't have much of the byte code stuff there. We are just only very basic routine, what is required by standard operating system. So in this case, everything which the real life operating system needs is probably there. But there is no consist of like the terminal zone and lake and so on, because it can be either on some platform level by some other drivers and so on. So we don't need to be full blown, let me say ACPI, so we just support what's really necessary. And there are, so I guess I could add there that one implication would be that there needs to be a driver to handle some tasks that might otherwise be handled using ACPI on another operating system or, sorry, another firmware. But again, if Linux has that driver and you want to run Linux, then it's fine. Thanks. No more, yeah, okay, another question? Your program, your first instruction that will be ever found is immediately copied. Yes. I presume that you have to configure portals, which serial port you are using? Yeah, things like that, yes, that's part of the build. And there are also some variables that are set or some settings that you can change runtime. Well, not runtime, but are read from NB RAM. So if you built up your operating system, you use NB RAM tool to change the settings. And the next time you reboot, they will take effect. For example, there's a new motherboard with, I don't know, a newer version or a higher clocked RAM version. How can you extract the exact parameters? So a new main board with higher clocked RAM or a different type of RAM would be small to medium effort. Rulof is also going to talk about porting coreboot to a new board. And it would really be like adding a new main board if it's, say, an upgrade from DDR2 to DDR3. Not all of the work needs to be done as if it was a completely new main board, but still some things have to be changed. And like for the RAM, in order to get your RAM stabilized to new weights, is it some sort of file? I'm sorry to talk about that in the next presentation of RAM initialization. If you're, are you staying for that as well? Then maybe, okay, all right. Well, if you have, then maybe we can come back to the question. All right. Yes, there's one laptop supported at the moment. Two if you count the OLPC. So the laptop that is supported is, I mentioned that in the presentation. The development was funded by the German BSI. And it's a rugged, rugged laptop, but the components in it are fairly standard. So that code and that effort can be reused for supporting other laptops as well. And I also have one board that I'm, I'm sort of working on a laptop. They call it a network, but I, it's a 12 inch, it has a 12 inch screen. So I don't know if I think it's a network, but this is, this is the board anyway. This is all that is really in the laptop except for the screen and the hard drive. It's a VIA based platform. It's the Samsung NC20. So hopefully that will, will work at some point as well. Does that answer your question? Please do, but it, it might be a lot of work. And especially it depends a lot on the, which components are in your laptop. Rudolph will, will talk about that more also in his presentation. It can be really difficult to find out all the information that is necessary. All right. So no more questions. Thank you very much for coming. Sorry, I, I went over time a bit, but yeah, I hope you thought it was, was interesting. Thank you. Do we need a few minutes of a break between presentations before I start the next one, or should I just go straight away? All right, I'll continue then. Okay, yeah. So, Pourgoot and PC Technical Details is the title of this presentation. This is what I hope to be able to talk about here. Yeah, who am I again? I guess that's the same as before. A look at the 30 years of PCs. The PC has been around for a long time and it's changed quite a lot. I would like to have a look at the ISO bus, the first, well, actually the second extension bus in the PC, but it worked the same way as the first one. So we're going to look at that in order to learn some things that are very important and still apply to a lot of other buses and devices in a modern PC. Some thing about hardware registers, various, on various buses, ISO, PCIe and MSR. I'm going to talk a bit about NVRAM, I'm going to talk a bit about interrupts. RAM initialization, cache as RAM is a trick that is used by many firmers today. GCC and ROMCC is something that came out of Pourgoot as well. The different x86 execution modes, real mode, protected mode, dimensions mode, maybe embedded controllers if there's time and the thanks. This is the same as the last slide I've been doing Pourgoot for a while. I started in Hamburg and I do stuff. The PC in the 1980s, it might have looked like this. There was a CPU and there was a boot ROM and there was some RAM connected and it was a cassette player and the keyboard and an expansion port. All of this was really connected to the same communications bus. We went from cassette to DDR3 and this is what the PC might look like today. There's a lot of stuff in here. We can have four or however many, eight, sixteen CPUs maybe. Every CPU might have its own memory controller and the RAM is connected to the memory controller and that's one bus and different CPUs might be connected together in one special bus. Then there's some connection to the North Bridge and some IO stuff. There's a whole graphics block which is either in the North Bridge or might be on a PCI Express bus off somewhere. There's another bus down here to something, South Bridge, which has a slower old PCI bus. There's some USB and IDE. PS2 may be there or might be over here in the Super IO. LPC is a replacement bus for the old ISA bus. I would say that it's really on every main board these days. There's an LPC bus somewhere. It can connect to a Super IO. It can also connect to a boot flash or there could be an SPI bus which connects from the South Bridge to the boot flash. Or there could be an SPI in the Super IO. So it could be LPC over to the Super IO to SPI and then to the boot flash. The Super IO has lots of other stuff also, floppy. It could be PS2 as I mentioned, serial, parallel, GPIOs, watchdog, thermal measuring lots of temperatures on the board. And there might also be microcontroller. So another CPU inside the IO chip down here. That's the embedded controller that I hope to rant a bit about also. Oh yeah, and there's the SM bus. I mentioned in the previous presentation that Kevin had some issues waiting for the SM bus to stabilize. We'll come back to that when we're talking about RAM initialization because it's connected to the RAM. So this is a look at how it might be. And it can of course be even more complex. You can have, this might not be a single core CPU, but it might be a four core CPU. So you have four CPU cores behind that one connected to one memory controller, but connected also to all the other CPUs. It can be pretty complicated. So HG is hyper-transport. That's AMD's bus for interconnect, or AMD's interconnect between CPUs. And IO nodes. Intel developed their own. It's both quick path interface, I think, is the abbreviation, the QPI. That's the same thing, connection between many CPUs in a system which has many CPUs. So what about this ISO bus? The way it looked back when? There's IO and memory access in the X86 CPU. There's an 8 or 16-bit data communication path. And depending on if you're doing IO access or you're doing memory access, the address space has a different size. So for IO, it's always 16-bit, so we have 64K addresses. These addresses, they're usually called ports. I'm not really sure why, but if you see port somewhere, it's about an IO. The CPU instructions used for IO is in-b, in-w, out-b, out-w. And in newer CPUs, you have the in-l and out-l instructions also. These also are available as function calls in Linux. You can do direct IO from Linux user space if you do some preparations first. I think my, Carl Daniel might talk about that also. Well, that knows. In the lighting talk, I guess. For the porting in the L-O-S room. Well, anyway, it's possible to do this direct, this IO communication, this IO accesses from Linux. And even if there's no I-sub bus in the system anymore, it's still possible to do these operations. And where are they going to end up? Well, they will end up on LPC usually, and there might be something listening there. Typically, the super IO is what you want to talk to in that case. If you're doing memory accesses, then you have 20 bits of address. And we'll have a look at how those 20-bit addresses are created in a bit. In execution mode, stuff. And the memory accesses, they all use move instructions. So it's just memory read and memory writes. If you're programming in C, you're reading from a variable. That's a memory read. In the really early PCs, that memory was external. The new PC, the memory is actually connected to the CPU itself. And of course, has a lot longer address space than 20 bits. There's a whole bunch of registers in all the hardware components that we looked at and in every add-on component that you can connect to a PC. And these register accesses, they will be either IO or the registers, they will either be IOMapped or they will be memory mapped. On ISAHearnware, it was kind of common on the really old, for example, really old networking cards. You had a whole bunch of jumpers. How many people remember those? Yeah? You had to choose the base IOPort, then you had to choose the interrupt, you had to make sure there were no conflicts and it never worked. They invented this plug-and-play stuff which was supposed to be clever, but I don't know. In theory, it was good, but I think the implementations weren't really that awesome. PCI is very different. There are no jumpers. There's no conflicts. It handles all the configuration. So Coreboot, that's all the long printouts that we saw from the first demo, is checking all the PCI devices connected to the system and making sure that they can coexist and be accessible at the same time. PCI devices, they have what's called configuration space, 256 bytes of registers. They are always reachable. I think the standard says that it's not necessarily always, but in practice it really is always. They are reachable on IOPort's CF8, hexadecimal, and CFC. This is an index data combination, so you first write the address of the register you want to access to CF8, and then you do the actual value access on CFC. So say you want to access... No, I'm not going to give you an example, because you have to encode the PCI device address and something that's called a function number and the register number into this access to CF8. I can do that in my head, so we'll have to skip that example. But anyway, first specify what you want to access and then do the actual access on a different IOPort. This is typically always available. If the system has PCI, then this is going to be there. This is called the Type 1 configuration interface, and maybe you've seen that in the Linux kernel sources. You can choose what type of configuration access method that's going to be used. This is also what CoreBoot uses. CoreBoot used to support another access method, but it was never used, so we threw that out. Configuration space can also be reached via memory mapped registers, and that's called MMConfig. Not every system supports it, but if they do, it's more convenient because you just access what could be a memory address. It looks just like any other address in memory, but there's no memory there. Instead, you're reading and writing, well, there is memory, but the memory is small registers on some PCI device, and it's not the dim, the main RAM in the system. So that's handy, and it's also faster. These IOP accesses tend to be pretty slow because they are so old and legacy compatibility stuff on the bus. The 16 first bytes of at least 256 are standardized by the PCI standard. So every single PCI device is going to have the first 16 bytes exactly the same. Well, not identical contents, but identical structure. The first four bytes show the vendor and the device ID. For example, there's also information about which interrupts is going to be used for this device and a couple of other things. Interruptible polarity detected errors on the PCI bus by this device. If this device is a busmaster and a whole bunch of other settings as well. And there are base address registers, or bars, as they're called. So maybe these 256 minus 16 bytes, these 240 bytes, maybe that's not enough for doing everything that this PCI device can do. Maybe you need a lot more if it's a graphics card. For example, you want access to the graphics memory. And 240 bytes isn't really a lot of graphics memory today. So you need some way to create a window into the graphics memory that is on the graphics card. So then you will configure a bar, or when the firmware will configure a bar, a base address register, saying to the PCI device that when the PCI bus sees an access to this particular address, then that is meant for you. So every PCI device looks at the traffic on the bus, and only the one that has been configured to access to this particular address is going to accept them and decode them and process them. So in case the firmware does a half-assed job and sets up base address registers which conflict, then you're going to have more than one device react to stuff going on on the PCI bus and nothing is going to be working. So in the example of a graphics card, the base address register would set up memory mapping because you want the graphics memory to be accessible as memory. But base address registers can also be used for IO mapping. In that case, you have some number of IO ports that you want to end up on this particular PCI device, and then you, the firmware, set a base address register in the same way which tells the PCI device to decode IO accesses to this particular port. This is really common for PCI devices to have one or both memory and IO bars. It could even be several. I think in the 200 and, sorry, in the 16 bytes, 16 standard bytes, I think there's room for four base address registers. I don't know. No, sorry, it's in the full 256. It's room for four or maybe even more base address registers. So you can have one PCI device that has several different memory regions or IO regions that it's decoding. There are also the MSRs. Yeah, almost can see. Model specific registers. That's low level registers in the CPU itself, in the North Bridge, in the IO controller, stuff like that. I'm going to come back to some of those. NV RAM, I mentioned that. It's also called CMOS. I don't know if, I probably doesn't use CMOS technology anymore, but the name has stuck. It's in its simplest form, with a basic form, it's 128 bytes of battery backed RAM, and it's stored in the real time clock chip. And the real time clock chip, in turn, is usually part of another chip in a modern PC. But in the original PC, that was one Motorola chip on its own. Now it's usually in the Super IO or maybe in the chipset. So these 100 odd bytes, they survive power down. You can have the system disconnected forever, well not forever, but for a long time, and the contents is still going to be the same. Also the clock keeps ticking, of course, when the system is shut down, that happens there. The standard way to access these registers is, again, one of these index value IO sequences. You write the address you want to access to port 70, and then you read or write port 71 hexadecimal to read or write that value. And this is where all the BIOS settings are stored, typically, and this is also what NVRAM tool messes with. So you give it the layout file of which bits are which setting, and it will do all the translation and make sure you don't overwrite any wrong bits. It accesses these ports 70 and 71, and it works out well. There are also extended registers, another 128 bytes, and there can also be another 256 bytes in other places, but that works just the same way. Ports 72 and 73 are really common. If you want to have a look at the driver for this in Linux, it's driver's car in VRAM. Somewhere in ART x86 there are a couple of macros which translate to the out-B and in-B, which will do the actual port accesses. Interrupts. How many recognize this picture? All right, excellent. How about 8, 9, 10 or so? So this is the legacy pick programmable interrupt controller. The way interrupts works in the beginning, single CPU systems, I guess all the way back to 8088, the original PC. There were 15 usable interrupt signals, interrupt inputs, to these two interrupt controllers that are connected together. And the chain of events is, as described here, a device. Well, typically one device would connect to each of these inputs 0 through 15. The device wants attention from the CPU because something has happened. There's a byte coming in from the modem or from the keyboard, or maybe it's possible now to send a byte out to the modem or to the keyboard or wherever. A network card for that matter. So the device signals an interrupt, pulls one of these strings. Now this is this, the interrupt controller, and if it's one of these high ones, it's going to trickle through to the master. And the only interrupt signal going to the CPU is the actual int. That one. Yeah, so the one interrupt signal from the master pick is all that is going to the CPU. The CPU only accepts one single interrupt signal. But what about all these devices? How does that work out? Well, so when there's an interrupt, the CPU will acknowledge that it received this interrupt signal by pulling on this int A signal to the interrupt controller. And then it's going to wiggle that interrupt acknowledge signal a little bit more, which causes then the program interrupt controller to write an address for the interrupt handler, or the interrupt vector to the data bus. So the CPU says, okay, I got the interrupt. The CPU says, okay, what should I do now? The interrupt controller has been programmed, hence programmable interrupt controller, has been programmed to know that interrupt this and that, should be handled by code running at this particular address in memory. So the CPU says, okay, what should I do now? The programmable interrupt controller replies, you should go to this address in memory where the interrupt handler lives. So it writes that out to the data bus. The CPU reads the address and jumps to the address. And there's an interrupt handler running in the CPU. So this was with just one CPU. Then there's only one interrupt signal, even though we can have many interrupt sources. And hopefully this explains all the interrupt problems that were with the old ESA cards a little bit. Okay, what about when there are multiple CPUs? Then it gets fun again. There's always one bootstrap processor. That's the first processor that comes up running when the system is starting. That is all arranged in hardware, which processor will be running when the power comes on. Then any other CPUs are going to be application processors. So there's always only one running in the beginning and it has to... Well, actually that's not true. That depends on if it's AMD or Intel, I think. But one of them, everyone comes up running and they have to agree to stop if they're not the BSP. But there has already been a decision made in hardware, so that there's only one which is designated the BSP. And it should check if it's the BSP and the other ones should stop, and the BSP will continue. Anyway, inside of these CPUs, there's a local APIC. APIC is, I guess, Advanced, Programmable Interrupt Controller. And the local APICs, there's one in each CPU, as I said, they communicate with each other. For example, this has a transport or it could be some front side bus or such, system bus, whatever. They also connect with this IO APIC, which is the one dealing with... Well, this looks familiar. This is the same, the legacy pick arrangement, which is still there, even if you have an APIC. It might not be used. If you... So the APIC situation, it needs to be configured before it's being used. And if it's not configured, then the system is still going to be using this legacy pick setup. But if you configure the full-on APIC situation, then you get the local APICs talking to each other and talking to the IO APIC, and you can do really flexible mapping of all the interrupts coming into the IO APIC, and all of the interrupts that can be generated by the local APICs also. Because by the time we have multiple CPUs, the CPUs also have a lot of more functionality included than maybe the older ones did. So for example, we have dimension-ready machine check exceptions, MCEs. If the CPU detects that it has broken, it can trigger an APIC interrupt, and that can call into an interrupt vector somewhere. So the interrupt vectoring part is still the same. The local APIC will make sure that the CPU runs... It will often run some configured interrupt handler. The difference from the legacy pick situation is that, well, first of all, the IO stuff which is connected to all the peripherals and the PCI bus down here, that's separated out. And the local APICs, they also have support for, I think, 256 interrupt sources instead of the 15. So there's plenty of interrupt signals available. They can come from... Interrupts can come from, as I mentioned, from within the APIC itself, from within the CPU itself. The APIC has also a timer which can generate interrupts. And yes. Yeah, of course, the APIC enabled there. It has to be enabled, as I mentioned. Here's also the system management interrupt signal, which goes into the CPU and not the APIC in this drawing, I think. So a lot more complicated, but basically still the same principle. You have programmed the pick, the interrupt controller, with all the interrupt vectors. And when the interrupt happens, it will send the CPU to run the code that it should. But there are a lot of possibilities with many different interrupts here. I think Rudolph will also come back to this. For RAM initialization, how are we doing on time? Okay. For RAM initialization, what do we have to do there? Well, our goal in RAM initialization is to configure this thick red connection over here. It could be DDR2, it could be DDR3. In any case, it's a lot of work. We need to know exactly what kind of RAM is connected here on this side. And the same for all of the CPUs and or memory controllers which have RAM connected. And well, since this communication link isn't working, what do we do? We then have to use this SM bus. So from the CPU, when we're doing memory configuration, we go through the North Bridge, South Bridge, out onto the SM bus and follow this green line and talk to this little green guy, which is an E squared prom on each dim. So a small serial E prom, it stores a couple of parameters. What size is this memory? How fast is it? Is it registered? Is it not registered? Et cetera, et cetera. All the parameters that, yeah, timing supported by this memory module, all the stuff that is needed to configure the memory controller correctly. And I'm not going to go into great detail with the memory controller configuration because it's so complicated. But I'm going to say that DDR2 at least requires some brute force searching for finding the correct tuning of the timing between the memory controller and the actual dim. So the firmware has to search through all possible settings or many possible settings for the tuning parameters in order to find the one that is working really well. And worst case, that parameter could actually change with the temperature in the room depending on how the board is laid out, the traces on the main board. So it's a long work. Cache's RAM is used in core boot. This RAM initialization stuff. So when the RAM initialization is running, there is no RAM available. That means it's not possible to run C code because C compilers, they assume that there is RAM available. And RAM is used for the stack, which is used to call functions. So we can't use C code when we're doing this RAM initialization. Back when memory technology was simpler, or the memory buses were simpler, it was kind of okay to do, I guess, the memory initialization, the RAM initialization in assembly. You could do it in assembly language. And it wasn't all that bad. It wasn't too long. It was okay. But with this, for example, with this brute force search stuff that is in DDR2, and which I can only assume is even more complex in DDR3, it's really not something that we want to do in assembly anymore. So one way around it is to use cache as RAM, which means that part of the CPU cache is used as memory. And in fact, it is memory. It's really fast memory. But normally it isn't addressable. But there's a way. It's documented by Intel, even. It doesn't exactly describe why you would do it, or I guess, well, they say how you do it, but not exactly that the result is cache as RAM, that you can run stuff without having RAM. You have to read between the lines a bit. But the information is there. You set up caching, and then you make sure that you load all the code that you want to run into the cache. And then you make sure that you don't run anything else, and that you don't access any code outside that. And if you do, it's possible to have ccode running without any RAM active. So that's used by Corbucci for many mainboards, but not for all, yet. Our ambition is to have this for every mainboard. We have the cache as RAM support for a lot of different CPUs and platforms for AMD64 and for GeoLX, and I think also for the VSC7, but all the boards aren't really using it yet. It can be tricky to do this in a general manner. We want cache as RAM support for everything, of course, but different platforms, different systems, they have restrictions on how big areas you can use for cache as RAM and where they need to live, in which addresses you can use for this. So it's not really easy to do this cache as RAM setup always. Another option. So that's GCC. If you have cache as RAM, you can use GCC compiled code. GCC assumes that there's memory. But before we started using cache as RAM, we had another thing, another solution. ROMCC was created by one of the Corbucci developers. It's a C compiler, custom-made, one big source file that's really long. It generates machine code which doesn't need any RAM. Of course, the X86 is sort of limited when it comes to the number of registers it has. So the C code cannot be infinitely complex because every time you call a function, the C compiler has to reserve one register. So eventually you run out of registers, and then the compiler will complain and it's not going to be able to compile the source code you have. But if you have simple source code, and if you write it in a certain way, in lines, for example, can help, then ROMCC does a fairly good job. There has been a couple of bugs in there which have been a bit difficult to track down. But I think the ROMCC code is pretty good by now. How can you make sure that you don't add up the nodes in the system? So how can the ROMCC compile nodes in any case that there's going to be not that much code? You basically cannot. So the question is, how does ROMCC know at compile time when it runs out of storage? Well, it has a model of the CPU that it's going to run on. And at compile time, it fills up that model, it fills up the registers, and eventually if it runs out of registers and it's impossible for the compiler to store the previous location, then it's going to fail. Then you can't do that function call at, I guess, level eight or nine. If the compiler knows about the CPU, but he probably doesn't know about the third-party kind of dynamic code on the front end. The compiler surely knows about the CPU on the desktop and he can cope with it, but he cannot know about somebody creating artificial calls. Artificial calls. Do you get dynamic calls or do you generate mistakes in your community? No dynamic calls. I think function pointers are much more... Yeah, for some reason. Well, it could be supported as long as there's a register free. But then you have to handle it on your own. Well, it would require one extra register, I guess, for saving the return or saving the function pointer somewhere. I think it's offline. Well, the sure explanation for this, basically every function call is inlined around CC. So if there is a function which calls itself around CC, it will try to inline and eventually detect that you have an infinite loop or something like that. So recursion or something like that, function pointers, forget it. But recursively you can't do it in a fully inlined assembly code with no calls at all. It can't be compiled by wrong CC. That's the thing. So I hope that... Basically working out to be unrolled. Yeah, right. It unrolls the source code completely. I think it should be possible to implement function pointers though, but it might not be in the current code. Excellent. Thank you. You can do it. Okay. Still, wrong CC is... Even though we're moving away from wrong CC code, I think it's still useful. For example, serialize, I believe, is the ROM shell for serialize is compiled with wrong CC. And it's really an amazing effort that went into it. Execution modes. In the X86, there's the good old real mode, the classic execution mode, that every modern CPU still starts up in. You have a bunch of 16-bit registers. The ones up there, I hope I don't forget one. The first four are segment registers, and the rest are... They have sort of intended purposes, but you can mix and match almost freely. Not quite, but you can mix and match a bit. And every memory address, as I said, in real mode is 20-bits. So two of these 16-bit registers need to be combined. And I've always seen that being called segmented addressing. And it's written in the form segment register colon offset register. They're both 16-bit, and the address ends up being... The segment register shifted left by four, or multiplied by 16, and then add on the offset register. So for an example, if ds equals f 000 hexadecimal, and si equals 6 000 hexadecimal, then the ds si segmented address would be a physical address of f 0006. So, yeah. That way you can reach a full megabyte of address space. And this was in 8086, 8088, 186 and 286. And then with the 386, there was the protected mode. Actually, there was one protected mode in the 286 as well, but it was so different that I'm not going to bother. I don't remember even all the details. But the protected mode, as we know it, and usually call it, is the one that came in 386. It has a concept of privilege levels, where you can specify that some parts of code is allowed to do some things and not some other things. And this is also... This is, of course, what every modern operating system relies on in order to do security properly. Otherwise, you wouldn't be able to do anything, even as a user in Linux, for example. But only the root user is really allowed, or the kernel is really allowed to do anything in the system. When one of these privilege instructions, or when you're trying to do, if you're trying to do something that you're not allowed to do, then the 386 or a protected mode CPU is going to throw an exception. And this can be handled by an interrupt handler and then all the APIC stuff comes into play. And you end up running some other piece of software which can sort of detect what happened. And then it goes all the way back and tells the user that, oops, you did something that you're not supposed to do instead of crashing or whatever. Also included in the protected mode is paging. This is a reference table, or a lookup table for addresses. So you're using an address, but it's not up here. If you say you want this address, it might actually be a completely different address. So there's a translation layer in between the address you're using, the virtual address, and the address that is actually seen on the bus, the physical address. The protected mode, not actually protected mode, this is more than 386. The 386 added 32-bit registers. So there are e versions of all the ones from AX out to HP. Then our 32-bit, the lower 16-bit are the same, and some of those can be divided into 8-bit registers. And then the segment registers, they change into what is called selectors. It's the same register name, it just has a different function. In protected mode, the selector will look up a data structure, which has information about paging and privileged instructions, and also base and limit. So this is all part of the translation. Depending on what you put in CS, if you say put, for example, 0, then you're going to get the first entry in this lookup table of selectors or descriptors. And that means if you access address 0, it's actually going to be somewhere completely different. But if you then change CS to be 8 instead, and you move one step forward in this table, the global descriptor table or the local descriptor table, as they're called, and then if you're accessing 0, it gets a completely different meaning. The limit specifies how big a memory block you can access, starting from the base address. So system management mode, I mentioned it's triggered by system management interrupt, when the processor enters system management mode, it's always running in real mode, but it's free to switch to protected mode if it wants to. Interrupts are always disabled, and the debug traps are always disabled, so when you're running in system management mode, you're really isolated. The machine is all yours. System management mode can be entered by, as I mentioned, IOTraps or even MMIOTraps, so the memory maps register accesses. Machine check exceptions, when the CPU detects that it's broken, and anything in the APIC can also generate or result in system management mode execution. Embedded controllers, I'm out of time, so unfortunately no RAM development embedded controllers, it's the 851 in the SuperIO. It can do a whole lot of stuff, which sort of messes up the system because it's transparent, and it might also be very difficult to detect. But, yeah, no. Thanks to Luke, and questions, if there's time. Yep. How does RonCC store loaded variables and variables passed to fantasy? In registers. So you can have only a few of those variables. Yes. How? In the SuperIO, the AD51, where does it get it's go from? Good question. So it depends on, sometimes the 851 there, it can be a standalone chip, and if it's a standalone chip, it can have a built-in firmware, but it could also be sharing the boot flash with the main firmware in the system. So, say the first 50, 56 kilobytes is the firmware for the microcontroller, the embedded controller. That's fairly common. Or it can have its own flash chip. Yep, it can definitely have its own flash chip as well. Yeah. Question? The build-run with the system management mode. System management mode? Does it also come from the boring? Yes. So you could actually disable some of our... Yes, definitely. Do you have a real-time system? Yes, definitely. Someone also earlier asked the question if... So the question was where the system management code that is run in Coreboot, where does it come from? And the answer is it is also in Coreboot. We have two separate implementations of system management code handlers in Coreboot. One is from AMD, that's the one for the Geo.LX, but they open-source that, and then there's the code that Stefan Reinhauer wrote for the Intel, Intel platforms. And I think, well, maybe a few of you also wrote some small system management code for the AMD64. Yeah. But it's all included in the Coreboot source, and there's full control, and it does really very little, because it wants to get out of the way. All right. Okay, thank you very much. Thank you.
boards are implemented by one single developer or at the 30 years of PCs. The PC has been around still apply to a lot of other buses and devices in a modern PC. Some thing about hardware do stuff. The PC in the 1980s, it might have SPI bus which connects from the South Bridge to initialization because it's connected to the RAM. of course be even more complex. You can have, different IOPort. This is typically always PC. But in the original PC, that was one Motorola CPUs are going to be application processors. So send the CPU to run the code that it should. But there are a lot of possibilities with many which is an E squared prom on each dim. So a