2012-10-12 23 views
7

Tôi đang làm việc trên một dự án có yêu cầu thời gian khởi động chặt chẽ. Kiến trúc được nhắm mục tiêu là một bộ xử lý dựa trên IA-32 chạy trong chế độ được bảo vệ 32 bit. Một trong những khu vực được xác định có thể được cải thiện là hệ thống hiện tại tự động khởi tạo IDT của bộ xử lý (bảng mô tả ngắt). Vì chúng tôi không có bất kỳ thiết bị cắm và chạy nào và hệ thống tương đối tĩnh nên tôi muốn có thể sử dụng một IDT được tạo tĩnh.IDT được xác định tĩnh

Tuy nhiên, điều này chứng minh là phiền hà đối với kiến ​​trúc IA-32 vì các bộ mô tả cổng ngắt 8 byte tách địa chỉ ISR. 16 bit thấp của ISR xuất hiện trong 2 byte đầu tiên của bộ mô tả, một số bit khác điền vào 4 byte tiếp theo, và sau đó cuối cùng 16 bit cuối cùng của ISR xuất hiện trong 2 byte cuối cùng.

tôi muốn sử dụng một mảng const để xác định IDT và sau đó chỉ cần chỉ thanh ghi IDT vào nó như vậy:

typedef struct s_myIdt { 
    unsigned short isrLobits; 
    unsigned short segSelector; 
    unsigned short otherBits; 
    unsigned short isrHibits; 
} myIdtStruct; 

myIdtStruct myIdt[256] = { 
    { (unsigned short)myIsr0, 1, 2, (unsigned short)(myIsr0 >> 16)}, 
    { (unsigned short)myIsr1, 1, 2, (unsigned short)(myIsr1 >> 16)}, 

, vv

Rõ ràng điều này sẽ không làm việc vì nó là bất hợp pháp để làm điều này trong C vì myIsr không phải là hằng số. Giá trị của nó được giải quyết bởi trình liên kết (có thể chỉ làm một số lượng giới hạn của toán học) chứ không phải bởi trình biên dịch.

Bất kỳ đề xuất hoặc ý tưởng nào khác về cách thực hiện việc này?

Xin cảm ơn,

+0

Đề xuất của tôi là đảm bảo IDT và ISR của bạn nằm trong cùng một mô-đun (và rõ ràng là ISR được tải ở vị trí cố định) và sau đó sử dụng nhãn. Tôi đã thử làm điều này với GCC nhưng nó không thích sử dụng cú pháp '&& myIsr0' bên ngoài một hàm và tôi không có các kỹ năng lắp ráp nội tuyến để khai báo IDT bằng cách sử dụng cú pháp' __asm__'. Tôi có lẽ chỉ cần biên dịch một mô-đun này bằng cách sử dụng NASM (sở thích cá nhân) với các ISR được gọi là các hàm C. Đó sẽ là gợi ý của tôi, mặc dù tôi chắc chắn không thể yêu cầu được một chuyên gia :) – Justin

+0

Đây là một loại gợi ý gây phiền nhiễu mà tôi muốn đưa ra: sử dụng lắp ráp. Khi sử dụng các tính năng xử lý rất cụ thể hoặc các cấu trúc mức cực thấp, hãy gọi vào một số lắp ráp. Nó làm cho nó dễ dàng hơn. – Linuxios

+0

Đây không phải là sở trường của tôi; ai đó có thể giải thích ngắn gọn hoặc chỉ cho tôi biết tại sao điều này là bất hợp pháp? – taz

Trả lời

2

Bạn đã gặp một x86 nổi tiếng. Tôi không tin rằng các mối liên kết có thể công cụ địa chỉ của thói quen isr của bạn trong các hình thức swizzled dự kiến ​​của mục nhập IDT.

Nếu bạn cảm thấy tham vọng, bạn có thể tạo tập lệnh trình xây dựng IDT để thực hiện điều gì đó tương tự như vậy (dựa trên Linux). Tôi đã không thử nghiệm chương trình này và nó có thể đủ điều kiện như là một hack khó chịu anyway, vì vậy tread cẩn thận.

Bước 1: Viết kịch bản để chạy 'nm' và nắm bắt giá trị xuất chuẩn.

Bước 2: Trong tập lệnh của bạn, phân tích đầu ra nm để lấy địa chỉ bộ nhớ của tất cả các thường trình dịch vụ ngắt của bạn.

Bước 3: Xuất tệp nhị phân, 'idt.bin' có IDT byte tất cả được thiết lập và sẵn sàng cho lệnh LIDT. Kịch bản của bạn rõ ràng sẽ xuất ra các địa chỉ isr theo đúng dạng bị xáo trộn.

Bước 4: Chuyển đổi nhị phân thô của mình vào một phần tinh với objcopy:

objcopy -I binary -O elf32-i386 idt.bin idt.elf

Bước 5: Bây giờ tập tin idt.elf có nhị phân IDT của bạn với một cái gì đó biểu tượng như thế này:

> nm idt.elf 
000000000000000a D _binary_idt_bin_end 
000000000000000a A _binary_idt_bin_size 
0000000000000000 D _binary_idt_bin_start 

Bước 6: liên kết lại nhị phân của bạn bao gồm idt.elf. Trong các tập hợp lệnh và các kịch bản liên kết của bạn, bạn có thể tham khảo biểu tượng _binary_idt_bin_start làm cơ sở của IDT. Ví dụ: tập lệnh trình liên kết của bạn có thể đặt ký hiệu _binary_idt_bin_start tại bất kỳ địa chỉ nào bạn muốn.

Cẩn thận rằng việc liên kết lại với phần IDT không di chuyển bất kỳ điều gì khác trong tệp nhị phân của bạn, ví dụ: thói quen isr của bạn. Quản lý điều này trong kịch bản trình liên kết của bạn (tệp .ld) bằng cách đặt IDT vào phần riêng của nó.

--- CHỈNH SỬA --- Từ nhận xét, dường như có sự nhầm lẫn về sự cố. 32-bit x86 IDT hy vọng địa chỉ của dịch vụ thường xuyên ngắt được chia thành hai từ 16-bit khác nhau, như vậy:

 
31   16 15   0 
+---------------+---------------+ 
| Address 31-16 |    | 
+---------------+---------------+ 
|    | Address 15-0 | 
+---------------+---------------+ 

Một mối liên kết là như vậy, không có khả năng plug-in địa chỉ ISR như bình thường tái định cư. Vì vậy, tại thời điểm khởi động, phần mềm phải xây dựng định dạng phân tách này, làm chậm thời gian khởi động.

+0

Đây là kết luận tôi đã đến. Một kịch bản hoặc một số chương trình khác sẽ phải phân tích cú pháp bảng biểu tượng của hình ảnh ELF và xây dựng IDT bị xáo trộn. Tệp đầu ra nhị phân là một ý tưởng hay. Tôi đã nghĩ đến việc tạo ra một tệp C thực tế nhưng với phương thức nhị phân, tôi có thể tránh được bước biên dịch mà có thể là một cơn ác mộng xem xét cách thức hoạt động của hệ thống xây dựng của chúng tôi. – jkayca

+0

Phương thức nhị phân cũng tránh được sự cần thiết phải chèn mã vào hình ảnh phần vững đã được liên kết của bạn. – srking

0

Bạn có thể làm một cái gì đó như thế này:

main.c:

#include <stdint.h> 
#include <stdio.h> 

void isr0(); 

struct idt_entry 
{ 
    uint32_t idt_a; 
    uint32_t idt_b; 
}; 

extern char idt_a_0; 
extern char idt_b_0; 

struct idt_entry idt0 = { 
    (uint32_t)&idt_a_0, 
    (uint32_t)&idt_b_0 
}; 

int main() 
{ 
    printf ("isr0: %08x\n", &isr0); 
    printf ("%08x\n", ((uint16_t*)&idt0)[0]); 
    printf ("%08x\n", ((uint16_t*)&idt0)[1]); 
    printf ("%08x\n", ((uint16_t*)&idt0)[2]); 
    printf ("%08x\n", ((uint16_t*)&idt0)[3]); 

    return 0; 
} 

link.ld:

seg_selector = 1; 
other_bits = 2; 
isr0_lo = isr0 & 0xFFFF; 
isr0_hi = isr0 >> 16; 

idt_a_0 = (seg_selector << 16) | isr0_lo; 
idt_b_0 = (isr0_hi << 16) | other_bits; 

isr0.c:

void isr0() 
{ 
} 

Makefile:

CFLAGS=-m32 
main: main.o isr0.o link.ld 
    gcc -m32 -Wl,link.ld -o [email protected] $^ 
main.o: main.c 
isr0.o: isr0.c