Phân trang x86 hoạt động như thế nào?


91

Câu hỏi này nhằm lấp đầy khoảng trống thông tin miễn phí tốt về chủ đề này.

Tôi tin rằng một câu trả lời hay sẽ phù hợp với một câu trả lời SO lớn hoặc ít nhất là trong một vài câu trả lời.

Mục tiêu chính là cung cấp cho người mới bắt đầu đầy đủ thông tin vừa đủ để họ có thể tự mình thực hiện hướng dẫn sử dụng và có thể hiểu các khái niệm hệ điều hành cơ bản liên quan đến phân trang.

Nguyên tắc được đề xuất:

  • câu trả lời phải thân thiện với người mới bắt đầu:
    • các ví dụ cụ thể, nhưng có thể đơn giản hóa là rất quan trọng
    • ứng dụng của các khái niệm được hiển thị được hoan nghênh
  • trích dẫn các nguồn hữu ích là tốt
  • sự lạc đề nhỏ về cách hệ điều hành sử dụng các tính năng phân trang được hoan nghênh
  • Giải thích PAE và PSE được hoan nghênh
  • lạc đề nhỏ vào x86_64 được hoan nghênh

Các câu hỏi liên quan và tại sao tôi cho rằng chúng không phải là trò lừa đảo:


1
Điều này phải được gắn thẻ "faq" và được đánh dấu là "community-wiki".
Kerrek SB

@KerrekSB Tôi thực sự không biết cách trả lời những câu hỏi kiểu này. Câu trả lời nên được wiki cộng đồng là nó? Tôi không thể tìm thấy một faqthẻ.
Ciro Santilli 郝海东 冠状 病 六四 事件 法轮功

3
Tôi muốn nói câu trả lời ngắn gọn là, "đọc Tập 3, Chương 4: Phân trang trong Hướng dẫn sử dụng Intel". Nó khá rõ ràng, ngắn gọn và được viết tốt, và nó không có thẩm quyền hơn.
Kerrek SB

4
@KerrekSB Tôi đồng ý rằng hướng dẫn sử dụng rõ ràng và có thẩm quyền, nhưng nó hơi quá khắc nghiệt khi đọc lần đầu đối với tôi, tôi cần một số ví dụ đơn giản và cụ thể + cơ sở để hiểu mọi thứ tốt hơn.
Ciro Santilli 郝海东 冠状 病 六四 事件 法轮功

Câu trả lời:


144

Phiên bản của câu trả lời này với một TOC hay và nhiều nội dung hơn .

Tôi sẽ sửa chữa bất kỳ lỗi nào được báo cáo. Nếu bạn muốn thực hiện các sửa đổi lớn hoặc bổ sung một khía cạnh còn thiếu, hãy tự tạo chúng trên câu trả lời của riêng bạn để nhận được đại diện xứng đáng. Các chỉnh sửa nhỏ có thể được hợp nhất trực tiếp trong.

Mã mẫu

Ví dụ tối thiểu: https://github.com/cirosantilli/x86-bare-metal-examples/blob/5c672f73884a487414b3e21bd9e579c67cd77621/paging.S

Giống như mọi thứ khác trong lập trình, cách duy nhất để thực sự hiểu điều này là sử dụng các ví dụ tối thiểu.

Điều làm cho chủ đề này trở thành một chủ đề "khó" là ví dụ tối thiểu có dung lượng lớn vì bạn cần tạo một hệ điều hành nhỏ của riêng mình.

Hướng dẫn sử dụng Intel

Mặc dù không thể hiểu được nếu không có các ví dụ trong đầu, hãy cố gắng làm quen với sách hướng dẫn càng sớm càng tốt.

Intel mô tả phân trang trong Hướng dẫn lập trình hệ thống Tập 3 bằng tay Intel - 325384-056US Tháng 9 năm 2015 Chương 4 "Phân trang".

Đặc biệt thú vị là Hình 4-4 "Định dạng CR3 và các mục nhập cấu trúc phân trang với phân trang 32-bit", cung cấp các cấu trúc dữ liệu chính.

MMU

Phân trang được thực hiện bởi phần Đơn vị Quản lý Bộ nhớ (MMU) của CPU. Giống như nhiều người khác (ví dụ như bộ đồng xử lý x87 , APIC ), điều này từng là bởi chip riêng biệt vào những ngày đầu, sau này được tích hợp vào CPU. Nhưng thuật ngữ này vẫn được sử dụng.

Sự thật chung

Địa chỉ logic là địa chỉ bộ nhớ được sử dụng trong mã đất người dùng "thông thường" (ví dụ: nội dung của rsiin mov eax, [rsi]).

Phân đoạn đầu tiên chuyển chúng thành địa chỉ tuyến tính, sau đó phân trang sau đó chuyển địa chỉ tuyến tính thành địa chỉ vật lý.

(logical) ------------------> (linear) ------------> (physical)
             segmentation                 paging

Hầu hết thời gian, chúng ta có thể coi địa chỉ vật lý là lập chỉ mục các ô nhớ phần cứng RAM thực tế, nhưng điều này không đúng 100% vì:

Phân trang chỉ khả dụng ở chế độ được bảo vệ. Việc sử dụng phân trang trong chế độ được bảo vệ là tùy chọn. Phân trang được bật khi PGbit của thanh cr0ghi được thiết lập.

Phân trang so với phân đoạn

Một điểm khác biệt chính giữa phân trang và phân đoạn là:

  • phân trang chia RAM thành các phần có kích thước bằng nhau được gọi là trang
  • phân đoạn chia bộ nhớ thành nhiều phần có kích thước tùy ý

Đây là ưu điểm chính của phân trang, vì các phần có kích thước bằng nhau giúp mọi thứ dễ quản lý hơn.

Phân trang đã trở nên phổ biến hơn nhiều đến mức hỗ trợ phân đoạn đã bị loại bỏ trong x86-64 ở chế độ 64-bit, chế độ hoạt động chính của phần mềm mới, nơi nó chỉ tồn tại ở chế độ tương thích, mô phỏng IA32.

Ứng dụng

Phân trang được sử dụng để thực hiện các quy trình không gian địa chỉ ảo trên hệ điều hành hiện đại. Với các địa chỉ ảo, hệ điều hành có thể phù hợp với hai hoặc nhiều quy trình đồng thời trên một RAM theo cách:

  • cả hai chương trình không cần biết gì về chương trình kia
  • bộ nhớ của cả hai chương trình có thể phát triển và thu nhỏ khi cần thiết
  • chuyển đổi giữa các chương trình rất nhanh
  • một chương trình không bao giờ có thể truy cập bộ nhớ của quá trình khác

Lịch sử phân trang xuất hiện sau khi phân đoạn và phần lớn thay thế nó cho việc triển khai bộ nhớ ảo trong các hệ điều hành hiện đại như Linux vì dễ dàng quản lý các phần bộ nhớ có kích thước cố định của các trang thay vì các phân đoạn có độ dài thay đổi.

Triển khai phần cứng

Giống như phân đoạn trong chế độ được bảo vệ (trong đó việc sửa đổi thanh ghi phân đoạn sẽ kích hoạt tải từ GDT hoặc LDT), phần cứng phân trang sử dụng cấu trúc dữ liệu trong bộ nhớ để thực hiện công việc của nó (bảng trang, thư mục trang, v.v.).

Định dạng của các cấu trúc dữ liệu đó là do phần cứng cố định , nhưng việc thiết lập và quản lý các cấu trúc dữ liệu đó trên RAM một cách chính xác là tùy thuộc vào HĐH, đồng thời cho phần cứng biết nơi tìm chúng (thông qua cr3).

Một số kiến ​​trúc khác để phân trang gần như hoàn toàn trong tay phần mềm, do đó, TLB bỏ lỡ chạy một chức năng do hệ điều hành cung cấp để xem các bảng trang và chèn ánh xạ mới vào TLB. Điều này khiến các định dạng bảng trang được chọn bởi HĐH, nhưng khiến phần cứng khó có thể chồng chéo các lần xem trang với việc thực thi không theo thứ tự các hướng dẫn khác, theo cách mà x86 có thể làm .

Ví dụ: lược đồ phân trang cấp một đơn giản

Đây là một ví dụ về cách phân trang hoạt động trên phiên bản đơn giản hóa của kiến ​​trúc x86 để triển khai không gian bộ nhớ ảo.

Bảng trang

Hệ điều hành có thể cung cấp cho họ các bảng trang sau:

Bảng trang được OS cung cấp cho quy trình 1:

RAM location        physical address   present
-----------------   -----------------  --------
PT1 + 0       * L   0x00001            1
PT1 + 1       * L   0x00000            1
PT1 + 2       * L   0x00003            1
PT1 + 3       * L                      0
...                                    ...
PT1 + 0xFFFFF * L   0x00005            1

Bảng trang được hệ điều hành cung cấp cho quy trình 2:

RAM location       physical address   present
-----------------  -----------------  --------
PT2 + 0       * L  0x0000A            1
PT2 + 1       * L  0x0000B            1
PT2 + 2       * L                     0
PT2 + 3       * L  0x00003            1
...                ...                ...
PT2 + 0xFFFFF * L  0x00004            1

Ở đâu:

  • PT1PT2: vị trí ban đầu của bảng 1 và 2 trên RAM.

    Giá trị mẫu: 0x00000000, 0x12345678vv

    Chính HĐH quyết định những giá trị đó.

  • L: độ dài của mục nhập bảng trang.

  • present: cho biết rằng trang đó có trong bộ nhớ.

Bảng trang nằm trên RAM. Ví dụ, chúng có thể được đặt dưới dạng:

--------------> 0xFFFFFFFF


--------------> PT1 + 0xFFFFF * L
Page Table 1
--------------> PT1


--------------> PT2 + 0xFFFFF * L
Page Table 2
--------------> PT2

--------------> 0x0

Các vị trí ban đầu trên RAM cho cả hai bảng trang là tùy ý và được kiểm soát bởi Hệ điều hành. Đó là tùy thuộc vào hệ điều hành để đảm bảo rằng chúng không trùng lặp!

Mỗi quy trình không thể chạm trực tiếp vào bất kỳ bảng trang nào, mặc dù nó có thể đưa ra các yêu cầu tới HĐH khiến bảng trang được sửa đổi, ví dụ như yêu cầu phân đoạn ngăn xếp hoặc đống lớn hơn.

Một trang là một đoạn 4KB (12 bit) và vì địa chỉ có 32 bit nên chỉ cần 20 bit (20 + 12 = 32, do đó 5 ký tự trong ký hiệu thập lục phân) được yêu cầu để xác định mỗi trang. Giá trị này được cố định bởi phần cứng.

Mục nhập bảng trang

Một bảng trang là ... một bảng các mục trong bảng!

Định dạng chính xác của các mục trong bảng được cố định bởi phần cứng .

Trong ví dụ đơn giản này, các mục nhập bảng trang chỉ chứa hai trường:

bits   function
-----  -----------------------------------------
20     physical address of the start of the page
1      present flag

vì vậy trong ví dụ này, các nhà thiết kế phần cứng có thể đã chọn L = 21.

Hầu hết các mục trong bảng trang thực đều có các trường khác.

Sẽ là không thực tế nếu căn chỉnh mọi thứ ở 21 bit vì bộ nhớ có thể định địa chỉ theo byte chứ không phải bit. Do đó, ngay cả khi chỉ cần 21 bit trong trường hợp này, các nhà thiết kế phần cứng có thể sẽ chọn L = 32cách làm cho việc truy cập nhanh hơn và chỉ dự trữ các bit còn lại để sử dụng sau này. Giá trị thực cho Ltrên x86 là 32 bit.

Dịch địa chỉ trong lược đồ cấp đơn

Sau khi hệ điều hành thiết lập các bảng trang, việc dịch địa chỉ giữa địa chỉ tuyến tính và địa chỉ vật lý được thực hiện bởi phần cứng .

Khi hệ điều hành muốn kích hoạt quá trình 1, nó đặt cr3để PT1, sự bắt đầu của bảng cho quá trình một.

Nếu Quy trình 1 muốn truy cập địa chỉ tuyến tính 0x00000001, mạch phần cứng phân trang sẽ tự động thực hiện những việc sau đối với Hệ điều hành:

  • chia địa chỉ tuyến tính thành hai phần:

    | page (20 bits) | offset (12 bits) |
    

    Vì vậy, trong trường hợp này, chúng tôi sẽ có:

    • trang = 0x00000
    • bù đắp = 0x001
  • nhìn vào bảng Trang 1 vì cr3chỉ vào nó.

  • nhìn mục nhập 0x00000vì đó là phần trang.

    Phần cứng biết rằng mục này nằm ở địa chỉ RAM PT1 + 0 * L = PT1.

  • kể từ khi nó hiện diện, quyền truy cập hợp lệ

  • bởi bảng trang, vị trí của số trang 0x00000là tại 0x00001 * 4K = 0x00001000.

  • để tìm địa chỉ thực cuối cùng, chúng ta chỉ cần thêm phần bù:

      00001 000
    + 00000 001
      -----------
      00001 001
    

    00001là địa chỉ vật lý của trang được tra cứu trên bảng và 001là phần bù.

    Như tên cho biết, phần bù luôn được thêm vào địa chỉ vật lý của trang.

  • sau đó phần cứng nhận bộ nhớ tại vị trí thực đó.

Theo cách tương tự, các bản dịch sau sẽ xảy ra cho quy trình 1:

linear     physical
---------  ---------
00000 002  00001 002
00000 003  00001 003
00000 FFF  00001 FFF
00001 000  00000 000
00001 001  00000 001
00001 FFF  00000 FFF
00002 000  00002 000
FFFFF 000  00005 000

Ví dụ, khi truy cập địa chỉ 00001000, phần trang là 00001phần cứng biết rằng mục nhập bảng trang của nó nằm ở địa chỉ RAM: PT1 + 1 * L( 1vì phần trang), và đó là nơi nó sẽ tìm kiếm.

Khi HĐH muốn chuyển sang tiến trình 2, tất cả những gì nó cần làm là chuyển cr3sang trang 2. Đơn giản vậy thôi!

Bây giờ các bản dịch sau sẽ xảy ra cho quy trình 2:

linear     physical
---------  ---------
00000 002  00001 002
00000 003  00001 003
00000 FFF  00001 FFF
00001 000  00000 000
00001 001  00000 001
00001 FFF  00000 FFF
00003 000  00003 000
FFFFF 000  00004 000

Cùng một địa chỉ tuyến tính chuyển thành các địa chỉ vật lý khác nhau cho các quá trình khác nhau , chỉ phụ thuộc vào giá trị bên trong cr3.

Bằng cách này, mọi chương trình có thể mong đợi dữ liệu của nó bắt đầu 0và kết thúc tại FFFFFFFF, mà không cần lo lắng về địa chỉ vật lý chính xác.

Lỗi trang

Điều gì sẽ xảy ra nếu Quy trình 1 cố gắng truy cập một địa chỉ bên trong một trang không có?

Phần cứng thông báo cho phần mềm thông qua một Ngoại lệ Lỗi Trang.

Sau đó, hệ điều hành thường phải đăng ký một trình xử lý ngoại lệ để quyết định những gì phải được thực hiện.

Có thể việc truy cập một trang không có trên bảng là lỗi lập trình:

int is[1];
is[2] = 1;

nhưng có thể có những trường hợp được chấp nhận, ví dụ như trong Linux khi:

  • chương trình muốn tăng ngăn xếp của nó.

    Nó chỉ cố gắng truy cập một byte nhất định trong một phạm vi nhất định có thể, và nếu hệ điều hành hài lòng, nó sẽ thêm trang đó vào không gian địa chỉ quy trình.

  • trang đã được đổi sang đĩa.

    Hệ điều hành sẽ cần thực hiện một số công việc đằng sau các quy trình để đưa trang trở lại RAM.

    Hệ điều hành có thể phát hiện ra rằng đây là trường hợp dựa trên nội dung của phần còn lại của mục nhập bảng trang, vì nếu cờ hiện tại rõ ràng, các mục nhập khác của mục nhập bảng trang hoàn toàn được để lại cho Hệ điều hành theo ý muốn.

    Ví dụ trên Linux, khi hiện tại = 0:

    • nếu tất cả các trường của mục nhập bảng trang là 0, địa chỉ không hợp lệ.

    • khác, trang đã được hoán đổi sang đĩa và giá trị thực của các trường đó mã hóa vị trí của trang trên đĩa.

Trong mọi trường hợp, Hệ điều hành cần biết địa chỉ nào đã tạo ra Lỗi trang để có thể xử lý sự cố. Đây là lý do tại sao các nhà phát triển IA32 tốt bụng đặt giá trị của cr2địa chỉ đó bất cứ khi nào xảy ra Lỗi trang. Sau đó, trình xử lý ngoại lệ có thể chỉ cần xem xét cr2để lấy địa chỉ.

Đơn giản hóa

Đơn giản hóa thực tế giúp ví dụ này dễ hiểu hơn:

  • tất cả các mạch phân trang thực sử dụng phân trang nhiều cấp để tiết kiệm không gian, nhưng điều này cho thấy một sơ đồ đơn cấp đơn giản.

  • bảng trang chỉ chứa hai trường: địa chỉ 20 bit và cờ hiện tại 1 bit.

    Bảng trang thực có tổng cộng 12 trường và do đó các tính năng khác đã bị bỏ qua.

Ví dụ: lược đồ phân trang nhiều cấp

Vấn đề với sơ đồ phân trang mức đơn là nó sẽ chiếm quá nhiều RAM: 4G / 4K = 1M mục nhập cho mỗi quá trình. Nếu mỗi mục nhập dài 4 byte, điều đó sẽ tạo ra 4M cho mỗi quá trình , quá nhiều ngay cả đối với máy tính để bàn: ps -A | wc -lnói rằng tôi đang chạy 244 quy trình ngay bây giờ, vì vậy sẽ chiếm khoảng 1GB RAM của tôi!

Vì lý do này, các nhà phát triển x86 đã quyết định sử dụng lược đồ đa cấp để giảm mức sử dụng RAM.

Nhược điểm của hệ thống này là có thời gian truy cập hơi cao.

Trong sơ đồ phân trang 3 cấp đơn giản được sử dụng cho bộ xử lý 32 bit không có PAE, 32 bit địa chỉ được chia như sau:

| directory (10 bits) | table (10 bits) | offset (12 bits) |

Mỗi quy trình phải có một và chỉ một thư mục trang được liên kết với nó, do đó, nó sẽ chứa ít nhất 2^10 = 1Kcác mục nhập thư mục trang, tốt hơn nhiều so với 1M tối thiểu được yêu cầu trên một sơ đồ cấp đơn.

Bảng trang chỉ được cấp phát khi cần thiết bởi Hệ điều hành. Mỗi bảng 2^10 = 1Ktrang có các mục nhập thư mục trang

Thư mục trang chứa ... mục thư mục trang! Các mục nhập thư mục trang giống như mục nhập bảng trang ngoại trừ việc chúng trỏ đến địa chỉ RAM của bảng trang thay vì địa chỉ vật lý của bảng . Vì các địa chỉ đó chỉ rộng 20 bit, các bảng trang phải ở đầu các trang 4KB.

cr3 bây giờ trỏ đến vị trí trên RAM của thư mục trang của tiến trình hiện tại thay vì bảng trang.

Các mục nhập của bảng trang hoàn toàn không thay đổi so với lược đồ một cấp.

Bảng trang thay đổi so với lược đồ cấp đơn vì:

  • mỗi quy trình có thể có tới 1K bảng trang, một mục nhập thư mục trên mỗi trang.
  • mỗi bảng trang chứa đúng 1K mục nhập thay vì 1 triệu mục nhập.

Lý do sử dụng 10 bit ở hai cấp độ đầu tiên (và không phải, chẳng hạn 12 | 8 | 12) là mỗi mục nhập Bảng trang dài 4 byte. Sau đó, 2 ^ 10 mục nhập của thư mục Trang và Bảng Trang sẽ vừa khít với các trang 4Kb. Điều này có nghĩa là việc phân bổ và phân bổ các trang cho mục đích đó nhanh hơn và đơn giản hơn.

Dịch địa chỉ trong lược đồ nhiều cấp

Thư mục trang được hệ điều hành cung cấp cho quy trình 1:

RAM location     physical address   present
---------------  -----------------  --------
PD1 + 0     * L  0x10000            1
PD1 + 1     * L                     0
PD1 + 2     * L  0x80000            1
PD1 + 3     * L                     0
...                                 ...
PD1 + 0x3FF * L                     0

Bảng trang được HĐH cung cấp cho quá trình 1 ở PT1 = 0x10000000( 0x10000* 4K):

RAM location      physical address   present
---------------   -----------------  --------
PT1 + 0     * L   0x00001            1
PT1 + 1     * L                      0
PT1 + 2     * L   0x0000D            1
...                                  ...
PT1 + 0x3FF * L   0x00005            1

Bảng trang được HĐH cung cấp cho quá trình 1 ở PT2 = 0x80000000( 0x80000* 4K):

RAM location      physical address   present
---------------   -----------------  --------
PT2 + 0     * L   0x0000A            1
PT2 + 1     * L   0x0000C            1
PT2 + 2     * L                      0
...                                  ...
PT2 + 0x3FF * L   0x00003            1

Ở đâu:

  • PD1: vị trí ban đầu của thư mục trang của tiến trình 1 trên RAM.
  • PT1PT2: vị trí ban đầu của bảng trang 1 và bảng trang 2 cho tiến trình 1 trên RAM.

Vì vậy, trong ví dụ này, thư mục trang và bảng trang có thể được lưu trữ trong RAM như sau:

----------------> 0xFFFFFFFF


----------------> PT2 + 0x3FF * L
Page Table 1
----------------> PT2

----------------> PD1 + 0x3FF * L
Page Directory 1
----------------> PD1


----------------> PT1 + 0x3FF * L
Page Table 2
----------------> PT1

----------------> 0x0

Hãy dịch địa chỉ tuyến tính 0x00801004từng bước.

Chúng tôi cho rằng cr3 = PD1, nghĩa là nó trỏ đến thư mục trang vừa được mô tả.

Trong hệ nhị phân, địa chỉ tuyến tính là:

0    0    8    0    1    0    0    4
0000 0000 1000 0000 0001 0000 0000 0100

Phân nhóm như 10 | 10 | 12cho:

0000000010 0000000001 000000000100
0x2        0x1        0x4

mang lại:

  • mục nhập thư mục trang = 0x2
  • mục nhập bảng trang = 0x1
  • bù đắp = 0x4

Vì vậy, phần cứng sẽ tìm mục nhập 2 của thư mục trang.

Bảng thư mục trang cho biết rằng bảng trang được đặt tại 0x80000 * 4K = 0x80000000. Đây là lần truy cập RAM đầu tiên của quá trình.

Vì là mục nhập bảng trang 0x1, nên phần cứng sẽ nhìn vào mục nhập 1 của bảng trang 0x80000000, điều này cho nó biết rằng trang vật lý được đặt tại địa chỉ 0x0000C * 4K = 0x0000C000. Đây là lần truy cập RAM thứ hai của quá trình.

Cuối cùng, phần cứng phân trang thêm phần bù vào và địa chỉ cuối cùng là 0x0000C004.

Các ví dụ khác về địa chỉ đã dịch là:

linear    10 10 12 split   physical
--------  ---------------  ----------
00000001  000 000 001      00001001
00001001  000 001 001      page fault
003FF001  000 3FF 001      00005001
00400000  001 000 000      page fault
00800001  002 000 001      0000A001
00801008  002 001 008      0000C008
00802008  002 002 008      page fault
00B00001  003 000 000      page fault

Lỗi trang xảy ra nếu mục nhập thư mục trang hoặc mục nhập bảng trang không có.

Nếu hệ điều hành muốn chạy một quá trình khác đồng thời, nó sẽ cung cấp cho quá trình thứ hai một thư mục trang riêng biệt và liên kết thư mục đó với các bảng trang riêng biệt.

Kiến trúc 64-bit

64 bit vẫn còn quá nhiều địa chỉ cho kích thước RAM hiện tại, vì vậy hầu hết các kiến ​​trúc sẽ sử dụng ít bit hơn.

x86_64 sử dụng 48 bit (256 TiB) và PAE của chế độ kế thừa đã cho phép địa chỉ 52 bit (4 PiB).

12 trong số 48 bit đó đã được dành riêng cho phần bù, còn lại 36 bit.

Nếu phương pháp tiếp cận 2 mức được thực hiện, sự phân chia tốt nhất sẽ là hai mức 18 bit.

Nhưng điều đó có nghĩa là thư 2^18 = 256Kmục trang sẽ có các mục nhập, sẽ chiếm quá nhiều RAM: gần bằng phân trang mức đơn cho các kiến ​​trúc 32 bit!

Do đó, kiến ​​trúc 64 bit tạo ra các cấp trang thậm chí còn xa hơn, thường là 3 hoặc 4.

x86_64 sử dụng 4 cấp trong một 9 | 9 | 9 | 12lược đồ, do đó cấp trên chỉ chiếm 2^9các mục nhập cấp cao hơn.

PAE

Phần mở rộng địa chỉ thực.

Với 32 bit, chỉ có 4GB RAM có thể được giải quyết.

Điều này bắt đầu trở thành một hạn chế đối với các máy chủ lớn, vì vậy Intel đã giới thiệu cơ chế PAE cho Pentium Pro.

Để giải quyết vấn đề, Intel đã thêm 4 dòng địa chỉ mới, để 64GB có thể được giải quyết.

Cấu trúc bảng trang cũng bị thay đổi nếu bật PAE. Cách chính xác mà nó được thay đổi phụ thuộc vào việc PSE đang bật hay tắt.

PAE được bật và tắt thông qua PAEbit cr4.

Ngay cả khi tổng bộ nhớ địa chỉ là 64GB, quá trình cá nhân vẫn chỉ có thể sử dụng tối đa 4GB. Tuy nhiên, hệ điều hành có thể đặt các quy trình khác nhau trên các khối 4GB khác nhau.

PSE

Phần mở rộng kích thước trang.

Cho phép các trang có độ dài 4M (hoặc 2M nếu bật PAE) thay vì 4K.

PSE được bật và tắt thông qua PAEbit cr4.

Lược đồ bảng trang PAE và PSE

Nếu PAE và PSE đang hoạt động, các lược đồ mức phân trang khác nhau sẽ được sử dụng:

  • không có PAE và không có PSE: 10 | 10 | 12

  • không PAE và PSE: 10 | 22.

    22 là độ lệch trong trang 4Mb, vì 22 bit địa chỉ 4Mb.

  • PAE và không có PSE: 2 | 9 | 9 | 12

    Lý do thiết kế tại sao 9 được sử dụng hai lần thay vì 10 là bây giờ các mục nhập không thể phù hợp với 32 bit nữa, tất cả đã được lấp đầy bởi 20 bit địa chỉ và 12 bit cờ có nghĩa hoặc dành riêng.

    Lý do là 20 bit không còn đủ để biểu diễn địa chỉ của các bảng trang: 24 bit bây giờ là cần thiết do có thêm 4 dây dẫn vào bộ xử lý.

    Do đó, các nhà thiết kế quyết định tăng kích thước mục nhập lên 64 bit, và để làm cho chúng vừa với một bảng trang duy nhất, cần giảm số mục nhập xuống 2 ^ 9 thay vì 2 ^ 10.

    Cấp độ thứ 2 bắt đầu là cấp độ Trang mới được gọi là Bảng con trỏ thư mục trang (PDPT), vì nó trỏ đến các thư mục trang và điền vào địa chỉ tuyến tính 32 bit. PDPT cũng rộng 64 bit.

    cr3bây giờ trỏ đến các PDPT phải có trên bốn 4GB bộ nhớ và được căn chỉnh trên bội số 32 bit để xử lý hiệu quả. Điều này có nghĩa là bây giờ cr3có 27 bit có ý nghĩa thay vì 20: 2 ^ 5 cho 32 bội số * 2 ^ 27 để hoàn thành 2 ^ 32 của 4GB đầu tiên.

  • PAE và PSE: 2 | 9 | 21

    Các nhà thiết kế quyết định giữ một trường rộng 9 bit để làm cho nó vừa với một trang duy nhất.

    Điều này để lại 23 bit. Để lại 2 cho PDPT để giữ mọi thứ đồng nhất với trường hợp PAE mà không có PSE để lại 21 cho bù đắp, có nghĩa là các trang có chiều rộng 2M thay vì 4M.

TLB

Bộ đệm tìm kiếm bản dịch (TLB) là một bộ đệm cho các địa chỉ phân trang.

Vì nó là một bộ nhớ cache, nó chia sẻ nhiều vấn đề về thiết kế của bộ nhớ cache CPU, chẳng hạn như mức độ liên kết.

Phần này sẽ mô tả một TLB kết hợp đầy đủ được đơn giản hóa với 4 mục nhập địa chỉ duy nhất. Lưu ý rằng giống như các bộ nhớ đệm khác, TLB thực thường không liên kết hoàn toàn.

Hoạt động cơ bản

Sau khi dịch giữa địa chỉ tuyến tính và địa chỉ vật lý xảy ra, nó được lưu trữ trên TLB. Ví dụ: TLB 4 mục bắt đầu ở trạng thái sau:

  valid   linear   physical
  ------  -------  ---------
> 0       00000    00000
  0       00000    00000
  0       00000    00000
  0       00000    00000

Dấu >chỉ mục nhập hiện tại sẽ được thay thế.

và sau khi địa chỉ tuyến tính của trang 00003được dịch sang địa chỉ thực 00005, TLB sẽ trở thành:

  valid   linear   physical
  ------  -------  ---------
  1       00003    00005
> 0       00000    00000
  0       00000    00000
  0       00000    00000

và sau khi một bản dịch thứ hai của 00007để 00009nó trở thành:

  valid   linear   physical
  ------  -------  ---------
  1       00003    00005
  1       00007    00009
> 0       00000    00000
  0       00000    00000

Bây giờ nếu 00003cần được dịch lại, trước tiên phần cứng sẽ tra cứu TLB và tìm ra địa chỉ của nó bằng một quyền truy cập RAM duy nhất 00003 --> 00005.

Tất nhiên, 00000không có trên TLB vì không có mục nhập hợp lệ nào chứa 00000làm khóa.

Chính sách thay thế

Khi TLB được lấp đầy, các địa chỉ cũ hơn sẽ bị ghi đè. Cũng giống như đối với bộ nhớ cache của CPU, chính sách thay thế là một hoạt động có khả năng phức tạp, nhưng một phương pháp đơn giản và hợp lý là loại bỏ mục nhập ít được sử dụng gần đây nhất (LRU).

Với LRU, bắt đầu từ trạng thái:

  valid   linear   physical
  ------  -------  ---------
> 1       00003    00005
  1       00007    00009
  1       00009    00001
  1       0000B    00003

thêm vào 0000D -> 0000Asẽ cho:

  valid   linear   physical
  ------  -------  ---------
  1       0000D    0000A
> 1       00007    00009
  1       00009    00001
  1       0000B    00003

CAM

Sử dụng TLB giúp dịch nhanh hơn, vì bản dịch ban đầu có một quyền truy cập cho mỗi cấp TLB , nghĩa là 2 trên sơ đồ 32 bit đơn giản, nhưng 3 hoặc 4 trên kiến ​​trúc 64 bit.

TLB thường được thực hiện dưới dạng một loại RAM đắt tiền được gọi là bộ nhớ địa chỉ theo nội dung (CAM). CAM thực hiện một bản đồ liên kết trên phần cứng, nghĩa là, một cấu trúc đã cho một khóa (địa chỉ tuyến tính), truy xuất một giá trị.

Ánh xạ cũng có thể được thực hiện trên địa chỉ RAM, nhưng ánh xạ CAM có thể yêu cầu ít mục nhập hơn nhiều so với ánh xạ RAM.

Ví dụ, một bản đồ trong đó:

  • cả khóa và giá trị đều có 20 bit (trường hợp của lược đồ phân trang đơn giản)
  • nhiều nhất 4 giá trị cần được lưu trữ tại mỗi thời điểm

có thể được lưu trữ trong một TLB với 4 mục nhập:

linear   physical
-------  ---------
00000    00001
00001    00010
00010    00011
FFFFF    00000

Tuy nhiên, để thực hiện điều này với RAM, cần phải có 2 ^ 20 địa chỉ :

linear   physical
-------  ---------
00000    00001
00001    00010
00010    00011
... (from 00011 to FFFFE)
FFFFF    00000

thậm chí còn đắt hơn sử dụng TLB.

Mục nhập không hợp lệ

Khi cr3thay đổi, tất cả các mục nhập TLB đều bị vô hiệu, vì một bảng trang mới cho một quy trình mới sẽ được sử dụng, vì vậy không chắc rằng bất kỳ mục nhập cũ nào có bất kỳ ý nghĩa nào.

X86 cũng cung cấp invlpghướng dẫn làm mất hiệu lực rõ ràng một mục nhập TLB. Các kiến ​​trúc khác cung cấp nhiều hướng dẫn hơn cho các mục nhập TLB đã bị vô hiệu, chẳng hạn như làm vô hiệu tất cả các mục nhập trên một phạm vi nhất định.

Một số CPU x86 vượt ra ngoài các yêu cầu của đặc tả x86 và cung cấp tính chặt chẽ hơn những gì nó đảm bảo, giữa việc sửa đổi mục nhập bảng trang và sử dụng nó, khi nó chưa được lưu trong bộ nhớ cache trong TLB . Rõ ràng Windows 9x đã dựa vào điều đó để xác định tính chính xác, nhưng các CPU AMD hiện đại không cung cấp các bước chuyển trang mạch lạc. CPU Intel làm được, mặc dù họ phải phát hiện ra những suy đoán sai để làm như vậy. Lợi dụng điều này có lẽ là một ý tưởng tồi, vì có lẽ không thu được gì nhiều và có nguy cơ lớn gây ra các vấn đề nhạy cảm về thời gian mà khó có thể gỡ rối.

Sử dụng nhân Linux

Nhân Linux sử dụng rộng rãi các tính năng phân trang của x86 để cho phép chuyển đổi quy trình nhanh với phân mảnh dữ liệu nhỏ.

Trong v4.2, hãy xem dưới arch/x86/:

  • include/asm/pgtable*
  • include/asm/page*
  • mm/pgtable*
  • mm/page*

Dường như không có cấu trúc nào được xác định để đại diện cho các trang, chỉ có macro: include/asm/page_types.hđặc biệt thú vị. Trích:

#define _PAGE_BIT_PRESENT   0   /* is present */
#define _PAGE_BIT_RW        1   /* writeable */
#define _PAGE_BIT_USER      2   /* userspace addressable */
#define _PAGE_BIT_PWT       3   /* page write through */

arch/x86/include/uapi/asm/processor-flags.hxác định CR0, và đặc biệt là PGvị trí bit:

#define X86_CR0_PG_BIT      31 /* Paging */

Thư mục

Miễn phí:

  • rutgers-pxk-416 chương "Quản lý bộ nhớ: ghi chú bài giảng"

    Đánh giá lịch sử tốt về các kỹ thuật tổ chức bộ nhớ được sử dụng bởi hệ điều hành cũ.

Không tự do:

  • bovet05 chương "Định địa chỉ bộ nhớ"

    Giới thiệu hợp lý về địa chỉ bộ nhớ x86. Thiếu một số ví dụ hay và đơn giản.


Câu trả lời tuyệt vời, nhưng tôi vẫn chưa rõ về cách LRU được quyết định. Gọi OS mỗi khi truy cập một trang không phải MRU có vẻ tốn kém. Ngoài ra, tôi có thể thấy phần cứng sắp xếp lại bảng trang cho LRU, điều này có thể gây nguy hiểm cho các chương trình đồng thời. Một trong hai điều này có đúng không? Làm thế nào hệ điều hành biết trang nào là LRU khi xảy ra lỗi trang?
Keynan

@Keynan Tôi nghĩ đó là phần cứng làm điều đó, vì vậy thời gian thực hiện không phải là mối quan tâm. Đối với đồng thời, tôi không biết nó được quản lý như thế nào. Tôi nghĩ rằng có một CR3 và bộ nhớ cache cho mỗi bộ xử lý và hệ điều hành chỉ phải đảm bảo rằng các trang bộ nhớ không chồng chéo.
Ciro Santilli 郝海东 冠状 病 六四 事件 法轮功

1
real TLBs are not usually fully associativeThe TLB is usually implemented as … CAMHai câu này không mâu thuẫn nhau sao?
a3f

>>> x86_64 sử dụng 4 cấp trong một 9 | 9 | 9 | Sơ đồ 12 nó phải là 9 | 9 | 9 | 9 | 12?
Monlof

@monklof Tôi nghĩ điều này là chính xác: 9 9 9 12 đã cho phép 512gb RAM. Lược đồ 5 cấp là một sự phát triển gần đây hơn chỉ nhằm vào máy chủ, điều này được đề cập trong câu trả lời trong trang web của tôi, nó cập nhật hơn.
Ciro Santilli 郝海东 冠状 病 六四 事件 法轮功

22

Đây là một câu trả lời rất ngắn gọn, cấp cao:

Bộ xử lý x86 hoạt động ở một trong số các chế độ có thể có (khoảng: thực, được bảo vệ, 64-bit). Mỗi chế độ có thể sử dụng một trong số các mô hình địa chỉ bộ nhớ có thể có (nhưng không phải chế độ nào cũng có thể sử dụng mọi mô hình), đó là: định địa chỉ chế độ thực, định địa chỉ phân đoạn và định địa chỉ tuyến tính phẳng.

Trong thế giới hiện đại, chỉ địa chỉ tuyến tính phẳng ở chế độ được bảo vệ hoặc chế độ 64 bit là phù hợp và hai chế độ này về cơ bản giống nhau, với sự khác biệt chính là kích thước của từ máy và do đó là dung lượng bộ nhớ có thể định địa chỉ.

Bây giờ, chế độ định địa chỉ bộ nhớ cung cấp ý nghĩa cho các toán hạng bộ nhớ của các lệnh máy (chẳng hạn như mov DWORD PTR [eax], 25lưu trữ dwordsố nguyên 32-bit (hay còn gọi là ) giá trị 25 vào bộ nhớ có địa chỉ được lưu trong thanh ghi eax32-bit). Trong địa chỉ tuyến tính phẳng, số này trong eaxđược phép chạy trên một phạm vi liền kề, từ 0 đến giá trị lớn nhất (trong trường hợp của chúng tôi là 2 32  - 1).

Tuy nhiên, địa chỉ tuyến tính phẳng có thể được phân trang hoặc không phân trang . Không phân trang, địa chỉ trực tiếp tham chiếu đến bộ nhớ vật lý. Với phân trang, đơn vị quản lý bộ nhớ của bộ xử lý (hoặc MMU) sẽ cung cấp một cách minh bạch địa chỉ mong muốn (bây giờ được gọi là địa chỉ ảo ) vào cơ chế tra cứu, cái gọi là bảng trang và nhận được một giá trị mới, được hiểu là địa chỉ vật lý. Hoạt động ban đầu hiện hoạt động trên địa chỉ mới đã được dịch này trong bộ nhớ vật lý, mặc dù người dùng chỉ nhìn thấy địa chỉ ảo.

Lợi ích chính của phân trang là các bảng trang được quản lý bởi hệ điều hành. Do đó hệ điều hành có thể sửa đổi và thay thế các bảng trang một cách tùy ý, chẳng hạn như khi "chuyển đổi nhiệm vụ". Nó có thể giữ toàn bộ bộ sưu tập các bảng trang, một bảng cho mỗi "quy trình" và bất cứ khi nào nó quyết định rằng một quy trình cụ thể sẽ chạy trên một CPU nhất định, nó sẽ tải các bảng trang của quy trình đó vào MMU của CPU đó (mỗi CPU có tập hợp các bảng trang). Kết quả là mỗi tiến trình thấy không gian địa chỉ ảo của riêng nó trông giống nhau bất kể trang vật lý nào còn trống khi HĐH phải cấp phát bộ nhớ cho nó. Nó không bao giờ biết về bộ nhớ của bất kỳ quá trình nào khác, vì nó không thể truy cập trực tiếp vào bộ nhớ vật lý.

Bảng trang là cấu trúc dữ liệu dạng cây lồng nhau được lưu trữ trong bộ nhớ thông thường, do HĐH ghi nhưng đọc trực tiếp bằng phần cứng nên định dạng cố định. Chúng được "nạp" vào MMU bằng cách thiết lập một thanh ghi điều khiển CPU đặc biệt để trỏ đến bảng cấp cao nhất. CPU sử dụng bộ nhớ đệm được gọi là TLB để ghi nhớ các tra cứu, do đó, các truy cập lặp lại vào một vài trang giống nhau nhanh hơn nhiều so với các truy cập phân tán, vì lý do bỏ sót TLB cũng như lý do bộ nhớ cache dữ liệu thông thường. Chúng ta thường thấy thuật ngữ "mục nhập TLB" được sử dụng để chỉ các mục nhập bảng trang ngay cả khi chúng không được lưu trong bộ nhớ cache trong TLB.

Và trong trường hợp bạn lo lắng rằng một quy trình có thể chỉ vô hiệu hóa phân trang hoặc thử và sửa đổi các bảng trang: Điều này không được phép, vì x86 triển khai các mức đặc quyền (được gọi là "vòng") và mã người dùng thực thi ở mức đặc quyền quá thấp để cho phép nó để sửa đổi các bảng trang của CPU.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.