1 00:00:03,400 --> 00:00:07,140 Good afternoon. Let's get started. 2 00:00:07,860 --> 00:00:12,810 So today, we are going to be continuing our quest into Computer Architecture. 3 00:00:12,810 --> 00:00:17,500 And we're going to be talking about virtual memory and address translation. 4 00:00:17,500 --> 00:00:21,800 Together with how you do virtual memory protection, on top of that. 5 00:00:22,569 --> 00:00:27,597 So this is a crossover between architecture and operating systems topic. 6 00:00:27,597 --> 00:00:32,974 So, your operating systems, many times, has to worry about how to manage memory. 7 00:00:32,974 --> 00:00:38,281 Also, many times, you have to worry about how to manage who can access memory. 8 00:00:38,281 --> 00:00:43,588 You have to worry about how much memory different users could possibly have. 9 00:00:43,588 --> 00:00:48,266 But even in a uni-processor system, this becomes an important thing. 10 00:00:48,476 --> 00:00:51,811 That a uniprocessor system and a uniuser system, 11 00:00:51,811 --> 00:00:54,932 Not a multiprogram system and not a multiuser system, 12 00:00:54,932 --> 00:00:58,962 But just a single user system also has to worry about layout of memory. 13 00:00:58,962 --> 00:01:03,389 And worrying about running different libraries, different portions of programs, 14 00:01:03,389 --> 00:01:06,000 And how to lay that out effectively in memory. 15 00:01:07,100 --> 00:01:12,395 So, we're going to continue videotaping our lecture today, put online so you guys 16 00:01:12,395 --> 00:01:16,698 can go look at later. And so let's get off by starting to talk 17 00:01:16,698 --> 00:01:20,670 about memory management. And we're going to talk about a couple 18 00:01:20,670 --> 00:01:23,891 different schemes today which aren't very popular. 19 00:01:23,918 --> 00:01:27,925 [laugh] We're going to talk about some schemes that have some historical basis 20 00:01:27,925 --> 00:01:32,731 that are still important in, important to understand and there's some vestiges in 21 00:01:32,731 --> 00:01:36,410 today's architectures. So, for instance, one of the things we're 22 00:01:36,410 --> 00:01:41,156 going to be talking about today is called segmentation or base and bound registers 23 00:01:41,156 --> 00:01:43,826 which still shows up in X86 processors today, 24 00:01:43,826 --> 00:01:46,970 But is not very common as a memory protection system. 25 00:01:46,970 --> 00:01:51,480 But it was designed as a memory protection system when it first got started. 26 00:01:52,080 --> 00:01:56,008 And then, we're going to go, and at the end of today's lecture, we're going to 27 00:01:56,008 --> 00:02:00,721 talk about fancier virtual memory systems that are used in modern day computers, how 28 00:02:00,721 --> 00:02:05,154 your operating system goes about managing memory with that, how it pro, provides 29 00:02:05,154 --> 00:02:08,690 efficient use of memory, and how it protects different accesses. 30 00:02:08,690 --> 00:02:16,000 So, we can broadly separate memory management into three really important and 31 00:02:16,000 --> 00:02:19,566 orthogonal functions. First of all, translation. 32 00:02:19,566 --> 00:02:24,899 So, in translation, what we're doing is we're taking one address and we're turning 33 00:02:24,899 --> 00:02:28,850 it into some other address. So, we're able to remap addresses. 34 00:02:28,850 --> 00:02:32,115 Now, you might say, Why do we want to do that? 35 00:02:32,115 --> 00:02:34,865 Well, By doing that, we can have more flexible 36 00:02:34,865 --> 00:02:38,012 memory layouts and prevent things like fragmentation. 37 00:02:38,012 --> 00:02:42,466 So, fragmentation, we'll talk about that more later in today's lecture. 38 00:02:42,466 --> 00:02:47,336 But fragmentation basically is the problem that you have lots of little pieces of 39 00:02:47,336 --> 00:02:51,315 data or code that get loaded. And then some of them completes or go 40 00:02:51,315 --> 00:02:53,928 away. You're going to end up with holes in your 41 00:02:53,928 --> 00:02:57,194 memory space. And it's very hard to reclaim that unless 42 00:02:57,194 --> 00:02:59,807 you try to compress or re-layout the memory. 43 00:02:59,807 --> 00:03:04,440 And lots of program models don't allow you to go and recompress the memory. 44 00:03:04,440 --> 00:03:13,283 This is familiar if you've ever taken a, a basic data structures course, where you 45 00:03:13,283 --> 00:03:16,133 had to go deal with managing something like a heap. 46 00:03:16,133 --> 00:03:20,938 In a heap, you have pretty common to, it's pretty common to allocate different sized 47 00:03:20,938 --> 00:03:25,576 objects on your heap, and then you free up those different sized objects, and if you 48 00:03:25,576 --> 00:03:30,102 happen to free them in a bad order, you end up with little chunks of memory that 49 00:03:30,102 --> 00:03:32,616 are really hard to go use for something else. 50 00:03:32,616 --> 00:03:36,639 Especially if you want to go allocate something very large, you might have 51 00:03:36,639 --> 00:03:39,880 enough memory in your system, but it's just not contiguous. 52 00:03:39,880 --> 00:03:44,650 So, what approached to this is to have things like garbage collectors which is 53 00:03:44,650 --> 00:03:48,427 what Java and a lot of the managed programming languages do. 54 00:03:48,427 --> 00:03:52,801 But something like C or C+++ does not a notion of garbage collectors. 55 00:03:52,801 --> 00:03:58,433 So, we're going to look at more not from a heap perspective but from a perspective of 56 00:03:58,433 --> 00:04:02,627 the entire memory system. So, sort of one level out from a heap. 57 00:04:02,627 --> 00:04:07,018 So, interprogram fragmentation and interprogram garbage collection. 58 00:04:07,018 --> 00:04:12,093 The second important function of our memory management here is we want to 59 00:04:12,093 --> 00:04:17,101 restrict access or protect access to memory and allow only users who are 60 00:04:17,101 --> 00:04:22,588 supposed to be able to touch a certain piece of memory to be able to touch that 61 00:04:22,588 --> 00:04:26,361 certain piece of memory. And this is important if, for instance, 62 00:04:26,361 --> 00:04:30,340 you have one system which has someone's bank records on it. 63 00:04:30,340 --> 00:04:35,664 And on that same system, someone else can log in, they can telnet or SHS into it or 64 00:04:35,664 --> 00:04:39,755 remotely log into it. And you don't want one user to be able to 65 00:04:39,755 --> 00:04:44,884 go read some other user's bank records that just happen to be laying in memory. 66 00:04:44,884 --> 00:04:49,560 So, we need some way to protect that and memory protection gets us there. 67 00:04:49,560 --> 00:04:55,079 It allows us to have different users using the same system, different processes using 68 00:04:55,079 --> 00:05:00,663 the same system, and we can restrict the access to different locations in memory or 69 00:05:00,663 --> 00:05:04,040 protect the access to different locations in memory. 70 00:05:04,040 --> 00:05:09,137 Finally, memory management. One of the important sort of points in 71 00:05:09,137 --> 00:05:15,251 memory management is that you can actually think about having more memory than your 72 00:05:15,251 --> 00:05:19,062 machine has memory. Now, you might say, that doesn't make any 73 00:05:19,062 --> 00:05:21,580 sense. No, it doesn't make any sense. 74 00:05:21,580 --> 00:05:27,811 But if you have a flexible enough hardware system, you can think about using other 75 00:05:27,811 --> 00:05:32,472 things to look like memory. So, for instance, if you have a hard drive 76 00:05:32,472 --> 00:05:37,475 in your computer, you can use that hard drive which is very, very large to 77 00:05:37,475 --> 00:05:43,164 effectively increase your memory size by taking the data which is laying in memory 78 00:05:43,164 --> 00:05:47,687 and put it onto the disk. And sometime later in the future, take it 79 00:05:47,687 --> 00:05:54,314 off the disk, and put it back into memory and trick the user into thinking they have 80 00:05:54,314 --> 00:06:00,174 a larger memory space, and this is virtual memory so it allows us to have transparent 81 00:06:00,174 --> 00:06:03,829 extension of the memory space using something slower. 82 00:06:03,829 --> 00:06:09,482 I mean, could be disk, it could be in the older days some drum that spins where you 83 00:06:09,482 --> 00:06:13,136 sort of store things on the drum you could even, I could even, nowadays, you can even 84 00:06:13,136 --> 00:06:17,342 swap on flash. If you ever go look in or something like 85 00:06:17,342 --> 00:06:23,335 that, this is called your swap partition. Sometimes called a backing store, a couple 86 00:06:23,335 --> 00:06:29,726 different names it goes by, but it's a virtual manage virtual memory storage 87 00:06:29,726 --> 00:06:31,830 location. Nowadays, 88 00:06:31,830 --> 00:06:36,173 Most systems provide us with some sort of page based system, which we'll be talking 89 00:06:36,173 --> 00:06:38,632 about. But there, these ideas are all orthogonal, 90 00:06:38,632 --> 00:06:42,766 and you can have different mechanism is to solve all of them in different ways. 91 00:06:42,766 --> 00:06:46,220 And we'll be talking about some of the historical aspects of that. 92 00:06:46,620 --> 00:06:49,480 Okay, so, let's start off in the beginning. 93 00:06:49,480 --> 00:06:53,736 Well, in the beginning, we didn't have fancy memory management. 94 00:06:53,736 --> 00:06:57,993 Instead, we had addresses. You want to go access some piece of 95 00:06:57,993 --> 00:07:03,365 memory, you come up with an address. And that directly indexes into our memory, 96 00:07:03,365 --> 00:07:08,361 and you get back the data. Well, that's okay if you're running one 97 00:07:08,361 --> 00:07:13,034 program at a time. So if you go back and look at EDSAC, which 98 00:07:13,034 --> 00:07:17,283 is one of the original, probably the second computer, I think. 99 00:07:17,283 --> 00:07:22,240 Maybe the first computer. Oh, the first sort of, modernish looking 100 00:07:22,240 --> 00:07:25,568 computer. It only had physical memory addresses. 101 00:07:25,568 --> 00:07:30,100 So, what this really meant is only one program can run at a time. 102 00:07:30,520 --> 00:07:36,847 And, it had all of memory. And the addresses that were used, 103 00:07:36,847 --> 00:07:43,512 basically didn't move around because there was only one program running and it owned 104 00:07:43,512 --> 00:07:47,120 everything. An IO could directly touch memory. 105 00:07:47,590 --> 00:07:51,119 Main processor could directly touch memory. 106 00:07:51,119 --> 00:07:56,629 And life was simple and okay. But, unfortunately you couldn't really run 107 00:07:56,629 --> 00:08:00,404 multiple programs, you couldn't protect multiple programs. 108 00:08:00,404 --> 00:08:05,902 You could definitely not take memory off of disk and put it into memory, cuz you 109 00:08:05,902 --> 00:08:11,201 had no way to sort of remap things. So, it did not fulfill those sort of three 110 00:08:11,201 --> 00:08:16,433 requirements that we were talking about. We didn't, it didn't do any translation. 111 00:08:16,433 --> 00:08:21,930 It didn't do any ability to protect, and it didn't have any notion of virtual 112 00:08:21,930 --> 00:08:25,242 memory. One thing that did happen is that users 113 00:08:25,242 --> 00:08:29,795 still wanted to be able to write sub-routines that were location 114 00:08:29,795 --> 00:08:33,317 independent. So, what I mean by that is you write a 115 00:08:33,317 --> 00:08:39,375 subroutine, and this was back in the days when people were writing these subroutines 116 00:08:39,375 --> 00:08:44,223 in machine code or assembly code, And you still want to do the regular, one 117 00:08:44,223 --> 00:08:49,657 subroutine and use it and call it, and use it in different portions of your programs. 118 00:08:49,657 --> 00:08:54,897 So, one of the trick that people sort of thought about is, how can you still have 119 00:08:54,897 --> 00:09:00,073 location independence even when you only have one physical address space, so you 120 00:09:00,073 --> 00:09:03,696 can't remap things, there's no translation going on here. 121 00:09:03,696 --> 00:09:07,357 Well, In fact, you can actually use the linker 122 00:09:07,357 --> 00:09:14,200 or the loader to be able to go do this. So, actually, quick show of hands here who 123 00:09:14,200 --> 00:09:18,924 knows what a loader is? Who knows what a linker is? 124 00:09:18,924 --> 00:09:25,220 Okay, so we've got a little bit of coverage with linker. linker, 125 00:09:25,600 --> 00:09:30,179 What it does is it takes multiple different compilation objects or 126 00:09:30,179 --> 00:09:34,211 compilation units. So if you take a computer program that's 127 00:09:34,211 --> 00:09:38,996 made out of a bunch of little files, a bunch of different source files, 128 00:09:38,996 --> 00:09:44,366 You compile up each of those separately. And when you link it, you take them and 129 00:09:44,366 --> 00:09:48,759 you put them all together into one program, and you resolve all the 130 00:09:48,759 --> 00:09:53,490 addresses, all the jumps, and the data accesses across that one program. 131 00:09:53,490 --> 00:09:56,194 So, that's linking. That's static linking. 132 00:09:56,194 --> 00:09:59,573 Now, dynamic linking. You guys might have seen, DLLs. 133 00:09:59,573 --> 00:10:04,249 Did I make dynamically linkable loadable objects. 134 00:10:04,249 --> 00:10:10,697 So, what happens with DLLs is, you'll actually do that linking step of resolving 135 00:10:10,697 --> 00:10:15,204 the addresses at runtime. So, you could actually do either, 136 00:10:15,204 --> 00:10:18,855 You can either do it dynamically or statically. 137 00:10:18,855 --> 00:10:25,149 And the loader is the piece of code which actually takes a binary off a disc, and 138 00:10:25,149 --> 00:10:31,006 puts it into memory somewhere. And typically, the loader will go and do a 139 00:10:31,006 --> 00:10:35,624 last level linking step at the end. So, on a modern day Linux system, your 140 00:10:35,624 --> 00:10:37,594 linker, Or excuse me, your loader, 141 00:10:37,594 --> 00:10:42,581 When you type a when you go to execute a program and you type I don't know, 142 00:10:42,581 --> 00:10:45,968 You run LS or something like that on your Linux system. 143 00:10:45,968 --> 00:10:51,079 First thing it does is it goes and finds the LS bits on the disk and it takes that 144 00:10:51,079 --> 00:10:53,750 and copies it up into RAM, Somewhere. 145 00:10:53,750 --> 00:10:57,283 So, you could do this on this absolute addressing system. 146 00:10:57,283 --> 00:11:02,330 And then what it does is it goes and it figures out all of the dynamic vibrates 147 00:11:02,330 --> 00:11:05,852 that are needed. And it goes and takes those off disk and 148 00:11:05,852 --> 00:11:10,292 puts them into RAM somewhere. And then, it's going to, last step here is 149 00:11:10,292 --> 00:11:15,352 the original program had pointers to address that didn't actually exist yet. 150 00:11:15,352 --> 00:11:20,612 Cuz it didn't know where the respective loaders, respective libraries are going to 151 00:11:20,612 --> 00:11:23,541 be loaded. So, it has to patch the program up. 152 00:11:23,541 --> 00:11:29,067 It has to rewrite addresses to make sure that the newly load program points up the 153 00:11:29,067 --> 00:11:33,061 correct location. So, that's a runtime linker doing its job. 154 00:11:33,061 --> 00:11:38,387 The static linker can do that same sort of thing but at a compile time could be an 155 00:11:38,387 --> 00:11:41,450 assembly time or linking time in your program. 156 00:11:41,450 --> 00:11:43,927 Okay. So, that's absolute addresses and if you 157 00:11:43,927 --> 00:11:48,002 have the physical hardware for an absolute address machine, it's simple. 158 00:11:48,002 --> 00:11:51,085 It's kind of what we have been looking at, at this point. 159 00:11:51,085 --> 00:11:55,545 You have your program counter, you stick it in your cache, it gets, the instruction 160 00:11:55,545 --> 00:11:59,289 cache gets an instruction out. You take your address if you're doing 161 00:11:59,289 --> 00:12:03,363 memory access, you stick it into your data cache, and it gets some data out. 162 00:12:03,363 --> 00:12:07,713 If you take misses everything to physical address, it goes into the memory control 163 00:12:07,713 --> 00:12:10,362 and goes out to DRAM. Seems, seems simple. 164 00:12:10,362 --> 00:12:14,290 It is. But, like I said, it doesn't solve all the 165 00:12:14,290 --> 00:12:19,789 problems we want to solve. Okay, so now, let's start talking about 166 00:12:19,789 --> 00:12:25,917 stuff that's a little bit more, more complex if we actually want to do address 167 00:12:25,917 --> 00:12:30,717 translation. So, address translation, actually before 168 00:12:30,717 --> 00:12:36,287 we leave this, we're going to call addresses that touch main memory, physical 169 00:12:36,287 --> 00:12:41,369 addresses. And we're also going to talk about this 170 00:12:41,369 --> 00:12:46,003 notion of a virtual address. A virtual address is actually just an 171 00:12:46,003 --> 00:12:51,551 address that the main processor uses which might be translated somehow into an 172 00:12:51,551 --> 00:12:54,080 address which is out in main memory.