Advertisement
Guest User

Untitled

a guest
Apr 21st, 2019
138
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C 23.56 KB | None | 0 0
  1.  
  2. // Incoming pte_flags should be as if 4KB page (bit 7 is PAT bit)
  3. void paging_map_physical(uint64_t phys_addr, uint64_t linear_base,
  4.                          uint64_t length, uint64_t pte_flags)
  5. {
  6.     if (unlikely(low_bits(phys_addr, 12) != low_bits(linear_base, 12)))
  7.     {
  8.         printf("ERROR: "
  9.                     "Impossible linear->physical mapping,"
  10.                     " bits 11:0 of the physical and linear address"
  11.                     " must be equal");
  12.         return;
  13.     }
  14.  
  15.     // -------------------------========---------------------------  //
  16.     //                                                               //
  17.     //                          4KB Only                             //
  18.     //                                                               //
  19.     //   <- phys_addr                        phys_addr + length ->   //
  20.     //   <- linear_base                                            B //
  21.     //                                                             C //
  22.     //                                                             D //
  23.     //                                                             E //
  24.     // A <------------------------ r ----------------------------> F //
  25.     // |                                                           | //
  26.     // | L                                                         | //
  27.     // | |                                                         | //
  28.     // ↓ ↓                                                         ↓ //
  29.     // +-----------------------------------------------------------+ //
  30.     // |                        4K pg ...                          | //
  31.     // +-----------------------------------------------------------+ //
  32.     // ↑                                                           ↑ //
  33.     // |                                                           | //
  34.     // 4K                                                         4K //
  35.     // \------------------------ alignment ------------------------/ //
  36.     //                                                               //
  37.     //                                                               //
  38.     // --------------------------=======---------------------------  //
  39.     //                                                               //
  40.     //                           4KB/2MB                             //
  41.     //                                                               //
  42.     // r_up(A,21) -↘                                   ↙- r_dn(F,21) //
  43.     //                                                 C             //
  44.     //             ↙                                   D             //
  45.     // A <-- r --> B <------------- s ---------------> E <-- v --> F //
  46.     // |           |                                   |           | //
  47.     // | L         |                                   |           | //
  48.     // | |         |                                   |           | //
  49.     // ↓ ↓         ↓                                   ↓           ↓ //
  50.     // +-----------+-----------------------------------+-----------+ //
  51.     // | 4K pg ... |             2M pg ...             | 4K pg ... | //
  52.     // +-----------+-----------------------------------+-----------+ //
  53.     // ↑           ↑                                   ↑           ↑ //
  54.     // |           |                                   |           | //
  55.     // 4K          2M                                  2M         4K //
  56.     // \------------------------ alignment ------------------------/ //
  57.     //                                                               //
  58.     //                                                               //
  59.     // ------------------------===========-------------------------  //
  60.     //                                                               //
  61.     //                         4KB/2MB/1GB                           //
  62.     //                                                               //
  63.     //                                                               //
  64.     //              r_up(B,30)-↘           ↙-r_dn(E,30)              //
  65.     //                         |           |                         //
  66.     // A <-- r --> B <-- s --> C <-- t --> D <-- u --> E <-- v --> F //
  67.     // |           |           |           |           |           | //
  68.     // | L         |           |           |           |           | //
  69.     // | |         |           |           |           |           | //
  70.     // ↓ ↓         ↓           ↓           ↓           ↓           ↓ //
  71.     // +-----------+-----------+-----------+-----------+-----------+ //
  72.     // | 4K pgs... | 2M pgs... | 1G pgs... | 2M pgs... | 4K pgs... | //
  73.     // +-----------+-----------+-----------+-----------+-----------+ //
  74.     // ↑           ↑           ↑           ↑           ↑           ↑ //
  75.     // |           |           |           |           |           | //
  76.     // 4K          2M          1G          1G          2M         4K //
  77.     // \------------------------ alignment ------------------------/ //
  78.     //                                                               //
  79.     //                                                               //
  80.     // A is phys_addr rounded down to a 4KB boundary                 //
  81.     // F is phys_addr + length rounded up to a 4KB boundary          //
  82.     // B is A rounded up to a 2MB boundary                           //
  83.     // C is B rounded up to a 1GB boundary                           //
  84.     // E is F rounded down to a 1MB boundary                         //
  85.     // D is E rounded down to a 1GB boundary                         //
  86.     //                                                               //
  87.     // r = B - A (4KB pages)                                         //
  88.     // s = C - B (2MB pages)                                         //
  89.     // t = D - C (1GB pages)                                         //
  90.     // u = E - D (2MB pages)                                         //
  91.     // v = F - E (4KB pages)                                         //
  92.     //                                                               //
  93.     // Usually, several regions are empty. When alignment permits,   //
  94.     // only the largest page sizes will be used. It starts as a      //
  95.     // single run of 4KB pages, then a run of 2MB regions is carved  //
  96.     // out of it, eliminating some or all 4KB runs, then a run of    //
  97.     // 1GB pages is carved out of it, eliminating some or all of the //
  98.     // 2MB runs                                                      //
  99.  
  100.     // It's impossible to use a 1GB mapping if the low 30 bits of the
  101.     // physical address and the linear address are not equal
  102.     bool can_use_1G = low_bits(phys_addr, 30) == low_bits(linear_base, 30);
  103.  
  104.     // It's impossible to use a 2MB mapping if the low 21 bits of the
  105.     // physical address and the linear address are not equal
  106.     bool can_use_2M = low_bits(phys_addr, 21) == low_bits(linear_base, 21);
  107.  
  108.     uint64_t phys_end = phys_addr + length;
  109.  
  110.     uint64_t A, B, C, D, E, F, X, Y;
  111.  
  112.     // Start with a simple run of 4KB pages
  113.     A = round_dn(phys_addr, 12);
  114.     F = round_up(phys_end, 12);
  115.     B = C = D = E = F;
  116.  
  117.     // Compute 2MB rounded boundaries for B,C/D/E
  118.     X = round_up(A, 21);
  119.     Y = round_dn(F, 21);
  120.  
  121.     if (X < Y && can_use_2M)
  122.     {
  123.         B = X;
  124.         C = D = E = Y;
  125.     }
  126.  
  127.     // Compute 1GB rounded boundaries for C,D
  128.     X = round_up(X, 30);
  129.     Y = round_dn(Y, 30);
  130.  
  131.     if (X < Y && can_use_1G)
  132.     {
  133.         C = X;
  134.         D = Y;
  135.     }
  136.  
  137.     int64_t r = B - A;  // 4KB
  138.     int64_t s = C - B;  // 2MB
  139.     int64_t t = D - C;  // 1GB
  140.     int64_t u = E - D;  // 2MB
  141.     int64_t v = F - E;  // 4KB
  142.  
  143.     int64_t phys_to_virt = linear_base - phys_addr;
  144.  
  145.     // 4KB page region
  146.     if (r > 0)
  147.         paging_map_physical_impl(A, A + phys_to_virt, r, pte_flags);
  148.  
  149.     // 2MB page region
  150.     if (s > 0)
  151.         paging_map_physical_impl(B, B + phys_to_virt, s, pte_flags);
  152.  
  153.     // 1GB page region
  154.     if (t > 0)
  155.         paging_map_physical_impl(C, C + phys_to_virt, t, pte_flags);
  156.  
  157.     // 2MB page region
  158.     if (u > 0)
  159.         paging_map_physical_impl(D, D + phys_to_virt, u, pte_flags);
  160.  
  161.     // 4KB page region
  162.     if (v > 0)
  163.         paging_map_physical_impl(E, E + phys_to_virt, v, pte_flags);
  164. }
  165.  
  166. void paging_map_physical_impl(uint64_t phys_addr, uint64_t linear_base,
  167.                               uint64_t length, uint64_t pte_flags)
  168. {
  169.     // Mask off bit 63:48
  170.     linear_base &= 0xFFFFFFFFFFFF;
  171.  
  172.     // Make sure the flags don't set any address bits
  173.     assert((pte_flags & PTE_ADDR) == 0);
  174.  
  175.     // Automatically infer the optimal page size
  176.     uint64_t page_size;
  177.     uint8_t log2_pagesize;
  178.  
  179.     // Try 1GB, 2MB, 4KB pages, select largest size that would work
  180.     page_size = 1 << 30;
  181.     for (log2_pagesize = 30; log2_pagesize > 12; log2_pagesize -= 9) {
  182.         // If the physical address, virtual address,
  183.         // and length are suitably aligned...
  184.         if ((phys_addr & -page_size) == phys_addr &&
  185.                 (linear_base & -page_size) == linear_base &&
  186.                 (length & -page_size) == length) {
  187.             // ...then use huge page
  188.  
  189.             // Move PAT bit over to PDPT/PD location
  190.             pte_flags |= (unsigned) (!!(pte_flags & PTE_PAGESIZE)) << PTE_PAT_BIT;
  191.  
  192.             // Set PSE bit
  193.             pte_flags |= PTE_PAGESIZE;
  194.  
  195.             break;
  196.         }
  197.  
  198.         // Try the next smaller page size
  199.         page_size >>= 9;
  200.     }
  201.  
  202.     // Make sure the parameters are feasible
  203.     assert((phys_addr & (page_size - 1)) == (linear_base & (page_size - 1)));
  204.  
  205.     // Page align and round length up to a multiple of the page size
  206.     size_t misalignment = linear_base & (page_size - 1);
  207.     linear_base -= misalignment;
  208.     phys_addr -= misalignment;
  209.     length += misalignment;
  210.     length = (length + page_size - 1) & -page_size;
  211.  
  212.     uint64_t end = linear_base + length;
  213.  
  214.     pte_t *pte = NULL;
  215.  
  216.     for (uint64_t vaddr = linear_base; vaddr < end; vaddr += page_size) {
  217.         // Calculate pte pointer at start
  218.         // or when transitioning to another table
  219.         if (!pte || ((vaddr & -(uint64_t)(1 << (log2_pagesize + 9))) == vaddr))
  220.             pte = paging_find_pte(vaddr, log2_pagesize, true);
  221.  
  222.         *pte++ = phys_addr | pte_flags;
  223.         phys_addr += page_size;
  224.     }
  225. }
  226.  
  227. uint32_t paging_root_addr()
  228. {
  229.     return (uintptr_t) new_pml4;
  230. }
  231.  
  232. // Returns true if the CPU supports that leaf
  233. // Hypervisor leaves are asinine and it always returns true for them
  234. bool cpuid__(cpuid_t *output, uint32_t eax, uint32_t ecx)
  235. {
  236.     // 0x4000xxxx (hypervisor) leaves are utterly ridiculous
  237.     if ((eax & 0xF0000000) != 0x40000000) {
  238.         // Automatically check for support for the leaf
  239.         if ((eax & 0x1FFFFFFF) != 0) {
  240.             cpuid__(output, eax & 0xE0000000U, 0);
  241.             if (output->eax < eax)
  242.                 return false;
  243.         }
  244.     }
  245.  
  246.     output->eax = eax;
  247.     output->ecx = ecx;
  248.     __asm__ __volatile__ (
  249.         "cpuid"
  250.         : "+a" (output->eax), "+c" (output->ecx)
  251.         , "=d" (output->edx), "=b" (output->ebx)
  252.         :
  253.         : "memory"
  254.     );
  255.  
  256.     return true;
  257. }
  258.  
  259. bool cpu_has_global_pages()
  260. {
  261.     static int has;
  262.  
  263.     if (has)
  264.         return has > 0;
  265.  
  266.     cpuid_t cpuinfo;
  267.     has = (cpuid__(&cpuinfo, 1U, 0) &&
  268.             (cpuinfo.edx & (1<<13)))
  269.             ? 1 : -1;
  270.  
  271.     return has > 0;
  272. }
  273.  
  274. static inline void cpu_page_directory_set(uintptr_t addr)
  275. {
  276.     __asm__ __volatile__ (
  277.         "movq %[addr],%%cr3\n\t"
  278.         :
  279.         : [addr] "r" (addr)
  280.         : "memory"
  281.     );
  282. }
  283.  
  284. // Incoming pte_flags should be as if 4KB page (bit 7 is PAT bit)
  285. void paging_map_physical(uint64_t phys_addr, uint64_t linear_base,
  286.                          uint64_t length, uint64_t pte_flags)
  287. {
  288.     if (unlikely(low_bits(phys_addr, 12) != low_bits(linear_base, 12)))
  289.     {
  290.         printf("ERROR: "
  291.                     "Impossible linear->physical mapping,"
  292.                     " bits 11:0 of the physical and linear address"
  293.                     " must be equal");
  294.         return;
  295.     }
  296.  
  297.     // -------------------------========---------------------------  //
  298.     //                                                               //
  299.     //                          4KB Only                             //
  300.     //                                                               //
  301.     //   <- phys_addr                        phys_addr + length ->   //
  302.     //   <- linear_base                                            B //
  303.     //                                                             C //
  304.     //                                                             D //
  305.     //                                                             E //
  306.     // A <------------------------ r ----------------------------> F //
  307.     // |                                                           | //
  308.     // | L                                                         | //
  309.     // | |                                                         | //
  310.     // ↓ ↓                                                         ↓ //
  311.     // +-----------------------------------------------------------+ //
  312.     // |                        4K pg ...                          | //
  313.     // +-----------------------------------------------------------+ //
  314.     // ↑                                                           ↑ //
  315.     // |                                                           | //
  316.     // 4K                                                         4K //
  317.     // \------------------------ alignment ------------------------/ //
  318.     //                                                               //
  319.     //                                                               //
  320.     // --------------------------=======---------------------------  //
  321.     //                                                               //
  322.     //                           4KB/2MB                             //
  323.     //                                                               //
  324.     // r_up(A,21) -↘                                   ↙- r_dn(F,21) //
  325.     //                                                 C             //
  326.     //             ↙                                   D             //
  327.     // A <-- r --> B <------------- s ---------------> E <-- v --> F //
  328.     // |           |                                   |           | //
  329.     // | L         |                                   |           | //
  330.     // | |         |                                   |           | //
  331.     // ↓ ↓         ↓                                   ↓           ↓ //
  332.     // +-----------+-----------------------------------+-----------+ //
  333.     // | 4K pg ... |             2M pg ...             | 4K pg ... | //
  334.     // +-----------+-----------------------------------+-----------+ //
  335.     // ↑           ↑                                   ↑           ↑ //
  336.     // |           |                                   |           | //
  337.     // 4K          2M                                  2M         4K //
  338.     // \------------------------ alignment ------------------------/ //
  339.     //                                                               //
  340.     //                                                               //
  341.     // ------------------------===========-------------------------  //
  342.     //                                                               //
  343.     //                         4KB/2MB/1GB                           //
  344.     //                                                               //
  345.     //                                                               //
  346.     //              r_up(B,30)-↘           ↙-r_dn(E,30)              //
  347.     //                         |           |                         //
  348.     // A <-- r --> B <-- s --> C <-- t --> D <-- u --> E <-- v --> F //
  349.     // |           |           |           |           |           | //
  350.     // | L         |           |           |           |           | //
  351.     // | |         |           |           |           |           | //
  352.     // ↓ ↓         ↓           ↓           ↓           ↓           ↓ //
  353.     // +-----------+-----------+-----------+-----------+-----------+ //
  354.     // | 4K pgs... | 2M pgs... | 1G pgs... | 2M pgs... | 4K pgs... | //
  355.     // +-----------+-----------+-----------+-----------+-----------+ //
  356.     // ↑           ↑           ↑           ↑           ↑           ↑ //
  357.     // |           |           |           |           |           | //
  358.     // 4K          2M          1G          1G          2M         4K //
  359.     // \------------------------ alignment ------------------------/ //
  360.     //                                                               //
  361.     //                                                               //
  362.     // A is phys_addr rounded down to a 4KB boundary                 //
  363.     // F is phys_addr + length rounded up to a 4KB boundary          //
  364.     // B is A rounded up to a 2MB boundary                           //
  365.     // C is B rounded up to a 1GB boundary                           //
  366.     // E is F rounded down to a 1MB boundary                         //
  367.     // D is E rounded down to a 1GB boundary                         //
  368.     //                                                               //
  369.     // r = B - A (4KB pages)                                         //
  370.     // s = C - B (2MB pages)                                         //
  371.     // t = D - C (1GB pages)                                         //
  372.     // u = E - D (2MB pages)                                         //
  373.     // v = F - E (4KB pages)                                         //
  374.     //                                                               //
  375.     // Usually, several regions are empty. When alignment permits,   //
  376.     // only the largest page sizes will be used. It starts as a      //
  377.     // single run of 4KB pages, then a run of 2MB regions is carved  //
  378.     // out of it, eliminating some or all 4KB runs, then a run of    //
  379.     // 1GB pages is carved out of it, eliminating some or all of the //
  380.     // 2MB runs                                                      //
  381.  
  382.     // It's impossible to use a 1GB mapping if the low 30 bits of the
  383.     // physical address and the linear address are not equal
  384.     bool can_use_1G = low_bits(phys_addr, 30) == low_bits(linear_base, 30);
  385.  
  386.     // It's impossible to use a 2MB mapping if the low 21 bits of the
  387.     // physical address and the linear address are not equal
  388.     bool can_use_2M = low_bits(phys_addr, 21) == low_bits(linear_base, 21);
  389.  
  390.     uint64_t phys_end = phys_addr + length;
  391.  
  392.     uint64_t A, B, C, D, E, F, X, Y;
  393.  
  394.     // Start with a simple run of 4KB pages
  395.     A = round_dn(phys_addr, 12);
  396.     F = round_up(phys_end, 12);
  397.     B = C = D = E = F;
  398.  
  399.     // Compute 2MB rounded boundaries for B,C/D/E
  400.     X = round_up(A, 21);
  401.     Y = round_dn(F, 21);
  402.  
  403.     if (X < Y && can_use_2M)
  404.     {
  405.         B = X;
  406.         C = D = E = Y;
  407.     }
  408.  
  409.     // Compute 1GB rounded boundaries for C,D
  410.     X = round_up(X, 30);
  411.     Y = round_dn(Y, 30);
  412.  
  413.     if (X < Y && can_use_1G)
  414.     {
  415.         C = X;
  416.         D = Y;
  417.     }
  418.  
  419.     int64_t r = B - A;  // 4KB
  420.     int64_t s = C - B;  // 2MB
  421.     int64_t t = D - C;  // 1GB
  422.     int64_t u = E - D;  // 2MB
  423.     int64_t v = F - E;  // 4KB
  424.  
  425.     int64_t phys_to_virt = linear_base - phys_addr;
  426.  
  427.     // 4KB page region
  428.     if (r > 0)
  429.         paging_map_physical_impl(A, A + phys_to_virt, r, pte_flags);
  430.  
  431.     // 2MB page region
  432.     if (s > 0)
  433.         paging_map_physical_impl(B, B + phys_to_virt, s, pte_flags);
  434.  
  435.     // 1GB page region
  436.     if (t > 0)
  437.         paging_map_physical_impl(C, C + phys_to_virt, t, pte_flags);
  438.  
  439.     // 2MB page region
  440.     if (u > 0)
  441.         paging_map_physical_impl(D, D + phys_to_virt, u, pte_flags);
  442.  
  443.     // 4KB page region
  444.     if (v > 0)
  445.         paging_map_physical_impl(E, E + phys_to_virt, v, pte_flags);
  446. }
  447.  
  448. void paging_map_physical_impl(uint64_t phys_addr, uint64_t linear_base,
  449.                               uint64_t length, uint64_t pte_flags)
  450. {
  451.     // Mask off bit 63:48
  452.     linear_base &= 0xFFFFFFFFFFFF;
  453.  
  454.     // Make sure the flags don't set any address bits
  455.     assert((pte_flags & PTE_ADDR) == 0);
  456.  
  457.     // Automatically infer the optimal page size
  458.     uint64_t page_size;
  459.     uint8_t log2_pagesize;
  460.  
  461.     // Try 1GB, 2MB, 4KB pages, select largest size that would work
  462.     page_size = 1 << 30;
  463.     for (log2_pagesize = 30; log2_pagesize > 12; log2_pagesize -= 9) {
  464.         // If the physical address, virtual address,
  465.         // and length are suitably aligned...
  466.         if ((phys_addr & -page_size) == phys_addr &&
  467.                 (linear_base & -page_size) == linear_base &&
  468.                 (length & -page_size) == length) {
  469.             // ...then use huge page
  470.  
  471.             // Move PAT bit over to PDPT/PD location
  472.             pte_flags |= (unsigned) (!!(pte_flags & PTE_PAGESIZE)) << PTE_PAT_BIT;
  473.  
  474.             // Set PSE bit
  475.             pte_flags |= PTE_PAGESIZE;
  476.  
  477.             break;
  478.         }
  479.  
  480.         // Try the next smaller page size
  481.         page_size >>= 9;
  482.     }
  483.  
  484.     // Make sure the parameters are feasible
  485.     assert((phys_addr & (page_size - 1)) == (linear_base & (page_size - 1)));
  486.  
  487.     // Page align and round length up to a multiple of the page size
  488.     size_t misalignment = linear_base & (page_size - 1);
  489.     linear_base -= misalignment;
  490.     phys_addr -= misalignment;
  491.     length += misalignment;
  492.     length = (length + page_size - 1) & -page_size;
  493.  
  494.     uint64_t end = linear_base + length;
  495.  
  496.     pte_t *pte = NULL;
  497.  
  498.     for (uint64_t vaddr = linear_base; vaddr < end; vaddr += page_size) {
  499.         // Calculate pte pointer at start
  500.         // or when transitioning to another table
  501.         if (!pte || ((vaddr & -(uint64_t)(1 << (log2_pagesize + 9))) == vaddr))
  502.             pte = paging_find_pte(vaddr, log2_pagesize, true);
  503.  
  504.         *pte++ = phys_addr | pte_flags;
  505.         phys_addr += page_size;
  506.     }
  507. }
  508.  
  509. uint32_t paging_root_addr()
  510. {
  511.     return (uintptr_t) new_pml4;
  512. }
  513.  
  514. // Returns true if the CPU supports that leaf
  515. // Hypervisor leaves are asinine and it always returns true for them
  516. bool cpuid__(cpuid_t *output, uint32_t eax, uint32_t ecx)
  517. {
  518.     // 0x4000xxxx (hypervisor) leaves are utterly ridiculous
  519.     if ((eax & 0xF0000000) != 0x40000000) {
  520.         // Automatically check for support for the leaf
  521.         if ((eax & 0x1FFFFFFF) != 0) {
  522.             cpuid__(output, eax & 0xE0000000U, 0);
  523.             if (output->eax < eax)
  524.                 return false;
  525.         }
  526.     }
  527.  
  528.     output->eax = eax;
  529.     output->ecx = ecx;
  530.     __asm__ __volatile__ (
  531.         "cpuid"
  532.         : "+a" (output->eax), "+c" (output->ecx)
  533.         , "=d" (output->edx), "=b" (output->ebx)
  534.         :
  535.         : "memory"
  536.     );
  537.  
  538.     return true;
  539. }
  540.  
  541. bool cpu_has_global_pages()
  542. {
  543.     static int has;
  544.  
  545.     if (has)
  546.         return has > 0;
  547.  
  548.     cpuid_t cpuinfo;
  549.     has = (cpuid__(&cpuinfo, 1U, 0) &&
  550.             (cpuinfo.edx & (1<<13)))
  551.             ? 1 : -1;
  552.  
  553.     return has > 0;
  554. }
  555.  
  556. static inline void cpu_page_directory_set(uintptr_t addr)
  557. {
  558.     __asm__ __volatile__ (
  559.         "movq %[addr],%%cr3\n\t"
  560.         :
  561.         : [addr] "r" (addr)
  562.         : "memory"
  563.     );
  564. }
  565.  
  566. void paging_init()
  567. {
  568.     paging_map_physical(framebuffer, 0xffffff8000000000ull, 4*boot_info.vres*boot_info.hres,
  569.                         PTE_PRESENT | PTE_WRITABLE |
  570.                         (-cpu_has_global_pages() & PTE_GLOBAL) |
  571.                         PTE_PCD | PTE_PWT);
  572.     cpu_page_directory_set(new_pml4);
  573.     framebuffer = 0xffffff8000000000ull;
  574. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement