Tip: Reducing the repetitive asm code from Bran's tutorial

Question about which tools to use, bugs, the best way to implement a function, etc should go here. Don't forget to see if your question is answered in the wiki first! When in doubt post here.
Craze Frog
Member
Member
Posts: 368
Joined: Sun Sep 23, 2007 4:52 am

Tip: Reducing the repetitive asm code from Bran's tutorial

Post by Craze Frog »

There is a good tutorial that walks you through writing a kernel here: http://www.osdever.net/bkerndev/index.php

However, you're expected to write a lot of similar functions:

Code: Select all

global _isr0
global _isr1
global _isr2
...                ; Fill in the rest here!
global _isr30
global _isr31

;  0: Divide By Zero Exception
_isr0:
    cli
    push byte 0    ; A normal ISR stub that pops a dummy error code to keep a
                   ; uniform stack frame
    push byte 0
    jmp isr_common_stub

...                ; Fill in from 2 to 7 here!

;  8: Double Fault Exception (With Error Code!)
_isr8:
    cli
    push byte 8        ; Note that we DON'T push a value on the stack in this one!
                   ; It pushes one already! Use this type of stub for exceptions
                   ; that pop error codes!
    jmp isr_common_stub

...                ; You should fill in from _isr9 to _isr31 here. Remember to
                   ; use the correct stubs to handle error codes and push dummies!
Using a simple fasm macro you can avoid that, and write the code once. This makes your program less vulnerable to typing errors.

I made two different macros, one to generate code for the ISRs that need to push a dummy error code and one for the ISRs where the processor pushes the error code.

Code: Select all

macro ISR_AUTOERR [NUM] {
  public isr#NUM
  isr#NUM:
        cli
        push 0
        push NUM
        jmp  isr_common_stub
}

macro ISR_CPUERR [NUM] {
  public isr#NUM
  isr#NUM:
        cli
        push NUM
        jmp  isr_common_stub
}

; This works the same as calling the macro many times with
; a different number as the parameter each time.
; Reason for this is the [] around NUM in the macro declaration
ISR_AUTOERR 0, 1, 2, 3, 4, 5, 6, 7
ISR_CPUERR  8
ISR_AUTOERR 9
ISR_CPUERR  10, 11, 12, 13, 14
ISR_AUTOERR 15, 16, 17, 18, 19, 20, 21, 22, 23, 24
ISR_AUTOERR 25, 26, 27, 28, 29, 30, 31
A similar macro can of course also be used for the IRQ handlers.
User avatar
Brynet-Inc
Member
Member
Posts: 2426
Joined: Tue Oct 17, 2006 9:29 pm
Libera.chat IRC: brynet
Location: Canada
Contact:

Post by Brynet-Inc »

It just makes sense using GAS or NASM, believe it or not... some people actually like the ability of cross-compiling their x86 OS on a PowerPC Mac.. ;)

Anyway, the last time I talked to Brandon, he didn't seem very interested in OSDev anymore... 8)
Image
Twitter: @canadianbryan. Award by smcerm, I stole it. Original was larger.
User avatar
Dex
Member
Member
Posts: 1444
Joined: Fri Jan 27, 2006 12:00 am
Contact:

Post by Dex »

Brynet-Inc wrote:It just makes sense using GAS or NASM, believe it or not... some people actually like the ability of cross-compiling their x86 OS on a PowerPC Mac.. ;)

Anyway, the last time I talked to Brandon, he didn't seem very interested in OSDev anymore... 8)
But you can just as easy say:
"it just makes sense using FASM, believe it or not... some people actually like the ability to port there assembler to there OS"
User avatar
elderK
Member
Member
Posts: 190
Joined: Mon Dec 11, 2006 10:54 am
Location: Dunedin, New Zealand
Contact:

Post by elderK »

If you actually felt like it, you could read about macros in GAS and do the exact same thing ...

~Z
User avatar
JamesM
Member
Member
Posts: 2935
Joined: Tue Jul 10, 2007 5:27 am
Location: York, United Kingdom
Contact:

Post by JamesM »

... Or you could read my tutorials and find the NASM version of those macros...
Craze Frog
Member
Member
Posts: 368
Joined: Sun Sep 23, 2007 4:52 am

Post by Craze Frog »

JamesM wrote:... Or you could read my tutorials and find the NASM version of those macros...
How would you make your nasm macros take multiple parameters?
User avatar
JamesM
Member
Member
Posts: 2935
Joined: Tue Jul 10, 2007 5:27 am
Location: York, United Kingdom
Contact:

Post by JamesM »

Read tutorial 5 and find out! :o
User avatar
os64dev
Member
Member
Posts: 553
Joined: Sat Jan 27, 2007 3:21 pm
Location: Best, Netherlands

Post by os64dev »

zeii wrote:If you actually felt like it, you could read about macros in GAS and do the exact same thing ...

~Z
done it already for my os.

Code: Select all


.text
.code64

.macro function name
    .align 0x10;
    .globl          \name;
    .type           \name, @function;
    \name:
.endm

.macro  vector1     number
    .align 0x10;
    pushq           %rdi;
    movq            $(_ZN3x6420interruptVectorTableE + (\number * 8)), %rdi;
    jmp             interruptVectorStage2;
.endm

.macro  vector1List from, to
    .align 0x10;
    vector1        \from;
    .if             \to - \from
        vector1List "(\from+1)", \to
    .endif
.endm

.macro  vector2     number
    .align 0x10;
    pushq           %rdi;       //- 1 Byte opcode for dummy error code.
    pushq           %rdi;
    movq            $(_ZN3x6420interruptVectorTableE + (\number * 8)), %rdi;
    jmp             interruptVectorStage2;
.endm

.macro  vector2List from, to
    .align 0x10;
    vector2         \from;
    .if             \to - \from
        vector2List "(\from+1)", \to
    .endif
.endm

function    interruptVectorBase
    vector2List       0,   7
    vector1           8
    vector2           9         //- reserved
    vector1List      10, 14
    vector2List      15, 16     //- reserved
    vector1          17
    vector2List      18,  63
    vector2List      64, 127
    vector2List     128, 191
    vector2List     192, 255

//function    interruptVectorStage2
.align 0x10;
interruptVectorStage2:
    //- stackframe at this point:
    //- %SS | %RSP | %RFL | %CS | %RIP | ERR | %RDI
    //- %RDI : contains vector address.
    //- save general purpose registers.
    pushq           %rsi;
    pushq           %rax;
    pushq           %rbx;
    pushq           %rcx;
    pushq           %rdx;
    pushq           %rbp;
    pushq           %r8;
    pushq           %r9;
    pushq           %r10;
    pushq           %r11;
    pushq           %r12;
    pushq           %r13;
    pushq           %r14;
    pushq           %r15;
    pushw           %fs;
    pushw           %gs;

    //- call the interrupt handler (vector).
    movq            %rsp, %rsi;
    call            *(%rdi);

    //- restore general purpose registers.
    popw            %gs;
    popw            %fs;
    popq            %r15;
    popq            %r14;
    popq            %r13;
    popq            %r12;
    popq            %r11;
    popq            %r10;
    popq            %r9;
    popq            %r8;
    popq            %rbp;
    popq            %rdx;
    popq            %rcx;
    popq            %rbx;
    popq            %rax;
    popq            %rsi;
    popq            %rdi;
    addq            $0x08, %rsp;
    iretq;
Author of COBOS
Craze Frog
Member
Member
Posts: 368
Joined: Sun Sep 23, 2007 4:52 am

Post by Craze Frog »

JamesM wrote:Read tutorial 5 and find out! :o
I mean how to make them behave like this:

Code: Select all

ISR_AUTOERR 0, 1, 2, 3, 4, 5, 6, 7 
ISR_CPUERR  8 
ISR_AUTOERR 9
Your code requires this:

Code: Select all

ISR_AUTOERR 0
ISR_AUTOERR 1
ISR_AUTOERR 2
ISR_AUTOERR 3
ISR_AUTOERR 4
ISR_AUTOERR 5
ISR_AUTOERR 6
ISR_AUTOERR 7
ISR_CPUERR  8
ISR_AUTOERR 9
User avatar
JamesM
Member
Member
Posts: 2935
Joined: Tue Jul 10, 2007 5:27 am
Location: York, United Kingdom
Contact:

Post by JamesM »

Well, that can't be done with the NASM macro mechanism.
Craze Frog
Member
Member
Posts: 368
Joined: Sun Sep 23, 2007 4:52 am

Post by Craze Frog »

I think it can, using %rep and %rotate, but I don't know how.
User avatar
neon
Member
Member
Posts: 1567
Joined: Sun Feb 18, 2007 7:28 pm
Contact:

Post by neon »

I personally do not like the setup either way. It works, but is very repetitve no matter how one looks at it. With that, it requires a common IRQ stub function to bring everything together, requiring the testing of individual interrupt numbers to determine what to do.

Would it not be better to register function callbacks inside of the IDT when needed? This not only will take out all of the repetitive functions, but will separate the hardware dependency (The x86 specific IDT) from the kernel. Assuming the HAL is a separate dynamic library, this will work great. I am actually looking for comments on this setup ;)

Let me describe my idea a little more...

Inside of the HAL's initialization routine, the HAL maps the IDT, and registers a single stub routine for each entry to trap kernel errors. Upon returning control back to the Kernel, The Kernel can later register callback functions through the HAL to register its own interrupt handlers.

The HAL's stub routine only halts the processor and ends execution--no more. As the Kernel has to go through the HAL in order to register callbacks, the IDT is completely independent of the Kernel.

This is both non repetitive, and very portable, as the IDT is seperate from the kernel. And for interrupts that the Kernel has not registered, the HAL's stub routine tkes control.

What do you think?
OS Development Series | Wiki | os | ncc
char c[2]={"\x90\xC3"};int main(){void(*f)()=(void(__cdecl*)(void))(void*)&c;f();}
User avatar
JamesM
Member
Member
Posts: 2935
Joined: Tue Jul 10, 2007 5:27 am
Location: York, United Kingdom
Contact:

Post by JamesM »

Would it not be better to register function callbacks inside of the IDT when needed?
But... But... how would you know which interrupt was called? And what would happen if a particular interrupt fired that was "unhandled"?
User avatar
neon
Member
Member
Posts: 1567
Joined: Sun Feb 18, 2007 7:28 pm
Contact:

Post by neon »

But... But... how would you know which interrupt was called? And what would happen if a particular interrupt fired that was "unhandled"?
Unhanded interrupts would be handled by the HAL:
Inside of the HAL's initialization routine, the HAL maps the IDT, and registers a single stub routine for each entry to trap kernel errors.
As for which interrupt was called...Hm... I'll get back on that one :/ While we can easily provide a way of deciding interrupt numbers when registering each interrupt handler, the interrupt numbers themselves are x86 dependent. I guess we will need to find a way to abstract the numbers is some way... Perhaps behind constants defined within the HAL?

So, it would be something simular to:

Code: Select all

LoadLibrary ("hal.dll");                 // load dynamic library
void (*Initialize) () = GetProcAddress ("Initialize");

// Initialize HAL. Initialize default chipset configuration for x86 specific
// motherboards
(*Initialize) ();

// enable interrupts. HAL has set up default stub interrupt handler
sti();

// register whatever callbacks we want to handle hardware faults:
void (*RegisterHandler)(LPHANDLER, int) = GetProcAddress ("RegisterHandler");

// Register our interrupt handler. DivideHandler is the interrupt handler,
// ID_DIVIDE_BY_0 is a special name given in the HAL meaning
// divide by 0 interrupt handler (interrupt 0)
(*RegisterHandler) (DivideHandler, ID_DIVIDE_BY_0);
The handler might look something like this:

Code: Select all

int __cdecl DivideHandler (REGS* regs, int lparam, int rparam, int code) {

   // regs contains the register state at the time of the interrupt.
   // lparam and rparam contains extra data, if any.
   // code contains the error code. The HAL should have symbolic names
   // for the error codes.

   return HANDLER_CONTINUE;  // continue execution after handler
}
OS Development Series | Wiki | os | ncc
char c[2]={"\x90\xC3"};int main(){void(*f)()=(void(__cdecl*)(void))(void*)&c;f();}
frank
Member
Member
Posts: 729
Joined: Sat Dec 30, 2006 2:31 pm
Location: East Coast, USA

Post by frank »

What about shared interrupts? Of course when asking this I am thinking you are patching the IDT with the ISR for the driver and not a middle man function that then signals the driver. If you mean the middle man thing then ignore this post.
Post Reply