Làm thế nào để bộ xử lý tìm mã hạt nhân sau khi bị gián đoạn?


13

Khi xảy ra ngắt, bộ xử lý sẽ xử lý trước tiến trình hiện tại và gọi mã kernel để xử lý ngắt. Làm thế nào để bộ xử lý biết nơi để nhập kernel?

Tôi hiểu rằng có các trình xử lý ngắt có thể được cài đặt cho mỗi dòng ngắt. Nhưng vì bộ xử lý chỉ thực thi 'logic cứng', nên phải tồn tại một số vị trí được xác định trước chỉ đến một trình xử lý ngắt hoặc một số mã thực thi trước trình xử lý (vì có thể có nhiều trình xử lý cho một dòng ngắt, tôi giả sử sau này).

Câu trả lời:


13

Khi khởi động, kernel sẽ khởi tạo bảng vectơ ngắt (được gọi là bảng mô tả ngắt hoặc IDT trên x86) trỏ đến một trình xử lý ngắt cho mỗi dòng.

Trước 80286, IDT luôn được lưu trữ tại một địa chỉ cố định; bắt đầu với 80286, IDT được tải bằng LIDThướng dẫn.

Các bảng vectơ ngắt chỉ đến một trình xử lý duy nhất trên mỗi dòng ngắt; như đã nói, một hạt nhân có thể chọn, ví dụ, cung cấp một trình xử lý ngắt chạy một số thói quen ngắt khác hoặc cung cấp một trình xử lý duy nhất bao gồm một số hoặc tất cả các ngắt. Linux thực hiện những điều này bằng cách cung cấp một trình xử lý ngắt chung để xác định dòng ngắt nào được gọi và tìm trình xử lý xuôi dòng thích hợp để gọi.


1
Vì vậy, bộ xử lý sử dụng dòng ngắt làm chỉ mục cho IDT, đặt mục nhập vào PC và bắt đầu thực thi? nhưng không có một chức năng chung chạy trước tất cả các trình xử lý ngắt? đối với linux, nó sẽ là do_IRQ (). Đây có phải là chức năng mà mọi mục nhập IDT trỏ tới, bất kể dòng ngắt?
Philipp Murry

@PhilippMurry có. Sau đó, hạt nhân sử dụng bộ trình xử lý ngắt riêng của nó (trong đó có thể có nhiều hơn một dòng trên mỗi dòng) để thực sự xử lý ngắt, trước khi quay lại mã thực thi trước đó.
Adam Maras

được rồi, vì vậy thực sự có hai loại trình xử lý ngắt: những loại mà bộ xử lý gọi (luôn là do_IRQ ()) và những loại mà kernel gọi (loại mà tôi đã đăng ký qua request_irq ()). bạn có thể thêm điều này vào câu trả lời của bạn? tôi nghĩ sau đó tôi sẽ chấp nhận nó :) cảm ơn rất nhiều
Philipp Murry

1
@PhilippMurry Tôi không phải là chuyên gia về cách Linux xử lý các ngắt (và cách các nhà phát triển nhân truy cập vào hệ thống đó) nhưng tôi đã thêm một số thông tin theo nghĩa rộng hơn về cách các hạt nhân có thể quản lý ISR ​​của riêng họ.
Adam Maras

12

Vâng, có một nơi được xác định trước có chứa địa chỉ mã để nhảy tới: một vectơ ngắt . Tùy thuộc vào bộ xử lý, đây có thể là một vị trí cụ thể trong bộ nhớ vật lý (8088), một vị trí cụ thể trong bộ nhớ ảo, thanh ghi bộ xử lý, một vị trí trong bộ nhớ được chỉ định bởi một thanh ghi (ARM, 386)

Các chi tiết khác nhau trên các bộ xử lý khác nhau, nhưng các yếu tố phổ biến chính để xử lý một ngắt trong bộ xử lý là:

  • Mặt nạ ngắt (để bất kỳ gián đoạn tiếp theo sẽ phải chờ).
  • Đặt chế độ bộ xử lý thành kernel hoặc chế độ ngắt (nếu bộ xử lý có các chế độ như vậy).
  • Lưu giá trị của bộ đếm chương trình vào một nơi đã biết (thanh ghi hoặc bộ nhớ).
  • Có thể lưu giá trị của các thanh ghi khác, hoặc chuyển đổi giữa các ngân hàng đăng ký).
  • Thực hiện hướng dẫn tiếp theo (tại giá trị PC mới).

1

Hai câu trả lời khác (tại thời điểm viết) nói về các ngắt và IDT. Điều này là chính xác, tuy nhiên, trên CPU Intel-esque hiện đại, không có ít hơn ba cách để gọi vào kernel.

Phương pháp # 1: Ngắt.

Điều này được giải thích ở trên. Bạn thiết lập một mục trong bảng mô tả ngắt / vectơ ngắt, sau đó thực hiện ngắt phần mềm để nhập kernel.

Ưu điểm chính của phương pháp này là một hạt nhân điển hình cần có khả năng xử lý các ngắt dù thế nào và nó hoạt động trên phần cứng cổ xưa.

Phương pháp # 2: Cổng gọi.

Cổng gọi là một loại bộ chọn phân đoạn đặc biệt. Mục tiêu của cuộc gọi cần được tải trong bảng mô tả phân đoạn toàn cầu hoặc cục bộ (tương ứng GDT và LDT). Nếu sau đó bạn thực hiện một lệnh gọi xa bằng cách sử dụng cổng cuộc gọi làm phân đoạn (phần bù của cuộc gọi bị bỏ qua), điều này cho phép bạn gọi thêm mã đặc quyền. Cổng gọi cực kỳ linh hoạt; kiến trúc IA-32 có bốn cấp đặc quyền và cổng gọi cho phép bạn gọi bất kỳ cấp nào.

Tôi không tin rằng Linux đã từng sử dụng cổng gọi, nhưng Windows 95 thì có. Các dịch vụ kernel Win95 ( krnl386.exekernel.dll) thực sự chạy ở chế độ người dùng (vòng 3). Mức đặc quyền cao nhất (vòng 0) chỉ được sử dụng cho trình điều khiển và hạt nhân vi mô chỉ thực hiện chuyển đổi quy trình. Gọi vào trình điều khiển đã được thực hiện bằng cách sử dụng cổng gọi. Điều này cho phép mã 16 bit kế thừa (trong đó có rất nhiều!) Để sử dụng trình điều khiển Win95 chỉ bằng cách sử dụng một cuộc gọi xa tiêu chuẩn, giống như họ luôn làm.

Bảo vệ không đầy đủ của bảng mô tả toàn cầu là nguyên nhân của một số khai thác Windows 95, đã quản lý để cài đặt các cổng gọi của riêng họ bằng cách ghi vào bộ nhớ.

Phương pháp # 3: SYSCALL / SYSRET và SYSENTER / SYSEXIT

Đây là hai bộ hướng dẫn, được phát minh độc lập bởi AMD và Intel, nhưng về cơ bản chúng cũng làm điều tương tự. SYSCALL / SYSRET xuất hiện đầu tiên và chỉ dành cho AMD, SYSENTER / SYSEXIT là Intel, nhưng AMD triển khai ngay bây giờ. Vì vậy, tôi sẽ mô tả SYSENTER / SYSEXIT.

Không giống như cổng gọi, SYSENTER chỉ có thể được sử dụng để chuyển sang chuông 0 và chỉ có thể chuyển đến một vị trí. Tuy nhiên, nó có ưu điểm là độ trễ cực thấp vì không giống như một cuộc gọi hoặc ngắt, nó không chạm vào ngăn xếp.

Vị trí truyền được thiết lập bằng ba thanh ghi dành riêng cho mô hình: một thanh ghi cho thông tin phân đoạn và một thanh ghi cho con trỏ lệnh và con trỏ ngăn xếp của mã hạt nhân. Vì không có gì được "đẩy" vào ngăn xếp, mã chế độ người dùng có trách nhiệm báo cho kernel biết nơi quay lại bằng cách chuyển con trỏ lệnh trả về và con trỏ ngăn xếp trong các thanh ghi. Hạt nhân chịu trách nhiệm khôi phục con trỏ ngăn xếp và lệnh SYSEXIT khôi phục con trỏ lệnh.

Thông tin thêm về các hướng dẫn SYSENTER và SYSEXIT.

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.