 There we go. So, how much memory is at an individual address? Do we remember 105? Yeah. Yeah, it's quite addressable. So every address represents a byte. So you can only read and write a byte at a given time. That's like the smallest chunk you can access in memory at a given time. So if I had a hash table or something like that, well, I would have to have an entry for every single address. Then every single address would have to correspond to the physical address. So if... Should we start it now? Yeah. So if I had to keep track of the mapping... If I had to keep track of the mapping, then, well, for every address I need a key that would be the virtual memory and then I need an address which would map it to. So for every byte, I would need a 64-bit virtual address and then as a key and then 64-bit physical address of the value. So every single byte you have would need 16 bytes for the hash table entry. So you're going to be using memory at the rate of 16 to 1 if we use a hash table. So that probably is not a good idea. And also every single time you access any address, you have to do a hash table lookup instead of just accessing memory directly. It's also going to be probably really slow. So, any other ideas? Yeah. Yeah, that sounds pretty reasonable. That's actually our first solution. So, we'll go back to it. So, let's remember a checklist. So here are some things our virtual memory needs to do. So, multiple processes need to be able to coexist. Every process has its own virtual memory, needs to be independent. All processes should not be aware of sharing physical memories so so far our hash table idea could satisfy those requirements. We'd also want to make sure that a process, you know, you can't really access each other's data unless you're explicitly allowed to because otherwise, one process could read the memory of another process, read your password, read your private key, do something really bad that you wouldn't want to do. And you also want performance close to using physical memory. So, that kind of goes out of that hash table solution. And we also want to limit the amount of fragmentation or wasted memory which comes from that idea of just having a big chunk of the memory. So, and here's a note. So, remember that memory is byte addressable. Every single address represents a single byte. You can read or write one byte at a time minimum. And each address, another way to think of it, you can just think of all the addresses as just like a big byte already. And the address is just indexing to that array. So, that's another way you can think of memory. It might be a bit easier to think of it that way. So, the first solution is something called segments. So, we divide the virtual address space into like a segment for code, a segment for data, a segment for your stack, and a segment for your heap. Kind of looks like an alt file that you actually like core open a program or like an executable file. You would see that it has sections in it that correspond to different parts of your program. So, each segment can be a variable size. And you can dynamically resize them if you want. But this is like a really old technique that's no longer used and we'll get into some drawbacks with it. Mostly, the major ones that are there are very large and costly to relocate. There's only four segments. So, if I want to try sharing memory between processes, it becomes really, really difficult. You might have to move a bunch of memory around physical memory, which is not very good. No longer used in modern operating systems. But guess what? Whenever you access like a null array or something, and you see a segmentation fault, it has to do with this. It has to do with segments. Even though no operating system ever uses segments anymore. But the term is still around because once they start a term, they're no longer around to change it. So, the details for this is each segment would just only do a translation per segment. So, each segment to describe it, you would say where it starts in physical memory. So, the space address would be a physical address in memory, the limit, which is just the size of the segment in physical memory, and then permission. So, you can say memory is readable, writeable, or executable, something like that. So, to get a physical address, this is what your virtual addresses look like. They look a bit weird. So, you have to say what segment it is in, and then a colon, and then an offset. An offset is just how many bytes from the beginning of a segment. So, your virtual addresses are just going to start with a segment, and you're not going to actually say a full address. You're just going to say how many bytes from the beginning of the segment is in my memory I want. So, the memory management unit, which is the piece of hardware actually responsible for translating virtual to physical addresses. All it does has a very quick job. It will check that your offset is within that limit for that section, and then it would calculate the physical address by doing a very simple calculation. You'll have table lookup, no nothing. It would just grab the base address, add the offset you want to it, and then do permission check. So, as long as all that passes within the limit, and if you're trying to write it, it's writable, then it would successfully translate. Otherwise, you get that segmentation fault. So, for example, an address would look really weird like this. So, it would say, hey, this is section, so in section one, I want to access offset ff, which is 255, and then in the memory management unit that actually is describing sections, it would say, hey, section one has a base physical address, it would say something like x2000, has a limit of 1 ff, so this would be within limit, and then to do the translation, all it would do is add the base address to this offset. So, the physical address would be 20 ff. So, on modern offering systems at least, on like old x86 hardware still has support for segments because as soon as you put it in, you don't want to take it out, but Linux, to get around this and any program using segments, it sets the base of every segment to zero, which is getting a memory and a limit to the amount of memory it has. So, essentially, it becomes a no-hop. So, even if you have hardware support for it, you can just get rid of it. So, this is closer to your suggestion up there. Like, well, that's like a variable-sized chunk. What if I just have a bunch of chunks? So, I just have a defined fixed-size chunk and I'll just translate a single block at a time. So, if I'm in my virtual block, these would be like offsets, so like by zero, by one, by two, by three. Well, I could have the same idea where I don't have to translate how far into a block I go. I just translate block to block. So, I could take my virtual block and then map it to a physical block and then have it so that if I'm accessing, like, seven, it's the same on both. All I have to do is essentially translate the base address and that's all I have to do here. So, we have a few problems. If we do this, we have to decide how big of a block we need to use and, yeah, we have to decide how big of a block we need to use. That's one of our main strengths here. So, like I said, the memory management unit, or MMU, is the thing that is actually doing the translation and checking for permissions. So, this technique is dividing memory into fixed-size blocks. What your MMU actually does and what pretty much every single system in the world does right now is divide it into pages. So, pages are just a block, but they have a defined size. So, typically, they are 4,096 bytes and that has been true since like the 80s or something like that. So, I use that magical number at some point in some of the examples and that's where it comes from because it is the size of a page and your memory operates on the granularity or at least your translation of pages. So, this is a few terminal terms you might encounter. So, sometimes a page in virtual memory, sometimes you'll call it a virtual page, sometimes you'll call it a page, and then a page in physical memory, sometimes people will just call that a frame, just as that branch is true too, but you could also call it a physical page or a page in physical memory or sometimes it's a page in some of those that you're talking about. So, other considerations, all of our CPUs now are 64 bits, which means that size of the address is 64 bits. It can access a lot of bytes if you have 64 bits to use for an index. So, CPUs will have different levels of virtual addresses you can use, but the implementation details are the same and we'll see why some of those trade-offs occur. So, on your X86, on any modern 64 bit system, your virtual address space for a process is actually restricted to 39 bits. So, let's take this number as a factor now and we'll see why this is a number. So, typically you just want it big enough that any program will work just fine. And 39 bit virtual address means we can address up to 512 gigabytes of RAM per process. So, at least right now, that seems to be enough memory. Maybe in like 2 years, Chrome is going to require more than that, but I guess we'll see. So, what this does, it's implemented with just a big lookup table. So, it's a page table and it's indexed by a virtual page number. So, all it does is translate a virtual page number to a physical page number and then otherwise it would treat where you are in the page and it wouldn't have to translate that part because it's going to be the same no matter what. So, what's that look like? So, for this case, our virtual address we said, well, we have up to 64 bits, but we're only going to do 39. So, our virtual address looks like this. So, the offset part of it is where you are in the page. So, if our page is 4096 bytes, we need to be able to index every single byte within a page. So, we would need 12 bits. Why? Because 2 to the power of 12 is 4096. So, that would let us address every single byte within a page. So, that is what the offset is. So, if we need 12 bytes to figure out where we are within a page and then we have a 39 bit address, we just do a simple subtraction. So, it's just 30 minus 12. So, we would have 27 bits here acting as like an index being the virtual page number. And then our page table would have an entry for every single virtual page number. So, it's just used as an index. So, in this case, it would have 2 to the 27 entries because this is 27 bits. So, from the page table, all it would spit out is the physical page number which would just be replaced. You just replace the virtual page number with the physical page number. So, that means our physical address would be the physical page number which is up to 44 bits because they support 556 bits. Physical addresses and we'll figure out why that is a bit. And then this offset, we don't have to do any translation. Those 12 bits where we are within a page, just stay the same. So, any questions with that? Await, good to go? I got a thumbs up. So, processes cannot have access to physical memory directly. Processes only deal with virtual memory. So, this is page table. The page table is managed by the kernel. So, the kernel controls what virtual addresses go to what physical addresses. And the kernel is the only thing that controls page table. So, this would be, this page table would be unique per process. Alright, any issues we've seen so far? So, the 44 came from just the, do I have it? Oh, sorry, I have it on the slide. So, the 44 came by because they mapped, they support a 39 bit virtual address with a 56 bit physical address. So, it's just the number they choose. So, seem to be big enough for right now. It will support, like that's like the most physical memory you'll have. 59 bits represent a lot of physical memory. So, it's just the decision they took over right now. Okay, so, well, let's see what is in the page table entry. So, one of the things that are in the page table entry, the most important thing in this course is that physical page number. So, the physical page number is just what you do, what you translate for that virtual page. So, it is 44 bits. And since the computer is like powers of two, the page table entry is going to be 64 bits. So, after the physical page number being 44, we have 20 bits to play around with. So, there are eight bits over on this side starting at D, A, D, so on and so forth that are used for permission checks. So, they are the single bit permission checks. So, valid just means this entry is valid and then it is usable for translation. That's one of the few we should know. The other one is readable. So, does this memory represent something I can actually read? And the next one, does this memory actually represent something I can actually write? So, in this course, we will only be concerned with valid, read, write, and physical page number. So, that are things that have to be in the page table entry. But there are other things like, you know, is this memory executable? Should this memory always, users just mean should it only be accessed in user mode? Global means it's mapped to the same physical address in every single process. Or performance play. And then there's some like, like, does this keep track of things? Has memory been accessed? Is this memory dirty? Which get your head out of the gutter? Does it mean what you think it means? Does it mean that it has been modified or written to? So, there's also two bits here that are reserved for supervisor use. Remember, supervisor is just another word for kernel. So, this means two extra bits that the kernel can use to keep track of things. And in lab three, your next lab, you're going to simulate some virtual memory. You're going to get a bit that you are going to use for your own uses to implement something fun. And then here, they just reserve ten other bits, just if they want to increase the size of the physical page number or add new features or whatever, this is in the fact they just reserve ten minutes that they can use later. So, the offset you don't have to translate in the page table entry. So, here the offset states the same no matter the virtual page or physical page. So, you don't have to translate that part of the address. So, this physical address is only 56 minutes. So, 44 plus 12. In this case. Is this page table entry in this? So, the page table entry is what is in these entries. So, in this page table, it would have this many page table entries. So, that two to 27. That's how many entries are in the page table. One for every virtual page number. And this is what the entry looks like. So, the most important thing is that it has the physical page number because we need that to translate and also has some permissions. So, we have some extra space because we don't need to translate the offset too. So, that's why it doesn't have to be ginormous and we have some extra space. So, the offset is just where you are within the page and you don't have to translate it. No, this index is what virtual page you're on. So, this index is like which page and then the offset is where within the page. That's important to know because having this offset you also have some restrictions where pages have to start at a divisible number by the page size so everything lines up. So, you don't have to do any messy translation or any hard addition or anything like that or multiplication or anything that's low. You just keep the offset the same and that's it. And then you just do the translation figure out virtual page corresponds to what is on the page. Okay. So, here's some examples. So, this could be your page table. So, a simplified version of the page table instead of just writing the whole page table entry I'll just assume all the flags are valid and that I just care about the divisible page number. So, in this case it's essentially index here and then what the value is it would actually just be a giant array. If you want to think of it that way. So, this means virtual page zero and this is all hex corresponds to physical page one virtual page one corresponds to physical page four then two corresponds to three, three corresponds to seven so on and so forth. So, the nice thing about doing this translation if you write it out in hex so a single hex character represents how many bits? 16? Four, right? So, a single hex character can represent 16 different numbers but it's four bits because it's two to the power of four, 16. Yeah. So, you'll get some actual practice with the power of two now that you've taken this course because yeah, it helps you translate. So, because this offset part is 12 bits it's a nice number because every hex digit is four bits so how many hex digits represent the offset? Three, right? 12 divided by four. So, if there are three hex characters then that represents the index. So, it also makes it easier to translate if you're using that page size. So, if I'm translating an address like zero A B zero well, I can look at the three lower hex digits A B zero and I don't have to translate them because they represent the offset where I am within the page. So, I would just keep them the same when or in my physical address and then to look up the physical address well, this, the rest of it is my virtual page number. So, this is virtual page zero. I go up, look at my table and replace it with one. So, zero A B zero would be translated to one A B zero. Same thing for the rest of these. So, these three digits do not have to translate them so, F A zero and then I would look up one in my page table and see that, hey, it corresponds to this in page four. So, if I do that, if I just do that substitution this is my physical address. This is four F A zero. So, any questions with the other translations? I'm just looking them directly up in my table on the left. These are all virtual addresses. These are physical addresses. So, any questions with that? Big improvement over last year's people couldn't do this. So, if we can do this, you're well in your way to becoming an expert in virtual memory except we have some other problems here. All right, let us do a much harder question than that. So, that is nice if you have those translations and your page size, you know, you can represent a text character but for some you have some weird choices you can make and sometimes writing in text isn't the best. So, let's go through a fun example. So, for these questions you'll always be given like how big of virtual addresses do we have how big of physical addresses do we have and then how big is a page and if something doesn't say how big of a page your answer should be 4096. So, that's the default page size of anything. So, for this given the system some questions that you might get can hit nudge nudge would be something like hey, how many virtual pages are there? Oh, how many physical pages are there in the system? How many entries are there in the page table? And then given a page table which is just represented as an array so it would be, you know, virtual page zero and then these are all physical page numbers so it would be zero, one, two, three. Then what is the physical address of something like F1? So, I'll give you some time to think about it and then you can tell me what to do. So, our first thing we need to figure out is how many bits do we need for our offset? How many bits do we need to be able to access within the page? So, if we have a 64-byte page how many bits do I need to access every single byte in that page? Three? Yes. Six. Everyone agree with six? All right. So, if you want to be fast at this too we can remember some fun powers of two numbers and you only really need to remember like two. So, to make this easy, all you have to do is remember that two to the power of five is 32 and two to the power of 10 is 1024 and then as long as you know two to the power of one is two and two to the power of zero is one then you can figure out the rest of them pretty easy just remember these two numbers. So, I can only multiply by two like two or three times that's why I just pick a few numbers and then pass that I can figure them out. So, if I want to know like two to the power of x equals 64 that is how many bytes I need to represent any byte or like six to the power of four different things well, if I know two to the power of five is 32 I just have to multiply by two once to get 64 so I know that it is two to the power of six without doing silly logs or any calculator or anything like that. So, that means this also corresponds to six bit for an offset. Right, any problems with that? So, if I have six bits for an offset how many bits would I have for my vertical page number? So remember we have an 8-bit virtual address we know it's always divided like the virtual page number and offset. So now we know that this one is six bits so how many is my virtual page number actually? Two, right? Because I have an 8-bit virtual address six of those, six, the lower six bits are where I am within the page so that means my virtual page number is two. So, now can I answer this question? How many virtual pages do I have? Anyone want to tell me? Four. Two to the power of how many bits I need for a virtual page number. So, this is two to the power of two which is four. What about the number of physical pages? 16. Why is that? Well, it's going to be the same argument. So, for the physical address well the offset is still six bits because I don't have to translate that so to know how many bits I need for my physical page number well this is ten minus six so I need four bits. So, if I need four bits that means I can have up to two to the power of four different physical pages which is 16. What about the next question? How many entries are there within the page table? Yeah. Four. You just need an entry for every single virtual page number. So, that's all you need. So, we already answered that question. That is there to make sure that you know what you're talking about. Then, the next part it says hey, here is a page table I'll write it out in hex and these are all physical page numbers and then I'll write it blue under them what the virtual page numbers are so it's just the index into this big array. So, our question was what is the physical address of hex F1? So, for this this is kind of annoying because it's written in hex so this is you know eight bits but for the offset the part we don't translate it's six so it doesn't like nicely align with the hex characters so unfortunately we have to write this in binary. So, you also want to remember some fun binary things. So, instead of like the powers of two instead of remembering all the single translation for everything, once it gets difficult you only really have to remember one and then you figure out the rest from there so the special one you should remember is that eight is equal to one zero one zero. What's a good way to remember that? Well, eight is supposed to be ten in decimal so if you want to remember the binary it's just ten two times in a row so A is just ten ten if you want to think of it that way but really it's binary. So, if you just remember that A is ten ten generally you can figure out the rest of the hex characters and you should know that F is all one. So, if I write out this physical address in terms of binary what is F one in binary? Yep. One one one one zero zero zero one. Alright, everyone agree with that? Alright, so what part of this do I not have to translate? What part of this represents my offset? Yeah, offset should be the last six bits, right? So, this part of the virtual address I do not need to translate. So, let us be clear here say that this is virtual and this is physical. So, if I don't have to translate them I'll just write them directly. So, this is the same part of the offset. Okay, well then this number should be the virtual k number. What is one one and let's say decimal? Yep, three, right? So, if it's three which entry in the page table does that correspond to? This one? Which one? The last one, right? So, the last one. So, this entry. So, all I have to do is replace the virtual page number with this which is the physical page number. So, what is text eight in binary? Yeah, one and then three, zero. So, zero, zero, zero, one. So, that gives me my physical address and it's done. Now, for these, we'll typically say give me the address and text if everyone likes text. So, you just have to go the other way. So, to go the other way, all we have to do is group them into fours like this and just write out their hex characters. So, what is zero, zero, zero, one, hex? One. What is zero, zero, one, one in hex? Three. You can see that I was kind of nice to hear. What is one hex? Two. So, the address we get, the physical address is two, three, one. Neat, huh? Any questions about that? Yeah, so the page table would be provided to you and if you were a kernel, this is what you manage. So, the kernel manages the page table, each process gets its own page table. Okay. Yeah, so that's a good question. So, it might seem a bit weird that there are four virtual pages and 16 physical pages and then your question was does that just mean that 12 are unused? So, remember that this is her process. So, if I have 16 pages worth of physical memory that the kernel is operating, well, what could happen is I could have four processes open and then the kernel gets each four different physical pages. So, they're all running at the same time. They're using all the memory and the microphone. Sorry. And they can each use their entire address space. So, that's why the design is also on a real system. It's like 39-bit virtual address and 56-bit physical address. So, typically the virtual address size will always be smaller than the physical size. All right. We also still have an issue. So, in here, anyone want to tell me how big this is and page table is? Extremely large. How extremely large is extremely large? To the what? So, there's two to the 27 entries. And remember, each entry is this. So, this entry is eight bytes or two to three and then if I have two to the 27 of them, how big does that mean my page table is? Yeah. Two to the 33. Two to the, it would be two to the 33 bits or two to the 30 bytes. Yeah. So, two to the 30 bytes. Which, if we do our math, well, let's go back. So, two to the 30 bytes. Oh, that sounds kind of bad because two to the 10 and you might notice I write things like MIB. So, that means, it's a specialty here, that means powers of two. So, if you see MIB, it will be two to the 10 while if you see just megabyte, it could mean that it is ten to the power of three. And you might notice that these numbers are slightly different. So, this number is actually bigger and is more what computers use and then this number is what, like, people that sell you things will report. So, how many of you have ever got a hard drive that's like 500 gigs and then you format it and try to use it at like 400 or something? Well, guess what. So, two to the 30 is megabyte. Oh, sorry. Kilopytes. So, megabyte is two to the 20 and then gigabyte is two to the 30 like this, but if you do powers of ten, hey, guess what? It looks like this. So, if you compare these two numbers, well, the two to the power of 30 is way bigger than two to the power of nine. So, your hard drive, if you read the fine print, they say one gigabyte equals one billion bytes, which is not what computers use. Computers typically like this number and I always use this number. So, we can go back to our page table. Well, if it is two to the 30 bytes, that means our page table is one gigabyte. That sucks. So, that is the issue. We will have to deal with it in the next class. But first, some other fun things. So, like I said before, each process would get its own page table. When you fork a process, one thing we know that also has to happen is it will copy the page table from the parent. And one way to make this really, really fast is it can just copy the page table and actually share the physical memory. So, it will do something like turn off the write permission to memory and that way the kernel can implement something called copy on write because the two processes could share memory if all they're doing is reading information. They don't have to be independent. You can create the illusion that both of them read the same physical memory. They still look independent if they're just reading and not modifying anything. So, the kernel will only actually physically make copy of a page and update the mapping if you modify variables. So, it's really lazy about it and it only allocates new memory if you actually modify something in new process after fork. That's something called copy on write. That's library. So, you will get to implement that. So, yeah, here's the problem I was talking about earlier, where our page tables are absolutely gigantic and here is that note I should have put it earlier that there's 39 virtual addresses and 56 physical addresses. So, the big part of why these numbers why is one bigger than the other two is, well, the size of the virtual address determines how many indexes you need and is directly related to how big this page table is. So, it is very expensive to make this number bigger because even if I just add a single bit here then that means I double the size of the page table. So, that's why typically the virtual addresses are really, really small. While this physical address, this size is just restricted by the size of the page table entry and generally it has to be part of two anyways if it was only eight or if it was only four bytes then it wouldn't be usable because I can only support up to like four gigs which isn't good enough nowadays so essentially you get the rest of three. So, you also might be thinking it seems like a lot of work so like in our sub-process lecture we did like four followed by exact and my question might be why do I need to copy the page table if I'm immediately starting to execute a new program while there is a system called v4 that will leave the page table alone and not copy it it just comes with the caveat that while now all these processes both processes have to share all memory after the fork which is not what you would expect because they are now not completely independent so you are expected in the child process to immediately call exact and then exact as part of loading the new program you're ready to create new page tables and replace the page tables for that process so they specifically if you modify anything it's going to define the behavior it can lead everything so this is only for like really a performance sense of the things so that's it today's lecture we used pages for memory translation our idea was to buy memory into blocks then only translate once per block we used page tables which are just essentially an array of page table entries and the important things that entries had were a physical page number and some flags we probably would care about that's about it but now we have a new problem to tackle in the next lecture that these page tables are huge one gigabyte can you imagine you have 16 gigs of RAM 16 processes open and all your memory is used for page tables and you're not allowed to use any memory for your actual programs yeah that would suck obviously that is not how things work and we will figure that out in the next lecture so just remember we're all in this together