 All right, welcome back to operating systems. So this lecture will be slightly confusing, but that's okay, you actually don't need to take that much away from this lecture, we'll be figuring out how stuff actually works and it will hurt a little bit, but I'll point out what you actually need to know. For the most part this is mostly like how things actually work and it's okay if this is a little bit confusing, but it should be mostly understandable, so again feel free to ask questions. So this is our Hello World program I alluded to last lecture. Let's just go verify that it actually works. So if we go and execute it, prints Hello World. That's what we expect, that's Hello World, it's just really really small. So as a first aside that you don't really have to know this, but it might help you whenever you look at stuff and try and understand stuff. So there's three major ISAs or instruction set architectures today. You'll probably touch all three of them at some point in your life. So it's machine code or numbers the CPU understand, so your assembly code is really really close to this. It's just a human representation of machine code just so you can read it a bit better even though it's probably not that readable. So the three architectures are x86 64-bit and that is like desktops, non-Apple laptops, computer or servers like most things running in the cloud, things like that. Then there's ARCH 64 which is called ARM 64 and that's if you're lucky enough to have an Apple laptop that's what it's running. Your phones are going to be running that architecture, tablets, things of that nature. Your computer organization course that was some flavor of ARM so it's used for things like that. So there's another one that you might not have seen yet called RISC-5. It's basically an open source implementation of ARM so you can actually implement your own RISC-5 processor if you want without having to pay X million dollars which is kind of nice. So we'll be looking at a kernel that uses RISC-5 in this course but if you can read ARM, you can read this and we won't really have to read that much assembly anyways. It basically looks like an ARM processor but again we'll touch all them in this course. It's good to know them. Won't test you on this. So our next abstraction that we alluded to before is something called a file descriptor because why do we even have something called a file descriptor? Well we discovered before all our processes are independent and if they're all truly independent that means they're all truly worthless because we can't read anything from them, we can't see what they're doing, we can't get any information out of them. A truly independent process is completely useless. So since they're independent we need an explicit way to transfer data and that's where file descriptors come in and this is a type of something called IPC which is one of the core things an operating system has to do. IPC stands for inner process communication. What that means is basically you just want to communicate between two different processes that are running. They don't even have to be running at the same time. So anytime you transfer data between two processes that's IPC inner process communication. What a file descriptor is it's a resource that users may either read bytes from or write bytes to and it is identified by just an index and that index is stored as part of the processes information and the actual index is independent to that process. So if you open a file and you get file descriptor 3 and that represents your open file as long as you don't close file descriptor 3 for as long as your process runs file descriptor 3 will represent that file no one else will monkey with it. So for now a file descriptor could literally represent a file which probably makes the most amount of sense to you but because it's abstract it's only something we can read bytes from and write bytes to. Well it could represent pretty much anything so it could also represent a terminal. So what you type in that could be writing bytes to it or sorry reading bytes from it and then whenever it's displaying output while the process is writing somewhere and then you can see whatever it writes. So next we have to get into system calls. You do need to know system calls just not how they're implemented and we'll explain throughout this lecture what a system call is that's like one of the main things you'll take away from this lecture we're gonna go over it like a thousand times. So system calls are a way to make a request to the operating system itself so they can kind of look like regular C functions you can think of them that way but they're a bit different but if we think of them as C functions for now let's just kind of explain two of them. So the first one is called write and that writes bytes to a file descriptor so it has three arguments there the first argument fd that's the number representing the file descriptor to write bytes to and then the second argument that buff is the address at the start of a byte array so you just give it a big array of bytes and then the last argument count is how many bytes to write from that array and what it returns is the number of bytes actually written to that file descriptor. So if it can't do anything it might return zero even though you say write a bunch of bytes to it or if you say write 10 billion bytes to it it might be like no I'll write a thousand instead and then you could do another write system call if you want just depends and the reason that it's there's you see size t and s size t is the return type while s size t is just a signed size which just means it can go negative so if write returns negative it means there's an error then the other system call is called exit group and it takes one argument called a status and what that system call does is exit the current running process and then sets some error code so the exit status is just a number that you can use to represent whatever usually the common convention zero means your program exited without any problems which is why you return zero from main that just means nothing went bad and if something went bad you return something other than zero you'll see here that the only valid values are zero to 255 which is one byte so if you but it's the argument's an int so if you use a bigger number it'll just get rid of all the more significant bytes and only keep the least significant byte do you need to know that not really but it's how it works so to explain the hypothetical hello world program those are the system calls we need but I also need to explain a convention so there's a convention between every single process running on your operating system at least it's it's if it's macOS or Linux Windows does weird things but by convention whenever you a process starts there are three valid file descriptors but file descriptor zero is supposed to represent standard input so that's where you read bytes from if it's a file descriptor if you used C and you took user or input from a user and it was called standard input standard input on Linux at least this means it's reading from file descriptor zero it's it's just a convention that would represent your terminal most of the time so the standard C library will make dealing with it a bit easier and you might be able to get an integer out of it or something like that but the other day it's just doing some work for me it's just reading some bytes from somewhere then the next two one is standard output so that's where it's expected that anything you see on your terminal you'll see that's normal output so normal output goes to file descriptor one so if you have printf it actually goes to file descriptor one again on macOS or Linux then there is file descriptor two that is meant for standard error the convention is anything you write there most of the time your terminal you can't tell the difference where the output's coming from but if you want to be nice and we'll see why it's kind of useful in a little bit if any error happens in your program you write your error messages to that file descriptor so if you use so some of the built-in C functions will actually use that file descriptor to write errors for you if you use them hopefully you've checked for errors in this course you will want to check for errors because you will figure out that literally everything your computer does can fail and yeah you probably want to check for errors so the most basic hello world program if we assume C didn't exist and main didn't exist and we could just magically define a function here the name doesn't even matter but we could just define a function that doesn't return anything and doesn't take any arguments and if we could magically have our computer start executing this function this is all it would need for hello world it would need a write system call to file the descriptor one because it's hello world I'm just writing the standard output then I would need the address of this string so hello world with a new line character and then how many bytes to write so I'm going to write 12 bytes why is it 12 well pretty much every character is one byte so hello is five bytes space is another byte that gets us to six world is another five that gets us to 11 and this backslash n that's actually a new line byte so that's actually one byte which gets us to 12 so if magically I could just start executing this function this is all I would need for hello world and it's just by convention of those file descriptors so another quick aside so you've probably heard of an API before I hope so but in this course we don't have to know the ABI but it's going to be useful to have some background with what that means so an API is like very high level it tells you what to do an ABI stands for application binary interface is like the real low level details that hopefully you never have to see outside of computer organization and this course so API it's like application programming interface abstracts to details it's just supposed to describe what the function does what arguments it takes and what it returns so like a function takes two integer arguments and it returns an integer that's supposed to be the addition of them or the multiplication them or something like that it's like very high level description I'm not telling you registers or anything weird like that but an ABI or the binary interface will tell you in gory details exactly where everything goes on that specific CPU so that function would have an ABI so I could say hey I to make a function call to this function I have to use the C calling convention so that's an ABI basically without getting to the gory details of that it passes arguments on the stack in your computer organization course you probably passed arguments and registers right everyone remember that so remember when you made function calls in that course you passed arguments and registers and then you had to make sure they lined up on both sides of the function call and that was all fun so that would be an example of an ABI so it's a contract between the function that says this value has to be in this register otherwise if it's not there it's not going to work so to make request for to make request to the operating system you can't just call functions so there is no functions to the operating system so the only way to make request to the operating system is through a function call and in because there's no address or anything the way you make system calls on every single operating system again now this is like window includes windows is you generate an interrupt and there's a specific CPU instruction that will generate an interrupt to the operating system so you've dealt with handling interrupts in that course so you can imagine what the operating system has to do but now you are generating interrupts yourself although you never aside from this one example will see you'll never generate your own interrupt actually that's not true but for the most part we won't do it we won't do it in assembly so specifically on ARM to generate an interrupt there is this SVC instruction and that will generate an interrupt and in order for the operating system to handle your system call while there needs to be some type of calling conventions like the same thing you had in that organization course so there's some registers that are defined to be some things so the x8 register is just a number that's representing what system call you want to make so if you want to make a right system call it's a certain number you can look up you want to make exit group it's another number you have to look up and then you can have up to six arguments and they are passed in registers x0 to x5 so can anyone think of any limitations of this ABI yep yeah I only have six arguments how many arguments can I have and see a lot until my stack wears out pretty much so any other limitations for this yep oh so that was it slow technically passing registers is really fast sorry oh the interrupt is slow as hell yeah but yeah just in terms of passing things in registers like this so any other limitations yep yeah all the registers are the same size so if they if all my arguments don't fit in exactly a register I might be wasting space or I won't have enough space so they're all a set size and see you can pass ints you can pass doubles you can do whatever and it's fine so those are two limitations it's good to know those limitations you do not have to know all you have to know here is that it passes things and registers you don't have to know the specific register numbers it's only going to be for this example all right so the next thing we need to understand is that programs on Unix use the L file format you will never be tested on file formats this is just so we can explain that hello world program so you can relax so like I said the elf was a coincidence it actually stands for executable and linkable format has nothing to do with me and it specifies the file format for both executables and libraries and like we saw before it always starts with the same four bytes and they're literally called magic the more you learn about computers the more you realize that magic is just random numbers and knowing what those random numbers are supposed to be at the other day that's like literally all of computing machine code is just magic numbers strings are magic numbers that means something if you know how to decode them everything's just a magic number and there's a whole list to see that I'm not lying it's like the file format for everything you can look at the Wikipedia list so if you want to explore PDF files everything is going to start with that ampersand not ampersand sorry percent sign PDF and a dash every single PDF file so the bytes I showed you before for that hello world program what they actually represent that we know is they represent an elf file so this elf file what it has to do is tell the offering system what to do with it and it also contains the instructions of data so basically all that file does is to say load this entire file into memory starting at address 10,000 in hex why 10,000 well memory is virtual we can pick any number we want some are reserved so we can't pick starting at zero because zero is by definition some invalid memory and that's why if you dereference null you get an error and all bad things happen so you can't do that but otherwise we could actually tell the the operating system to load this program at any old address we please because this is all virtual memory and we just have it figured out but in the specific thing I wrote its address 10,000 in hex so there's two parts of an elf file it always has to start with a header file which is 64 bytes which is like almost a third of that file and then a program header which is 56 bytes so all this information to tell the offering system about our program is 120 bytes which is most of our program and again you don't have to know about elf headers or anything like that so the next 36 bytes in our that binary file actually represents the machine code for the actual instructions to make some system calls so there's 36 bytes in instructions and then after that there are 12 bytes that are supposed to represent the string hello world so if we load this entire program in the memory at address 10,000 hex and these two headers take up 120 bytes well if we need the memory address of where our instruction start it is at the hundred and 20th byte is the first byte of the instruction if you convert that to hex it is seven eight and then because the file we've pulled it to load it at 10,000 we just add it to 10,000 so the instructions would actually start at address 10,078 and then the string is going to be after the data in this program so it starts at address 10,009c because the string is after all the instructions so it would start at byte 156 which is 9c in hex so the string would start there this is like gory detail you don't have to know that but this is like what the operating system has to understand if you want to go into the gory details which I don't recommend but hey you're all adults I can't tell you what to do except I can kind of so I guess I set labs and stuff like that in the exams but I can't tell you what to do on your free time but so if you want to see all the gory details you can use that we will we'll just skip that so visually how it looks is that first 64 bytes are up here in the blue in the file header it specifies a few other things so it begins with that elf and then if you know which bytes to read it will describe the endianness so little ending or big endian the instruction said architecture that this file is supposed to run on so that way your operating system knows what is a it's running and can read that information and if it doesn't match it means it can't execute it so it doesn't even have to try it can just bail out the next is the entry point the entry point tells the operating system where to start executing from so in this case if our instructions start at this address this would be our entry point for this program and whenever the kernel starts executing it would start executing at that address which is good because that's the beginning of our instructions and this is what the operating system cares about so you might have heard that hey and see execution begins at main that's that's a lie it begins wherever this tells it to begin and if you compile a C program it's not main so sorry for that but we'll figure out what C does in a little bit okay so this all the bytes in cyan basically tells what to load into memory and where and this is where it just says load everything at address 10,000 hex and it wastes a bunch of bytes for that and then we have our instructions and then our data so those bytes that represent the machine code if you were so you might actually do some of the stuff if you get into like cybersecurity or like you know you want to hack stuff or do other fun disassembly stuff or see how programs are actually made you could actually just take the bytes and put them into a disassembler and if we do that to these bytes these are a disassembled instructions and they look similar to how system calls are being made because these are supposed to represent system calls so it's okay if we forgot already but x8 is the register where you put in the number of the system call you want to make so if we want to do hello world we want to do a right system call first and it just so happens that the right system call is 64 and then the first argument it's a file descriptor we want to write to file descriptor one then the next is the address of the starting address of the string so that was at 10,009 c so because it's arm we have to do it in two parts so we have to load the lower bit or lower byte of x1 with 9c and this just adds 10,000 to it to get the address we expect again don't have to know this this is just some arm crap and then the next argument is the number of bytes to write and here we just write 12 so that's how many bytes are in our hello world string and then we have this SVC instruction then that will generate an interrupt the operating system gets to do the system call and whatever the operating system is done with the system call it will just continue executing your program after that SVC instruction so after it's done the right system call it will do this instruction so we're going to do a different system call we want to do exit group it happens to be number 94 and then the argument we give it is 0 and then we do an SVC instruction so that does another system call and because it's exit group our process is dead now and it can't execute anything so it doesn't exist anymore and the rest of the things are 12 bytes for hello world of the string itself it's ASCII encoded and for some reason if you or just as a fun to know whenever they made the ASCII standard they made it really easy to tell whether a character is an uppercase or a lowercase number by looking at a single bit as like an optimization so if you want to check if something's an uppercase you check bit five if it's zero it's uppercase if it's one it's lowercase means the different the values differ by 32 why I'm telling you this I don't know but hopefully it might be useful to one of you at some point in your life but probably not so that's every that's every single byte so we load the program in we tell it where to start executing we just have a few instructions and we have a string and before I even start executing can you already tell a difference between the string I used and like a C string so was a C string oh way back there yeah yeah then the null character so the null character at the end of a string is literally just a C convention your operating system doesn't care so that's literally just a thing in C and we'll see that as it goes on and why that might make sense okay so this is also an important part and this is also captain obvious so well it will be captain obvious in the next slide so the kernel is a core part of your operating system you probably heard the term kernel before but you might not know what it is so on your CPU there is a special privilege mode called kernel mode and if your CPU is it's just basically a switch and if your CPU is currently in this kernel mode it can access more instructions so it can access special instructions that can directly communicate with the hardware depending on your architecture and whoever made the CPU they might call kernel mode something different on risk five it's called s mode or supervisor mode I believe it's it's called the same thing on arm on x86 the old processors it's called ring zero so it might be called different things but the generic term for it is called kernel mode that's the term we'll use in this course and this is the captain obvious part is the kernel is a software or the part of your operating system that runs in kernel mode so if it if it's software running in kernel mode it's part of the kernel it's kind of like a just a big tautology there so again kernel mode instructions they're the only ones that are allowed to directly interact with hardware so this means for example any instructions whoa that was aggressive okay that doors heavier than I thought my bad I didn't try and be that aggressive all right so for example in supervisor mode or kernel mode you can access instructions that will let you play with virtual memory and you know reconfigure virtual memory which you don't want your application could to do because if it could well then it could probably reconfigure virtual memory to read other processes memory and then suddenly they're not independent anymore so the kernel has to manage that and there has to be like actual hardware privileges so that there's no way that any application there's like a clear separation so that no user application can change it so this is kind of how it looks like on a modern CPU so this is as complicated as privilege modes get so where you've been at so far in like anything you've ever written in like any C program so like 105 that code is actually executing in something called user mode or you mode on risk 5 and those are the least privileged instructions so if you try and execute an instruction that tries to interact with hardware the operating system won't let you do it then there is s mode or supervisor mode or kernel mode which is where your kernel exists and this is the core part so there's a kernel as part of macOS Linux is actually the name of a kernel not an operating system and on Windows Windows will also have its own kernel then as you get more complicated there is an H mode for hypervisor mode because virtual machines while they need to be independent so there needs to be something to manage virtual machines and that is something called a hypervisor which we won't have to know until the very end of the course but that's what enables something called virtual machines it runs in that mode and then at the very end there's machine mode which is just access to literally every single instruction this is what you've had in like your computer organization course there is no CPU modes or anything you could just access any instruction you wanted there is no checks no checks no balances nothing like that you could just do whatever you wanted so in risk 5 it's called machine mode it's just full access to everything generally like really low level hardware operates there something we won't touch on this course so there's only one way to get between user mode and kernel mode no matter what and that's what system calls are so system calls will actually transition between user mode and kernel mode on the Linux kernel there's only 453 of these functions so that's the entire interface to your to your kernel on Linux so there's only that many functions some of these we already have seen briefly read write open close we can kind of imagine what they do and then at the end of this course you will know what all of these do by looking at them and be able to explain actually how they work but for now they are a complete mystery you might be able to guess but you should have no idea what the rest of these do you can probably guess a little bit okay so the nice thing about having this clear separation where if you want to interact with the hardware you have to go through the operate you have to go through a kernel and you have to do it through system calls because we have this on Linux you can actually trace system calls using a command called s trace and it will tell you what literally any program does since every program has to interact with a kernel you can tell no matter what language it's written in no matter even if it's not written in a language if it's just some psychopath writing in bytes like what I did it will tell you what the hell it's doing so we can use this program to see what our hello world problem does and hopefully it makes those two system calls so if I run s trace on that well I can see so first off this line doesn't count we'll figure out what did this and where this came from but this is not what we did but we can see it's a little bit jumbled but it looks kind of correct we wrote to file descriptor one hello world 12 and then we actually see the hello world line we read itself so they're kind of jumbled together here and then we have the rest of the trace that says we didn't exit group so this is where so s trace actually writes everything to file descriptor two standard error so if we wanted to get rid of what s trace is doing on macOS or Linux you can do this what this means is take file descriptor two and redirect it somewhere so instead of going your terminal I can tell it to go to the special location where it just deletes everything so it just kind of goes off into the void and no one ever sees those bites again so if I do that I won't see any output from s trace and if I go ahead and change that from a two to a one then I won't see hello world anymore and I'll only see s trace so if I want to see it a bit cleaner I can do something like that so my hello world program it does a right system call file descriptor one standard out hello world exits that's it that's hello world so let's see what C does so above there I have hello world in C everyone agree that that's hello world so hello world everyone has seen before so if I compile it so it's already compiled so my program is 168 bytes anyone want to guess how big the C version is and he guesses whatsoever throw them out there kilobyte we got a kilobyte five megabytes all right someone thinks we're writing JavaScript all right so if we got five megabytes we got a kilobyte let's see build so the size is right here so it's 70 K which is 70 times 1024 so number of bytes so it's pretty big so it must be doing some special stuff so if we s trace it well first let's execute to make sure it works so Prince hello world doesn't seem to do anything different so if I want to see what's actually doing what should I use s trace yeah I can see what's doing so let's get rid of the output so if it's doing just hello world and nothing else it'll just be right exit that's it so at the end it did right exit so it did hello world it did some other things too so even without knowing what it's doing let's see if we can take a guess so this means nothing to us hopefully oh you have a question so the question is this is some of this is doing the include is that what you think some of this is doing no so when your C compiler so when's compiling it will use that include but your executable won't have an include or anything that's just so it knows how to compile things so this includes specifically will just have like the function arguments for printf and that's pretty much all we need from this include so yeah it's a good guess but that's not what it's doing when it gets compiled that doesn't exist anymore all right let's see if we can guess so BRK means nothing to us most of these probably won't mean anything to us and map means absolutely nothing to us we couldn't guess f-axis at means not that much to us but that kind of looks like a file path that kind of looks like a file so some cash it's using some cash on our caches are good caches are fast so that's probably good more stuff we don't know this one is interesting so here it's C that looks like libc so that's it loading your C library so if it's using C it's going to use the standard C library so it has to load it at some point so if we have to if we get to monitor everything it's doing well it should do something with the standard C library so here it's opening the standard C library and then it's reading from it and we can tell that the standard C library is just an l file like I said before because it starts with ELF and that magical byte so we saw before that that byte in hex is 7f this is actually 7f for some reason I don't know why this is an octal so that number is an octal don't ask me why but 1 7 7 in octal is the same as 7f anyways so it has to open the standard C library it reads some information from the standard C library that does some magical stuff that we don't know so mmap we'll get to it in this course but that's basically requesting the operating system to monkey around with virtual memory somehow so it's doing a lot of monkeying with virtual memory it's doing some more monkeying around that we don't understand it did some eye octal but got an error inappropriate so it was very inappropriate so that's probably not good who knows what C is doing and then at the last case so this BRK is actually it's setting up it requesting space for a heap so this is like the start of your heap and then this is it requesting heap space from the offering system so that's what BRK is doing in a more advanced course this is what so your memory allocator like malloc and things like that it uses this memory and it manages it but it has to do system calls like anything else and then at the end of the day it does write exit group that's it so eventually at the end of the day it did do hello world but took a while but hey because we have this S trace now we can see what other things do so Python prints hello world well we can S trace Python so if we S trace Python it does some more stuff but at the other day it does exit group so that's the only way to exit and then after a few things it did write but did some other things in between that and if we scroll up well we can see hey it opened that file it had to read from that file so it had to read my print command so it read print it actually read the file twice for some reason don't know why but hey you can see what Python's doing and you can scroll up and see that it does a lot of stuff that that that that so I ran this ahead of time so Python does like roughly 300 and over 350 system calls to print hello world so for fun JavaScript that's a language it's a language I hate that's a language it does hello world and you can S trace it whoops wrong number so at the end it did exit group where's its right system call very good question there's an unrelated right to file descriptor 14 nice da da da da da da doo doo doo can't find it so it's somewhere there so let's just see what how many system calls Java makes oh over a thousand nice so you can actually get you know undisputed proof of what your programs are doing and undisputed proof that JavaScript's at least three times worse than Python even for hello world so that's fun you can even monkey you can even use that for any program you've written so you can go back to your APS 105 things just S trace them all just for fun although they'll probably do more or less what hello world does oops code so yeah the system calls finding the standard library loading it basically what it was doing so you can think of the kernel as a long-running program that never ends so if you want to like in lab zero when you write a bit of code that is a kernel part of the kernel well you didn't write a main or anything so it's more like writing library code there's no main and the kernel lets you load code into it as it's running and then it will execute that code in kernel mode so you will have the ultimate power to do whatever you want so this code is just called modules because they're supposed to be kind of loaded on demand and you can unload them on demand and the kernel can manage them so mostly what these are used for is if you plug in new hardware the kernel knows what module that hardware corresponds to so it will try and load that and that will have all that code that will handle that specific hardware and then if you unplug it it doesn't need that code anymore so it would unload it but when you write your kernel code in lab zero that doesn't really do that much if you really wanted to and you knew what calls to make you could do whatever you wanted you have unfettered access your code is actually running in kernel mode when you insert it into the kernel so if you knew what you were doing you could read the memory of any process you wanted to you could kill you could just exit any process you wanted to you could you could do whatever you want right possibilities would be actually endless for that code as long as you knew what to do which is why if you have code that can escalate privileges and be inserted into your kernel well then your computer is pretty much gone because it can do whatever it wants your kernel is the thing that's maintaining security so if your kernel gets compromised you're kind of hosed at that point because kernel code can do anything so it's a really important part of the software stack so there's a bunch of different architectures for the kernel that separates out what the kernel is responsible for so the Linux kernel is an example of a monolithic kernel so these are just little terms you should actually know so a monolithic kernel tries to run as much as it can in kernel mode to make things as simple as possible and but it makes the kernel really really big but Linux is an example of that but in this architecture the kernel is responsible for managing virtual memory it's responsible for managing process scheduling with which is what executes on the CPU at any given time responsible for IPC or inter process communications it will be responsible for any file system code so how you actually read data from a device what formats it's structured in and the vice drivers so how to talk to a video GPU how to talk to all sorts of controllers on your machine there's another form of thought of that hey if kernel code is like really really sensitive and you want to eliminate your attack surface as much as possible well we should take things out of the kernel instead of putting everything in the kernel so a microkernel tries to run the minimum amount amount of services in kernel mode and then run everything else in user mode so that if that gets hacked or if it's wrong or if it has an error or whatever that none of that code actually runs in kernel mode so nothing can actually touch your hardware so what would actually be running in kernel space that the kernels responsible for would be managing virtual memory process scheduling because it needs to that has to be directly with the hardware you can't move that out of the kernel and then you have to have some form of basic IPC that the kernel handles so that other processes can't read other processes information and that is the bare minimum more or less the bare minimum you can actually have in your kernel and then kick everything up to this normal application code that runs in user mode there's all types of other kernels where they split that line so there's hybrid kernels that are somewhere in between monolithic and micro kernels so for example windows it's like a hybrid kernel because it has emulation services in user mode because that's like the old DOS stuff windows also had like an HTTP server in kernel mode which is kind of weird and a bad idea but yeah so macOS isn't quite a microkernel but it does have device drivers in user mode but it has it has other things like file systems that are still in kernel mode but it tried to push some more stuff out into user mode than curl mode to make it smaller and you might argue that hey that's one of the reasons that macOS is more secure than windows there's also like research in this area if you want to do OS research way off into grad school if you want to do that where you try and make it even smaller than a micro kernel so there's something called nano kernels and Pico kernels and it's just a whole form of research that tries to make them even smaller than micro kernels but for all this there's different lines you can draw different trade-offs this is engineering so wherever you draw that line there's no clear winner one isn't always better than the other in any respect so the big thing you have to know the lecture is that the kernel it interfaces between different CPU mode boundaries so the kernel is a part of the operating system that interacts directly with the hardware it is running in a special CPU mode called kernel mode and the only way to go from user mode to kernel mode is with a system call and that's primarily where this course is focused we're going to be on the boundary of system calls so we're pretty much going to be making system calls and then explaining what's actually happening in on the kernel and that's pretty much where this course lies and the nice thing about is no matter again no matter what language you write in even JavaScript every single program uses this interface so no matter what you end up doing if you write a computer program this course is applicable you can write s trace on literally everything we saw some more unimportant stuff like the file format and instructions to define hello world that wasn't important the difference between API and ABI you might want to know you don't have to know any specific ABI at all just like you just knowing like C uses a stack and the system call interface uses registers good enough for that and then we saw how to explore system calls with s trace s trace will be your friend if you get nothing out of this course you you will get just s trace everything if you don't know what the heck's going on or if it's really slow or whatever you can s trace it and you can get some idea what it's actually doing then we saw some different kernel architectures that shifts what runs in kernel mode so that's it just remember pulling for you we're all in this together and have a good week