 Although, yeah, it's the story of my life, right? All right. So, welcome back to virtual memory. This is where things get fun. So, first, I will start something new and ask you a question. Oops. So, how should we implement virtual mapping? So, what are your ideas? How should we do this before we see what the actual solution might be? So, I'll try something new, and see if you can drop stuff in Discord too. I'll give you a minute with that. If anyone has any bright ideas, yep. So, this question is just how to do the mapping from virtual to physical, not like actually grabbing big blocks of memory. Unless you want to just do one, yeah? Yeah, the bottom, yeah. A hash table, so just address to address. Everyone likes hash tables. So, if we did hash tables, what would we have to do for virtual memory? A hash table is not a cache. So, for each process, I have a hash table that just has a mapping of an address, which represents a byte to an address for another byte. Does that sound reasonable? How would one byte to 100 bytes work? So, I use address 1000, I get some bytes out of it, or how's that supposed to work? So, if I did have mapping for each address, each address points to a byte. So, for each byte, I would need a whole address, which is like 64 bits, then map it to physical, which is another 64 bits. So, that's 128 bits to map a single byte. That sounds real bad. Does your memory, like, every single byte you use, you have to use 16 to keep track of virtual memory? Does that sound like a good trade-off? Probably not. No other fun ideas? Swap out bigger blocks of memory. Okay, we're on the right track. That's better. So, like, if it's within this range, just keep track. If it's within this block, let's go to another block, something like that. All right, well, let's keep that in mind. I guess no suggestions from the Discord. So, let's go to a checklist then. So, what do we want virtual memory to do? So, we also want multiple processes to be able to coexist. They shouldn't, they should be independent. They shouldn't be able to see that they are actually sharing physical memory. They, we want to make sure they can't access each other's information unless there's some, you're explicitly allowing it, because if one process could read your banking information or something like that, that would probably be real bad or your keyboard presses or whatever. We also want good performance, right? Close to using physical memory as possible, which, if every byte we looked at was like a hash table lookup, that would be a lot of memory operations for just what should essentially just be a single byte memory load. And we also want to limit the amount of fragmentation, which is just another fancy word for just wasted memory. So, remember, again, like I said, oh, why is my iPad dead? Oh, that's not going to be good. All right, so remember that memory is byte addressable, so every address represents a single byte or eight bits, and you can only read and or write one byte at a time minimum, and each address is just basically like the address of an array. You can think of it that way. So, there is this old technique, something called segmentation when computers were really, really slow and not terribly great. So, what they did is they had like four virtual memory regions, one for code, one for data, which is like global variables and everything, one for the stack and one for heap, which is basically memory managed by malloc and friends. So, it looks a lot like an elf file, so large sections of memory with some memory permissions associated with them, and each segment is a variable size that can be just dynamically resized, and this is like a really old thing. We can talk later about disadvantages with this, but this is no longer used at all. They can be really large and really costly to reallocate and almost impossible to share information if you want to do something like that, and there is no longer a use to this, but these are some historical things. So, some details for that. Each segment contains like a base address, a limit, which is how big it is, and some permissions. So, you get the physical address by just using a segment selector, so that would correspond to like code, heap, data, or something like that, and then an offset, which is just how many bytes from the beginning into the segment do I want to go? So, we'll see later what the MMU is. I guess I have a little defined before use here, but the MMU is a memory management unit, which is the actual hardware on your machine, which does the actual virtual to physical memory translations. So, it will just check that your offset here into the segment fits within however large that segment is, so that limit could also be the size, and all it does is calculate the base address plus the offset, and then does permission checks. Otherwise, if you're not within this memory or there is some permission, like you're trying to write to some memory that you're not allowed to write from, you get a segmentation fault. So, there's where that word comes from whenever you de-reference an all pointer or something like that. This is why it's called a segmentation fault, even though fun fact, your computer is not using segments. Your ARM processor doesn't even have the concept, but the term stills around. So, for example, segments just get numbers, so this is what your virtual address would look like. It looks kind of funky. So, this would be like, I want address in segment one with offset ff, which is like 255 bytes into it, and as part of the translation, your MMU would know that segment one. Its base address, which is its real physical address, is hex 2000, and its limit is 1 ff, so that's its size, so it's bigger. So, because it's within the limit, this ff is less than 1 ff, then it would just take the base address and add this offset to it. So, our real physical address would be 20 ff. So, just a big chunk of memory. It can be variable size, and then it just translates it by doing an addition. Yep. So, the multiplication sign is not a real multiplication sign. That's how you denote hex numbers. No, like in C, it's 0x. That means it's a hex number. Yeah, that's two hex numbers. So, this is your segment. So, segment is hex one, and then colon the offset, which is hex ff. Yeah, this is just two hex numbers. Which one? 0x1. Oh, yeah. Oh, okay. Yeah, there's a weird formatting thing. Yeah, the other ones have multiplications instead of x's, which I don't know how that happened. All right, that's cool. So, now if you have x86 hardware that actually has support for segments, Linux just sets the base address to every segment to 0 and the limit to the maximum amount of memory you have, and therefore, if you program tries to use segments, it just doesn't get translated at all. So, they pretty much just straight up disable it. So, here is our first insight to divide memory into big, fixed-size chunks. That way, if we have a virtual block of memory, and then let's say it has bytes at index 1, or 0, 1, 2, da, da, da, da, da, up to however big we want it, well, we would just map it to a physical block of the same size, then we wouldn't have to change the offset or how many bytes into it we're accessing, and it would just represent some physical memory instead of virtual memory. And then that way, I could map virtual blocks to the same physical block or do whatever I want with that, right? I have a bit more freedom with it. So, MMU is going to do this. It will map the virtual address to physical address, also permission checks. So, that block is something we call a page and the fixed-size someone decided that was a good amount to have in like the 80s was 4,096 bytes. So, there is that magic number I've been using sometimes in the lecture that the operating system seems to like. That is the size of a page in virtual memory. So, that's the size of the block. That's what it's dealing with. So, there's some weird terminology you might see. A page typically just means a block of 4,096. So, a page in virtual memory, sometimes you just call it a page typically. You could call it a virtual page as well. While a page in physical memory is sometimes called a frame. Just if you want to differentiate them real quick with one word. So, other things we might notice here is typically we have a 64-bit address for everything now. And that is massive. That's like terabytes and terabytes of bytes you could address. And no one has that much RAM unless maybe you're something like Google or something like that. But for most of our systems, we probably have like at most 32 gigs of RAM or 64 gigs of RAM, which is like, you know, in the 30s of bits, not a bit more than 32, but 32 bits is 8 gigs or 4 gigs of RAM. So, we use a bit more than that. So, for most systems today, this number could easily change. Most things use a 39-bit virtual address space. So, that means for a single individual process, you are allowed to address up to 39 bits of virtual memory. What's 39 bits of virtual memory? That is 512 gigabytes. So, unless you're Chrome, you probably don't need to use more than that. We'll see if we need to adjust that later, but it's a number that's easy to adjust as soon as we understand the principles behind it. So, this is implemented with a page table. So, it's just a big lookup table indexed by virtual page number. And then it looks up the virtual page number and then you don't translate anything that has to do with where you are on a certain page. So, what does that look like? Well, you would have a virtual address, something like this. And we said that we only use 39 bits out of the 64 that our CPU will support. So, the upper bits here are unused. And then we have 27 bits, which we would use to index into this table. The page table is basically just a huge array. So, it is a huge array. We use this index to see which element in that array we need to look up. And the page table just contains what physical page number that this virtual page number should map to. So, the lower 12 bits, which to the 12 is 4096. So, that's like where you are within a page. And we don't have to translate that whenever we're computing a physical address from a virtual address. So, we would just take this index. There would be two to 27 entries in this page table. And then in the page table, you just look up the physical page number, you just substitute it in, and that's how you get a physical address. Not too bad, right? Any questions about that? Yeah. PPN is physical page number. Yeah. So, in this case, the virtual page number in the PPN is larger because this supports up to 56 bits of physical memory. So, we can actually translate more, we can actually support more physical memory in our machine than our virtual memory per process. So, if you had Google size, Google size amounts of RAM, it could still use all that physical memory. And it turns out that the size of this doesn't really matter. It's just like the size of the entries in the page table. And as soon as you go over 32 bits, because we have computers, they like powers of two. So, the entries in this page table have to be eight bytes anyways. So, you essentially can translate bigger physical addresses for free. Okay. Yeah. So, the page table would just be like a giant array of PPNs. Yeah. So, you can think of a page table as just an array of physical page numbers, and this is the index into that array. And that's how you look up an address. So, any of the lower 12 bits, which is like where you are in a page, which is what we call an offset here, we don't have to translate it whenever we come up with a physical address. And for the physical page number, we just look it straight up in the page table, and that's it. So, we'll see why these are unused, because, well, for this virtual address here, why we don't use more is because if we had a, like if we had a bigger virtual address space, that means our page table has to be bigger, and it would waste even more room. So, for picking the number of, like how big the virtual address is, you want to keep it essentially just small enough that it'll support anything you need, because it corresponds directly with the size of the page table. But the physical address doesn't really matter. That reserve space is just because they picked a number so they can, if some design decision happens later, they can adjust and use it for something else. Yeah. So, the page table itself would be stored in physical memory and managed by the kernel. So, remember, the kernel, like one of its jobs, is to manage virtual memory, which we can guess, if virtual memory is just mapped from page table, it means it creates page tables and handles all the mapping for that. Yep. Yep. Yeah, we'll get to that problem in a bit. All right. The page table entries, I said it's basically just an array of physical page numbers, but the entries actually look like this, so they store a bit more information in them. The main thing is the PPN or physical page number, which is, you know, over here, the 44 bits, but because computers like powers of two, the whole page table entry or PTE, you'll see this term come up a lot in this course, and it's going to be 64 bits, so if only 44 of them are designated to the physical page number, then there's 20 left over. So, what they did is they used 10, or sorry, they use 8 over here for some permission checks, like there is a bit that says whether or not this page table entry is valid, so you can use it to translate if this valid bit is 0, that means this virtual memory does not actually map to any physical memory, and then you would get something like a segmentation fault and all that fun stuff, and then there are some other permissions to see if you can read that memory, write that memory, execute that memory, which just means it contains instructions that your CPU would use, and there's some other ones, like a user bit which makes sure that you can only access this memory if you are in user mode, one, for global, that we won't really use in this course, it's just for performance, and then some access and dirty bits, which we'll get into later in the course once we get to storage, and then there are two bits here that are reserved for the supervisor, which is just another word for kernel, that they can use for their own devices, and in Lab 3, we're going to be managing some virtual memory ourselves, so we're going to simulate this because you're going to find out why these bits are useful. So after that, they just had 10 bits left over, so they said we reserve it for future use, and that's it. So this is what is in a physical, or page table entry. The only things we really care about in this course is that they contain a physical page number or PPN, and then valid, read, and write are about the only ones we care about. Yeah. So it's just 27 because we said that we're going to have a 39-bit virtual address, and then since our page size is 4,096, that's to the 12, so that's the offset part. So to figure out how big our index would be, it's just 39 minus 12. So we have 27 left over. So the physical address being 56 in this case, it's just because they picked it that that was a large enough number that that supports anything for now. I think that's 64 giga-terra exabytes, something like that. It's a very large number. So in this, 39 is just the number we choose. That is what all your systems are currently using because it is big enough right now. But we'll see how to extend this if we want it to go further with it. But it pretty much corresponds to how big that page table is right now if we just have a single big page table. Okay. So here's how you would translate some addresses. Consider this is our page table and we would just consider everything to be valid. Alright. So in that case this is our page table where we have four entries. So our virtual page number can be 0, 1, 2, 3. And then our physical page number is just whatever it would map to. So virtual page 0 maps to physical page 1 which would be a natural physical address and then 4, 3, 7 something like that. So to do the translations if this was a normal size page so the 4096 who here remembers how many bits are represented by a single hex character? Yeah. Anyone else? Any hands? We got four. Alright. That is a number you want to know. So remember the offset or where you are in a page is 12 bits. Each hex character is 4 which means how many hex characters represent where I am in a page? Three. Right? So that means if I write an address in hex and it is a 4096 byte page size I don't have to translate the last three hex characters because that corresponds to my offset. So I don't have to translate that. So if I translated the first address here this AB0 I don't have to translate that because that is where I am within a page. So do not translate it and then I would just have the upper part be the virtual page number and then the virtual addresses to physical pages or to physical addresses. So I would just look it up here see that zero corresponds to physical page one and I would just do that replacement. So I would just replace this zero here with one and then I otherwise leave it alone. Same thing with this. So this one would be virtual page one I look it up in the table and then I just substitute it in I do not touch the last three hex characters because again that's where I am within a page. So any questions about any of these translations? No we're good? Hopefully we're good? Thumbs up anyone for good? Yeah? Alright good enough because if not ask questions now because things are going to get real weird real quick. Although I don't think it gets much harder than this but that is not the evidence I have I have understood it. How? Which one? So say we took this virtual address so it is three like in hex 3d 2 8 and if this is if our page size is that 12-bit one well then we don't have to translate the last three hex digits because each one represents four bits three of them, that's 12 so I don't have to translate that and then anything above that would be where we are like the virtual page number or the index so in this context it would be this part, this index part and then I would just look it up in this page table so anything that's not the offset is the virtual page number and then I would just look it up in here and I just replace three with seven so if I replace three with seven keep the other three the same I just get seven two d zero okay well let's see how good we are then so here's another problem that has you working on your toes and we change up the page size so let's assume we have an address and a 10-bit physical address so they do not need to match so what we saw before they didn't match here they don't have to match the virtual address again corresponds to how big our page table has to be and the 10-bit physical address corresponds to how big our PTE or page table entry has to be so in this case each page is and then we can ask ourselves some questions so how many virtual pages are there how many physical pages are there how many entries are there and then given a page table what is the physical address of some address so I will give you some time to think about it I will also write it over here and we can go through it also for some fun numbers how many yeah if I had a page size of 64 bytes how many offset bits would I need to index into that yeah all memories are going to be byte addressable so 6 right everyone knows 6 okay so let's start going through this so quick little fun tips we have 64 byte pages whatever you do something in this remember we had something like a virtual page number and then our offset which is where we were in a page so all memory is going to be byte addressable so we need to address all 64 bytes within a page so we need to know how many bits we need to do that which would be you know like 2 to the x number equals 64 so some fast numbers that you should remember when you deal powers with 2 I don't know about you but I can only do multiply by 2 like 2 or 3 times so there's only like 2 powers of 2 you need to remember and then you can figure out the rest so 2 to the 5 equals 32 and 2 to the 10 equals 1024 if you remember those 2 numbers you can figure out the rest and you should also know that 2 to the power 0 is 2 sorry 2 to the power 0 is 1 2 to the power 1 is 2 screw that up nice alright so after that hey if I know 2 to the power 5 is 32 I can multiply by 2 once must be 2 to the power of 6 I don't have to waste time getting logs out or anything silly like that so because of that I know my offset I need 6 bits here everyone on the same page alright that's like the only good joke I have for this and it'll probably come up a few times alright so if I have a 8 bit virtual address and 6 of those bits are for my offset how big is this thing 2 so my virtual page number would only be 2 bits okay first question was number of the number of virtual pages how many virtual pages are there 4 everyone know how we get that so to figure out the number of virtual pages well we can just do some simple math so our total the total number of virtual bytes we can address is 2 to the power of 8 because we have an 8 bit virtual address and then our page size is 2 to the power of 6 for this just keep everything in powers of 2 because you can use that special little math thing where if you divide by exponents then it's actually the same as 2 to the power of 8 minus 6 which is 2 to the power of 2 and you should be able to figure out 2 to the power of 2 is 4 so therefore we have 4 virtual pages makes sense total address space divided by the size of a page that's how many virtual pages we need okay what about next question the number of physical pages or frames whatever you want to call them how many we got here 16 16 yeah so it's the same idea we have a 10 bit physical address which means physically we can address 2 to the 10 divided by the size of a page which is 2 to the 6 which is if I subtract exponents that's 2 to the 4 which is just 1 away from my special 32 number so I can also divide by 2 because I'm very skilled so 32 divided by 2 is just 16 so there are 16 physical pages that I can represent any questions about that okay so next question was how many entries in the page so how many entries would need to be a page table what I hear 4 right so it's the same as the number of virtual pages I should just be able to map those to whatever physical pages that I want so I should be able to map up to all 4 of them so it's just the same number as the number of virtual pages it's the same question so then it says given a page table that looks like this which is just array format which means this is index 0 1 2 and 3 so this is our so now it just says given this page table what is the physical address of F1 so we're given that as our virtual address physical address so this is where things get annoying and you should also know how to translate from hex because these are not nice numbers because our page size is 6 bits which doesn't fall nicely within our hex characters of being like every 4 bits so unfortunately the easiest thing for us to do is just to write it out in binary which is always fun but it will always work so what is F1 in binary so F1 in binary should be 1 1 1 1 0 0 0 1 and I assume this might be the first time you have actually used binary to do something useful so they trained you so that you could survive by the time you got here I guess so if you want to translate stuff really fast who off the top of their head knows what B is how to translate B 1 0 1 1 yet but if you want to be lazy you can use the same shortcut and you can only just remember 1 so the one that I just remember to make my life easier is just know that A is 1 0 1 0 yeah that's what everyone should use so this is the only one you actually really need to know and then you can figure it out from there F is going to be all 1s A is going to be 1 0 1 0 how to remember that well A is supposed to be 10 so just write 10 twice so A is 10 twice you'll never forget it you can figure it out from there luckily this one is nice enough that it gave you F so F is another one you should know you can just figure it out so that is John's fun shortcut of the day so if we are even though this is a bit messier than before our rules for translating this virtual address to a physical address are the same so we don't have to translate any bits that have to do with the offset or where we are within a page so what should I not translate here so tell me when to stop and anything under this I will not translate stop ok so that is 6 bits so I don't need to translate that because that's where I am within a page so that also looks ugly so I will fix that so this is what we called our offset and I'll just write up here too that this is our virtual address even though it looks a bit funky so if I am translating that to a physical address well then I don't have to translate that I can keep 1, 1 oops 0, 0, 0, 1 and those are those are my offset bits don't have to translate them then the next thing I have to do is well if those are the offset bits this should be my virtual page number what is 1, 1 if I translated I guess into decimal 3 so this is the ones column this is the 2's column 1 plus 2 is 3 so if this is the virtual page number it's the same as the index into the page table so it's 3 so I should use this one so this is going to be my physical page number and it is 8 in yeah it is 8 in hex so what is 8 in hex in binary 1, 0, 0 right? that's 8 so that's it I'm done I could make it a bit nicer and turn this back into hex so I just have to group by 4's and you can see that I was actually very nice so if I group it back into 4's to write this physical address back into hex well it would be 4 4 and then you know the leading ones are just 0's so what is 0, 0 what's the least significant hex character here that is 0, 0, 0, 1 or I said yeah should just be 1 what is the next one 3 what is the next one 2 so our physical address should be in hex 2, 3, 1 so this would translate f1 to 2, 3, 1 any questions about that? yeah so the offset is specifically 6 bits because the offset needs to address every single byte within a page our pages are 64 bytes so we need to address 64 things so because of that we need 6 bits because 2 of the 6 is 64 so we could address all of them so the number of entries in the page table is just the same as the number of virtual pages in this case virtual memory is not too hard well right now we can it seems pretty solved, we're good so all we have to do is in this case if we just want to have independent virtual memory for each process all that means is each process gets its own page table and this is what happens when you fork so when you fork you get an exact copy of the page table from the parent and what the kernel does is this really quick is it turns off write permissions so that your new process cannot write to memory without actually getting an error and then the kernel does some magic called copy on write which will only do the memory copy of the page in order to fake it and split it off from the original one whenever it actually modifies memory because if two processes are reading from the same physical memory that's fine, I can still keep up the illusion that they are completely independent as long as neither of them are modifying that memory, they can both just share the actual physical memory and it's nice and fast that's what you get to implement in lab 3 so look forward to that so our problem right now though that we will have to wait until the next lecture to solve is what I heard up here that pay attention, our page table was 2 to the 27 entries and if you do a bit of math about that, well each entry is 8 bytes so that's 2 to the 3 so that means our page table size in number of bytes would be 2 to the 30 and 2 to the 30 means each page table is a gigabyte notice here that GIB so it turns out that the term gigabyte is kind of ambiguous so for computer people that like powers of 2 gigabyte means 2 to the power of 30 which is more than a million like slightly more than a million or sorry slightly more than a billion so GIB means 2 to the power of 30 GB it could mean to the power of 30 or someone could be selling you a hard drive in which case it means 1 billion and not slightly more so that's whenever you buy a new hard drive that's a 500 gigabyte hard drive that's why it's always in the 400 gigabyte range because you did not read the FIDEN print and they ripped you off so that's marketing so for this course I'll always use GIB or it could mean real powers of 2 yeah, giggly bytes but I'm not going to say that so I can call it a giggly bytes alright so RISC-5 ARM processors they do that translation with a 39-bit virtual to 56-bit physical address and reason behind that while it has 10 bits left in the page table entry it could expand there's no need to expand now because they could either make the physical page number bigger they could add more flags if they wanted to add more features so the designers would say hey we reserved them for future use and this is also because of our page size so that directly corresponds to the size of the offset field with some questions like we saw before if I vary the page size then you have to figure out what offset needs to be so might also be thinking this seems like a lot of work so in the sub-process lecture we did a fork followed by an exec so you might ask yourself why do we even need to copy the page tables if I'm just starting to execute a new program anyways that seems like a lot of work and you don't, there is actually a special system call called Vfork which makes the new child process it doesn't do anything with the page tables it makes them use the same page tables so that one process can directly affect the other one and they essentially just said only use this if you are immediately doing exec after that otherwise we do not guarantee anything about your program it'll, you know it might corrupt itself so it's actually undefined behavior to modify anything and not a great idea so this is only used in really performance sensitive applications where copying the page tables would just take too long and if I know I'm going to exec anyways which would re-initialize all the page tables anyways then I don't need to do a wasted step so for this what we will actually do is use pages for memory translation so what we did right now we divided memory into block so we only have to translate once per block that seems to work out fairly well and that is actually what happens but right now our page table which is basically an array of page table entries which again page table entries just have the physical page number and some flags mostly like valid read and write but our big problem now is that page tables are always gigantic and we will solve that in the next lecture so just remember we're on this together