Chúng cũng có thểđược nhóm thành hai loại khác dựa trên khả năng trì hoãn hoặc vô hiệu hóa tạm thờingắt: Synchronous Đồng bộ, được tạo bằng cách thực hiện một lệnh Asynchronous Không đ
Trang 1Interrupts: Ngắt Mục tiêu bài giảng
Ngắt và ngoại lệ (x86)
Ngắt và ngoại lệ (Linux)
Công việc có thể trì hoãn
Bộ hẹn giờ
Ngắt là gì?
Ngắt là một sự kiện làm thay đổi luồng thực thi thông thường của chương trình và
có thể được tạo ra bởi các thiết bị phần cứng hoặc thậm chí bởi chính CPU Khi xảy ra gián đoạn, luồng thực thi hiện tại bị tạm dừng và trình xử lý ngắt sẽ chạy Sau khi trình
xử lý ngắt chạy, luồng thực thi trước đó sẽ được tiếp tục
Các ngắt có thể được nhóm thành hai loại dựa trên nguồn ngắt Chúng cũng có thể được nhóm thành hai loại khác dựa trên khả năng trì hoãn hoặc vô hiệu hóa tạm thời ngắt:
Synchronous (Đồng bộ), được tạo bằng cách thực hiện một lệnh
Asynchronous (Không đồng bộ), được tạo bởi một sự kiện bên ngoài
Maskable (có thể che giấu hoặc tạm dừng)
o Có thể được bỏ qua
o Được báo hiệu qua chân INT
Non-maskable (không thể che giấu hoặc không thể tắt)
o Không thể bỏ qua
o Được báo hiệu qua chân NMI
Các ngắt đồng bộ, thường được đặt tên là ngoại lệ, xử lý các điều kiện được chính
bộ xử lý phát hiện trong quá trình thực hiện lệnh Chia cho số 0 hoặc cuộc gọi hệ thống
là những ví dụ về trường hợp ngoại lệ
Các ngắt không đồng bộ, thường được đặt tên là các ngắt, là các sự kiện bên ngoài được tạo ra bởi các thiết bị I/O Ví dụ, card mạng tạo ra các ngắt để báo hiệu rằng gói đã đến
Trang 2Hầu hết các ngắt đều có thể tạm dừng được, có nghĩa là chúng ta có thể tạm thời trì hoãn việc chạy trình xử lý ngắt khi chúng ta vô hiệu hóa ngắt cho đến khi ngắt được kích hoạt lại Tuy nhiên, có một số ngắt quan trọng không thể tắt/hoãn lại được
Ngoại lệ
Có 2 nguồn cho các trường hợp ngoại lệ:
Bộ xử lý phát hiện
o Lỗi
o Bẫy
o Hủy bỏ
Lập trình
o int n
Các ngoại lệ do bộ xử lý phát hiện được đưa ra khi phát hiện thấy tình trạng bất thường trong khi thực hiện lệnh
Lỗi là một loại ngoại lệ được báo cáo trước khi thực hiện lệnh và thường có thể được sửa chữa EIP được lưu là địa chỉ của lệnh gây ra lỗi, do đó sau khi lỗi được sửa, chương trình có thể thực hiện lại lệnh bị lỗi (ví dụ: lỗi trang)
Bẫy là một loại ngoại lệ được báo cáo sau khi thực hiện lệnh trong đó phát hiện ngoại lệ EIP đã lưu là địa chỉ của lệnh sau lệnh gây ra bẫy (ví dụ: bẫy gỡ lỗi)
Câu hỏi: Thuật ngữ ngắt
Đối với mỗi thuật ngữ sau đây ở bên trái, hãy chọn tất cả các thuật ngữ từ bên phải
mô tả chúng đúng nhất
Cơ quan giám sát (Watchdog) Ngoại lệ (Exception)
Phân trang theo yêu cầu (Demand
paging)
Ngắt (Interrupt)
Chia cho số không (Division by
zero)
Tạm dừng (Maskable)
Cuộc gọi hệ thống (System call) Bẫy (Trap)
Trang 3Câu trả lời:
Watchdog: Interrupt, Maskable, Non-maskable
Demand paging: Trap, Fault
Division by zero: Exception, Trap, Fault
Timer: Interrupt, Maskable, Non-maskable
System call: Trap
Breakpoint: Exception, Trap, Fault
Khái niệm phần cứng
Bộ điều khiển ngắt lập trình
Thiết bị hỗ trợ ngắt có chân đầu ra được sử dụng để báo hiệu Yêu cầu ngắt Các chân IRQ được kết nối với một thiết bị có tên Bộ điều khiển ngắt khả trình (PIC) được kết nối với chân INTR của CPU
PIC thường có một bộ cổng dùng để trao đổi thông tin với CPU Khi một thiết bị được kết nối với một trong các dòng IRQ của PIC cần sự chú ý của CPU, luồng sau sẽ xảy ra:
Thiết bị tạo ra một ngắt trên chân IRQn tương ứng
PIC chuyển đổi IRQ thành số vectơ và ghi nó vào cổng để CPU đọc
PIC tăng một ngắt trên chân INTR của CPU
PIC đợi CPU xác nhận một ngắt trước khi đưa ra một ngắt khác
CPU xác nhận ngắt sau đó nó bắt đầu xử lý ngắt
Trang 4Sau này sẽ xem CPU xử lý ngắt như thế nào Lưu ý rằng PIC theo thiết kế sẽ không tạo ra một ngắt khác cho đến khi CPU xác nhận ngắt hiện tại
Ghi chú
Sau khi CPU xác nhận ngắt, bộ điều khiển ngắt có thể yêu cầu một ngắt khác, bất
kể CPU đã xử lý xong ngắt trước đó hay chưa Do đó, tùy thuộc vào cách hệ điều
hành điều khiển CPU mà có thể có các ngắt lồng nhau
Bộ điều khiển ngắt cho phép từng dòng IRQ bị vô hiệu hóa riêng lẻ Điều này cho phép đơn giản hóa thiết kế bằng cách đảm bảo rằng các bộ xử lý ngắt luôn được thực thi tuần tự
Bộ điều khiển ngắt trong hệ thống SMP
Trong hệ thống SMP, chúng ta có thể có nhiều bộ điều khiển ngắt trong hệ thống
Ví dụ: trên kiến trúc x86, mỗi lõi có một APIC cục bộ được sử dụng để xử lý các ngắt từ các thiết bị được kết nối cục bộ như bộ định thời hoặc cảm biến nhiệt Sau đó, có APIC I/O được sử dụng để phân phối IRQ từ các thiết bị bên ngoài đến lõi CPU
Trang 5Kiểm soát ngắt
Để đồng bộ hóa quyền truy cập vào dữ liệu được chia sẻ giữa trình xử lý ngắt và các hoạt động đồng thời tiềm năng khác như khởi tạo trình điều khiển hoặc xử lý dữ liệu trình điều khiển, thường cần phải bật và tắt các ngắt theo cách được kiểm soát
Điều này có thể được thực hiện ở nhiều cấp độ:
Ở cấp độ thiết bị
o Bằng cách lập trình các thanh ghi điều khiển thiết bị
Ở cấp độ PIC
o PIC có thể được lập trình để vô hiệu hóa một dòng IRQ nhất định
Ở cấp độ CPU; ví dụ: trên x86, người ta có thể sử dụng các hướng dẫn sau:
cli (Cờ ngắt Clear)
sti (Cờ ngắt SeT)
Ưu tiên ngắt
Hầu hết các kiến trúc cũng hỗ trợ các ưu tiên ngắt Khi tính năng này được bật, nó chỉ cho phép lồng ngắt đối với những ngắt có mức ưu tiên cao hơn mức ưu tiên hiện tại
Ghi chú
Trang 6Không phải tất cả các kiến trúc đều hỗ trợ mức độ ưu tiên ngắt Cũng khó hỗ trợ
việc xác định sơ đồ chung cho các ưu tiên ngắt cho các hệ điều hành sử dụng
chung và một số hạt nhân (bao gồm cả Linux) không sử dụng các ưu tiên ngắt
Mặt khác, hầu hết các RTOS sử dụng mức độ ưu tiên ngắt vì chúng thường được
sử dụng trong các trường hợp sử dụng hạn chế hơn, trong đó việc xác định mức
độ ưu tiên ngắt sẽ dễ dàng hơn
Câu hỏi: Khái niệm phần cứng
Khẳng định nào sau đây là đúng?
CPU có thể bắt đầu xử lý một ngắt mới trước khi ngắt hiện tại kết thúc
Ngắt có thể bị vô hiệu hóa ở cấp độ thiết bị
Các ngắt có mức ưu tiên thấp hơn không thể ưu tiên các trình xử lý cho các ngắt có mức ưu tiên cao hơn
Ngắt có thể bị vô hiệu hóa ở cấp độ bộ điều khiển ngắt
Trên hệ thống SMP, cùng một ngắt có thể được định tuyến đến các CPU khác nhau
Ngắt có thể bị vô hiệu hóa ở cấp độ CPU
Câu trả lời:
CPU có thể bắt đầu xử lý một ngắt mới trước khi ngắt hiện tại kết thúc:
Đúng Điều này thường được gọi là lồng ngắt, trong đó ngắt có mức ưu tiên
cao hơn có thể làm gián đoạn việc xử lý ngắt có mức ưu tiên thấp hơn
Ngắt có thể bị vô hiệu hóa ở cấp độ thiết bị: Đúng Các thiết bị có thể có cơ
chế điều khiển để kích hoạt hoặc vô hiệu hóa khả năng tạo ra các ngắt
Các ngắt có mức ưu tiên thấp hơn không thể ưu tiên các trình xử lý cho các
ngắt có mức ưu tiên cao hơn: Sai Trong hầu hết các hệ thống ngắt, các ngắt
có mức ưu tiên cao hơn có thể ưu tiên các ngắt có mức ưu tiên thấp hơn
Ngắt có thể bị vô hiệu hóa ở cấp độ bộ điều khiển ngắt: Đúng Bộ điều
khiển ngắt thường có cơ chế cho phép hoặc vô hiệu hóa việc tạo ngắt
Trên hệ thống SMP, cùng một ngắt có thể được định tuyến đến các CPU
khác nhau: Đúng Điều này phổ biến trong các hệ thống đa xử lý đối xứng
(SMP), trong đó các ngắt có thể được phân phối trên nhiều CPU
Trang 7 Ngắt có thể bị vô hiệu hóa ở cấp độ CPU: Đúng CPU thường có cơ chế
kích hoạt hoặc vô hiệu hóa việc xử lý ngắt tạm thời
Xử lý ngắt trên kiến trúc x86
Phần này sẽ xem xét cách CPU xử lý các ngắt trên kiến trúc thex86
Bảng mô tả ngắt
Bảng mô tả ngắt (IDT) liên kết mỗi ngắt hoặc mã định danh ngoại lệ với một bộ mô
tả cho các lệnh phục vụ sự kiện liên quan Chúng ta sẽ đặt tên mã định danh là số vectơ
và các lệnh liên quan là trình xử lý ngắt/ngoại lệ
IDT có các đặc điểm sau:
Nó được CPU sử dụng làm bảng nhảy khi một vectơ nhất định được kích hoạt
Nó là một mảng gồm các mục 256 x 8 byte
Có thể cư trú ở bất cứ đâu trong bộ nhớ vật lý
Bộ xử lý định vị IDT bằng IDTR
Dưới đây chúng ta có thể tìm thấy bố cục vector IRQ của Linux 32 mục đầu tiên được dành riêng cho các trường hợp ngoại lệ, vectơ 128 được sử dụng cho giao diện tòa nhà và phần còn lại được sử dụng chủ yếu cho các trình xử lý ngắt phần cứng
Trang 8Trên x86, mục nhập IDT có 8 byte và được đặt tên là cổng Có thể có 3 loại cổng:
Cổng ngắt, giữ địa chỉ của trình xử lý ngắt hoặc ngoại lệ Việc chuyển sang trình
xử lý sẽ vô hiệu hóa các ngắt có thể che được (cờ IF bị xóa)
Cổng bẫy, tương tự như cổng ngắt nhưng nó không vô hiệu hóa các ngắt có thể che được trong khi chuyển sang trình xử lý ngắt/ngoại lệ
Cổng tác vụ (không được sử dụng trong Linux)
Chúng ta hãy xem xét một số trường của mục nhập IDT:
Bộ chọn phân đoạn, lập chỉ mục vào GDT/LDT để tìm điểm bắt đầu của đoạn
mã nơi chứa trình xử lý ngắt
Offset, offset bên trong đoạn mã
T, đại diện cho loại cổng
DPL, đặc quyền tối thiểu cần thiết để sử dụng nội dung phân đoạn
Trang 9Địa chỉ xử lý ngắt
Để tìm địa chỉ trình xử lý ngắt, trước tiên chúng ta cần tìm địa chỉ bắt đầu của đoạn
mã nơi chứa trình xử lý ngắt Để làm điều này, chúng tôi sử dụng bộ chọn phân đoạn để lập chỉ mục vào GDT/LDT nơi chúng tôi có thể tìm thấy bộ mô tả phân đoạn tương ứng Điều này sẽ cung cấp địa chỉ bắt đầu được lưu trong trường 'cơ sở' Sử dụng địa chỉ cơ
sở và phần bù, bây giờ chúng ta có thể đi đến điểm bắt đầu của trình xử lý ngắt
Ngăn xếp xử lý ngắt
Tương tự như việc chuyển điều khiển sang một hàm thông thường, việc chuyển điều khiển sang một trình xử lý ngắt hoặc ngoại lệ sử dụng ngăn xếp để lưu trữ thông tin cần thiết để quay lại mã bị gián đoạn
Như có thể thấy trong hình bên dưới, một ngắt sẽ đẩy thanh ghi EFLAGS trước khi lưu địa chỉ của lệnh bị gián đoạn Một số loại ngoại lệ nhất định cũng khiến mã lỗi được đẩy lên ngăn xếp để giúp gỡ lỗi ngoại lệ
Trang 10Xử lý yêu cầu ngắt
Sau khi một yêu cầu ngắt được tạo ra, bộ xử lý sẽ chạy một chuỗi các sự kiện mà cuối cùng kết thúc bằng việc chạy trình xử lý ngắt kernel:
CPU kiểm tra mức đặc quyền hiện tại
Nếu cần thay đổi cấp độ đặc quyền
o Thay đổi ngăn xếp bằng ngăn xếp được liên kết với đặc quyền mới
o Lưu thông tin ngăn xếp cũ vào ngăn xếp mới
Lưu EFLAGS, CS, EIP vào ngăn xếp
Lưu mã lỗi vào ngăn xếp trong trường hợp hủy bỏ
Thực thi trình xử lý ngắt kernel
Trở về từ trình xử lý ngắt
Hầu hết các kiến trúc đều đưa ra các hướng dẫn đặc biệt để dọn sạch ngăn xếp và tiếp tục thực thi sau khi trình xử lý ngắt đã được thực thi Trên x86 IRET được sử dụng
để trả về từ trình xử lý ngắt IRET tương tự như RET ngoại trừ việc IRETin tăng thêm ESP thêm bốn byte (do các cờ trên ngăn xếp) và chuyển các cờ đã lưu vào thanh ghi EFLAGS
Để tiếp tục thực thi sau khi bị gián đoạn, trình tự sau được sử dụng (x86):
Bật mã lỗi (trong trường hợp hủy bỏ)
Trang 11 Gọi IRET
o POPS các giá trị từ ngăn xếp và khôi phục thanh ghi sau: CS, EIP, EFLAGS
o Nếu mức đặc quyền thay đổi sẽ trở về ngăn xếp cũ và mức đặc quyền cũ
Kiểm tra xử lý ngắt x86
Các lệnh gdb sau đây được sử dụng để xác định trình xử lý ngoại lệ cuộc gọi hệ thống dựa trên int80 Chọn và sắp xếp các lệnh hoặc đầu ra của lệnh theo đúng thứ tự
(void *) 0xc15de780 <entry_SYSENTER_32>
set $idtr_addr=($idtr_entry>>48<<16)|($idtr_entry&0xffff)
print (void*)$idtr_addr
set $idtr = 0xff800000
(void *) 0xc15de874 <entry_INT80_32>
set $idtr = 0xff801000
set $idtr_entry = *(uint64_t*)($idtr + 8 * 128)
monitor info registers
Câu trả lời:
1 set $idtr = 0xff800000: Đây là lệnh để thiết lập giá trị của biến $idtr, một địa chỉ
cụ thể trong bộ nhớ
2 set $idtr_entry = *(uint64_t*)($idtr + 8 * 128): Lệnh này sử dụng giá trị của
$idtr để truy cập một địa chỉ cụ thể trong bộ nhớ và gán giá trị tại đó cho biến
$idtr_entry
3 set $idtr_addr=($idtr_entry>>48<<16)|($idtr_entry&0xffff): Tính toán giá trị của $idtr_addr dựa trên giá trị của $idtr_entry theo công thức đã cho
4 print (void*)$idtr_addr: In ra giá trị của $idtr_addr dưới dạng con trỏ
5 (void *) 0xc15de780 <entry_SYSENTER_32>: Đây là đầu ra của lệnh trước đó,
có thể là một địa chỉ cụ thể trong bộ nhớ
6 set $idtr = 0xff801000: Lệnh này lại một lần nữa thiết lập giá trị mới cho $idtr
7 (void *) 0xc15de874 <entry_INT80_32>: Đây cũng là một địa chỉ cụ thể trong
bộ nhớ, có thể liên quan đến trình xử lý ngoại lệ cuộc gọi hệ thống
Trang 128 monitor info registers: Đây là lệnh để hiển thị thông tin về các thanh ghi trong máy tính
Xử lý ngắt trong Linux
Trong Linux, việc xử lý ngắt được thực hiện theo ba giai đoạn: quan trọng, ngay lập tức và trì hoãn
Trong giai đoạn đầu tiên, kernel sẽ chạy trình xử lý ngắt chung để xác định số ngắt, trình xử lý ngắt cho ngắt cụ thể này và bộ điều khiển ngắt Tại thời điểm này, mọi hành động quan trọng về thời gian cũng sẽ được thực hiện (ví dụ: xác nhận ngắt ở cấp bộ điều khiển ngắt) Các ngắt bộ xử lý cục bộ bị vô hiệu hóa trong suốt giai đoạn này và tiếp tục
bị vô hiệu hóa trong giai đoạn tiếp theo
Trong giai đoạn thứ hai, tất cả các trình xử lý của trình điều khiển thiết bị liên quan đến ngắt này sẽ được thực thi Vào cuối giai đoạn này, phương thức "kết thúc ngắt" của
bộ điều khiển ngắt được gọi để cho phép bộ điều khiển ngắt xác nhận lại ngắt này Các ngắt bộ xử lý cục bộ được kích hoạt tại thời điểm này
Ghi chú
Có thể một ngắt được liên kết với nhiều thiết bị và trong trường hợp này người ta
nói rằng ngắt được chia sẻ Thông thường, khi sử dụng các ngắt được chia sẻ,
trình điều khiển thiết bị có trách nhiệm xác định xem ngắt có nhắm mục tiêu đến
thiết bị của nó hay không
Cuối cùng, trong giai đoạn cuối của quá trình xử lý ngắt, các hành động trì hoãn bối cảnh ngắt sẽ được chạy Đôi khi chúng còn được gọi là "nửa dưới" của ngắt (nửa trên là phần xử lý ngắt chạy với các ngắt bị vô hiệu hóa) Tại thời điểm này, các ngắt được kích hoạt trên bộ xử lý cục bộ
Trang 13Các ngắt và ngoại lệ lồng nhau
Linux từng hỗ trợ các ngắt lồng nhau nhưng điều này đã bị loại bỏ một thời gian trước để tránh các giải pháp ngày càng phức tạp cho các vấn đề về stackoverflow - chỉ cho phép một cấp độ lồng nhau, cho phép nhiều cấp độ lồng nhau đến một độ sâu ngăn xếp hạt nhân nhất định, v.v
Tuy nhiên, vẫn có thể có sự lồng ghép giữa các ngoại lệ và các ngắt nhưng các quy tắc khá hạn chế:
Một ngoại lệ (ví dụ: lỗi trang, lệnh gọi hệ thống) không thể tránh được sự gián đoạn; nếu điều đó xảy ra thì đó được coi là một lỗi
Một ngắt có thể ngăn chặn một ngoại lệ
Một ngắt không thể chặn trước một ngắt khác (trước đây có thể xảy ra)
Sơ đồ dưới đây cho thấy các tình huống lồng nhau có thể xảy ra:
Trang 14Bối cảnh ngắt
Trong khi một ngắt được xử lý (từ lúc CPU chuyển sang bộ xử lý ngắt cho đến khi
bộ xử lý ngắt quay trở lại - ví dụ: IRET được phát hành), người ta nói rằng mã đó chạy trong "ngữ cảnh ngắt"
Mã chạy trong ngữ cảnh ngắt có các thuộc tính sau:
Nó chạy do IRQ (không phải là ngoại lệ)
Không có bối cảnh quy trình được xác định rõ ràng liên quan
Không được phép kích hoạt chuyển đổi ngữ cảnh (không có quyền truy cập chế
độ ngủ, lịch trình hoặc bộ nhớ người dùng)
Hành động có thể trì hoãn
Các hành động có thể trì hoãn được sử dụng để chạy các hàm gọi lại sau này Nếu các hành động có thể trì hoãn được lên lịch từ trình xử lý ngắt, hàm gọi lại liên quan sẽ chạy sau khi trình xử lý ngắt hoàn tất
Có hai loại hành động lớn có thể trì hoãn: những hành động chạy trong ngữ cảnh không bị gián đoạn và những hành động chạy trong ngữ cảnh tiến trình
Mục đích của các hành động có thể trì hoãn ngữ cảnh ngắt là để tránh thực hiện quá nhiều công việc trong hàm xử lý ngắt Chạy quá lâu với các ngắt bị vô hiệu hóa có thể gây ra những tác động không mong muốn như độ trễ tăng lên hoặc hiệu suất hệ thống kém do thiếu các ngắt khác (ví dụ: làm mất các gói mạng vì CPU không phản ứng kịp thời để loại bỏ các gói khỏi giao diện mạng và bộ đệm card mạng đã đầy)
Các hành động có thể trì hoãn có các API để: khởi tạo một phiên bản, kích hoạt hoặc lên lịch hành động và che/vô hiệu hóa và vạch mặt/cho phép thực thi chức năng gọi lại Cái sau được sử dụng cho mục đích đồng bộ hóa giữa hàm gọi lại và các ngữ cảnh khác
Thông thường, trình điều khiển thiết bị sẽ khởi tạo cấu trúc hành động có thể trì hoãn trong quá trình khởi tạo phiên bản thiết bị và sẽ kích hoạt/lên lịch hành động có thể trì hoãn từ trình xử lý ngắt