 All right, welcome back to operating systems another fun fun lecture. We have so today. We might have heard the word kernels before or May have not but today we'll be talking about kernels So a lot of this stuff will be like a lot of low-level details. You don't actually need to know There's not that much you need to know from this lecture. So I'll point it out This is more kind of understanding how things actually work So I left you off with this example at the end of lecture one I told you this is a full hello world example in Only a hundred and sixty-eight bytes So I will again prove that it actually works So if I switch over and I try to execute it Prince hello world exactly like you would expect if you wrote it in C or Whatever language you want So with that let's try and explain what in the heck this mess is So first decide is the term ISA or instruction set architecture So there's three major ones in use today. You should probably know what they are again You won't be tested on this but we'll touch on them in various aspects of this course And it's probably good to know what you're actually running on So it's the actual machine code or what numbers your CPU actually understands and can execute so x8664 is The dominant CPU architecture for like servers desktops any non-apple laptops will be this architecture Most of the yeah, most of the desktops on the planet are that game consoles all that stuff then there is ART 64 or arm 64 So that's arm you've done that in your computer organization class at least some variety of arm arm 64 Is just kind of the latest one and that's used in all your phones your tablets And if you're lucky enough to have an apple up top, that's new It's in that too and then risk five is an open source Implementation or an open source architecture. That's kind of similar to arm But you're actually allowed to use it without paying millions of dollars. So you could make your own CPU in that So some of the Assembly will read in this course or is risk five, but it's really readable and if you have any questions you can ask This lecture since I'm executing it on my laptop. It's going to be arm 64 assembly But throughout the course you never have to write assembly. So don't worry about it. All right Substrations everyone likes a good abstraction. So we touched on it before but I'll really explain it now So our next abstraction is what's called a file descriptor So because all our processes are completely independent We argued that they have virtual registers and virtual memory that you should know Well, if they're completely independent, they're actually kind of useless if they can't talk to each other So there is an explicit way for processes to communicate with each other And it's just called IPC or inter-process communication and that just means communicating between processes and because You otherwise want to be completely independent you have to be really explicit about this So what a file descriptor is is just a resource. You don't know exactly what type of resource We can argue what some resources it could be But it's just a resource that is really generic that can either you can either read bytes from or you can write bytes to it And it's identified by an index that's stored in the process. So that index is unique to the process So as that process goes on it's the the process itself is the only one that can manipulate that But what the file descriptor points to or what bytes it gets sent to it could change It depends It could close it could whatever the thing it represents could disappear. You're not quite sure So right now what a file descriptor could represent for us is it could represent an actual file because it's named a file descriptor that would be a pretty good name or Actually, it might represent your terminal your terminal works the same way like if you say Print anything to your terminal You're really just writing bytes to your terminal and then your terminal is being nice and displaying it to you and something you can actually read so Whenever you're trying to make calls directly to the core part of the operating system You can represent them like regular old C functions So we'll explore two system calls We need for a basic hello world program and the first would be called write and it takes three arguments a file descriptor Just called fd a buffer Which is just a pointer to some array of bytes and then accounts Which is how many bytes you want to write to this file descriptor? so When the function returns it will return the number of bytes actually written to that file descriptor and again We're not too sure what it could represent. It could represent anything and Then the next system call we need is something called exit group and it takes one argument a status and It exits the current process and sets a status exit code, which can be any number between 0 and 255 Which is just a byte which is bigger than an int so if you pass a large number on it It will essentially just take the least significant byte of that and set that as your exit status So That's the only two system calls. We need to actually make a hello world program in Unix, which is Mac OS or Linux So to explain a little bit more. There's other conventions that just Help make the magic of your computer work. So by convention whenever a process starts there are three magic file descriptors that are already open for your process and they're just numbers and You just follow the convention everyone agrees on it and the numbers actually have some type of meaning So by convention file descriptor zero is supposed to represent Standard input, which is a file descriptor you can read from or get information from So when you wrote your C application in 105 and you took input from the user Well, if it was running on Linux or Mac OS It was using file descriptor zero to read that information from the user and your operating system handled with whoops Getting all the information out of it but at the end of the day is file descriptor zero and then similarly there is Standard output which is file descriptor one and that's where things go by default if you do a print F So if you do a print F Under the hood it will actually write to file descriptor one because that's the magical number that's supposed to represent standard output Then there is also a magical file descriptor two that you can write things that are supposed to represent error messages and things like that and We'll figure it. We'll see in a little bit why that convention is useful so The most basic hello world program assuming I don't need I don't even need main anymore If I just created a magic function called start and I could tell my operating system to just start executing this function This is all I would need for hello world So I would need to write to file descriptor one An array of characters called hello world that has all the data I need and then 12 because that's the length of the string that I want to print to my terminal and Then after that's done All I need to do is exit group because I'm just printing hello world hello world was already printed so I can end this process So any questions about this? Minimal hello world. So this is like the smallest we could possibly get hello world if we figured out how to start just Executing this straight away Yep Yeah, so there's a question in 243 we use This underscore start is there anything special with it? So yeah, there's a special thing with it So for most assemblers if it's called underscore start it will actually start executing at that and that's just a convention by the assemblers So I just kind of called it that because it kind of lines up But if you could magically make it Make your things start executing you could call it whatever you want. You just have to tell the your assembler Okay, so this is as simple as hello world can get so As another aside So you've probably heard the term api before Um an api is like a very generic thing in this course. We might actually care about something called the abi So an example of an api or application programming interface All it does is give you very vague details about what the function does and what arguments it takes So for example, if you said hey a function takes two integer arguments And returns an integer that's supposed to represent the addition of them or the multiplication or whatever That's your like abi or api description So an abi is like the low level detail specific to your architecture Where every argument exactly is How you know the calling convention works between them where arguments need to be So again in two 243 The abi would be like You know you're making a function call you have to set up registers a certain way and then you've in whenever You're in the function You know you have to use those same registers as you pass they have to agree with each other So an abi would be like hey for this function. I need to pass Argument x and register zero or something like that There's a c calling convention The c calling convention just puts arguments on the stack. So that's an example of another one and I'll put it out but We don't need to know the details other than c uses the stack for its calling convention in general So here's the abi the system call abi for linux on arm 64 Because the operating system It doesn't really have functions because the functions require an address And you're not allowed to monkey with the operating system like you can't just call An address and just have it work So instead of calling address if you want to make a request to the operating system and do a system call There's actually a special instruction that will generate and interrupt for the operating system to handle And then two four three. Well, you dealt with interrupts. So you could imagine what the operating system has to do So there's actually a special instruction You you can call if you really know what you're doing and it's called svc on arm 64 And that's the instruction that will trigger the interrupt and then the os or the Yeah, the os would go ahead and service that interrupt do whatever it needs to do and then return back to wherever it was executing So the actual abi is like There are certain registers that need to have certain arguments So in the x8 register that just has to have the system call number So each system call is associated with a number So it's like if I want to do the right system call I put a specific number in that register if I want to do another system call. It's just another It's just another number And then system calls can take up to six arguments and registers So can anyone think of any limitations to this abi? for making system calls Yeah, the numbers are limited. I can only have six arguments. So and see how many arguments are you allowed to have infinite Pretty pretty much infant until you run out of stack space Or you run out of memory But this six total anyone think of any other limitation of this? Yeah Yeah, there are limited numbers you can pass as a system call, but specifically for like the other arguments Like well if I wanted to pass a double or something No Yeah, so that's the other limitation the other limitation of this Six arguments and they're the size of a register So if you want if you want something bigger, it won't fit if you want something smaller It'll waste space But because c is stack based they can be of different sizes. It's okay. It doesn't matter So you'll never need to know the actual register numbers. The only important thing you need to know is like system call abi uses registers That's the details are like because I have to painstakingly Show you what the code actually does So here's the aside of a cab i it's stack based arguments are pushed on the stack from right to left order This is for x 86 64 bit Again We don't have to know this and the advantages that this gives us compared to the system call abi and disadvantages Is pretty much the complete opposite So in general path using registers is also faster than using a stack because that would use memory and But you get more flexibility with the capi because you can have any number of arguments. They can be different sizes all that fun stuff so Next thing so now we have to discuss the executable file format So programs on linux and playstation, I guess Use the elf file format And I told you that it was just a coincidence. It kind of looked like my last name So elf stands for executable and linkable format. It's A kind of boring generic title And that's the file format for both executables and libraries. So it always starts with the four bytes. We saw before If you encoded naski, the first character represents a delete character and then it's elf all in capitals And those four bytes are literally called magic It lets you know what kind of file this is other file formats just have Other special numbers and if you read them Then you know what type of file that's supposed to be and you can try reading it like for example if you do that Read four bytes on any pdf He'll start with a percent sign pdf and then a dash So every pdf file on the planet will start like that. And that's how you know what a pdf file is Okay, so the bytes I showed you at the very beginning that Printed hello world those actually represent an elf file because while we also looked at the first four bytes of them all this f elf file does is It tries to load the entire executable into memory at address 10 000 hex And if you go into the specification of the elf file format, you'll find out that the file header has to be 64 bytes and the program header which Uh, basically just tells it where to load is 56 bytes So of that 168 bytes 120 of them are dedicated to this elf file format to just tell it some fairly basic information And then the next 36 bytes are the actual instructions And then after that are 12 bytes for the actual string hello world So if we can do a bit of math The instructions start after the header files in here. So they start at byte 120 So if we convert 120 to hex it's 75 in hex And because the entire executable got loaded at 10 000 hex we can add 75 to 10 000 To know where in memory our instructions start. So our instructions should start at 10,078 in hex Similarly, our string should start after the instructions. So it's 156 byte is where it starts at which is 9c So the string starts at address 10,009 c Again, hopefully you don't have to calculate this yourself. This is why we use compilers. So you don't have to calculate this stuff Uh, if you really want there's a read elf Or executable that will give you all the information about it I don't suggest it. But again, I can't tell you what to do your adults Except for on exams. I can tell you what to do So Here's visually what that elf file looks like. Oh, yeah Oh, so the question is what tells it to actually start at this address Yeah, so it's we'll here we'll be here so In the file header itself, which is the first 64 bytes I won't go into detail about what bytes represent what but Some of the things you get told from this are the endiness of what the instructions are the isa it runs off The entry point. So the entry point is where you tell the offering system to begin executing So that address 10,078 would be here and it would be specified in the elf file Here and you can actually see it. So it's right here where my cursor is So that's where it is. And that's How you tell the offering system where to start executing from So if you had an assembler like in the other class and you weren't a psychopath like me that just wrote this in In bytes, then it would have calculated that address for you and it would have stuck it right there But I didn't do that So that's like the important thing that's in the file Or file headers just where to start executing And then the programmer program header All it basically tells is what to load into memory where and what permissions it has Which we'll get into later in the course But that's the part that just says load this thing at address 10,000 hex Why 10,000 hex well because I virtual memory I could have picked any old address I wanted to I just had to recalculate where the string starts and where the instructions start But I could have picked whatever I wanted. I just that day I like 10,000 And then here are the instructions. So those are the next 37 bytes and then The data is the 12 bytes So if you actually disassemble the instructions And put it into online disassembler, which you don't have to do for this course. Thankfully, but if you get into You know reverse engineering or you want to do some malware stuff and all that fun Stuff you might use a disassembler at some point So this would be an exercise in that So if you disassemble it, this is what the instructions look like and they kind of correspond because we're making direct system calls here so x8 We're just moving values into registers here. The x8 register Stored the system call number. So for hello world, we need to make a right system call. So we put in the number 64 64 represents right And you just look that up or it's to find a header file or something Next is the first argument, which is file descriptor since we're hello world. We want to Essentially print to file descriptor one. So we put one in register x0, which is the first argument And the second argument because it's arm. We have to load that register in two steps So first we load the byte with 9c And then we add 10,000 hex to it to get the address of the Yeah, to get the address of the string, which was that 10,009 c And then the next argument is the length of the string, which is just 12 or c in hex And then this svc would trigger A interrupt to the operating system and then it would do the system call And whenever it returns back from you, we would see hello world And then next we need to make that exit system call So we load up the new system call number, which for exit is 94 And then it only takes one argument We'll give it zero and then we do a system call here And then the operating system kills our process And yes, that is a technical term We'll get lots of tech we'll get lots of gruesome terms your Your google searches are going to get very interesting because of this course But by the end of next week, it's going to get trust me. It's going to get real weird All right any questions about this Arguments that this is kind of hello world Well, it must be hello world because I executed it and it worked So the next 12 bytes again are the data they're asking coded Do you need to know asking coding? No, not really. Should you know what it is? It probably won't be bad There's like a low level tip if you ever get really into ASCII because of the way they designed it So if you want to figure out whether character is upper or lower case They made it really easy that you only have to check a single bit So bit five if it is zero it means it's an upper case if it's one it means it's a lower case Which just means the values differ by 32 They designed it that way because computers back in the day were really really really really slow. So checking a Byte or sorry checking a bit is like the fastest thing you can do. So that's why they did that So that's every single byte of our program We didn't waste anything aside from the header files might you might argue that are kind of wasteful But let's go ahead and see what c does and Before this Can we spot some difference between our string and a c string? Yep Yeah, it doesn't end in an all character so it would be Yeah, so just doesn't end in an all character an all character Terminating strings is purely a c thing the offering system doesn't care about that Because if the write system call had to end with a zero string or a zero to terminate a string It would stop writing by the time it got to zero and if you ever want to Actually write zero to a file you couldn't do that if you were having c strings It would just wouldn't happen because they're defined like that. So Strings ending in all terminating characters just a thing in c although we'll be in c for this whole course Aside from this crazy example So we finally got to the point where we can say what a kernel is so a kernel is a core part of your operating system that interrupt and Changing and making a request to the operating system Well, that actually corresponds to a different physical privilege level on your cpu. So on your cpu There's something called kernel mode, which is just a generic term that As long as you are in that Operating in that mode you have access to more instructions than you can otherwise use So those are where all the instructions are that I can actually interact directly with hardware and that Forms the security that makes the operating system or the kernel have ultimate control over the hardware there's actually Like a physical barrier in the way your your program is not allowed to change any hardware Even if you knew the instructions that change hardware Because you're operating in a different physical cpu mode. You're not allowed to execute those instructions So kernel mode is a generic name different architectures call it different things on arm And risk it's called supervisor mode on the risk 5. It's called s mode if you want to have it shorter on 86 it is called ring zero because they used to say They used to represent as like a Venn diagram and have privilege rings where it gets smaller and bigger So that's where the name is from and those naming conventions get really weird as things get more modern Which we'll see at the end of the course but that actual Barrier for cpu mode That is a very strong barrier and If any software is running in kernel mode. It is part of the kernel It's kind of a dumb definition But the kernel is just the part of your operating system that runs in kernel mode so We'll see at the end This makes a bit more sense when you figure out what's actually running in kernel mode can change between different full operating systems So these instructions again You're only allowed to touch something like virtual memory if you are in kernel mode that way Normal applications like your hello world or anything you've written in c Can't change virtual memory Otherwise if any old process could change virtual memory Then you could read any other processes memory by just kind of monkeying around with it So you would have absolutely no security without this privilege level on your cpu So this is kind of what it looks like graphically on real modern cpus. There's four mode four different modes so The first one is user mode, which is if you've written everything in c you've run any application on your machine It's all running in user mode. So this is applications libraries And that has the least privilege it can access the fewest amount of instructions on your cpu The next layer beyond that is the kernel that runs in supervisor mode or kernel mode Whatever you want to call it and that will be able to do things like manage virtual memory and do some other things directly with the hardware Now there's some other modes that we won't get into in this course until the end where we'll get into the hypervisor a little bit but the hypervisor Well, you need a different physical mode because your Most traditional operating systems run in kernel mode So if we want to have virtual machines and want to have an illusion of One physical machine being independent there needs to be something with ultimate control of the hardware So for virtual machines If they're hardware supported it will actually run in a cpu mode called the hypervisor And the this hypervisor mode will actually manage all of your virtual machines So if you're using windows and using hyper v windows is actually running as a hypervisor And then your virtual machine is running in kernel mode and it thinks it has access to the whole machine But windows is ultimately still in charge And then at the very bottom there's machine mode or m mode And that just has unrestricted access to every single instruction. That's what you did in 243 where there was no barriers. You could just execute any old instruction you wanted to So that's like real low level embedded code where you're running one application. You don't need security or anything like that So system calls Aren't just requests the operating system But they are a request because they transition between user mode and kernel mode That's the only way you can switch your application and request kernel mode and then the kernel takes over and does whatever so On linux, there is only 453 different system calls or functions if you want to think of them that way And that is your entire interface to your kernel So we've already seen some of these instructions like read and write open and close and at the bottom there's Exit group, but at the end of this course The goal is you will understand What each of these system calls do how to use them and how they're implemented without actually implementing them yourself So that's kind of where this course is aimed So the very nice thing about having system calls is you can trace them there's this clear separation between user mode and kernel mode And you can actually monitor any system calls that happen on your machine at least on linux So on linux, there is this s trace program So you can just stick it in front of whatever you're trying to run And it will tell you all of the system calls that program makes So let's go ahead and see what Our hello world program does So if we just stick an s trace in front of it, whoops We can see the system calls it actually makes It looks a bit weird here and first off this line We'll explain it two lectures from now But we didn't make this that's how your Program starts But we start here with our write system call and it looks a bit weird Because we have our write and then we have hello world and then a new line and then a bracket So it looks like they're kind of fighting with each other our hello world and s trace And this is where having two file descriptors for standard Output and standard error is useful so s trace Outputs things to standard error. So if we want to get rid of whatever s trace is printing We can do a shortcut like this Do you have to know the shortcut? No. Well, it may be useful to you probably So two and then the arrow means redirect file descriptor two from this program To somewhere else and somewhere else could be on linux There's this dev null file that just kind of represents the void anything that goes there gets deleted immediately And it's really really fast at deleting things So if we do that We just see hello world because we're printing to file descriptor one and s trace is using file descriptor two So if we want to just see hello world, we could do that Which kind of defeats the purpose of running s trace But if I don't care about the output of my program I could redirect file descriptor one instead and then I should just be able to see s trace itself So now it looks a bit cleaner. So we can See what our program actually does So our program right exit group. That's hello world All right So now that we have s trace in our back pocket. We can see the nice thing about it is Nothing can lie to you anymore So you can tell what any application on your at least linux machine is doing because you can monitor their system calls So let's see what c does so That's hello world and c anyone disagree with hello world and c looks pretty standard, right? Your guess is that it should probably do the same thing a right and an exit if everything has to go through The kernel anyways, so if we want to see what it does, we'll s trace it. Yep Sorry Oh, so like this time So hello world doesn't print for this one because I'm sending it to nowhere So it's not getting printed anymore. So I'm just seeing only the output of s trace here Yeah, all right. So let's go ahead and make sure our c works So c works looks the exact same right prints. Hello world doesn't look very special So let's get rid of that So if c is like a real low level language that doesn't do much it should look exactly the same So let's run it And see what it does That's a bit more doesn't it So Can we argue what it does? Well, let's see this means nothing to us M map also means nothing to us. We'll learn it midway through the course. It's actually a way to request Changing virtual memory in your process, but we don't really know what that's doing There's this no such file directory. So that didn't work whatever that was then here. Oh, it opens a cache I don't know caches are fast. So that's good. I guess cool Some more m map things. Oh, that's interesting Oh, it's written in c. What's this? Well, that's the standard c library. So the standard c library is just a file. So it has to open it So it opened the standard c library So that makes sense. We wrote our hello world in c. So it probably had to use the standard c library So it got filed to descriptor four and then here at red And we can see here that the standard c library is an l file It doesn't say 7f because for some odd reason this output is an octal So 1 7 7 an octal is 7f in hex Aside from some weird utilities, you should never see octal and you should burn octal because it's kind of silly But read some information from the standard c library kind of makes sense Did some more playing with memory? Did some more playing with memory? Get random that's kind of cool. And then at the end It did another brk and then another brk with the address it got from the first one So that is actually the system called to request heap space. So this is what malloc is doing So if you use malloc, it's actually using these system calls malloc is not a System call or anything. It's built on top of system calls that just manipulate the heap And it works because mallocs the only thing that should manipulate the heap So cool. So the nice thing about s trace is well, it works on anything. So oops python 3 So if I write hello world in python It does the same thing If I want to figure out what the hell python is actually doing, what should I do? S trace it right can't lie to me can't hide anything So Let's see. Let's just see what python does Hang on python seems to do a lot more Then see it's still going Still going so python does a lot So we can kind of see what it's doing though So python it did that right it had to Because we saw it in our terminal and it ended in exit group, but it did a lot of other stuff But you can see some of it kind of makes sense So it opened the script it had to execute that makes sense And it had to read from that file. So it read my print hello world What didn't make sense is it had to read it twice. I don't know why it had to read it twice But it read it twice for some reason so Maybe you can go back to the python developers and fix that say hey, you don't need to read the file twice You read it once so you could fix some python performance problems I ran it before so we can see just how many system calls it makes And it makes over 350 So I'm obligated to do this now So javascript I hate javascript And I will illustrate why it's bad. So if we want to figure out what javascript is doing, what should I run? S trace. Let's see what javascript does That certainly seemed bigger So let's see. There's exit group. So it had to end with that because it ended the process Let's go up to see where our write system call was for hello world Let me know when you see it So if there's a write but it's the right to file the script or 13 8 bytes 0 1 0 0 0 what I have no idea who wrote javascript, but Yikes We can scroll up Again, we're looking for write hello world. Hey, there it is So it eventually did it but it did a lot of other stuff We can see Just how many system calls it made over a thousand For hello world So if you want to you can judge kind of judge a language by how many system calls it has to make or just the implementation of that So at least judging up that pythons at least three times better than javascript Uh Yeah, there's your warning against javascript. It does a lot of stuff Sorry. Oh, so how so the question is how many system calls did c have? uh, sorry C at 34 And some of it was just loading the standard c library and doing some other stuff. So suddenly It's better than our it's way worse in our two, but 34 is nothing compared to you know over a thousand But for fun You can do that on literally any program you run So we could s trace you could s trace wherever you want you could s trace vs code if you wanted to It's gonna output a lot of stuff though So here I just have it was basically finding the standard c library there loading it And then setting up the heap and printing So at the end of the day It was our system calls No matter what language it had that right system call and that exit system call so The kernel like the linux kernel you can think of it as a long running process and Writing kernel code which what you did in lab zero or like over half of you have at least submitted the crowd mark thing So you're I guess done with lab zero so When you're doing that the kernel is actually running at all times because if the kernel is not running Your computer is not running. It's the thing that's managing everything. So the kernel is always running at all times So writing kernel code is a lot more like writing library code. There's no main function or anything like that. It's already running so the kernel lets you Insert code into it and it will execute that as it's running and that is called a module Which is what you wrote as part of lab zero And in general those modules are done like that because they execute on demand So sometimes A module will be associated with a specific piece of hardware. So if you plug something into your computer The kernel will know that hey that hardware Corresponds to this module which has the code to actually use it So I'll load that module and do whatever it needs me to do and access the hardware And that module will be running in kernel mode. So it can actually access that hardware and do things with it so the kernel Module you wrote whenever you did that instmod command and inserted it into the kernel Your code was running in kernel mode if you knew what to call You could manipulate hardware directly if you really really wanted to In the code you're right. Yeah in the code you're writing for lab zero if you wanted to you could go You could end every single process. You could read any processes memory You could do whatever you wanted to if you knew the linux thing to actually To actually call to do whatever you wanted to do So your code is actually running in kernel mode. It can access hardware It's date. It's fairly dangerous And that's also why The machines here will not let you run a kernel module because if you could run a kernel module Then you could do whatever you want to on the system and it would have essentially No security because you could read any processes memory and now things suddenly aren't independent anymore So that's why we're doing a virtual machine So you can actually run code in kernel mode and do whatever you want. It's your machine And it won't break anything else because it's virtualized So there's some different uh kernel architectures which change How much software is actually running in kernel mode because Kernel mode it has direct access to the hardware It's a big target for hackers because if you can get something that can Escalate privileges and run in kernel mode while you have access to the entire system. It has no security anymore so One of the kernel architectures is called Monolithic which basically just means hey, we're kernel developers. We write perfect code all the time So anything that can run in kernel mode. We will put in kernel mode So this is the architecture of linux So that means your kernel is going to take care of virtual memory It's going to take care of process scheduling like what process is running at on your cpu at any given time It's going to take care of inter-process communication It's going to take care of file systems device drivers using your gpu all of that stuff so Some people are of the opinion that that is a horrible architecture because all your code is there More code equals more opportunities to get exploited So if I want to reduce my surface area of attack, I should use an architecture more like this So there's another one called a micro kernel and the whole philosophy behind that is I will put only what's really needed running in kernel mode everything else i'll use in user mode and i'll just do system calls between them So the minimum you have to do in the kernel is virtual memory management has to be done in the kernel Otherwise, you could read each other processes or you could read memory from other processes kernel still has to maintain control over the cpus and process what runs on the cpu at any given time And it has to do some basic inter-process communication at least transferring bytes between things But you can move things up into user space. So your file systems your device driver code could all be in user space Or like advanced types of IPC that are just more than sending bytes between like sending messages or something like that And those are not the only two options There's way different way. There's many different ways to draw those lines each with different trade-offs Another trade-off why to use a monolithic kernel like this where everything is running in kernel space Is doing system calls is actually slow Transferring from user mode to kernel mode and actually physically switching the mode Is way slower than just doing like a function call in c So the more function calls you have to or the more system calls you have to do the slower It's going to be so if you only have to make one system call that does everything That's going to be a lot faster than if you have an architecture like this where to do something simple You might have to make you know Dozens of system calls or maybe even hundreds So one reason to do a monolithic is performance But there's plenty of different lines. You can draw that all have their different trade-offs oops So hybrid kernels are kind of in between monolithic and micro kernels So like in windows sometimes emulation is in kernel mode in windows. It's in user mode So they moved it out there. So it's not completely monolithic. They try to move some stuff out like emulating DOS and all of that On macOS device drivers are actually running user mode They're not part of the kernel because the kernel is sacred to apple and they also don't trust you So that is another reason why apple does that and then there's another form of research where Researchers try and get even smaller than a micro kernel So they've come up with terms like nano kernels and pico kernels And the goal is to just push the boundary and move more stuff out of the kernel and into user mode So there's no right answer for this. This is all engineering everything Every different architecture you come up with has different trade-offs and the main one being Between monolithic and micro kernels is just speed reducing the number of system calls because they are slow So what do we have to take away from this lecture? Well, the kernel interfaces between different cpu mode boundaries specifically user mode and kernel mode are the generic terms for them So we need to know that the kernel is part of the operating system that interacts directly with the hardware to Transfer to kernel mode and make requests for it to do things you have to do system calls And every program has to use that interface No matter what and because of that We can strace strace will become your friend In this course and later on in your career again Nothing can hide from you with strace because it has to interact with the operating system or else It's not going to do anything useful So strace is applicable No matter what language you use or what you run We saw the file format instructions to define hello world Again, don't need to know the file format. Don't need to know what the crazy bytes were Just know the system call abi uses registers and c uses the stack is good enough for our purposes And the difference between api and abi which we'll explore more in next lecture And like just using strace is like probably one of the core things you should get out of this lecture And all of those different kernel architecture that shifts how much Code runs in kernel mode and how much runs in user mode So that's it. Just remember i'm pulling for you. We're all in this together