 All right, everybody. Good morning. Good morning. How's everybody's weekend? Good. Restful, relaxing. Give you guys something to do, Sunday night, so you can start delving into the code. So this week we're going to start looking at how the operating system actually multiplexes and abstracts hardware resources. Last week we talked about processes that are one of the operating systems of abstractions that do not count down onto a particular piece of hardware. Today we're going to start talking a little bit about and the next few weeks will be essentially a unit in this class where we'll talk specifically about the process. How do we share the processor? How do we do it effectively? The sort of abstractions are necessary to give the process easy illusion that they have exclusive access to a processor when there are in general not a non-processors on the system to give every application their own process. So today in particular we're going to talk a little bit about operating system proof. So in fact something we've talked about so far hasn't really required the operating system to specifically have any special powers, right? And today we're going to talk about the special powers the operating system has, but why it has those. And a little bit about how we transition between normal modes of execution on the processor and what are called privileged modes of execution which is where the mode that the operating system runs in in order to do what it needs. So a couple of announcements. So I put out the code reading portion of Simon Zero last night. It's uploaded through a web forum. As I put in the warning there we're experimenting this year with this online submission system. So my suggestion is that you complete the answers to the code reading questions on Google Docs or on, you know, a text file in your virtual machine or somewhere else and then upload those answers through the web forum. And that will mean that just in case, you know, I'm sure this is nothing like this has ever happened before, just in case the fat figure professor blows away the database on Friday night and all of your uploaded answers are gone they'll still have some market to put you down. So just consider yourself. Recitation start this week, right? So the first recitation is today at noon led by Sonali and then the recitations will go on throughout the week. So as I emailed out several times there's been several queries from 521 students. So 521 students were not assigned recitations. It doesn't mean you can't go to a recitation. Take a recitation that you want to attend and you don't pick multiple recitations. Go. As far as I'm concerned, you guys should go to any or all recitations and find a recitation that you like, find a TA that you think does a good job of presenting the material and feel comfortable with. Particularly once you guys start the second two assignments where you'll be working in pairs, it's usually useful to go to a recitation with your partner so that you guys can see the same material, you know, and sit next to each other talking about things during the recitation and kind of have some sense of how you're going to approach the assignment together. Okay? I'm going to pull off the service today right after class until noon, just in case people have questions about the class in general or issues with assignment zero and then Fung will be holding office hours today from noon to pm and we actually have an office hours schedule for the rest of the week as well and I'll post those online. Alright, any questions? Oh, one more announcement. So the ACM student chapter here at UB has been started to become, I think, more active. Is that an taxpayer description? So Sean is somehow mixed up with this group of people and they've been doing some cool stuff. So I think they're planning a hackathon this semester that the department is going to support. Last semester we did a mock interview event which any of you guys that are seniors and are thinking that you might do a programming interview at some point might want to get some sense of what it's like. So if you're interested in participating in these sorts of things or helping plan them, two general interest meetings this week at 6 pm, Tuesday and Wednesday nights in Davis 338A. So if you've met with Davis you know that Davis has rooms 338A through 338Z. So good luck finding 338A. Actually I have no idea where it is but I have a general sense of the part of the building. So today's slides are unfortunately figure free and I just wanted to quickly apologize for that. So let me just do a quick poll of the class. Because if you guys have made slides before you may or may not be surprised by the fact that putting figures up on the slides actually consumes a fair amount of time. So how many people in here really find those figures on these slides to be useful during class? Okay, well I better start doing it for you. Okay, I don't want to know because if people were like, I'm making my own mental images but it's what we'll have to do today, right? So everybody said like get out of your mental canvas and start all along. So okay, so I will work harder in the future on making sure that the slides have some degree of animation and figures in which to help with understanding. Today grew up in the Charleston area. I could do that with chocolate. I hate chocolates though and that thing just looks terrible. So I really wish we were in a room with a white board. In a room with a white board I could really go to town. If you guys come to office hours you have questions I'll definitely go to town with a white board. But yeah, I wish I could do the video. Try to figure out how to use that little dual equation as well. Alright. Okay, so last week, processes. We did process structure. We did process creation. We talked a little bit about file handles which is important. We talked a little bit about IPC. Any questions about the material that was presented like this? Alright, so let's see. Let's do something different today. Let's start in the front of the room with process equations. Alright, so processes contain what? Give me one answer. Three answers on the slide. One answer. CPU utility? CPU utility? No. Again? You're not sure. The address? Interspace. Interspace. Good. Threads. Good. What else? Files. Done. Okay, good. Actually files? A little more tricky. A file table which has several levels in the direction where it comes to navigate process. Alright, how do I create a new process? Or how do I replace a new process with a new image? How do I exit a process? And how do I collect the X-node with child process? The question is about the process we call file handles. What is for view to the process file table? Copies it. What is exact view to the process file table? That's what exact does. What is exact view to the process file? Trick question. And why do we have these semantics with respect to the file table? What does this enable? I can see communication between parent and child processes through shared file handles after four and a second. It allows us to build pipelines to do all sorts of other things. Alright, questions about this stuff? Any other questions about... Anything else? Okay. So, today we're starting this period in the class, this unit where we'll talk about how the operating system abstracts and multiplexes across. And multiplexing is something that we haven't really discussed so far with regard to processes. And the question is these are the kind of issues that we're going to look at over the next couple of weeks. And this is the kind of pattern that we'll try to follow whenever we look at a hardware resource and how the operating system builds abstractions on top of it. So the first question is what's wrong with the resource? As is. Why wouldn't I just let the system use the bare hardware? What's the limitation of the resource that the operating system is trying to put? The second question is what are the mechanisms that are necessary to allow the operating system to multiplex the resource? So what's happened over the 50 or 60 years that operating systems have developed is that hardware has come to provide more and more features that are useful to operating system programming. And specifically features that allow the operating system to enforce sharing and to actually provide some form of sharing. So we're going to talk about one of those features today which is called privilege nodes. Third, so what are the consequences of multiplexing? As a programmer, why does it matter? As a systems programmer inside the operating system, and also maybe as an application programmer, what's happening behind the scenes that you might need to know about? And then finally, how do we design good policies to make sure that this multiplexing is efficient? So whenever I start to divide resources between processes how I perform that division can have a major effect on how fast the system goes. If I do it badly and your big expensive new computer is essentially equivalent to some little tablet or it's slow. And if I do it well, I can give lots of processes on the system the illusion that they have this big back computer all to themselves. And how I do this in a clever way is really critical. So when it comes to the processor, let me just go through and give you an example of one sort of pattern that we'll continue to look at here. What's the limitation of the processor? It's up on the slide. Speed is one, but speed is kind of fixed. When it comes to multiplexing, somebody said it over here, there's only one processor. There's a lot of applications. Maybe now we've got four cores or eight cores, but in general the number of cores is fewer than the number of things that the system is trying to do. So what are the mechanisms that the system provides in order to allow the resource to be shared? Interrupts in context, which is right. This is easy stuff, right? This is the reading comprehension part of the class. I made that joke last week and everybody laughed, too. So let's keep making it. So what's one consequence of the fact that behind the scenes the processor is actually being shared? If you have a programmer, you can't what looks like a linear stream of execution to a programmer, a processor programmer, can actually be interrupted at any time. Arbitrary amounts of time can go by and then it can be restarted. So the assumptions that you make about how the state of the world changes have to be relaxed and swing. You have to figure out why I modified that variable and then I did some other things to it. At any point in time, my execution stream may have stopped and somebody else may have run and they may have done all sorts of weird things to the world. So you have to be much more defensive when you start to realize that the processor actually needs to switch between a lot of things. And then finally, policies when it comes to sharing the processor. What do we call this? How do I choose what to run and for how long? Does the linear maker system seem really responsive or incredibly slow? So we'll talk in much more detail about different general approaches to processing the data. Alright, but today the first thing that we need to do is establish some basis for the operating system being able to multiplex resources at all. So it turns out, it's very interesting that Zient had a kind of inspired some degree how I'm approaching this class. There was a research operating system about ten years ago that was developed in MIT called the ExoCurrent. We'll come back to it later in the class when we talk about operating system construction. What the ExoCurrent was actually able to show was that you can separate these two functions of the operating system. Resource multiplexing and abstractions. And it turns out that in order to build abstractions, you don't need any special privileges at all. What they did is they built an operating system where all the privileged code, all it did was multiplex resources and enforce resource sharing. And all the stuff like processes and all these abstractions that require hardware resources were implemented in libraries, in user states. So this is actually possible. It's not how operating systems are actually designed. But I think it's an interesting example of a design that points out the fact that the reason that operating system needs special privileges is not different from abstractions. It's just to provide and share resources. And again, if you don't believe me, you can look at user space threading libraries. So user space threading libraries actually implement, at least to some degree, some of what we've already talked about. They implement four, a threaded version of four. They can implement weight and exit all in user space without the kernel having any idea what's going on. So why does the operating system need special privileges? Why does it have to have this privileged execution mode? What makes it different from other processes? Anybody? Because it's responsible for successful running of the computer. Okay, that's true. But what specifically about the, what tasks do the operating system... Separating processes from one another. You're talking about a lot of things in the process that the system does. I'm talking about the general principle. Operating systems have two jobs. What are abstractions? Multiplication and abstraction. Which of those functionalities requires special privileges? Multiplication. Multiplication. Why? Well, it's because in order to divide resources between processes you need some sort of trust identity on the system. You need a trust identity to decide first of all how resources are going to be divided. And then enforce the division that was agreed upon actually is taking place. So imagine, why can't processes do this themselves? So why don't the processes on your system gang up and say, you know what, had enough of this operating system guy bossing us around all the time. I don't know why this idiot user decided to give him all these special powers. But I'm tired of this guy. Let's kick him off the system. And we'll just... It's kind of like communism. We'll just divide things up, fair and square. And we'll figure out how things work. Why doesn't this work? A couple of reasons. Security. Security. But what... So processes could be malicious. So a process might say, hey, I don't want you to have any memory. I want all the memory. All the memory belong to me. They could take all the memory and they could leave some other core process. It's really trying to do something important with no memory. Even if they're not malicious. What else do processes do? They're working by fallible human beings like me. They make mistakes. They goof. They say, oh, well, you know, I... I thought that was my memory and I just, I forgot. I wrote it down somewhere and now I'm not sure where it is. But let me just try using that as a memory and see what happens. So again, the reason why we can't trust processes to do this division is that if they're malicious, they can really take advantage, right? Because they can just push other processes out of the way and make the resources what they want. But even if they're not malicious, they're potentially bugging, right? And a buggy process can simply accidentally overwrite memory that's in use by another process or open file, you know, grab a file, processes file handles and start mucking with them or whatever. Or, you know, start running on the CPU and the other process isn't finished and it doesn't even stop you. So this is the actual thing, right? In fact, we're going to get back to this when we talk about CPU scheduling, but there have been variants up until fairly recently. There have been commercial operating systems that have tried to let processes kind of figure it out themselves, right? So as we've mentioned before, one of the causes for a lot of problems with early versions of Windows was that they didn't enforce these resource divisions, right? They tried, you know, they said, well, here's your memory. But it was kind of up to the process to be like, okay, that's my memory and I shouldn't use that other guy's memory because that would be bad. Another interesting example of this is with CPU scheduling. So for a while, even I think on early versions of MacOS, they had a policy called Cooperative CPU Schedule, which meant that a process would only give up the CPU and it asked the operating system to do something. So as long as it didn't ask the operating system to do something, if it was just sitting there executing instructions like let's say, you know, stuck in a while one loop somewhere, right? It could run on the processor forever and no other process could take over, right? And, you know, I had a friend who had an early version of Mac and in general it worked okay, right? Because, you know, if you installed an application and suddenly your computer didn't run any other applications, you might be a little annoying, right? So you might get rid of that if you could. But I think he had a DVD burner application that would do this. So when he burned DVDs, basically the computer would just lock up for about 15 minutes, right? Completely unresponsive, right? And then when the DVD burner finished, back to noise, right? Because just in the interim, the DVD burner didn't make any system calls and so it was just either doing work and it never yielded the CD. So in general we've decided that this is a bad idea and operating systems that are out there today essentially are collectives where they've elected this one guy, the operating system, this special application to enforce and manage these sharing divisions between the processor, right? So how do we do this, right? So again, if I'm going to manage and enforce resource divisions I need the process that does that to be special, right? And this is the root of privileged execution mode of what I think is operating system privilege, right? The operating system, in order to enforce these protection boundaries and perform them, has to have access to certain, some special things that the rest of the processes don't, right? Why? What if every process had access to the same state on the machine? What would happen? Why? Just because all of them can act as operating systems themselves. Right. So the operating system might perform some additional resources but the application could just override whatever it wanted. It would say, okay, well, you know, it's nice that you gave me that much memory but I was like, all right, so I'm going to modify the page to get more memory. Or it's nice that you asked me to stop using the CD, but I've not managed yet. So I'm going to keep going. So, no, no, no, we need to make sure the operating system has some way to push the other normal applications. And this is how it's done. So, and note that this is one of those cases where hardware is going to help, right? Hardware is designed to do this and to help the operating system do this, right? Several different ways, right? So typically, CPUs, which is what we're going to talk about today, have a privileged execution mode. And when the system is running in that mode, there are instructions in state that whatever program is running can execute. And when it's not running in that mode, those instructions in state are off limits. And there are well-defined ways for entering and leaving privileged mode, which is, again, what we're going to cover for the rest of time. The other thing that we'll talk, we'll come back to in about a month when we start talking about memory is that frequently the operating system also has a different view of memory or a different way of memory than normal processes, right? So this is another form of privileged. Privilege execution's privileged mode. If you want to see how this plays out, right? The nice thing about this class, I think, is that you guys all have an operating system at your disposal, right? And it's a fairly simple operating system that was designed for people to poke around in and designed for people to answer these sort of questions. So, if you want to, we're going to put up a handout later this week that describes the MIPS architecture. And you can go in and you can look and you can see what are the privileged instructions on MIPS architecture, what's the privileged state that MIPS creates. And there are a set of instructions in the MIPS architecture that cannot be executed if you are not in privileged mode. Exactly the sort of thing. And there's also a different memory mapping on MIPS that occurs when the process is privileged. Questions about? Questions about? What I'm trying to explain is why we need this privileged mode, right? Why do we need privileged mode? So I can do what? Why do I need it? So I can enforce resource multiplex. So I can multiplex resources. So I can divide and tweak processes and make sure that those processes can't override or ignore those issues. I think maybe this will make more sense after we go through some examples. So, okay, I think I've talked about this. So again, when the CPU is not in kernel mode, so we can talk that one of the things that we use to describe this data is kernel mode. The mode that the kernel is, the kernel port typically executes it. And when you're in kernel mode you have special instruction for your user mode, if you try to execute those instructions an exception is raised, which we'll talk about in a second. It's one of the ways that the kernel gets controlled. So the goal of protection boundaries and what we try, what systems try and enforce, right, this is the overall goal of these mechanisms, is that kernel code has these special privileges and only trusted kernel code is given access to kernel mode. Only trusted kernel code. And user code, any untrusted code that you install on your system, only runs in normal, right, without access to these special models. So, and there are mechanisms for transitioning, which we're about to talk about. So, yeah, so, so again, and there's some terminology that I'm going to be using, I'll probably use it fairly interchangeably, right. When we talk about an application on the system, we're talking about code running in user mode. We're talking about the kernel, we're talking about kernel running in kernel, right. And that's, we go back to what we talked about last week. The kernel is appropriate, right. It has an interface and it executes instructions, right. What makes it the kernel is this, that it's able to run with these special privileges, right. Now the question is how did the operating system, how did this program, right. So when you build your kernel for this class, that kernel file that is a program that you provide, right. How does it get to execute in this special mode, right. Or how does your Windows kernel get to execute in special mode. You're a bunch of people. How, like, what gave it that right? Who gave it that right? Who gave it that right? Go back to stuff, go back to stuff. What did you do to the computer? I don't know, what did you do to the computer that hated a Windows machine? You installed the operating system. Who said, you ran a program that basically said this machine is going to be a Windows machine because I'm going to get the Windows kernel these special things, right. You did it. So don't blame the kernel, blame you, right. And if you want a, if you want a different program to run these special privileges, install something else, right. If you don't like you know, the app, the special program that you have designated to run the special mode, it's all different, yeah. There's something like an OPEX which runs, I guess, before the normal operating system that's installed. How does that feed into Windows? So, so there's a whole, yeah, so there's a whole, I don't, it would probably take an entire lecture to walk through what actually happens when you boot your system, right. But there is actually an even more basic piece of code that runs before the operating system called bootloader, right. And that bootloader, if any of you guys want to boot your system, that's how it's done. It's by installing a bootloader that's capable of either choosing to give the Ubuntu kernel these special privileges and line up a bunch of environment or give the Windows kernel these special privileges, right. So that's how it's done. Essentially, there's another, there's another level of bootstrapping that's open, right. And typically the bootloader is sort of hardwired directly into the computer itself, right. So when the computer turns on, the first thing it does is run the bootloader. The first thing the bootloader does is try to load an operating system itself, right. And then it starts executing that operating system. So yeah, I don't want to get too into the gory details of the boot because I just don't think they're super interesting. But yes, the bootloader technically is what chooses what to run. But you chose to install the operating system and to tell the bootloader it was okay to give this program these special privileges. So let me go back here. So it turns out that and this is something we're going to come back to later, that this concept of special modes of execution actually generalizes further. And certain systems like the original X86 architecture actually generalized it further, right. So there's no requirement that there be two modes, right. I can have an arbitrary number with different privileges assigned to each mode, right. And different mechanisms for entering and leaving different modes. So the X86 processor has all, for a long time they always included a first one D. But for a long time it supported four protection rings is what the terminology that they use, right. And these rings are kind of concentric, right. So ring zero has all the privileges, right. Whereas ring three has some small subset of them. For a long time systems that ran on X86 architecture only really used ring zero and ring three, right. So ring zero corresponded to what we would call kernel mode or privilege mode. And ring three corresponded to users. Now this has gotten a little bit more interesting because with the rise in virtualization software there's been a lot of work to get operating systems to actually run in ring one, right. To be able to execute in ring one. Now why would I want a kernel to be able to run with only the privileges that it has in ring one? What am I going to run a ring zero? The hypervisor. So it turns out that the way Zen and other pair of virtualization systems work is by exploiting this feature of this architecture, right. So Zen runs in ring zero, right. It has the most privilege. Like the hypervisor which manages the operating systems and then the operating systems run in ring one, right. So we'll come back to this, you don't really need to understand this but I just want to point out that there's no limitation to the number of modes, right. I mean at some level a large number of modes would get really unfeeling and stupid, right. But systems have been around that have more than two modes, right. But for this class and for your system, your OS 161 system has two modes. User mode. Alright, so we did this. Okay, so and then one more other piece of terminology I'll show you. Yes, I mean the running command work on in a computer we can set up only one piece of code one entity can run in So, yeah, basic, right. Is it to be like that or simulation of hardware that is done at the full time? So that's a good question. So I guess I don't think there's actually any specific requirement that means, so technically, we're going to come to this in a second we're going to talk about how we get in and out of kernel mode, right. But, yeah, I mean there are mechanisms that the hardware enforces, which again I'm about to get to for starting the operating system, right. They're used to start the operating system. So the question would be could you use those to start multiple operating systems, sort of concurrently. I don't see why not. I haven't thought about it in a huge amount of detail, right. But remember, right, what's the problem with that? You're, again, the programs that you run as a Windows user or Mac user or an Ubuntu user make assumptions about the kernel that they're operating, right. So for example, when I get the kernel's attention, right, the mechanism is the same whether I run a Windows kernel or an Ubuntu kernel, but the semantics of the exchange of information are completely different, right. So the same hardware instructions will get me into privileged mode, but once that code starts running, right, if it's Windows, it's going to say oh, well here's where the arguments are and this is what it's trying to do and if it's Ubuntu it's going to say something completely different, right. So all the code that runs on your system makes assumptions about the operating system interface that break. I mean that's why you can't take code piled for one system if I run it on another one, right. Because the calling conventions are completely different. The calling mechanism is the same, right. It's the same instruction that you execute to start the kernel running, right. But after that it's a completely different set of agreements about how we're going to exchange information. Does that make sense? If we are able to write two operating systems such as that they can go into this and if we can write a operating both can run on the same hardware in the same time. So it turns out that there was a period of time when this was a popular idea, right. I can't remember what the systems were called. There was something called Lindows and I mean I think if you look up Lindows you know it's Linux it's a portfolio of Linux and Windows, right. If you look up Lindows there was a whole sort of group of these kind of operating systems that tried to essentially allow you to run native Windows binaries on native Linux and Windows binaries side by side. So it turned out that I mean you can imagine how many man hours have gone into developed Linux, right. And then how many man hours have gone into developing Windows, right. And now you want to start a project that's going to provide the super set of the functionality provided by both systems, right. Good luck. And that's essentially what happened. None of those systems ever worked that well. So for a long time there's been it's a Windows that essentially tries to translate Windows system calls down to Linux and it kind of works, right. Every time I tried to do something on one it did work, right. But then the question is so what happened that kind of I think made a lot of these projects kind of obsolete. Virtualization, right. So now I've got technologies where I can actually run you know I can be sitting there at my Mac desktop and one window that has a bunch of Linux running in it and one window that has Windows running in it and I can just and now even VMware they'll actually even put the icons in your dock so I can launch a Linux program I can open it up just it looks like it's running in it, right. So virtualization has really changed this whole thing it's made this kind of unnecessary, right. The idea of running multiple operating systems simultaneously in kind of the same next to each other, right. Any other questions about so tracks, right. So when a piece of code calls a system call we frequently talk about it trapping into the kernel we call these system calls or tracks, right. So this is just terminology that indicates that a user program has requested the kernel's attention through a mechanism which we're about to discuss. Alright and then yeah so I couldn't decide maybe I shouldn't put this up here at all this is confusing but I sometimes think about a thread that has trapped into the kernel as quote unquote running in the kernel, right. You think of it as making this transition across the user kernel boundary and now it's executing kernel code and then at some point later it'll come back, right. That's not really super accurate, right. It works for me but as you guys will see when you start to look at assignments one and two there's enough state that stays behind at that boundary that it's not really accurate to think of it as the same thing. So you can think of it in the best way for me. We'll come back to this. Yeah, probably. If you're programming nips then by instantiating the address space for the kernel 800180 you can actually run in the kernel mode and use kernel instruction to speed you can track without error conditions there are instructions that allow you to track on the register being zero and it will actually execute that instruction in the kernel and then you put it in the kernel space. Now the difference being if you can set, accept by mc you have to define an exception about the exception if you want to trap or you want to catch try to catch the same thing in MIPS is done trap instructions that will actually trap and allow you to execute in the kernel address space if you instantiate the kernel address space and implement code in there. So we're going to talk about that in a second. But in general the transition between the kernel and kernel mode is extremely well defined and well made because the idea is if I could just run any code I'm allowed to in the kernel then it goes back to the problem I had before where I essentially allowed any application that arbitrary proves and that's what I'm trying to prevent. So let's talk about ways that we get in and out of the kernel. So this is essentially these are things that happen on your system that will cause the system to transition from user mode into kernel. There are three different cases. I don't know what these are called. So the first one is the hardware needs some sort of attention. What do we call that? Hardware interval. It's going to be a little more specific we talked about the operating system because there are also cases where software requires attention. What is that called? Software. Or a system call or a synthetic improvement. Finally, last case, the software needs attention. Not a system call, we just did that one. That system call is the second. So that's essentially equivalent to a software interval. Exceptional. So what is the difference between requesting and needing attention in my terminology system? So potentially in error. Not always in error. Sometimes. But requesting attention implies volition. It says that the user code asks the kernel to do something for. Needing attention means that the processor has noticed that the user application has done something that it's not exactly sure how to handle. And it asks the operating system to start running to help it figure it out. So the difference with a software or a trap the software process has asked the kernel with an exception. The software process may have done something that, again, the processor is just kind of like, hey, kernel, I need some help with this. We'll come back with it. So hardware interrupts are used by devices to signal that something is happening. Something that the kernel is interested in. The system is interested in. So for example, you asked me to read a block off the disk and now I've got the block ready for it. Or a network packet will run. And when it comes to scheduling a very important class of interrupts are timer interrupts. So your system in order to do the schedule enables regular timers. So there's a timer on your system that is triggered to fire every certain number of milliseconds or microsecond. And every time that timer fires there's a timer on our generator. And the kernel will start running. So processors will implement these interrupt lines. A lot of you guys have taken these kind of hardware classes so I think you're familiar with this sort of thing, right? And interrupt lines are, it's a wire, right? It's a wire on the processor that if I put a logic signal on it, usually an edge or a level, the processor is hard wired to process, begin processing them, right? So this is what happens when I trigger an interrupt, right? The first thing is, I enter privilege note. If I wasn't in privilege note before now I'm in privilege note, right? The second thing is the processor is going to record some state about what happened that helps the operating system process that interrupt, right? So there's something, you know, maybe it's which interrupt line was it, right? Which device signal the interrupt, right? Or some other state about the world that is going to help the operating system when it starts to run and figure out what to do to handle the interrupt, right? Yeah, yeah, yeah, yeah. It actually will record the program counter that was executing when that instruction occurred. Now this is interesting. So why would I record the program counter that was executing when the interrupt would come back? Because I need to come back, right? Because when I'm done handling the interrupt I want to go back to the normal flow of execution and I need to know where was the program counter. And as soon as I do the third thing, the program counter will change. So the third thing is the processor is hard wired to jump to a specific application in memory and start executing the instructions. That's how interrupts work, right? This is the feature that's provided by hardware. So on the MIPS, when there's a general interrupt the MIPS separates virtual memory interrupts and other kinds of interrupts, right? When there's a general interrupt the processor will jump to address 0x80,00080 and just start fetching and executing the instructions. And whatever code is there will start to run. Now, what code gets loaded there? Whose code gets loaded into that area? What do I want to have? I want the kernel to start running. So on boot one of the first things the kernel does and again in your system you can look and there's an assembly language file called start.s that you can find in your tree that contains the code that loads the interrupt handlers for your kernel when it runs, right? And you can see exactly how that's going to work, right? Interrupt handlers tend to be very, very, very small pieces of code normally because processors implement multiple interrupt slots, right? So for example, I told you that the general interrupt address is 0x80,00080 the memory fault address is 0x80,00080 so there's only 80 bytes in between those so it's not a lot of room for code to do complicated things so normally what happens is an interrupt service routine simply does a few small things and then jumps into some other piece of code, right? But this is how hardware devices cause the kernel to begin running and this is how the kernel gets into privileged method, right? This is how it works. So hardware interrupts can also be masked, right? And masking interrupts essentially means that the processor that in privileged mode can set a register potentially on the CPU telling the CPU to ignore interrupts from a certain device or on a certain wall and this is going to be important for a variety of reasons. So one of the reasons that I might want to... Okay, so a secret is interrupts, right? I think I just talked about this, right? And then, okay, sorry. So there is normally a class of interrupts that are non-masked, right? That the operating system cannot mask and these are interrupts that usually indicate that something really weakly happened, right? And the processor, like, went away or somebody had to reset button or something. So there's a certain class of interrupts that should never be involved. It's very small. The reason I might want to ask interrupts is because one of the things that allows me to do is prioritize interrupts. So you can imagine that certain devices might need higher priority than other devices and here is I think what is a good example, right? If I'm burning a DVD, right, about my example before and the right buffer for the DVD is empty. It turns out that if I don't, with some DVD burners, if I don't fill that pretty quickly and keep it full the right process is going to fail, right? You know, how many people have burned a DVD and it didn't work? Yeah. I always call it frisbee, right? Because it takes a one-way trick to burn. But yeah, so this happens, right? But the idea is that I might want to process the DVD right buffer low or empty interrupt before I process an interrupt from a network card because the network card, I mean, that data is going to be there in a second, right? Whereas the DVD has similar cases there. And then there are other cases where handling interrupts generate other interrupts that if I didn't mask them would prevent me from handling the original one. Don't think about that too much because your brain will explode. Okay? So let's go back to this idea of protection, right? So I told you that when the interrupt happens you have to jump to a certain memory address and start executing instructions. So what would happen if I allowed any process on the system to access to that memory? So OX80 million, I'm next. Let's just say I say, hey, anybody who wants to, you can write to OX80 million. What happens now? Why not? Right, exactly. So if I'm going to handle my own interrupts, prevent the operating system from taking control, I just install my own interrupt handler when it's my turn to run and then there I go. One of the things you guys, I will almost guarantee that you guys will do when you are programming your kernel for this course is that at some point you will blow away the exception handlers when you are writing your kernel code, right? And then the next thing that will happen is that your system will die in some spectacular way, right? And not actually that helpful, right? Why will you blow away the exception handlers? Well, it turns out that because of the way that the MIPS maps memory, OX80 million is also address, physical address, OX0, right? How many people have ever had a null pointer exception in your code, right? What normally happens when you have a null pointer exception? Segmentation fault, core dump, right? And then you can, you know, you can debug your code. In the kernel, if you have a null pointer exception, you just overwrite the exception handlers, right? And then things, again, things will keep going for maybe a few more instructions until you try to process and interrupt. And then the code that you are executing is essentially no-off, no-off, no-off, no-off, and then the way it is just that your system totally hoes, right? Nothing good is going to happen. All right. If I allow the application to override this, this would be terrible, right? And again, I pointed out before, one of the first things that kernel does when it starts to boot is install it here. Okay, I think I can get through this up. All right, so given that, so one of the things that hardware interrupts do is they allow the operating system to interpose itself between devices and applications, right? So applications don't have direct access to devices because when the device signals something to the processor, the kernel immediately starts running, right? So even if there's a user program running when the device says, hey, I've got some data ready, the kernel starts executing because the kernel is called by DNR service routine that the processor begins to execute, right? So the question is, there's a lot of cases now, because again, I put resources and I put all these devices behind the kernel, right? And applications have to ask the kernel for permission to use them and use them to use the kernel abstractions. So how do applications get the kernel's attention? Just talk to us. Software interrupts, right? So software interrupts reuse the same mechanism as regular interrupts. The only difference is rather than the interrupt being triggered by a logic level on a wire attached to the CPU, software interrupts are directly triggered by an instruction. So on MIPS and other architectures, I think on X86 it's int, interrupt. On MIPS it's called syscall, right? And syscall generates a synthetic software interrupt, right? System calls are secrets. So as soon as I execute that syscall, the same thing happens, right? I'm reusing the mechanism, right? So now, quick quiz. We just went over this. What happens when an interrupt is triggered by calling a syscall? I enter privilege mode. That's the first thing. What's the next thing? Store bit of state and then the third thing? Jump into the interrupt server. Good. So essentially, in order to give software access to the kernel, I reduce the same device, right? And what this means is that there's a well-defined entry point into the kernel, right? And the kernel controls that gate. So the kernel installs the interrupt handler, and all the code that the interrupt handler has run is under the control of kernel, hopefully, if I set things up correctly. And so this gives me a way to make sure that whenever an application wants to run for some reason, it has to run in kernel code. There's no other way to do it. So, and again, once you build your system, you can actually look and you can see, and if you poke around in the line directory, you can see the live-see wrappers that OS 161 implements around this instruction. But there is. I mean, once you build the system, it's a little bit weird. Actually, David set this up so that he automatically generates the interrupt cameras when you build the system. Once you've done it, there will be a file that will contain a series of macros, or I think maybe it's just one macro, that essentially takes your system call, figures out what the right arguments are for it, and then calls this instruction. So that's there, and you can look. All right. So, software exceptions, right? Who can give me some example of software exceptions? So again, interrupts. I'm asking the kernel for help, right? Exceptions. What is an exception? Here, right? Great. What else? I didn't get the software. No TAs. What's up with us? Page ball. Yeah, third ball. Yeah, overflow, or... What is what I have? Oh, attempt to use a privileged instruction. So exceptions are cases where the operating system gains control without direct, without the user application actually calling all, right? So there's some lack of intentionality here. It means that the OS took control, and maybe the operating system didn't, sorry, the user application didn't know, right? In certain cases, as people said before, this would probably mean that something bad has happened, right? Something bad that the operating system needs to deal with, potentially by just killing the process, right? Once you've divided by zero, I don't know what to do with you, right? The only real logical thing is to use a privileged instruction. I have no idea what you were trying to do, but you're messed up, right? And, you know, justice is swift. The exception to the rule of exception is virtual memory, right? And when we come back to virtual memory in a month, you'll see that the operating system uses this exception mechanism to transparently translate addresses that the user applications are using. So one of the things about that exception is that the user applies to address a piece of memory that the processor doesn't know how to translate already, and that, and basically it says to the kernel, hey, I've got this memory address that this process tried to use, and, you know, you haven't told me how to map it, and I'm not even sure if it's a good address or not, so can you help me out, right? So, okay, last little bit about this, and then this is the core of the station, right? Interviews are voluntary, right? So here's my little cute example here, right? Now, the Tom Brady process is super simple. The kernel says, okay, I can help you out with that. Not that hard, given it's the Tom Brady process. You know, on the other hand, the Eliminated process, it might be that the CPU is basically saying to the kernel, hey, now this Eliminated process tried to divide by zero, and I don't know if it's probably doing something really funky and weird, so why don't we just kill it? All right. Okay, so next time we're going to talk about how I use this mechanism to actually multiply the CPU. Where were you in 2008? I don't want to talk about that. Where were you the last time the Patriots lost? It's a long time ago. It's a long time ago. Yes. All right, I will see you guys on Wednesday. Office hours with me start now.