OSDev.org

The Place to Start for Operating System Developers
It is currently Mon Oct 22, 2018 7:54 am

All times are UTC - 6 hours




Post new topic Reply to topic  [ 7 posts ] 
Author Message
 Post subject: Vector of subroutine pointers in NASM
PostPosted: Sat Jul 28, 2018 8:48 am 
Offline
Member
Member

Joined: Wed Jul 25, 2018 2:47 pm
Posts: 36
Location: Pizzaland, Southern Europe
I'm currently following JamesM's tutorials, and I'd like to "clean up" the IRQ/ISR code a bit by reducing the amount of repetition it has. Right now, it does some NASM macro trickery to generate the different stubs for the various ISRs, which is already great for reducing the amount of assembly code required, but does little to reduce the C side of things, which looks like this for me:

Code:
  idt_entries [0] = IdtEntry::makeEntry(isr0,  0x08, PrivilegeLevel::Ring0);
  idt_entries [1] = IdtEntry::makeEntry(isr1,  0x08, PrivilegeLevel::Ring0);
  idt_entries [2] = IdtEntry::makeEntry(isr2,  0x08, PrivilegeLevel::Ring0);
  // ...
  idt_entries[31] = IdtEntry::makeEntry(isr31, 0x08, PrivilegeLevel::Ring0);

  idt_entries[32] = IdtEntry::makeEntry(irq0,  0x08, PrivilegeLevel::Ring0);
  idt_entries[33] = IdtEntry::makeEntry(irq1,  0x08, PrivilegeLevel::Ring0);
  // ...
  idt_entries[47] = IdtEntry::makeEntry(irq15, 0x08, PrivilegeLevel::Ring0);


Ideally, I'd like to turn that into something like this:
Code:
for(int i = 0; i < num_isrs; i++) {
  idt_entries[i] = IdtEntry::makeEntry(irqs[i], 0x08, PrivilegeLevel::Ring0);
}


To do that, I though of reserving some space in the assembly code like this:
Code:
isr_handlers: resd 32
irq_handlers: resd 16


So that I can put the pointers to all the different isrs into those two vectors... But I have no idea how to do it, or even if it's possible! Does NASM support this? Can I populate a reserved section with pointers?


Top
 Profile  
 
 Post subject: Re: Vector of subroutine pointers in NASM
PostPosted: Sat Jul 28, 2018 9:11 am 
Offline
Member
Member

Joined: Wed Jul 25, 2018 2:47 pm
Posts: 36
Location: Pizzaland, Southern Europe
Sorry, I should have made a better research the first time, I figured it out.
This is the final code I've come up with:
Code:
%macro ISR_NOERRCODE 1  ; define a macro, taking one parameter
  [GLOBAL isr%1]        ; %1 accesses the first parameter.
  isr%1:
    cli
    push byte 0
    push byte %1
    jmp isr_common_stub
%endmacro

%macro ISR_ERRCODE 1
  [GLOBAL isr%1]
  isr%1:
    cli
    push byte %1
    jmp isr_common_stub
%endmacro

; This macro creates a stub for an IRQ - the first parameter is
; the IRQ number, the second is the ISR number it is remapped to.
%macro IRQ 2
  [GLOBAL irq%1]
  irq%1:
    cli
    push byte 0
    push byte %2
    jmp irq_common_stub
%endmacro

%macro ISR_ADDR 1
  dd isr%1
%endmacro

%macro IRQ_ADDR 1
  dd irq%1
%endmacro

ISR_NOERRCODE 0
ISR_NOERRCODE 1
ISR_NOERRCODE 2
; ...
IRQ   0,      32
IRQ   1,      33
IRQ   2,      34
; ...

[EXTERN isr_handler]

; This is our common ISR stub. It saves the processor state, sets
; up for kernel mode segments, calls the C-level fault handler,
; and finally restores the stack frame.
isr_common_stub:
  ;... isr stuff

[EXTERN irq_handler]

; This is our common IRQ stub. It saves the processor state, sets
; up for kernel mode segments, calls the C-level fault handler,
; and finally restores the stack frame.
irq_common_stub:
  ;... irq stuff

[GLOBAL isr_handlers]
isr_handlers:
  %assign i 0
  %rep    32
    ISR_ADDR i
  %assign i i+1
  %endrep
 
  %assign i 0
  %rep    16
    IRQ_ADDR i
  %assign i i+1
  %endrep


It's mostly JamesM's code, but I though someone else following his tutorial might find it interesting nonetheless. I use it from the C++ code like this:
Code:
extern "C" IdtEntry::interrupt_handler *isr_handlers[];
...

for(int i = 0; i < 48; i++) {
  idt_entries[i] = IdtEntry::makeEntry(isr_handlers[i], 0x08, PrivilegeLevel::Ring0);
}


Top
 Profile  
 
 Post subject: Re: Vector of subroutine pointers in NASM
PostPosted: Sat Jul 28, 2018 9:21 am 
Offline
Member
Member
User avatar

Joined: Fri Oct 27, 2006 9:42 am
Posts: 1341
Location: Athens, GA, USA
Before I answer (or at least ask for further clarification), let me make an aside (less for you personally than for other newcomers who are seeing this). The James Molloy tutorial - as with all of the existing OS dev tutorials - is seriously flawed, with known bugs and poor choices, as well as being somewhat out of date. It has far fewer problems than some other ones (the contemptibly awful Darnell book comes to mind), but they do exist.

I am only mentioning this now because this disclaimer is a frequent piece of due-diligence for the regulars here. It isn't directly relevant to the question, as it happens.

For the OP, this is probably less of an issue, as the main problem is when someone follows the instructions blindly, rather than viewing them critically and getting additional sources of information. Frabert has already shown just that sort of initiative in their short time here, but that make them the exception, not the rule.

EDIT: I was about to try answering the question, but I wanted to make sure that this point was made immediately. After posting this, I saw that the OP had found their answer while I was composing this, so I think I can leave this as it is. Also, I am not sure if the JamesM listed as part of the Pedigree OS project is Molloy or not, buty either way, while it is possible that the OP is talking about a tutorial from a different JamesM, I doubt this is the case since Molloy's is the only one I know of from anyone using that name.

_________________
Rev. First Speaker Schol-R-LEA;2 LCF ELF JAM POEE KoR KCO PPWMTF
μή εἶναι βασιλικήν ἀτραπόν ἐπί γεωμετρίαν
Lisp programmers tend to seem very odd to outsiders, just like anyone else who has had a religious experience they can't quite explain to others.


Top
 Profile  
 
 Post subject: Re: Vector of subroutine pointers in NASM
PostPosted: Sat Jul 28, 2018 9:54 am 
Offline
Member
Member

Joined: Wed Jul 25, 2018 2:47 pm
Posts: 36
Location: Pizzaland, Southern Europe
Oooh thanks for the link, nice to know where the pitfalls are! Fortunately I managed to avoid or solve many of those, but it will come in handy nonetheless :)
EDIT: I also remember seeing Pedigree OS listed on http://www.jamesmolloy.co.uk back when it was still working properly, that's why I thought it was the same JamesM.


Top
 Profile  
 
 Post subject: Re: Vector of subroutine pointers in NASM
PostPosted: Sat Jul 28, 2018 3:19 pm 
Offline
Member
Member
User avatar

Joined: Sat Jan 15, 2005 12:00 am
Posts: 8561
Location: At his keyboard!
Hi,

frabert wrote:
Ideally, I'd like to turn that into something like this:
Code:
for(int i = 0; i < num_isrs; i++) {
  idt_entries[i] = IdtEntry::makeEntry(irqs[i], 0x08, PrivilegeLevel::Ring0);
}


Don't forget that:
  • For the first 32 interrupts (for exceptions) some don't exist (0x0F, 0x15, 0x16, ..., 0x1F) and their IDT entries should be marked "not present"; and some may or may not exist depending on which features the CPU supports (e.g. "0x14, Virtualisation Exception" doesn't exist if the CPU doesn't support hardware virtualisation).
  • For the first 32 interrupts, for some of them (double fault, NMI, machine check) you may need to use task gates (for protected mode) or IST (for long mode), so they end up being different to other exceptions (for more than just the "address of interrupt handler" part)
  • If the OS uses PIC chips (instead of IO APICs), IRQ2 doesn't exist (is used for a "cascade" line)
  • If the FPU is set to "native exceptions" (strongly recommended) and the OS uses PIC chips, then IRQ15 ("FPU error IRQ") doesn't exist
  • If the FPU is not set to "native exceptions" then exception "0x10, floating point exception" doesn't exist
  • If the OS uses IO APICs, there can be any number of IO APICs where each one can have any number of inputs/IRQs
  • If the OS uses IO APICs and PIC chips don't exist, you shouldn't create any IDT entries for any PIC chip IRQs
  • If the OS uses IO APICs and PIC chips do exist, you should create IDT entries for the PIC chips' spurious IRQs (but no other PIC chip IRQs)
  • If the OS uses IO APICs and supports MSI or MSI-X, you'd need to be able to dynamically allocate groups of multiple consecutive vectors
  • If the OS supports SMP; then it will need some vectors for "inter-processor interrupts" (IPIs)
  • If the OS supports "large SMP" systems; then you'll want something to balance IRQs (e.g. so a single CPU doesn't get swamped by IRQs while other CPUs are doing nothing)
  • If the OS supports "very large SMP" systems; then each CPU or group of related CPUs can have a different IDT to allow you to avoid having a "max. of no more than 224 IRQs for the entire computer" limitation
  • If the OS uses IO APICs, or if the OS supports SMP; then the OS will need to use the local APIC and therefore must assign a vector for the local APIC's spurious IRQ (but may also want to assign more vectors for things like the local APIC's thermal monitor interrupt, performance monitoring overflow, timer, ...)
  • For all interrupts from IO APIC or local APIC; the interrupt vector determines the priority of the interrupt, so you want important things (e.g. "multi-CPU TLB shootdown IPI") using higher priority vectors and less important things (floppy drive controller IRQ) using lower priority vectors; and don't want the vector number to depend on how the where the interrupt is connected (e.g. like "vector = IO APIC input number + 32").
  • Most of the things mentioned above depend on some kind of auto-detection (e.g. CPUID, ACPI's MADT, PCI bus enumeration)

Mostly; a single static table is a temporary step that will become far too inflexible very quickly.


Cheers,

Brendan

_________________
For all things; perfection is, and will always remain, impossible to achieve in practice. However; by striving for perfection we create things that are as perfect as practically possible. Let the pursuit of perfection be our guide.


Top
 Profile  
 
 Post subject: Re: Vector of subroutine pointers in NASM
PostPosted: Sun Jul 29, 2018 6:34 am 
Offline
Member
Member

Joined: Wed Jul 25, 2018 2:47 pm
Posts: 36
Location: Pizzaland, Southern Europe
Wow, that's a lot more complicated that I had initially hoped... Do you have any links for where I can look this stuff more in detail? I checked on the wiki but it seems there's just mostly generic info


Top
 Profile  
 
 Post subject: Re: Vector of subroutine pointers in NASM
PostPosted: Sun Jul 29, 2018 11:09 am 
Offline
Member
Member
User avatar

Joined: Sat Jan 15, 2005 12:00 am
Posts: 8561
Location: At his keyboard!
Hi,

frabert wrote:
Wow, that's a lot more complicated that I had initially hoped... Do you have any links for where I can look this stuff more in detail? I checked on the wiki but it seems there's just mostly generic info


Information for exceptions and local APICs is in Intel's Programmer's Reference Manual. For the PIC chips, there's a link to an appropriate datasheet at the bottom of the wiki page. IO APICs are covered by various datasheets (there's a link at bottom of wiki page for one), Intel's MultiProcessor Specification (old) and ACPI specifications. The "CPU side" of MSI (how the "address" and "data" fields are used for 80x86 systems) is covered Intel's Programmer's Reference Manual while the "device side" (detecting the capability, etc) is covered by PCI specs. There's also information for interrupt remapping (needed for virtualisation and x2APIC) in a document called "Intel Virtualization Technology for Directed I/O".

All of this covers what the hardware provides. How you use the hardware (how many IDTs, how IRQ balancing is done, what you use IPIs for and how many you feel like having, ...) is up to the OS developer and isn't documented.

Note that most of this is stuff you can worry about later. For now; you only really need to understand that interrupt vectors will eventually need to be dynamically assigned/allocated (and that a table containing "address of handler" and nothing else won't be flexible enough, even just for exceptions).

More specifically; I'd be tempted to use a static table for exceptions only to build an initial IDT; and then have 3 "overlays" (one for "no PIC", one for "spurious IRQs only" and one for "no IO APIC") where only one of the three "overlays" are merged into the initial IDT; then have some kind of "interrupt vector manager" to allow vector/s to be allocated and freed after that. Of course there'd also be minor special cases on top of that. However; for now you'd only need the static table for exceptions plus the "no IO APIC" overlay (and wouldn't need the other two overlays or the "interrupt vector manager").


Cheers,

Brendan

_________________
For all things; perfection is, and will always remain, impossible to achieve in practice. However; by striving for perfection we create things that are as perfect as practically possible. Let the pursuit of perfection be our guide.


Top
 Profile  
 
Display posts from previous:  Sort by  
Post new topic Reply to topic  [ 7 posts ] 

All times are UTC - 6 hours


Who is online

Users browsing this forum: Bing [Bot] and 17 guests


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot post attachments in this forum

Search for:
Jump to:  
Powered by phpBB © 2000, 2002, 2005, 2007 phpBB Group