 lecture in the course design and engineering of computer systems. So in the previous two lectures, we have studied some basic details about computer hardware, right? We have studied how the CPU works, what is main memory, how do IO devices work and so on. So if you take a course on computer organization and architecture, you will learn many more details about the hardware. But in this course, we are not going to go into any more details about hardware because the focus of this course is on the design of real life systems and we will mostly be covering software aspects of such systems. So starting from this lecture onwards, we are going to go into the actual contents of the course. So in this lecture, we will begin with an introduction to operating systems. So the next three weeks, we will go into a lot of detail on operating systems and this lecture is just an overview of what we are going to cover in the next three weeks. So let us begin. So what is an operating system? You all must have interacted with an operating system at some point like Linux or Windows and so on. So an operating system is what is called system software, that is it is a software that manages the hardware so that other user software like a web browser or a server or games or any other apps you have, all of these can run more easily, right? So an OS is what is called system software. So typically, you have hardware in a computer system and then you have the operating system running on top of the hardware and then all the other user software runs on top of the operating system. So an operating system is a special program. You can think of it as a special software and this is loaded, this is the first thing that starts when your computer starts up, right? When your computer boots up this operating system, the executable is stored on the hard disk and this gets loaded into memory and the operating system starts to run and from now on the operating system will start other user programs that are required in a computer system and run all of them. So just some terminology, we keep using the word kernel and operating system interchangeably. So they are more or less the same, the only difference is that the kernel is basically the core part, the central part of an operating system is called a kernel and an operating system has other small system programs like helper programs also in addition to this kernel, right? So the OS is simply the kernel plus these system programs. So an example is a program called LS that you would have used if you are using a Linux system. If you type LS it will show you all the files in that directory, right? So these are all extra system programs that come with your operating system and most operating systems today are what are called monolithic operating systems. That is the entire operating system is built as one big program, one big executable and of course you can install small things like kernel modules when the system is running for some extra functionality like device drivers and so on. But the core part of the operating system is in the form of one big executable that is loaded when the system boots up. So there also exists alternate architectures for how operating systems can be built which is called micro kernels which is the operating system, the core itself is very small and all the most of the operating system functionality runs as services on top of this core, right? It is built in a much more modular fashion but this architecture of operating systems is not very popular today so therefore we will not be covering this in this course. So before we understand what are operating systems the question comes up why do we even need an operating system, right? If it is not user program that you the user wants to use then why even bother having this piece of software? So there are many very important reasons why we need an operating system, right? The first one is convenience. So an operating system makes life easy for you. So you as a user program do not have to write a lot of extra code which is handled by the operating system. For example handling hardware, printing to the display all of these are common functionalities that every program needs and instead of every program writing it on its own the operating system provides all of that logic automatically to all user programs. So in this way using an operating system is very convenient but that is not all, right? You also need an operating system for isolation across multiple processes. If you have multiple programs running on the same hardware all of these programs should be isolated from each other, right? And you cannot trust any one program to not damage all the other programs and the way this isolation is achieved, the security is achieved is by using an operating system. An operating system ensures that the different programs that are sharing the hardware are isolated from each other and there is also another reason which is like a better utilization of the hardware resources, right? An operating system brings in efficiency because you have a central point of contact that is managing all the hardware resources. The OS can do a lot of optimization of these resources via some careful planning and so on as we will see in the course. So these are all some of the very good reasons why any user software of a computer system runs on top of a system software like the operating system. So convenience is of course as we said the most obvious reason why you would use operating systems. So therefore operating systems as expected started out as simple libraries for user programs. Then of course they have evolved. For example by providing to provide isolation you need to run at a different CPU privilege level. We have seen this two lectures back that CPUs have multiple privilege levels. So an operating system runs at a higher privilege level and provides isolation across user programs. So that functionality got added later. Then later on multi-programming that is the ability to run multiple programs concurrently got added on. So operating systems have evolved over the years from simple libraries to providing all of this complex rich functionality that we see today. So this lecture I will give you an overview of all the different aspects of operating systems we will be studying in the coming weeks, right? The most important thing that an operating system does is process management. It is responsible for concurrently running multiple processes on the underlying CPU, right? These processes can be programs written by the user, some system programs that the operating system itself has to run from time to time, right? All of these programs or processes are run concurrently on the underlying CPU and managing the life cycle of all of these processes. What does life cycle mean? Creating a process, enabling it to run, when a process terminates, cleaning it up, all of this life cycle of every process is managed by the operating system. So when you as a user, you write code, you write a program, you do not have to worry about all of these other things. It is taken care of by the operating system. The other thing that the operating system does is it schedules all of these processes and how does it decide which process to run? If there are 20 processes that want to run on a CPU core, how does it decide which process runs next? So we have what are called scheduling policies. There are certain policies that dictate how processes should be run in what order they should be run on the CPU. So these scheduling policies are also part of the operating system code. And another functionality that the OS does is it switches between these processes. So the scheduling policy decides, okay, next run this process, then run this process. And there is code in the operating system that actually executes that decision. It you know, we have seen this in previous lecture where you store the context, you store all the information about a process somewhere, then you start the next process, then you save that context, you restore another context. So all of this is also managed by the operating system. So this is called context switching between processes. And other things that the OS does is it handles interrupts. Now we have seen that external devices whenever they want to talk to the computer system, they will raise an interrupt when they have any event to deliver. So when this interrupt occurs, the CPU has to stop whatever it is doing to handle the interrupt. So all of this logic to handle interrupts is also part of the operating system, right? We have seen an example of this where the execution of a process is stopped, its context is saved, the operating system runs to handle the interrupt. So we will study all of this, how the operating system exactly does all of this in a lot of detail in this course. And another thing that the OS also does is manage the faults of your program. So suppose you have written a program which has a bug, which is accessing an array out of bounds or something like that, it is accessing memory that it is not supposed to, there is some bad behavior in a program. So then this program causes a fault and all such faults are also handled by the operating system, right? If you access an array out of bounds, you may get a segmentation fault, all of such things are also managed by the operating system. So overall everything to do with processes is handled by the operating system. So moving on, I would like to introduce this terminology called a system call, right? So what is a system call? Whenever a user program requires any service from the operating system, it makes a system call. For example, if a process wants to read some data that is stored in a file on the hard disk or it wants to read some input that the user is giving from a keyboard or your program wants to print something to the monitor, say by using the printf statement and see. So all of these require access to the underlying hardware, right? And you as a user cannot write code to directly do this, why? Because accessing hardware, all of these require privileged instructions and user code runs in an unprivileged CPU mode and you cannot invoke privileged instructions. Therefore then how do you achieve these tasks in your programs? You will make a system call, you will call the OS and the OS code will run and carry out this functionality for you, okay? So when you make a system call, the CPU will jump to the operating system code in a high privilege level, it will implement the system call, it will execute the system call and come back to user code again, right? So this is a way for isolation or protection also, right? You do not want to give access to the hardware to any program, but any hardware access you need, you go through the operating system by requesting it via a system call. So the system call supported by an operating system in some sense form the application programmer interface or the API of an operating system. So the OS exposes a bunch of functions and user program can call these functions for various services, okay? So now to avoid, you know, a user program written in one OS with one API to have to change to run on another OS, there has been some standardization done, right? So there is a standard API defined called the POSIX API. So this is for portability, that is if you have written code for one operating system, you should be able to run on another operating system also because the API is the same, right? So this POSIX API defines a standard set of system calls that have to be supported by an operating system. And if you write a program using this API, then you can run your program on any other operating system also that supports the same API, right? So this is OS1 and this could be OS2. If it has the same API, then your same code can run on this operating system also. So most common operating systems today are compliant with this POSIX API so that when you write a program on one version of Linux, it easily run on the other version of Linux also. So however, you do not have to change the program, but you may have to recompile it. If the underlying architecture, if the hardware architecture is different, then the CPU instructions are different, then you may have to recompile your program again, right? Because x86 and this is something else, the same instructions won't run on another hardware. You might have to recompile your program, but you don't have to rewrite it if you move to another POSIX compliant operating system. So that is the advantage of defining this standard API. So anyway, if you have ever written a code in any language, you would be wondering what is the system call API? I have never seen it. What could it be? That is because most user programs, you will never directly call the system calls anyways. So every language has a set of libraries that are provided for the convenience of users, right? The C programming language has the C library. So for example, you may have called a function like printf to print something to screen. So this printf function in the C library is the one that actually makes the right system call to print to screen, right? But you as a user, you will not directly make the system call. You will simply call printf, which will take care of all the details of making system calls on your behalf. So therefore, you as a user need not even worry about what are the system calls, what is the POSIX API. If you use your language libraries, this is automatically handled for you. So next, the next concept I'd like to discuss is what is called user mode and kernel mode, right? We have seen that modern CPUs have multiple privilege levels, also called rings in X86. So user programs run in an unprivileged mode and the operating system runs in a privileged mode, right? So this unprivileged mode is also called user mode. The privileged mode is also called kernel mode. So normally, your user program is running in user mode. Then you will jump to kernel mode periodically, run the OS and then you will once again come back to user mode to run user code, okay? So what causes this jump? When do you go from user mode to kernel mode and back? So the CPU shifts to the kernel mode and runs the operating system for the following events. When an interrupt happens, when some external device requests the services of the operating system, when you've typed something on the keyboard and that keyboard input has to be taken, the device driver has to be run. In such cases, you will jump from the user code to the kernel code and kernel mode and run the operating system. When the user makes a system call, user himself says, look, I need this work to be done. Then also you will jump into kernel mode, run the OS code and go back. And the third case is when some error happens when the program is running, some hardware says, the memory hardware says, look, something bad has happened, the user has accessed an array out of bounds or something like that, then also you will jump from the user code to the kernel mode, run the operating system, right? And once the OS has run, you have handled this event, then you will go back to user mode again, the CPU will switch to a lower privilege level, you will go back to running the user code. So these are called the user mode and the kernel mode of a CPU. So now we have seen process management, right? Processes runs for some time in user mode, sometimes in kernel mode and so on. The next thing that the operating system does is memory management, okay? So every process that is running, we have seen that it has a memory image consisting of the code and data and the executable, other things like the stack, heap, all of this is the memory image of a process in RAM, okay? There is code, there is data in RAM and the OS is responsible for allocating this memory for the process. And in a few lectures back, we have also seen that resources like memory are usually allocated at a fixed granularity. So most systems today allocate memory at the granularity of pages, fixed-sized pages of typical sizes, 4 kilobytes. And this makes it just efficient to manage the memory. So the OS is responsible for allocating some number of memory pages to processes to store the memory image when the process is created and freeing up this memory when the process terminates, all of this is, all of this memory allocation-deallocation is handled by the operating system. So the next question comes up. Now we have seen that every piece of code and data has some address, right? It is located at some memory address and the CPU will request this code and data by using this address, saying give me an instruction at this address, load a piece of data at this address into a register. So the CPU refers to the memory image using addresses. But the question comes up, if we do not know the memory addresses, if the OS is doing the allocation, how does the user program know what address its code and data is located in? For example, how will a compiler know when the compiler is compiling a program? How will it know at which memory location this code will be placed? At which memory location this variable will be placed? There is no way, right? Because the compiler is not doing the memory allocation, the OS is doing it. So how do we solve this problem? The way we solve this problem is by using what are called virtual addresses. So initially, the compiler assumes it has a lot of memory starting from address 0 and it starts putting in all the code, data, assigning, placing them in memory starting from address 0 and assigning addresses to all the code and data in this way. Then when the program starts to run the stack heap, all of these will get assigned various addresses starting from address 0. This does not mean that they are placed at these addresses in RAM. We do not know where they will be placed in RAM. But these addresses are initially assigned both by the compiler and later on at run time also for things like the stack and heap. And these are called virtual addresses. But in reality, this program could be placed at some other address, say, starting at address X in the RAM, right? This is the physical address. This code and data could be placed from address X to some address Y in RAM. And those are the real addresses or the physical addresses, which only the operating system knows. Why? Because the operating system is the one allocating this memory for the program. So the operating system knows these real addresses and it maintains a mapping between these virtual addresses and the real addresses. And the data structure that has this mapping is called the page table. So when the program is running, right, when the CPU wants to execute some instruction or fetch some data, CPU says, give me the piece of information at this memory address at that run time, the OS ensures that this addresses are translated from these dummy virtual addresses to actual locations in RAM, right? So the OS, because it has all this background information of where this program is in memory, it can ensure that this translation happens correctly, right? One of the main functions of an OS when it comes to memory management is also ensuring this translation of virtual addresses to physical addresses when the program is running. And there are also other things that the OS does, for example, it will allocate memory on demand. It will not give a program a lot of memory because memory might run out. So all of these things, there are many other things that the operating system does with respect to memory management that we will study in this course in a lot of detail. Moving on, the next functionality of the operating system is managing IO devices, right? We have seen in a previous lecture that there are many different types of IO devices and each comes with a device driver that talks to the device, that writes, reads from the various device registers in the device controller, issues, commands, handles interrupts, sets up, DMA buffers, all of this is done by the device driver and the OS has a bunch of device drivers for all the IO devices connected to the system. And in addition to the device drivers, the operating system also has other pieces of code called the file system, for example. So when you store data on your hard disk, this data is stored in the form of files, right? All of you must be familiar with what files are. So then the operating system is responsible for managing these files. You as a user, you will say open this file, read this file, write to this file, all of this the user will keep doing and the operating system ensures that all of this functionality is implemented on the underlying file and the piece of the OS code that does that is called the file system. And this file system of course works with the device driver of the hard disk to communicate with the hard disk itself and to store information on the hard disk in the form of blocks. Then the other piece of code, important piece of code the operating system has is the network stack that is every computer communicates with various other computers over the network, right? Either Ethernet or Wi-Fi, you all must be familiar with it. So the operating system also does a lot of this communication is also handled by the operating system in a piece of code called the network stack. So one final piece of the puzzle what happens when you boot up your system? So when you boot up your computer system, there is a very small piece of code that runs which is the which is called the basic input output system or your BIOS, right? This BIOS is part of your motherboard and this resides in non-volatile memory. So that even when the power is off the BIOS program still exists unlike RAM which is wiped clean when you turn off the power. So the BIOS program still exists when you turn on your computer. So this program, this BIOS starts running, it sets up all the hardware. Then this BIOS will then find the boot loader in the boot disk. So there is one disk which is identified as the boot disk in your system, usually the hard disk or if you are booting up an OS from the USB or a CD drive or DVD whatever there is a main boot disk. In that boot disk there is a program called the boot loader. What this boot loader does is this loads the operating system, right? So you have your BIOS, this BIOS starts the boot loader, it finds the boot disk which is the main disk to use and identifies and loads this boot loader and this boot loader then searches for the full operating system and loads the operating system in memory. So now by the end of all of this boot process in your RAM, a part of the RAM is occupied by the operating system, okay? And now the RAM has the operating system and the CPU starts executing the operating system code. So this is the end result of your boot process when you turn on your computer to the time you see some screen or a terminal or a shell, all of this happens. The BIOS has run, the boot loader has run, then the OS has been loaded and the CPU starts running the operating system code. So from now on, once the operating system starts, then you can run other programs whatever your computer system is supposed to do, you start your browser, email, games, other applications, web servers, databases, whatever you want to run, they all will be run after the OS starts and all of these other processes will be managed by the operating system, right? So this is the end of this fifth lecture. In this lecture what we have studied is we have studied what are operating systems and why do we need an operating system and then we have studied what are the various things the operating system does with respect to managing processes, memory, IO devices and so on. And starting from next week, we are going to go deep into operating systems, we are going to begin with understanding process management in operating systems. And in the next three weeks, we are going to cover all of these topics around process, memory and ION operating systems. And after that in the later part of the course, once the base layer is clear, we are going to move on higher up and understand how user programs and how software systems are built in general. So see you all next week when we begin our study of process management and operating systems. Thank you.