 All right, welcome back to operating systems. I guess it's too hot today. Not that many survivors left Yeah It's 28 degrees It'll get horrible later. All right so page tables where we left off we left off at a Gigantic page table size. It was a gigabyte Not not that useful So what can we do it do about it most programs don't really use all their virtual memory space So what could we do to take advantage of that any suggestions? so well like our page tables before we're like gig a gigabyte because Even with the 39 bit virtual address It was gigantic So most programs don't actually use all their virtual memory space. So what can we do about it? Well, yeah Dynamically size our page table Yeah, so we still need a page table dynamically resizing it Would get tricky So we got another suggestion for hash tables So we won't use hash tables for the same reason we didn't use hash tables before they're actually hash tables are basically just Arrays that are slightly slower So for this generally we want to just use arrays if we can just do quick little lookups and everything like that so the first easiest thing to do It's just make the page table smaller right, so One technique that actually makes things a lot easier is if we make a page table fit to the Exact size of a page So if we do that We'll see as we make this more complicated that that turns out to be a very nice property to have so in this case, I will just shrink the virtual address space in this example to 29 or 21 bits, so I will have a Essentially only use nine bits for my index because I want to make this page table right here fit on a page So we're still going to argue about page sizes of 4096 which is 2 the 12 So if we work backwards our page table entry is 8 bytes, which is 2 the 3 So if we want to figure out how many entries need to be in a page table such that it is the same size as a page Well, we just need to figure out 2 to the what times 2 to the 3 equals 2 to the 12 so 2 the 9 is The number of entries we would need and then this would fit exactly on a page, right? be small so Our page table exactly a size of a page We just make it smaller. Otherwise it works exactly the same as in the last lecture We just use the page table for the actual translation which holds our physical page number Nothing else change. Nothing else is different. So any problems with this Otherwise exact same process as before you might have noticed I changed the index to be L zero That's because we get into the real pain point where people's heads start to explode Because it looks like this So there are multiple levels of page tables and that is where we get our dynamic scaling So our dynamic scaling for page tables is going to be how many page tables we have at each Individual level and that will allow us to essentially Dynamically figure out how many page tables we have and they will be in increments of pages so This is what it actually looks like and this is Thankfully Thankfully, this is as complicated as it gets. So this is what happens on the real system So we are going to be talking about this all day So what it does is it divides that 39-bit virtual address into different levels of page tables So we still have our 12 bits for the offset Thankfully, we don't have to do anything different with that it stays the same and then what we previously had here as 27 bits for the virtual page number we divide it into levels and each level will have nine bits Because our page tables are going to be the exact size of a page We argued that here that it would have to be nine bits so the only difference here is that we have three different levels of them and You can do the addition here to figure out that this is 39 so Now in order to do the translation you would be given this L2 page table given by a register or something So this would be the page table where you start at So how you actually translate do the full translation for the address is you would take these nine bits for The L2 or the highest level of the page table use that as an index to figure out what entry in this L2 page table you need to look up and This would still have page table entries But the only difference here is instead of at the last step here where that page table Corresponded to the physical page number of the address We were actually interested for the physical page number here is going to be the physical page number of The L1 page table So it will tell you which page table to hop to next a level down and that is why It is nice to make them the size of a page Because we don't have to fool around with the offset or do anything like that Each of these page tables would start at offset zero and fill an entire page So we're not wasting anything does that make sense kind of Yeah, so this is yeah, the question is immediately why the hell am I doing this? This seems insanely complicated so before When we had a single page table and it was like two to 27 that page table was one gigabyte, right? To translate a single address So now whoops if we have something like this to translate a single address at minimum We only need one L2 page table One L1 page table and one L0 page table So we only need three pages to translate an address Which is only 12 12 kilobytes Right, so to translate a single address We only need 12 kilobytes as opposed to one gigabyte So that is why we're that is the primary reason why we are doing this Because we do not want to waste a gigabyte per process Otherwise, we would run out of memory just with page tables So Yeah, so here again the translation Starts off. We use the index in the L2 page table or the highest one We would be given where this starts at by a register or something This would be called like the root table register in arm or sorry risk five. It's called SATP It's basically the root the L2 page table pointer Then in that would have a bunch of page table entries we index it by this L2 here and It would give us the physical page number of the L1 page table and then we do the same process So using this page table given by the previous address We look at the index given by L1 It gives us a physical page number and it tells us where the L0 page table is Then in the L0 page table Mercifully it is the same as we did before that hopefully we all understood where you just look up the index from the L0 And then that physical page number is what you use for the translation So then it's finally done. Yep Why can't go from L0 directly to what sorry? So the primary reason for dividing it into different levels is because we don't want a page table. That's a gigabyte So here if each of these levels only occupies a page if I need to translate a single address I only need one L2 page table I only need one L1 page table and I only need one L0 page table So I only need three or 12 kilobytes of memory for those three page tables as opposed to a gigabyte Yeah, yeah, so also with this eventually I could have in my L2 page table it could point to two to the Nine different L1 page tables and then each of those could point to however many L0 page tables So the drawback of this is if you actually use your entire address space This is going to actually waste slightly more memory because we have we're using different levels and We'll see that in a little bit. Yeah Yeah, ideally if you want to waste as little memory as possible all your All your L0 entries should get full first Then as soon as that's full you make another L0 and then you would just have another entry in your L1 that points to that other one and then You could you could be like super Unlucky where the addresses are super spread around and then you have to have a different entry in Like if you have different entries in your L2 then you point to a bunch of different L1s. Yeah Yeah, just it's still just full of page table entries. So they're only primarily. It's just the physical page number So they can only point to one One huge page table Yeah, so on average most programs don't use 512 gigabytes Which would mean you have a full page table and you need a whole gigabyte to keep track of all the mappings But generally programs don't use 512 gigs Your programs you wrote probably use like a few kilobytes megabytes. Maybe You don't need that much room for page tables in that case So that's why we separate them that Yeah, yeah, so page tables well Primarily only for RAM so we can do little tricks with page tables where if you run out of physical memory Which we'll see way later in the course you can actually move pages to your hard drive and Make the illusion that you have way more memory than you actually physically have on your system But it's just gonna be slower because it writes it to disk, but we'll see that later But primarily page tables are just for mapping virtual addresses to physical ones Yeah, yeah Yeah, yeah, so we just have one L2 page table It can point up to two the nine things and each of the L1 page tables also can point to two the nine things The L0s to the nine things so it's to the nine to the power of three all to the power of three Which is to the 27 so we can still do all the mappings. We just had we just made it more complicated Primarily to get rid of that whole gigabyte page table thing That's the only reason because looking at this Does this look more complicated than what we had before? Kind of sorta would this be a lot slower than what we had before Probably right. So if I just had one page table, how many memory accesses do I actually need to do the translation? One I find the page table entry. I Read it. I'm done. How many memory accesses do I need here? Yeah, three I read L1 I read L2 so I'm taking a lot of penalties just to reduce that size so this is Way slower, so this is three memory accesses instead of one and at the end of the day You'll also have your original memory accesses so To use a virtual address here. You're taking one Memory access if you just directly use the physical address and turn it into two one for the translation Then one for accessing physical memory and this case. I turned it into a total of four so just by doing it I made it twice as slow as Already being twice as slow because it's now four times as slow seems really bad, right? So Don't worry we can cash that so that's this we'll get into that I believe in the next lecture because we'll actually see it in effect Doing allocations of pages because they are fixed size is actually really easy And it just uses a link list or sometimes they just called a free link or a free list So all that means is you divide your memory just into physical pages and then the operating system just Maintains a list of all them so when you boot up your system it would just put a pointer on each page to the next free block and Initially all the physical memory is free and then there's just a link list It is actually really fast to add things To the head or to remove them So whenever you need a new page it just has to Check Figure out what the next pointer in the free list is and then I use that physical page That's it and then whenever I free memory Well one page is just add it back to the free list and then you can reuse it for other purposes So because we have fixed size blocks of memory our memory allocator is dead simple It's just a free list every block is the same as any other block Doesn't really matter because if you're Implementing malloc or something like that which we'll do later on in the course and you have variable sizes of memory that is actually a giant pain and You have to do something way more complicated, but if everything's the same size Dead easy link list so that was our insight to use a page for each smaller page table and Again, this is why there are Two to the nine entries because we wanted each of them to fit on a single page and the rule behind this is well We could extend this as much as we wanted to so for each level Given how many levels we have well level end just points to the page table for the next lowest level So L2 the entry there would point to L1 L1 would point to L0 No matter how many levels you have eventually whatever you get to L0 It's just the translation. We had before which is just a single look up. So yeah Yeah, so in the L2 page table there are physical addresses and that's the physical location of the L1 page table Yeah, and so for this if we wanted to add another level that's easy We would just add L4 L3 to this so we could extend If we added another level to this it would be another nine bits So we would have a virtual address of like 48 bits in this case, right? So we just add another level. It's pretty easy to do, but it's just gonna be slower so on Some CPUs. It's a tall like it is a configurable thing your kernel can set whenever it boots It could use 48-bit virtual addresses But most of them use 39 bits because it is good enough and if we went up to the next Level of page tables, it would just make it slower for no reason and Also waste slightly more space So just to reiterate, I think we kind of got it so the smaller page tables and Page tables in general are just like a raise Same thing. They're not really that special. So instead of like int page table Two fifth or five hundred and twelve which we should know the size of this, right? What's the size of what's the size of an int? How many bytes is an int? Four bytes. So how big is this array? 2048 or two kilobytes, whatever you want to call it. So Other question is well if we access the element at page table at index two or the third integer What is the offset? So the offset is the number of bytes eight Eight, right. So if each element is four bytes or four bytes and We're using it like an array. Our offset remember is just the number of bytes to the beginning So the first the zeroth element would be offset zero starts at the beginning the first element or one Index would be at four bytes because each L four bytes and then index two would be at eight bytes so same thing this This isn't all you have to imagine is that instead of an int there's a page table entry there So as part of the questions you'll be given generally they'll always say what a page how big the page table entry size is or Otherwise you should be able to come up with it if I tell you how big, you know The physical address space is and you can guess at least how big it is so it would need Your page table entry remember when we talked about the important parts of it it would at least need enough room for this physical page number and then probably at least three flags like valid read and write Pass that you know you could argue that you don't need the rest of them so for all of This scheme the size of the page table should be equal to the size of the page size So in this case if I have a page table of 512 elements and my pte is eight bytes Well, that should mean that the size of the page table. It's just the same thing eight bytes times five hundred and twelve So it should be four thousand ninety-six, which is equal to the page size So if this if you're doing a question in this course for multi-level page table, and this isn't true You screwed up and you should probably fix it so that should be the property that always happens if we are trying to fit our page tables exactly on a page and also it should Be the same thing as this the size of the page table is the same thing we have learned for arrays It's the number of things in the array times the size of whatever that element is So in this case the size of the page table entry For the real system. We're looking at right now is eight bytes All right, cool. So let's see how that works in a translation. So if we just For the purposes of not Just writing more we can just consider one additional level so you can just have two levels of page tables So we'll just have an L zero and an L one So now if we have virtual address 3 f f f f 0 0 8 well It's the same thing as our translation. We can argue about the offset again. So the offset is 12 12 bits Which would be the same as three hex characters So I don't have to translate that zero zero eight at the end Otherwise I should probably write it out in binary because nine bits doesn't quite work with the size of some hex values so if I write it out in Hex this would be like a 30-bit number Or sorry if I write out in binary This would be it in binary where I just directly translate each hex character to binary and then on this step I just group them into L zero Or sorry L one then L zero and then the offset So these are the lower 12 bits that correspond to the offset and these are all of the bits The nine bits for the L zero index and then these are the nine bits for the L one index So in this case we also Yeah, so in this case all we would at minimum need is two page tables and Here let's go to it Oops new page So in this case we have what not one one one one one one one one one One one one one one So these were the nine bits for L one Yeah, is that nine now? Okay, so those are the nine bits for L one these are the nine bits for L two I won't write out the bits for the offset because I can just keep them in hex I don't really have to translate them and they were zero zero eight So how we translate something like this well We would be given the highest level page table, so there would be an L zero page table Or sorry an L one page table to use a different color So here is my L one page table. It would be somewhere in memory So it might be on like physical page number seven or something like that You would probably be given it or you could look it up or something like that So it would be in memory somewhere and it would have a bunch of entries So it would go all the way from zero up to 511 Because that's to the power of nine minus one so within this L zero or L one page table This number as the index all months to five hundred and Eleven so there would have to be a page table entry at this index So this page table entry Would probably have something like a physical page number and then like let's just assume a valid bit so right now It could have a valid bit and then it would be physical page number We could you would just be given it. It would be managed. We can make something up So we could just say that it starts at physical page number eight So Yeah, so now there's a question do they overlap so do they overlap? Yeah, so these are the sizes of page So they do not overlap because if our physical page number is seven the actual addresses that represents is Well starts with seven and then for the offset It would start like it's the size of a page. So we have three hex characters. So it would start at 7-0-0-0 and then go all the way to 7x the last one would be F F F Right, so Physical page number seven corresponds to this range of memory Which if you double check that this is 4096 bytes that address range So if I write out physical page number seven its addresses seven thousand to almost eight thousand Right make sense Okay, so that means that if I look into my L One page table and I see that I have a valid entry and the physical page number is eight Well, that means I have an L zero page table Starting at physical page number eight and That would represent addresses, you know, eight thousand all the way to eight F F F So If I need to follow this translation inside here, I would use this number here This in this as my index into this L zero page table So inside of here there would have to be an entry for 511 again because it's all ones and It would look like the same thing. So it would have physical page number and then a valid bit So in order to succeed with this translation It would have to be a valid bit of one and then the physical page number could be something I don't know it could be something like C F Or C a fe just to make it fun and in this case This would be the RL zero page table. So we just replace this So we just replace the virtual page number with the physical page number or otherwise Just slap that in front of the offset. Yeah, sorry Yeah, so so yeah, so zero zero eight is the offset so Here since we are in the L zero page table, that is the physical page number of our final physical address so Like what we had here We would use that as a physical page number and then we don't touch the offset. So we keep the offset the same So in this case, we finally looked it up We figured out that the physical page number was C a Fe and then the offset was zero zero eight. So this is our physical address sorry Yeah, so so this L one page table just points directly to that one Yeah, so this is only two levels of page table. So we only have an L one and an L zero Yeah, so what we did was this was our original virtual address, right? So we took that This is part of the offset that we don't have to translate and then all these bits are 18 bits that in this case We are only doing 30-bit virtual addresses. So we only have an L one and an L zero so if we go ahead and write it out and then Divide them up This these are the bits for the offset These are the bits for L Zero These are the bits for L one So three f f f f f f zero eight. This is the virtual address Yeah, so the only real memory that exists is physical memory So we need to change this virtual address the MMU we talked about later That does the translation and figures out where to access stuff It takes your virtual address then takes the page tables Yeah, and then using this it would follow the page tables and figure out that Well following the page tables for this address. I can translate it to cafe zero zero eight and then so Here right your Your kernel is your MMU is using the page table and the kernel is managing these page tables So if the kernel wanted to change in that process whatever Whatever physical memory that that address points to all it has to do is be like, okay. Well, I don't like it being there anymore I'll just change it to I don't know a A B something like that in which case my page tables look like this. I get the address a B zero zero eight and The process your process still uses virtual memory all your processes only use virtual memory Still using the same virtual address, but you can map it to any physical address you really want Well any page you want not any physical address because you don't translate the offset So any questions about that So you might have noticed even with this You can kind of see how it would waste more space, right? so If I had all of these entries Filled with things so say I had valid entries for each of these then Each of those would point to an L zero page table. So there would be essentially Two to the nine entries pointing to different L zero page tables and each L zero page table would take up a page So I would have two to the nine I Would have to the nine L zero page tables and then this case I would also need one times L one page table so if you go calculate the memory of that well each of these page tables is two to the 12 and this is also two to the 12 So in actuality we actually waste a little bit of space Right, so if we just had oh My god is hot in here So in this case Wait Yeah Wait, I screwed up the math. I might screw up the math So here. Let's just follow this line So if we have our 30-bit virtual address and their page size of that if we just had a single big page table Like we were arguing about before well, we would need to the 18 Which is the number of entries in that page table times the page table entry size So that would be two to the three bytes. So we would need what's that? two Two megabytes if we just had one big large page table Well instead if all our entries were full we would have one four kilobyte L one page table Which is just the size of a page and then we would have four kilobyte page tables times One thought or times to the nine So if you crunch the numbers for all that well We're going to waste or Yeah, we're going to waste two megabytes on that plus that four kilobyte L one page table But if we only have a single address, we are translating we only need one L one page table And we only need one L two page table. So we only need eight kilobyte So one of each page instead of having that big two megabyte table So you can see that this gets out. This isn't that bad for like a two-level page table Probably not worth it two megabytes isn't that big of a deal, but once you have three levels. It's a big deal So any questions about that before I have a heat stroke. This is like a prison. All right, cool So here's here's that Translating that again So if we figure out which index at which bits represent one index and then change them to decimal We keep them in hex however you want This is how we did the translation. So we looked up in our L one page table at index 511 where the physical page number was this case it was eight then you would start at the L zero page table starting at Address 8,000. There'd also be an entry where we have our since it's the L zero page table where we would have our final lookup So we have the physical address CAFE 008 All right any questions with that Yeah, so in this case where we just have two levels of page table There would just be one L one page table and then it could point up to two to the nine or five hundred and twelve L zero page tables Well in actuality once we have this so this is our actual system We'll have we'll have one L zero page or one L two page table Then they can point to two the nine L one page tables and then each of those L one page tables can point to another two the nine L zero page tables All right. Yeah Like what is actually doing using them? Yeah, so the colonel is the thing that chooses So you will get to simulate what the colonel does and manage page tables yourself So the colonel's responsibility is to manage page tables each process Right would get its own L To page table and it's stored in this register even so now we know another thing that a context which has to do is it has to change the page table to that process and The colonel gets to manage all these page tables and the MMU, which is like the physical hardware in your machine Uses those page tables in order to figure out where in physical memory and virtual address should map to All right, cool. We can we can do We can do lab Three now so we can play around with some code or we can do whatever so Here's a fun example. Let's see how far we can get into it. So this is going to be our own MMU simulator. So this is Going to do the job of walking through the page tables and that is written for you So it will do the translation of the addresses and in here we can just play with the page tables So in here, I just have a little assert that my page size is what I think it is and Otherwise, I'm just going to allocate page tables. All this function does is just give me a new page So I create a new page. I need an L to page table so in order for that I would All your MMU needs is where to start which is like the root page table So I set a global variable called root page table to this L2 page table Then if I want to actually translate an address I'm going to have to create an L1 page table and then in here I Need to add an entry to my L2 page table so I will add an entry at index what zero and I will create a page table entry from this all this does is figure out where this L1 page table starts and then sets the physical page number in the page table entry so this Little helper function plays with the bits and creates a page table entry for you Then I have to create an L0 page table here. I will create it in L1 I will point to it from index 5 So L1 at index 5 points to this new L0 page table and in this L0 page table I will put something at index 188 and in there I will create a page table entry directly from a physical page number and I'll just call it C-A-F-E so This MMU function is going to just simulate Walking the page tables and figuring out what the address is so if I go ahead and compile this Should be compiled And I run MMU sim Well, it will tell me The virtual address I used and then walk all these page tables to figure out what that Physical address is supposed to be Kind of neat so let us figure out What that is so all right any questions about that translation or steps that it must have taken Yeah Yeah, MMU is on your CPU Yeah, so the kernel would have to know how to set up the page tables that the MMU uses so like this right here Setting up all these page tables. This is done by the kernel the MMU is actually going to use them and How the MMU uses them is all it needs is the root page table to use and then it's off to the races So it will use that root page table and then just walk it down. Yep Yeah, so the question is does 5 and 188 matter in this translation. Well, we can see So if I change this to 187 or something like that and I try and compile it and run it says page fault Because I can't look it up anymore. Yeah, where did I pull these numbers from? so We would have to do the exact same thing we saw previously Except now we have a large virtual address So in here This is the address. We are translating a b c d e f So same rules apply. This is our offset the last three hex digits Don't have to translate that Otherwise we need to write it out in Probably binary because we have to group them into groups of nine So it's kind of a pain So a if we remember my shortcut from last lecture, what is a in binary? 10 10 So 1 0 1 0 that's a so b shouldn't be that hard to figure out because you just add 1 to 10 So it should be 1 0 1 1. That's be right Hopefully next one if we just add another one to that should be 1 1 0 0 so that's C so now If we work backwards and we figure out what our L 0 index is going to be in our L 1 index Well, we have to group of 9. That's 8 That's 9 so this would be our L 0 index and Then here The you know the rest of them are all leading 0 so this would be 0 0 0 0 0 So in here, this would be our L 1 index What is 1 0 1? 5 this would be our L 2 index so this would be 0 and If we go through all of this and translate this well spoiler alert. This is a hundred and eighty eight So that's why the entry has to exist. Otherwise. It's not going to work so if We wanted to make a valid translation. So say We change Let's go the other way So say we wanted to do something like this 180 we changed this from 188 to 189 so In here, we only it should be a page fault again if we want this to map to an actual page What is a valid virtual address now? Yeah, a b D Right, so this should line up. I just added I essentially just added one Here So I just changed this to a one It's just going to increase the hex number by one. So it should be a D. So if I make it valid it should be a Db Wow that so many letters a D a be God a Bddf I know my alphabet. So yeah, see now this address successfully translate so you can see Play with the number you need to follow all the entries all the way down. So any questions from this? Yeah, no, we're good. Okay So The L zero in here our L zero index or sorry the L zero index. Oh like why I increased it by one Why my there we go like why increase this by one? so before When I had something like this, right? It looked it looked like this So that mean we use L zero index 188 So in the code all I did was instead of 188 having the translation. I translated or I made the I made the entry with the translation equal to 189 So in order to get 189 out of this L zero index it just means that this number has to be a one and Now these nine bytes here equal 189 Yeah, if it if it uses all the indexes and it can't follow them all the way to a valid entry It's going to say page fault can't do the translation So that is also why if your process Does Uses random memory that it doesn't have mapped Colonel is going to know about because it will generate like you might have noticed. It's a page fault That will generate a interrupt to the kernel the kernel will see that your process is being bad and using memory It doesn't have access to and then it will give you a seg fault, which as we learned before Seg fault doesn't actually mean anything You don't use segments anymore. It just means you have invalid memory So other fun things we can do what other fun things can we do? Yeah, any other questions about this? Because this also is flexible and gives us the opportunity to really weird things. Oh, yeah core core dump means that it essentially takes a Snapshot of your memory and saves it to disk so you can see what the hell your program look like when it died That's why core dump is Which unfortunately we probably won't see but so other fun things well What happens if I do something like this or what happens if I do I Could do this too, so if I have two entries there and I'm mapping two different addresses Well, guess what? Now suddenly two different virtual addresses mapped to the same physical address Cool, huh? Not cool. I have data races. I The only thing you will have is more fun So Things like this curl can do We'll see that later. So just remember fooling for you. We're all in this together