WEBVTT

00:00:00.500 --> 00:00:02.910
In the last lecture we
introduced the notion

00:00:02.910 --> 00:00:07.130
of virtual memory and added a
Memory Management Unit (MMU)

00:00:07.130 --> 00:00:10.140
to translate the virtual
addresses generated by the CPU

00:00:10.140 --> 00:00:14.270
to the physical addresses
sent to main memory.

00:00:14.270 --> 00:00:16.040
This gave us the
ability to share

00:00:16.040 --> 00:00:18.660
physical memory between
many running programs

00:00:18.660 --> 00:00:21.400
while still giving each
program the illusion of having

00:00:21.400 --> 00:00:24.580
its own large address space.

00:00:24.580 --> 00:00:27.110
Both the virtual and
physical address spaces

00:00:27.110 --> 00:00:29.670
are divided into a
sequence of pages,

00:00:29.670 --> 00:00:32.810
each holding some fixed
number of locations.

00:00:32.810 --> 00:00:36.510
For example if each
page holds 2^12 bytes,

00:00:36.510 --> 00:00:44.760
a 32-bit address would have
2^32/2^12 = 2^20 pages.

00:00:44.760 --> 00:00:47.270
In this example
the 32-bit address

00:00:47.270 --> 00:00:49.440
can be thought of as
having two fields:

00:00:49.440 --> 00:00:52.420
a 20-bit page number formed
from the high-order address

00:00:52.420 --> 00:00:55.730
bits and a 12-bit
page offset formed

00:00:55.730 --> 00:00:58.230
from the low-order address bits.

00:00:58.230 --> 00:01:00.580
This arrangement ensures
that nearby data will

00:01:00.580 --> 00:01:04.140
be located on the same page.

00:01:04.140 --> 00:01:06.860
The MMU translates
virtual page numbers

00:01:06.860 --> 00:01:10.480
into physical page
numbers using a page map.

00:01:10.480 --> 00:01:12.680
Conceptually the
page map is an array

00:01:12.680 --> 00:01:15.960
where each entry in the array
contains a physical page

00:01:15.960 --> 00:01:19.520
number along with a couple
of bits indicating the page

00:01:19.520 --> 00:01:21.470
status.

00:01:21.470 --> 00:01:23.710
The translation
process is simple:

00:01:23.710 --> 00:01:26.500
the virtual page number
is used as an index

00:01:26.500 --> 00:01:29.440
into the array to fetch the
corresponding physical page

00:01:29.440 --> 00:01:30.920
number.

00:01:30.920 --> 00:01:33.090
The physical page
number is then combined

00:01:33.090 --> 00:01:38.670
with the page offset to form
the complete physical address.

00:01:38.670 --> 00:01:41.810
In the actual implementation the
page map is usually organized

00:01:41.810 --> 00:01:45.110
into multiple levels, which
permits us to have resident

00:01:45.110 --> 00:01:50.060
only the portion of the page
map we’re actively using.

00:01:50.060 --> 00:01:52.260
And to avoid the costs
of accessing the page

00:01:52.260 --> 00:01:55.060
map on each address
translation, we

00:01:55.060 --> 00:01:58.500
use a cache (called the
translation look-aside buffer)

00:01:58.500 --> 00:02:04.460
to remember the results of
recent vpn-to-ppn translations.

00:02:04.460 --> 00:02:07.580
All allocated locations of
each virtual address space

00:02:07.580 --> 00:02:10.340
can be found on
secondary storage.

00:02:10.340 --> 00:02:12.270
Note that they may
not necessarily

00:02:12.270 --> 00:02:14.290
be resident in main memory.

00:02:14.290 --> 00:02:17.860
If the CPU attempts to access
a virtual address that’s not

00:02:17.860 --> 00:02:21.000
resident in main memory,
a page fault is signaled

00:02:21.000 --> 00:02:23.870
and the operating system will
arrange to move the desired

00:02:23.870 --> 00:02:28.070
page from secondary
storage into main memory.

00:02:28.070 --> 00:02:31.400
In practice, only the active
pages for each program

00:02:31.400 --> 00:02:36.540
are resident in main
memory at any given time.

00:02:36.540 --> 00:02:39.710
Here’s a diagram showing
the translation process.

00:02:39.710 --> 00:02:43.230
First we check to see if the
required vpn-to-ppn mapping is

00:02:43.230 --> 00:02:45.450
cached in the TLB.

00:02:45.450 --> 00:02:48.450
If not, we have to access
the hierarchical page map

00:02:48.450 --> 00:02:51.380
to see if the page is
resident and, if so,

00:02:51.380 --> 00:02:53.880
lookup its physical page number.

00:02:53.880 --> 00:02:56.280
If we discover that the
page is not resident,

00:02:56.280 --> 00:02:59.060
a page fault exception
is signaled to the CPU

00:02:59.060 --> 00:03:01.540
so that it can run a
handler to load the page

00:03:01.540 --> 00:03:04.290
from secondary storage.

00:03:04.290 --> 00:03:07.280
Note that access to a
particular mapping context

00:03:07.280 --> 00:03:09.650
is controlled by two registers.

00:03:09.650 --> 00:03:12.190
The context-number register
controls which mappings

00:03:12.190 --> 00:03:13.500
are accessible in the TLB.

00:03:13.500 --> 00:03:16.770
And the page-directory
register indicates

00:03:16.770 --> 00:03:19.690
which physical page
holds the top tier

00:03:19.690 --> 00:03:22.440
of the hierarchical page map.

00:03:22.440 --> 00:03:25.950
We can switch to another context
by simply reloading these two

00:03:25.950 --> 00:03:27.540
registers.

00:03:27.540 --> 00:03:30.550
To effectively accommodate
multiple contexts we’ll need

00:03:30.550 --> 00:03:34.670
to have sufficient TLB capacity
to simultaneously cache

00:03:34.670 --> 00:03:37.690
the most frequent mappings
for all the processes.

00:03:37.690 --> 00:03:40.130
And we’ll need some number
of physical pages to hold

00:03:40.130 --> 00:03:43.290
the required page directories
and segments of the page

00:03:43.290 --> 00:03:44.330
tables.

00:03:44.330 --> 00:03:46.510
For example, for a
particular process,

00:03:46.510 --> 00:03:49.830
three pages will suffice hold
the resident two-level page

00:03:49.830 --> 00:03:55.690
map for 1024 pages at each end
of the virtual address space,

00:03:55.690 --> 00:04:00.950
providing access to up to 8MB
of code, stack, and heap, more

00:04:00.950 --> 00:04:03.860
than enough for many
simple programs.

00:04:03.860 --> 00:04:06.310
The page map creates
the context needed

00:04:06.310 --> 00:04:09.760
to translate virtual addresses
to physical addresses.

00:04:09.760 --> 00:04:12.360
In a computer system that’s
working on multiple tasks

00:04:12.360 --> 00:04:16.200
at the same time, we would like
to support multiple contexts

00:04:16.200 --> 00:04:21.149
and to be able to quickly switch
from one context to another.

00:04:21.149 --> 00:04:24.840
Multiple contexts would allow
us to share physical memory

00:04:24.840 --> 00:04:27.580
between multiple programs.

00:04:27.580 --> 00:04:30.250
Each program would have an
independent virtual address

00:04:30.250 --> 00:04:34.360
space, e.g., two programs could
both access virtual address

00:04:34.360 --> 00:04:36.620
0 as the address of
their first instruction

00:04:36.620 --> 00:04:40.190
and would end up accessing
different physical locations

00:04:40.190 --> 00:04:42.050
in main memory.

00:04:42.050 --> 00:04:45.570
When switching between programs,
we’d perform a “context switch”

00:04:45.570 --> 00:04:49.600
to move to the
appropriate MMU context.

00:04:49.600 --> 00:04:52.490
The ability to share the
CPU between many programs

00:04:52.490 --> 00:04:54.440
seems like a great idea!

00:04:54.440 --> 00:04:57.920
Let’s figure out the details
of how that might work…