Các thể loại địa chỉ trong Embedded Linux
embedded
16
Linux
110
White

Khó viết ngày 22/02/2020

Các thể loại địa chỉ trong Embedded Linux

Khi nhắc tới ô nhớ trong bộ nhớ (hoặc thanh ghi I/O trong ngoại vi), thứ định danh chúng chính là địa chỉ (tức vị trí của ô nhớ hoặc thanh ghi đó). Tuy nhiên, do xuất hiện nhiều các đối tượng cần tiếp cận tới bộ nhớ như hệ điều hành, CPU, DMA controller... Mỗi đối tượng trên lại muốn điều khiển bộ nhớ theo cách riêng của chúng, do đó chúng phải nhìn bộ nhớ dưới các loại địa chỉ khác nhau. Cụ thể, trong bài viết này, sẽ thảo luận về 3 loại địa chỉ là Virtual Address (được HĐH sử dụng), Physical Address (được CPU sử dụng) và DMA Address (được DMA Controller sử dụng).

1. Physical Address (Địa chỉ vật lý)

Đây là loại địa chỉ sơ khai nhất, là loại địa chỉ khi ta mới bắt đầu lập trình bare metal đã phải đối mặt. Tất cả bộ nhớ, hay I/O sẽ được kết nối vào một hệ thống bus (bao gồm bus địa chỉ và bus dữ liệu, ...) và CPU sẽ điều khiển bộ nhớ hoặc I/O qua hệ thống bus này. Việc gán địa chỉ vật lý cụ thể cho bộ nhớ sẽ do team hardware đảm nhiệm. Để biết được địa chỉ vật lý của một ô nhớ hoặc I/O, ta đơn giản chỉ cần tra datasheet.
Tuy nhiên việc truy cập tới địa chỉ vật lý cũng có sự khác biệt ở những kiến trúc vi xử lý khác nhau như ARM và x86. Để truy cập vào bộ nhớ hoặc I/O. Các bộ xử lý sử dụng một trong hai không gian địa chỉ là Memory-mapped I/O (MMIO) hoặc Port I/O (PIO).

alt text
Với MMIO :

  • Bộ nhớ chính (RAM) và các I/O device chia sẻ chung vùng địa chỉ vật lý
  • Truy cập I/O device bằng các tập lệnh thông thường như đối với bộ nhớ
  • Được sử dụng rộng rãi trên các kiến trúc như ARM

Với PIO:

  • Sử dụng hai không gian địa chỉ riêng biệt cho bộ nhớ chính và I/O device
  • Sử dụng các tập lệnh CPU đặc biệt để truy cập các I/O device
  • Được sử dụng chủ yếu trên kiến trúc x86

2. Virtual Address (Địa chỉ ảo)

Linux sử dụng cơ chế địa chỉ ảo với mục đích quản lý bộ nhớ một cách hiệu quả hơn bằng cách giải quyết các vấn đề:

  • giới hạn của bộ nhớ vật lý
  • phân mảnh bộ nhớ vật lý
  • các tiến trình cùng sử dụng chung bộ nhớ vật lý

Để dịch từ địa chỉ ảo sang địa chỉ vật lý, hệ thống sử dụng thêm một thành phần phần cứng khác là bộ MMU (Memory Management Unit). Tất cả chương trình trong Linux sẽ thao tác với bộ nhớ thông qua địa chỉ ảo. Các địa chỉ được trả về bởi kmalloc() hoặc vmalloc() đều là địa chỉ ảo, được lưu với kiểu void* . Ngoài ra, đối với MMIO, từ một địa chỉ vật lý biết trước của I/O (có kiểu phys_addr_t), ta có thể map nó về một địa chỉ ảo (kiểu void*) bằng hàm ioremap() và truy cập các vùng nhớ đó bằng các hàm ioread*() /iowrite*(). Cụ thể về truy cập bộ nhớ và IO, mời các bạn tham khảo thêm chương 11, sách Linux Device Drivers Development của John Madieu.

Để nói về cơ chế địa chỉ ảo của Linux thì rất dài và phức tạp. Bạn đọc có thể tham khảo rất nhiều bài viết chi tiết hơn khác về địa chỉ ảo.

3. DMA Address (địa chỉ DMA - hay còn gọi địa chỉ bus)

Các bộ DMA Controller có chức năng trao đổi dữ liệu giữa hai vùng nhớ mà không cần sự tham gia của CPU. Để hoạt động, ta cần cung cấp địa chỉ nguồn và địa chỉ đích cho bộ DMA Controller mà nó có thể hiểu được. Ta sẽ thắc mắc rằng, tạo sao DMA Controller không sử dụng chung dải địa chỉ mà CPU sử dụng? Nguyên nhân là với địa chỉ vật lý, có sự không nhất quán về không gian địa chỉ ,tức là sự tồn tại của MMIO và PIO ở các kiến trúc khác nhau. Do đó DMA Controller sử dụng dải địa chỉ riêng. Dải địa chỉ này được dịch từ địa chỉ vật lý thông qua bộ IOMMU hoặc qua host bridge.
Để mapping địa chỉ DMA (có kiểu dma_addr_t) từ một vùng địa chỉ ảo (có kiểu void*), Linux kernel cung cấp cho ta hàm dma_map_single() hoặc dma_map_sg(). Sau khi thực hiện mapping, ta có thể sử dụng địa chỉ nguồn & đích DMA (có kiểu dma_addr_t) để cung cấp cho DMA engine. Cụ thể về DMA Mapping, mời các bạn tham khảo thêm chương 12 sách Linux Device Drivers Development của John Madieu.

4. Tổng kết mối quan hệ giữa các loại địa chỉ

Mình sẽ tổng kết bằng hình vẽ sau (đối với trường hợp địa chỉ vật lý là MMIO):
alt text

P/s: Bài viết của mình chắc chắn sẽ có những sai sót. Mong các bạn đọc thông cảm và đóng góp ý kiến để bài viết hoàn thiện hơn. Xin cảm ơn.

Bình luận


White
{{ comment.user.name }}
Bỏ hay Hay
{{comment.like_count}}
Male avatar
{{ comment_error }}
Hủy
   

Hiển thị thử

Chỉnh sửa

White

Khó

12 bài viết.
35 người follow
Kipalog
{{userFollowed ? 'Following' : 'Follow'}}
Cùng một tác giả
White
8 2
Device Tree trong Linux Device Tree (DT) là một file mô tả phần cứng, có kiểu định dạng giống JSON, nó mô tả một cấu trúc cây, ở đó thì các device...
Khó viết hơn 1 năm trước
8 2
White
5 1
Những công cụ và hàm hay dùng trong Linux Device Driver (Phần 1) _Tham khảo từ Linux Device Drivers Development_ Bản thân kernel là một phần tác...
Khó viết gần 2 năm trước
5 1
White
4 0
Context trong Linux Process context, interrupt context, user(space) context, system call context, atomic context, nonatomic context,... là những k...
Khó viết gần 2 năm trước
4 0
Bài viết liên quan
White
8 2
Device Tree trong Linux Device Tree (DT) là một file mô tả phần cứng, có kiểu định dạng giống JSON, nó mô tả một cấu trúc cây, ở đó thì các device...
Khó viết hơn 1 năm trước
8 2
White
2 2
Những công cụ và hàm hay dùng trong Linux Device Driver (Phần 3) _Tham khảo từ Linux Device Drivers Development_ Chào mừng các bạn đã đến với phầ...
Khó viết gần 2 năm trước
2 2
{{like_count}}

kipalog

{{ comment_count }}

bình luận

{{liked ? "Đã kipalog" : "Kipalog"}}


White
{{userFollowed ? 'Following' : 'Follow'}}
12 bài viết.
35 người follow

 Đầu mục bài viết

Vẫn còn nữa! x

Kipalog vẫn còn rất nhiều bài viết hay và chủ đề thú vị chờ bạn khám phá!