From a3e7ad1fa8f1103140a779f619114780c825f206 Mon Sep 17 00:00:00 2001 From: Philipp Oppermann Date: Fri, 25 Jan 2019 19:56:54 +0100 Subject: [PATCH] Fix typo in graphics and replace SVGs with PNGs The SVG have rendering problems on some devices, e.g. when the text is zoomed. --- .../posts/10-advanced-paging/index.md | 12 ++++++------ .../recursive-page-table-access-level-1.png | Bin 0 -> 52566 bytes .../recursive-page-table-access-level-1.svg | 2 -- .../recursive-page-table-access-level-2.png | Bin 0 -> 51800 bytes .../recursive-page-table-access-level-2.svg | 2 -- .../recursive-page-table-access-level-3.png | Bin 0 -> 53659 bytes .../recursive-page-table-access-level-3.svg | 2 -- .../10-advanced-paging/recursive-page-table.png | Bin 0 -> 46989 bytes .../10-advanced-paging/recursive-page-table.svg | 2 -- .../temporarily-mapped-page-tables.png | Bin 0 -> 44984 bytes .../temporarily-mapped-page-tables.svg | 2 -- 11 files changed, 6 insertions(+), 16 deletions(-) create mode 100644 blog/content/second-edition/posts/10-advanced-paging/recursive-page-table-access-level-1.png delete mode 100644 blog/content/second-edition/posts/10-advanced-paging/recursive-page-table-access-level-1.svg create mode 100644 blog/content/second-edition/posts/10-advanced-paging/recursive-page-table-access-level-2.png delete mode 100644 blog/content/second-edition/posts/10-advanced-paging/recursive-page-table-access-level-2.svg create mode 100644 blog/content/second-edition/posts/10-advanced-paging/recursive-page-table-access-level-3.png delete mode 100644 blog/content/second-edition/posts/10-advanced-paging/recursive-page-table-access-level-3.svg create mode 100644 blog/content/second-edition/posts/10-advanced-paging/recursive-page-table.png delete mode 100644 blog/content/second-edition/posts/10-advanced-paging/recursive-page-table.svg create mode 100644 blog/content/second-edition/posts/10-advanced-paging/temporarily-mapped-page-tables.png delete mode 100644 blog/content/second-edition/posts/10-advanced-paging/temporarily-mapped-page-tables.svg diff --git a/blog/content/second-edition/posts/10-advanced-paging/index.md b/blog/content/second-edition/posts/10-advanced-paging/index.md index 5f86e003..16cd8d85 100644 --- a/blog/content/second-edition/posts/10-advanced-paging/index.md +++ b/blog/content/second-edition/posts/10-advanced-paging/index.md @@ -55,7 +55,7 @@ So in order to access page table frames, we need to map some virtual pages to th - Alternatively, we could **map the page tables frames only temporarily** when we need to access them. To be able to create the temporary mappings we only need a single identity-mapped level 1 table: - ![A virtual and a physical address space with an identity mapped level 1 table, which maps its 0th entry to the level 2 table frame, therey mapping that frame to page with address 0](temporarily-mapped-page-tables.svg) + ![A virtual and a physical address space with an identity mapped level 1 table, which maps its 0th entry to the level 2 table frame, therey mapping that frame to page with address 0](temporarily-mapped-page-tables.png) The level 1 table in this graphic controls the first 2 MiB of the virtual address space. This is because it is reachable by starting at the CR3 register and following the 0th entry in the level 4, level 3, and level 2 page tables. The entry with index `8` maps the virtual page at address `32 KiB` to the physical frame at address `32 KiB`, thereby identity mapping the level 1 table itself. The graphic shows this identity-mapping by the horizontal arrow at `32 KiB`. @@ -78,7 +78,7 @@ The idea behind this approach sounds simple: _Map some entry of the level 4 page Let's go through an example to understand how this all works: -![An example 4-level page hierarchy with each page table shown in physical memory. Entry 511 of the level 4 page is mapped to frame 4KiB, the frame of the level 4 table itself.](recursive-page-table.svg) +![An example 4-level page hierarchy with each page table shown in physical memory. Entry 511 of the level 4 page is mapped to frame 4KiB, the frame of the level 4 table itself.](recursive-page-table.png) The only difference to the [example at the beginning of this post] is the additional entry at index `511` in the level 4 table, which is mapped to physical frame `4 KiB`, the frame of the level 4 table itself. @@ -88,17 +88,17 @@ By letting the CPU follow this entry on a translation, it doesn't reach a level By following the recursive entry one or multiple times before we start the actual translation, we can effectively shorten the number of levels that the CPU traverses. For example, if we follow the recursive entry once and then proceed to the level 3 table, the CPU thinks that the level 3 table is a level 2 table. Going further, it treats the level 2 table as a level 1 table, and the level 1 table as the mapped frame. This means that we can now read and write the level 1 page table because the CPU thinks that it is the mapped frame. The graphic below illustrates the 5 translation steps: -![The above example 4-level page hierarchy with 5 arrows: "Step 0" from CR4 to level 4 table, "Step 1" from level 4 table to level 4 table, "Step 2" from level 4 table to level 3 table, "Step 3" from level 3 table to level 2 table, and "Step 4" from level 2 table to level 1 table.](recursive-page-table-access-level-1.svg) +![The above example 4-level page hierarchy with 5 arrows: "Step 0" from CR4 to level 4 table, "Step 1" from level 4 table to level 4 table, "Step 2" from level 4 table to level 3 table, "Step 3" from level 3 table to level 2 table, and "Step 4" from level 2 table to level 1 table.](recursive-page-table-access-level-1.png) Similarly, we can follow the recursive entry twice before starting the translation to reduce the number of traversed levels to two: -![The same 4-level page hierarchy with the following 4 arrows: "Step 0" from CR4 to level 4 table, "Steps 1&2" from level 4 table to level 4 table, "Step 3" from level 4 table to level 3 table, and "Step 4" from level 3 table to level 2 table.](recursive-page-table-access-level-2.svg) +![The same 4-level page hierarchy with the following 4 arrows: "Step 0" from CR4 to level 4 table, "Steps 1&2" from level 4 table to level 4 table, "Step 3" from level 4 table to level 3 table, and "Step 4" from level 3 table to level 2 table.](recursive-page-table-access-level-2.png) Let's go through it step by step: First the CPU follows the recursive entry on the level 4 table and thinks that it reaches a level 3 table. Then it follows the recursive entry again and thinks that it reaches a level 2 table. But in reality, it is still on the level 4 table. When the CPU now follows a different entry, it lands on a level 3 table, but thinks it is already on a level 1 table. So while the next entry points at a level 2 table, the CPU thinks that it points to the mapped frame, which allows us to read and write the level 2 table. Accessing the tables of levels 3 and 4 works in the same way. For accessing the level 3 table, we follow the recursive entry entry three times, tricking the CPU into thinking it is already on a level 1 table. Then we follow another entry and reach a level 3 table, which the CPU treats as a mapped frame. For accessing the level 4 table itself, we just follow the recursive entry four times until the CPU treats the level 4 table itself as mapped frame (in blue in the graphic below). -![The same 4-level page hierarchy with the following 3 arrows: "Step 0" from CR4 to level 4 table, "Steps 1,2,3" from level 4 table to level 4 table, and "Step 4" from level 4 table to level 3 table. In blue the alternative "Steps 1,2,3,4" arrow from level 4 table to level 4 table.](recursive-page-table-access-level-3.svg) +![The same 4-level page hierarchy with the following 3 arrows: "Step 0" from CR4 to level 4 table, "Steps 1,2,3" from level 4 table to level 4 table, and "Step 4" from level 4 table to level 3 table. In blue the alternative "Steps 1,2,3,4" arrow from level 4 table to level 4 table.](recursive-page-table-access-level-3.png) It might take some time to wrap your head around the concept, but it works quite well in practice. @@ -635,4 +635,4 @@ We're now able to map arbitrary pages and to allocate new physical frames when w TODO spellcheck TODO improve transition between sections TODO update post date -TODO check level 2 table diagram 24KiB -> 32KiB \ No newline at end of file +TODO use PNGs instead of SVGs? diff --git a/blog/content/second-edition/posts/10-advanced-paging/recursive-page-table-access-level-1.png b/blog/content/second-edition/posts/10-advanced-paging/recursive-page-table-access-level-1.png new file mode 100644 index 0000000000000000000000000000000000000000..1c6662ab32b22581afa4af5848ecd290b6eca93f GIT binary patch literal 52566 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