|
| 1 | +/* |
| 2 | +Copyright 2024 The Hyperlight Authors. |
| 3 | +
|
| 4 | +Licensed under the Apache License, Version 2.0 (the "License"); |
| 5 | +you may not use this file except in compliance with the License. |
| 6 | +You may obtain a copy of the License at |
| 7 | +
|
| 8 | + http://www.apache.org/licenses/LICENSE-2.0 |
| 9 | +
|
| 10 | +Unless required by applicable law or agreed to in writing, software |
| 11 | +distributed under the License is distributed on an "AS IS" BASIS, |
| 12 | +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| 13 | +See the License for the specific language governing permissions and |
| 14 | +limitations under the License. |
| 15 | +*/ |
| 16 | + |
| 17 | +use crate::interrupt_entry::{ |
| 18 | + _do_excp0, _do_excp1, _do_excp2, _do_excp3, _do_excp4, _do_excp5, _do_excp6, _do_excp7, |
| 19 | + _do_excp8, _do_excp9, _do_excp10, _do_excp11, _do_excp12, _do_excp13, _do_excp14, _do_excp15, |
| 20 | + _do_excp16, _do_excp17, _do_excp18, _do_excp19, _do_excp20, _do_excp30, |
| 21 | +}; |
| 22 | + |
| 23 | +// For reference, see: https://wiki.osdev.org/Interrupt_Descriptor_Table#Structure_on_x86-64 |
| 24 | +#[repr(C)] |
| 25 | +pub(crate) struct IdtEntry { |
| 26 | + offset_low: u16, // Lower 16 bits of handler address |
| 27 | + selector: u16, // code segment selector in GDT |
| 28 | + ist: u8, // Interrupt Stack Table offset |
| 29 | + type_attr: u8, // Gate type and flags (0x8E) |
| 30 | + offset_mid: u16, // Middle 16 bits of handler address |
| 31 | + offset_high: u32, // High 32 bits of handler address |
| 32 | + zero: u32, // Reserved (always 0) |
| 33 | +} |
| 34 | + |
| 35 | +impl IdtEntry { |
| 36 | + fn new(handler: u64) -> Self { |
| 37 | + Self { |
| 38 | + offset_low: handler as u16, |
| 39 | + selector: 0x08, |
| 40 | + // ^ this selector equates to the GDT's kernel code segment, |
| 41 | + // we set this manually because, currently, Hyperlight |
| 42 | + // guests only run in kernel mode. |
| 43 | + ist: 0, |
| 44 | + // ^ for now, we don't use the IST feature. |
| 45 | + // This means that the interrupt handler will use the |
| 46 | + // stack that was in use when the interrupt was triggered. |
| 47 | + // For some exceptions (like double faults), this can be |
| 48 | + // a problem, but we'll address that later. |
| 49 | + // TODO: set up IST for exceptions that need it |
| 50 | + type_attr: 0x8E, |
| 51 | + // ^ 0x8E is the type_attr for an interrupt gate |
| 52 | + offset_mid: (handler >> 16) as u16, |
| 53 | + offset_high: (handler >> 32) as u32, |
| 54 | + zero: 0, |
| 55 | + } |
| 56 | + } |
| 57 | +} |
| 58 | + |
| 59 | +// The IDT is an array of 256 IDT entries |
| 60 | +// (as per https://wiki.osdev.org/Interrupt_Descriptor_Table#Structure_on_x86-64) |
| 61 | +pub(crate) static mut IDT: [IdtEntry; 256] = unsafe { core::mem::zeroed() }; |
| 62 | + |
| 63 | +pub(crate) fn init_idt() { |
| 64 | + set_idt_entry(0, _do_excp0); |
| 65 | + set_idt_entry(1, _do_excp1); |
| 66 | + set_idt_entry(2, _do_excp2); |
| 67 | + set_idt_entry(3, _do_excp3); |
| 68 | + set_idt_entry(4, _do_excp4); |
| 69 | + set_idt_entry(5, _do_excp5); |
| 70 | + set_idt_entry(6, _do_excp6); |
| 71 | + set_idt_entry(7, _do_excp7); |
| 72 | + set_idt_entry(8, _do_excp8); |
| 73 | + set_idt_entry(9, _do_excp9); |
| 74 | + set_idt_entry(10, _do_excp10); |
| 75 | + set_idt_entry(11, _do_excp11); |
| 76 | + set_idt_entry(12, _do_excp12); |
| 77 | + set_idt_entry(13, _do_excp13); |
| 78 | + set_idt_entry(14, _do_excp14); |
| 79 | + set_idt_entry(15, _do_excp15); |
| 80 | + set_idt_entry(16, _do_excp16); |
| 81 | + set_idt_entry(17, _do_excp17); |
| 82 | + set_idt_entry(18, _do_excp18); |
| 83 | + set_idt_entry(19, _do_excp19); |
| 84 | + set_idt_entry(20, _do_excp20); |
| 85 | + set_idt_entry(30, _do_excp30); |
| 86 | + |
| 87 | + // TODO: set hardware interrupt handlers |
| 88 | + // (i.e., after we have the PIC set up) |
| 89 | +} |
| 90 | + |
| 91 | +fn set_idt_entry(index: usize, handler: unsafe extern "sysv64" fn()) { |
| 92 | + let handler_addr = handler as u64; |
| 93 | + unsafe { IDT[index] = IdtEntry::new(handler_addr); } |
| 94 | +} |
0 commit comments