tôi nghĩ bạn không thể thực hiện các thao dấu chấm động trong hạt nhân Linux
Bạn không thể an toàn: thất bại trong việc sử dụng kernel_fpu_begin()
/kernel_fpu_end()
không có nghĩa là hướng dẫn FPU sẽ lỗi (không trên x86 ít nhất).
Thay vào đó nó sẽ âm thầm làm hỏng trạng thái FPU của không gian người dùng. Thật tệ; đừng làm thế.
Trình biên dịch không biết kernel_fpu_begin()
có nghĩa là gì, do đó, nó không thể kiểm tra/cảnh báo về mã biên dịch theo hướng dẫn FPU bên ngoài vùng bắt đầu FPU.
Có thể có chế độ gỡ lỗi nơi hạt nhân tắt hướng dẫn SSE, x87 và MMX bên ngoài các khu vực kernel_fpu_begin
/end
, nhưng điều đó sẽ chậm hơn và không được thực hiện theo mặc định.
Có thể, mặc dù: thiết lập CR0::TS = 1
làm cho các lỗi chỉ dẫn x87, vì vậy việc chuyển ngữ cảnh FPU lười biếng có thể thực hiện được và có các bit khác cho SSE và AVX.
Có nhiều cách cho mã kernel lỗi gây ra vấn đề nghiêm trọng. Đây chỉ là một trong nhiều. Trong C, bạn khá nhiều luôn biết khi bạn đang sử dụng dấu chấm động (trừ khi một lỗi đánh máy kết quả trong một hằng số 1.
hoặc một cái gì đó trong một ngữ cảnh mà thực sự biên dịch).
Tại sao trạng thái kiến trúc FP khác với số nguyên?
Linux phải lưu/khôi phục trạng thái nguyên bất kỳ khi nào nó vào/thoát hạt nhân. Tất cả các mã cần phải sử dụng bản ghi số nguyên (ngoại trừ một khối đường thẳng khổng lồ của FPU tính toán kết thúc bằng một jmp
thay vì một ret
(ret
đổi rsp
).)
Nhưng mã hạt nhân tránh FPU thường, vì vậy Linux rời Trạng thái FPU chưa được lưu trên mục nhập từ cuộc gọi hệ thống, chỉ lưu trước khi chuyển ngữ cảnh thực tế sang một quy trình không gian người dùng khác hoặc trên kernel_fpu_begin
. Nếu không, nó thường trở lại cùng một quá trình không gian người dùng trên cùng một lõi, do đó, trạng thái FPU không cần phải được khôi phục vì hạt nhân không chạm vào nó. (Và đây là nơi tham nhũng sẽ xảy ra nếu một nhiệm vụ hạt nhân thực sự đã sửa đổi trạng thái FPU. Tôi nghĩ rằng điều này đi theo cả hai cách: không gian người dùng cũng có thể bị hỏng trạng thái FPU FPU của bạn).
Trạng thái nguyên là khá nhỏ, chỉ có thanh ghi 16x 64 bit + RFLAGS và phân đoạn regs. Trạng thái FPU lớn hơn gấp đôi thậm chí không có đăng ký AVX: 8x 80 bit x87 và thanh ghi 16x XMM hoặc YMM hoặc 32x ZMM (+ MXCSR và x87 trạng thái + điều khiển). Ngoài ra thanh ghi MPX bnd0-4
được gộp lại với "FPU". Tại thời điểm này "trạng thái FPU" chỉ có nghĩa là tất cả các thanh ghi không phải là số nguyên. Trên Skylake của tôi, dmesg
nói x86/fpu: Enabled xstate features 0x1f, context size is 960 bytes, using 'compacted' format.
Xem Understanding FPU usage in linux kernel; Linux hiện đại không làm công tắc ngữ cảnh FPU lười biếng theo mặc định cho các công tắc ngữ cảnh (chỉ dành cho chuyển đổi kernel/người dùng). (Nhưng bài viết đó giải thích Lazy là gì.)
Hầu hết các quy trình đều sử dụng SSE để sao chép/zeroing các khối bộ nhớ nhỏ trong mã do trình biên dịch tạo ra và hầu hết các triển khai chuỗi thư viện/memcpy/memset đều sử dụng SSE/SSE2. Ngoài ra, phần cứng hỗ trợ tối ưu hóa lưu/khôi phục là một điều bây giờ (xsaveopt
/xrstor), do đó, "háo hức" FPU lưu/khôi phục có thể thực sự làm ít công việc hơn nếu một số/tất cả các thanh ghi FP chưa thực sự được sử dụng. ví dụ. tiết kiệm chỉ 128b thấp của thanh ghi YMM nếu chúng được zeroed với vzeroupper
để CPU biết chúng sạch sẽ. (Và đánh dấu sự thật đó chỉ với một chút trong định dạng lưu.)
Chuyển ngữ cảnh "háo hức", các lệnh FPU luôn được kích hoạt, vì vậy mã hạt nhân xấu có thể làm hỏng chúng bất cứ lúc nào.
Tại sao hạt nhân không thể thực hiện thao tác dấu phẩy động? – Mysticial
Tại sao bạn lại ngạc nhiên? Một mô-đun hạt nhân, sau khi tất cả, chỉ là một đoạn mã được thực thi bởi CPU. Miễn là nó có thể thực thi các opcodes bạn ném vào nó, bạn ổn. –
Ngoài ra, nó hoàn toàn có thể là số học được thực hiện trong quá trình biên dịch và tất cả những gì còn lại là một 'trả về 7;'. –