OSDev.org

The Place to Start for Operating System Developers
It is currently Thu Mar 28, 2024 11:04 am

All times are UTC - 6 hours




Post new topic Reply to topic  [ 14 posts ] 
Author Message
 Post subject: Real Mode 32
PostPosted: Thu Dec 14, 2017 5:26 pm 
Offline

Joined: Thu Dec 14, 2017 5:08 pm
Posts: 7
Hello guys!

I'm posting this because recently (a couple months ago) I realised through testing that it is possible to run "native" 32 bit x86 code in "real mode".
If you do the exact same procedure as you would for unreal mode (entering protected mode, loading selectors with bigger limits, switching back), but you mark the code selector as 32 bit, you'll be (apparently) able to run 32-bit instructions in "real mode" while retaining the segment*16+offset memory model, and without the need for override prefixes (which in this case, would actually turn the instruction into a 16 bit instruction, as in protected mode 32).
The interrupts work the same as in real mode, using the IVT, with real mode addressing (so you can't have vectors that point to memory beyond ffff:ffff).
I, too, was pretty weirded out about this, but I did some testing in bochs (which marks the mode as "Real Mode 32"), in qemu (although I believe KVM crashes), and, most surprisingly, it works on real hardware! (Although it had some crashes at times)

I'll attach a small demonstration of this. To compile it you'll just need to have a i386-elf gcc toolchain in your path, and run the "make_me.sh" script in the archive.
It will create a test.img image which demonstrates the concept.

Cheers.


Attachments:
File comment: The source.
tests1.tar.gz [3.93 KiB]
Downloaded 26 times
Top
 Profile  
 
 Post subject: Re: Real Mode 32
PostPosted: Thu Dec 14, 2017 6:06 pm 
Offline
Member
Member

Joined: Fri Aug 26, 2016 1:41 pm
Posts: 671
I haven't looked at your code but I'm curious if you have interrupts enabled while in real mode? I hope you are aware that when using a code segment like this where EIP can be greater than 0xffff - interrupts will still only push CS:IP (not CS:EIP). So if you are executing code that happens to be above 0xffff only the lower 16 bits of EIP will be saved on entry to an interrupt/exception handle, and then when an iret is done only the lower 16-bits are restored. That could cause some serious issues.


Top
 Profile  
 
 Post subject: Re: Real Mode 32
PostPosted: Thu Dec 14, 2017 6:17 pm 
Offline

Joined: Thu Dec 14, 2017 5:08 pm
Posts: 7
Yes, sure. I'm fully aware of that. This is more of an experiment to demonstrate that I managed to run 32-bit GCC compiled code in what I assume is a 32-bit version of real mode.
All of the code in my test is for demonstration purposes only, and all of it resides in the first 64K of ram (aka the 0x0000 segment of real mode addressing).
Obviously an interrupt in this mode won't save the high 16 bit of EIP, but in this case that's not a concern I believe.
So yes, I do have interrupts enabled while in real mode 32, and obviously they point to the C functions that handle them, rather than the BIOS routines, since those are 16-bit only.


Top
 Profile  
 
 Post subject: Re: Real Mode 32
PostPosted: Fri Dec 15, 2017 1:00 am 
Offline
Member
Member

Joined: Tue Mar 04, 2014 5:27 am
Posts: 1108
If you care, there's a thread about how this was implemented in FASM.
Also, you can use my Smaller C compiler to compile C code for unreal mode and have interrupts and BIOS services working normally.


Top
 Profile  
 
 Post subject: Re: Real Mode 32
PostPosted: Fri Dec 15, 2017 1:18 pm 
Offline
Member
Member
User avatar

Joined: Sun Feb 20, 2011 2:01 pm
Posts: 110
I'd be concerned about two aspects of this:
Firstly, you're running a 32 bit eip. Of course, careful development can avoid this, but at the same time this negates many advantages of having a 32 bit code segment in the third place.
However, I'd be more concerned about the execution of 16 bit BIOS code in your 32 bit mode.
While you can write your code with a BITS 32 directive, you can make no assumptions about BIOS code.
In particular, the BIOS may internally use 32 bit registers. However, it will assume a 16 bit code segment. Result? An override prefix, which results in the opposite behaviour to desired. Basically, I would say you want 16 bit code segments calling the BIOS.

_________________
Whoever said you can't do OS development on Windows?
https://github.com/ChaiSoft/ChaiOS


Top
 Profile  
 
 Post subject: Re: Real Mode 32
PostPosted: Fri Dec 15, 2017 2:12 pm 
Offline
Member
Member

Joined: Fri Aug 26, 2016 1:41 pm
Posts: 671
bellezzasolo wrote:
In particular, the BIOS may internally use 32 bit registers. However, it will assume a 16 bit code segment. Result? An override prefix, which results in the opposite behaviour to desired. Basically, I would say you want 16 bit code segments calling the BIOS.
You could create a new Interrupt Vector Table(IVT) specifically for 32-bit Unreal mode with a base that isn't 0x00000. The unreal mode version of the IVT would have entries that point to a 32-bit thunk that in turn switches the IVT with the LIDT instruction to point to the real mode IVT at 0x0000; switch the code segment back to a 16-bit one; calls the original 16-bit vector; switch back to 32-bit code segment; and use LIDT to set the IVT to the 32-bit version again.


Last edited by MichaelPetch on Fri Dec 15, 2017 9:46 pm, edited 1 time in total.

Top
 Profile  
 
 Post subject: Re: Real Mode 32
PostPosted: Fri Dec 15, 2017 7:53 pm 
Offline
Member
Member
User avatar

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

bellezzasolo wrote:
I'd be concerned about two aspects of this:
Firstly, you're running a 32 bit eip. Of course, careful development can avoid this, but at the same time this negates many advantages of having a 32 bit code segment in the third place.
However, I'd be more concerned about the execution of 16 bit BIOS code in your 32 bit mode.
While you can write your code with a BITS 32 directive, you can make no assumptions about BIOS code.
In particular, the BIOS may internally use 32 bit registers. However, it will assume a 16 bit code segment. Result? An override prefix, which results in the opposite behaviour to desired. Basically, I would say you want 16 bit code segments calling the BIOS.


It'd be impossible to run BIOS code. For example, a trivial "mov ax,0x1234" would be executed as "mov eax,0x????1234" where the instruction/operand consumes more bytes than there are, and this will cause the CPU to either skip over the next instruction/s (if they're two 1 byte instructions or one 2 byte instruction) or execute garbage (if the next instruction is larger) because CPU thinks that a byte in the middle of the next instruction is the first byte of the next instruction.

I also wouldn't assume that this works the same on all CPUs. For an example, a while ago I had a function that switched from real mode to 32-bit protected mode, fixes (zero extends) the "return EIP" on the stack and then returns with a normal "ret" instruction. It worked fine on all Intel and AMD CPUs that I tested it on; but a VIA CPU treated the "ret" as a 16-bit return and crashed because ESP became wrong. Mostly, you can't really trust "very unusual but technically legal" code without extensive testing (because all CPUs have errata and "very unusual" is a lot more likely to become a victim of bugs that weren't discovered by the manufacturer before the CPU was released), and "very unusual and relying on undefined behaviour" is significantly worse than that (because there's no reason for the manufacturer to consider them bugs at all). I'd also worry about the firmware's SMM code; which (unlike BIOS functions) can't be avoided - e.g. something as simple as the user closing their laptop's lid and then opening it again could corrupt state.


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: Real Mode 32
PostPosted: Fri Dec 15, 2017 9:02 pm 
Offline
Member
Member

Joined: Fri Aug 26, 2016 1:41 pm
Posts: 671
xenos1 wrote:
in qemu (although I believe KVM crashes)
I missed this in your question originally. I suspect that what may be going on in that case is that you may be on an older VMX enabled processor that doesn't support Unrestricted Guest mode. Without it KVM is likely not running real mode code as you'd expect on real hardware, because your code utilizes unusual forms of real mode that KVM isn't emulating properly.. With Unrestricted Guest mode the virtual processor is placed into real mode to begin with. Without this feature most hypervisors emulate real mode until the switch is made to protected mode.


Top
 Profile  
 
 Post subject: Re: Real Mode 32
PostPosted: Fri Dec 15, 2017 9:43 pm 
Offline

Joined: Thu Dec 14, 2017 5:08 pm
Posts: 7
Hey everyone, thanks for the replies.

First of all, for everyone concerned about the fact that I might want to run 16-bit BIOS routines, either via software, or via hardware interrupts: no, that wasn’t really what I was planning to do with this. However as alexfru and MichaelPetch correctly pointed out, I could do that by switching back to (un)real mode 16 (by using a 16 bit code selector), but as mentioned, that would involve a piece of code that “detects” what mode the CPU is running in, and performs the switch (and back) when appropriate.

I often hear people using the terms “Real Mode” and “Protected Mode” to refer to 16, and 32 bit modes. I believe this is a common misconception. What I wanted to know was: since Protected Mode 16 does exist, does Real Mode 32 exist as well? Apparently you guys, as well as testing, are confirming me that, indeed, it does exist.

As Brendan pointed out, this is not a mode that’s “usual”, so (as I noted already when I talked about crashes on real hardware and KVM) it will probably be less likely to be bug checked by the hardware manufacturers, and thus it might contain otherwise unnoticed bugs.

So to wrap it up, this is 32 bit code running under Real Mode, right? Correct me if I’m wrong.

Cheers.


Top
 Profile  
 
 Post subject: Re: Real Mode 32
PostPosted: Fri Dec 15, 2017 11:11 pm 
Offline
Member
Member
User avatar

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

xenos1 wrote:
I often hear people using the terms “Real Mode” and “Protected Mode” to refer to 16, and 32 bit modes. I believe this is a common misconception. What I wanted to know was: since Protected Mode 16 does exist, does Real Mode 32 exist as well? Apparently you guys, as well as testing, are confirming me that, indeed, it does exist.


"Protected mode implies 32-bit" is a common misconception (wrong because protected mode is designed to allow 32-bit or 16-bit code); and "long mode implies 64-bit" is a common misconception (wrong because long mode is designed to allow 64-bit, 32-bit or 16-bit code).

"Real mode implies 16-bit" is correct. Once you modify real mode you get something else that is not real mode anymore, so you need to invent a new name for it and define exactly what that name implies (e.g. "unreal mode").

Note that underneath all of this the majority of the CPU doesn't really care about "CPU modes". The instruction decoder needs to know about default operand and address size and nothing else; and everything after that (execution units, etc) only need to know the actual operand and address sizes (after size override prefixes were applied). The only part that does care about "CPU mode" is micro-code (for things like segment register loads, starting an interrupt handler, etc).

xenos1 wrote:
So to wrap it up, this is 32 bit code running under Real Mode, right? Correct me if I’m wrong.


I'd be tempted to call it "32-bit unreal mode" so that later on there's no confusion when you try "64-bit unreal mode". ;)


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: Real Mode 32
PostPosted: Sat Dec 16, 2017 5:31 am 
Offline
Member
Member

Joined: Fri Aug 26, 2016 1:41 pm
Posts: 671
I spent a bit of time cleaning up some of the major issues. Your pit and kbd routines rely on leave/iretw to leave a C function. This makes big assumptions like the fact that there are stack frames present (may to be if you want optimizations or build without them). Your interrupt routines don't properly save and restore the volatile registers. When your interrupt handlers finally return it is possible for registers to change and become values that could make the code interrupted fail to work properly. GCC 7 added a new function attribute ( __attribute__(interrupt) ). that would be helpful. I modified your code with some C macros that create entry points for the interrupt handlers. They save the general purpose registers, the segment registers, clear the direction flag (forward movement), add an interrupt number (if you wish to multiplex multiple interrupts through a single handler), and I've set the code up to make the stack variables available through a parameter. These stubs can be changed to suit you (they may do extra work you may not care about).

If you ever move to physical media for testing and opt to ditch zeroing out more than the size of your kernel, I have added a BSS section in your linker script that allows you to determine the starting point and length of that section so your code can zero out the region explicitly. It is also possible that GCC can rearrange functions so _start isn't actually guaranteed to appear first in the output file. I modified the code to add an inline assembly stub that is placed in a special section (the linker script was modified to support it) called .text.startup. We make sure that section appears before all other code so we know it will be palced at the beginning of the kernel.

I did other minor changes in the C code here and there. I modified the make script to split up the linking and compiling phases and use objcopy to create the final binary file. This has the advantage that you can generate symbolic debug information and use it when debugging in QEMU.

The newer version of your payload.c code was:
Code:
#include <stdint.h>

typedef struct {
    /* Pushed explicitly in our common stub code */
    uint32_t gs, fs, es, ds;
    /* Pushed in our stub code by pushad instruction */
    uint32_t edi, esi, ebp, esp, ebx, edx, ecx, eax;
    uint16_t int_num;         /* Interrupt number */
    uint16_t ip, cs, flags; /* Pushed by processor */
} interrupt_frame_rm32_t;

/* This code will be placed at the beginning of the second stage
* in the special section .text.startup that the linker script is
* aware of. It zeroes the BSS section, ensures the direction flag
* is set to forward movement (CLD) and then transfers control to
* kmain */
__asm__(".pushsection .text.startup\n\t"
        ".global _start\n"
        "_start:\n\t"
        "cld\n\t"
        "lea edi, __bss_start\n\t"
        "lea ecx, __bss_size_l\n\t"
        "xor eax, eax\n\t"
        "rep stosd\n\t"
        "call kmain\n\t"
        ".popsection");

/* Make interrupt/exception entry point that calls specified handler
* Push all the segment registers and the general purpose registers
* so that they are available to interrupt function (intfun). Pushes a unique
* interrupt number (intno) after the error code so that a handler can be multiplexed
* if needed. Restore all the registers upon exit.
*
* intentry: Is the interrupt entry point that can be used in an Interrupt
*           vector table (IVT) entry.
* intfunc:  Is the C interrupt function that the stub calls to do processing
* intno:    Interrupt number. Can be used to multiplex multiple interrupts to one
*           intfunc handler.
*/
#define MAKE_RM32_INTERRUPT(intentry, intfunc, intno) \
    extern void intentry (void); \
    __asm__(".pushsection .text\n\t" \
            ".global " #intentry "\n\t" \
            #intentry ":\n\t" \
            "pushw "#intno"\n\t" \
            "pusha\n\t" \
            "push ds\n\t" \
            "push es\n\t" \
            "push fs\n\t" \
            "push gs\n\t" \
            "cld\n\t" \
            "push esp\n\t" \
            "call " #intfunc "\n\t" \
            "pop eax\n\t" \
            "pop gs\n\t" \
            "pop fs\n\t" \
            "pop es\n\t" \
            "pop ds\n\t" \
            "popa\n\t" \
            "add esp, 2\n\t"       /* Skip int_num */ \
            "iretw\n\t" \
            ".popsection\n\t");

MAKE_RM32_INTERRUPT (interrupt_pit_entry, pit,  0x00)
MAKE_RM32_INTERRUPT (interrupt_kbd_entry, kbd,  0x01)


#define port_out_b(port, value) ({                              \
        __asm__ __volatile__ (  "out dx, al"            \
                                        :                                           \
                                        : "a" (value), "d" (port)       \
                                        : );                                        \
})

#define port_out_w(port, value) ({                              \
        __asm__ __volatile__ (  "out dx, ax"            \
                                        :                                           \
                                        : "a" (value), "d" (port)       \
                                        : );                                        \
})

#define port_out_d(port, value) ({                              \
        __asm__ __volatile__ (  "out dx, eax"           \
                                        :                                           \
                                        : "a" (value), "d" (port)       \
                                        : );                                        \
})

#define port_in_b(port) ({                                              \
        uint8_t value;                                                          \
        __asm__ __volatile__ (  "in al, dx"                     \
                                        : "=a" (value)                          \
                                        : "d" (port)                            \
                                        : );                                        \
        value;                                                                      \
})

#define port_in_w(port) ({                                              \
        uint16_t value;                                                         \
        __asm__ __volatile__ (  "in ax, dx"                     \
                                        : "=a" (value)                          \
                                        : "d" (port)                            \
                                        : );                                        \
        value;                                                                      \
})

#define port_in_d(port) ({                                              \
        uint32_t value;                                                         \
        __asm__ __volatile__ (  "in eax, dx"            \
                                        : "=a" (value)                          \
                                        : "d" (port)                            \
                                        : );                                        \
        value;                                                                      \
})


void hook_int(int interrupt, void* handler) {
    uint16_t* intptr = (uint16_t*)(interrupt * 4);
    *(intptr++) = (uint16_t)((uint32_t)handler);
    *intptr = 0;
    return;
}


#define VGA_X_MAX 80
#define VGA_Y_MAX 25
#define VGA_MAX (VGA_X_MAX * 2 * VGA_Y_MAX)
#define VGA_LIN_POS ((vga_cur_x * 2) + (vga_cur_y * (VGA_X_MAX * 2)))

int vga_cur_x = 0;
int vga_cur_y = 0;
char vga_text_attr = 0x07;
char vga_cur_attr = 0x70;

void vga_init(void) {
    char* vidmem = (char*)0xb8000;

    vga_cur_x = 0;
    vga_cur_y = 0;

    for (int i = 0; i < VGA_MAX; i++) {
        vidmem[i++] = ' ';
        vidmem[i] = vga_text_attr;
    }

    vidmem += VGA_LIN_POS;

    *(vidmem + 1) = vga_cur_attr;
}

void vga_scroll(void) {
    char* vidmem = (char*)0xb8000;

    for (int i = VGA_X_MAX * 2; i < VGA_MAX; i++)
        vidmem[i - VGA_X_MAX * 2] = vidmem[i];

    for (int i = VGA_MAX - VGA_X_MAX * 2; i < VGA_MAX; i++) {
        vidmem[i++] = ' ';
        vidmem[i] = vga_text_attr;
    }
}

void vga_putchar(char c) {
    char* vidmem = (char*)(0xb8000 + VGA_LIN_POS);

    if (c == '\n') {
        *(vidmem + 1) = vga_text_attr;
        vga_cur_x = 0;
        if (vga_cur_y == (VGA_Y_MAX - 1))
            vga_scroll();
        else
            vga_cur_y++;
        vidmem = (char*)(0xb8000 + VGA_LIN_POS);
        *(vidmem + 1) = vga_cur_attr;
        return;
    }

    if (c == '\b') {
        if (!vga_cur_x && !vga_cur_y)
            return;
        *(vidmem + 1) = vga_text_attr;
        if (!vga_cur_x)
            vga_cur_x = VGA_X_MAX - 1, vga_cur_y--;
        else
            vga_cur_x--;
        vidmem = (char*)(0xb8000 + VGA_LIN_POS);
        *vidmem = ' ';
        *(vidmem + 1) = vga_cur_attr;
        return;
    }

    *(vidmem++) = c;
    *(vidmem++) = vga_text_attr;

    if (++vga_cur_x == VGA_X_MAX)
        vga_cur_x = 0, vga_cur_y++;

    if (vga_cur_y == VGA_Y_MAX) {
        vga_scroll();
        vga_cur_x = 0, vga_cur_y--;
        vidmem = (char*)(0xb8000 + VGA_LIN_POS);
    }

    *(vidmem + 1) = vga_cur_attr;
}

void vga_putstr(char* str) {
    while (*str)
        vga_putchar(*(str++));
}

// PIT ISR stuff

void pit(interrupt_frame_rm32_t *frame) {
    port_out_b(0x20, 0x20);
}

#define MAX_CODE 0x57

static const char keymap[] = {
    '\0', '?', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '-', '=', '\b', '\t',
    'q', 'w', 'e', 'r', 't', 'y', 'u', 'i', 'o', 'p', '[', ']', '\n', '\0', 'a', 's',
    'd', 'f', 'g', 'h', 'j', 'k', 'l', ';', '\'', '`', '\0', '\\', 'z', 'x', 'c', 'v',
    'b', 'n', 'm', ',', '.', '/', '\0', '\0', '\0', ' '
};

int inchar = -1;

void kbd(interrupt_frame_rm32_t *frame) {
    uint8_t in = port_in_b(0x60);
    if (in < MAX_CODE)
        inchar = (int)(keymap[in]);
    port_out_b(0x20, 0x20);
}

char kbd_getchar(void) {
    while (inchar == -1)
        __asm__("hlt");
    char ret = (char)inchar;
    inchar = -1;
    return ret;
}

char* kbd_getstr(char* str, int limit) {
    int i = 0;
    char c;
    for (;;) {
        switch (c = kbd_getchar()) {
            case '\n':
                vga_putchar(c);
                break;
            case '\b':
                if (i) {
                    vga_putchar(c);
                    str[--i] = 0;
                }
                continue;
            default:
                if (i < (limit - 1)) {
                    vga_putchar(c);
                    str[i++] = c;
                }
                continue;
        }
        break;
    }
    str[i] = 0;
    return str;
}

void set_PIC0_mask(uint8_t mask) {
    port_out_b(0x21, mask);
    return;
}

void set_PIC1_mask(uint8_t mask) {
    port_out_b(0xA1, mask);
    return;
}

uint8_t get_PIC0_mask(void) {
    return port_in_b(0x21);
}

uint8_t get_PIC1_mask(void) {
    return port_in_b(0xA1);
}

int strcmp(const char* str1, const char* str2) {
    int i = 0;

    while (str1[i] && str1[i] == str2[i])
        i++;

    return str1[i] - str2[i];
}

void usage(void) {

    vga_putstr(
        "Usage:\n"
        "clear      --      Clears the screen.\n"
    );

}

void kmain(void) {
    char prompt[16];
    hook_int(0x8, interrupt_pit_entry);
    hook_int(0x9, interrupt_kbd_entry);
    vga_init();
    set_PIC1_mask(0xff);
    set_PIC0_mask(0b11111100);
    __asm__("sti");
    vga_putstr("Real Mode 32 Research\n\n");
    for (;;) {
        vga_putstr(">> ");
        kbd_getstr(prompt, 16);
        if (!*prompt) continue;
        vga_putstr("input: `"); vga_putstr(prompt); vga_putstr("`.\n");
        if (!strcmp(prompt, "clear"))
            vga_init();
        else if (!strcmp(prompt, "usage"))
            usage();
    }
}
The new linker.ld:
Code:
/* When this exectuable is converted to a binary file ENTRY doesn't
* have any meaning, however this will stop the linker warning
* about the entry point not being found */
ENTRY(_start)

SECTIONS
{
  .text 0x7e00 : {
    /* Ensure the .text.startup code appears before all other code */
    *(.text.startup)
    *(.text)
  }
  .data : {
    *(.rodata)
    *(.data)
  }

  .bss : SUBALIGN(4) {
      __bss_start = .;
      *(COMMON);
      *(.bss)
  }
  . = ALIGN(4);
  /* Linker symbols thats can be used for zeroing BSS section */
  __bss_end = .;
  __bss_size = ((__bss_end)-(__bss_start));
  __bss_size_l = (__bss_size)>>2;
}
Update make_me.sh:
Code:
#!/bin/bash

set -e

i386-elf-gcc -g -c payload.c -ffreestanding -o payload.o -masm=intel -Os -Wall
i386-elf-gcc -T linker.ld payload.o -o payload.elf -nostartfiles -nostdlib
i386-elf-objcopy payload.elf -Obinary payload.bin
nasm test.asm -f bin -o test.img
If you want to debug with QEMU and use the symbols from the intermediate ELF executable you can do something like this to launch QEMU with remote debugging:
Code:
#!/bin/bash

qemu-system-i386 -hda test.img -S -s  &
gdb payload.elf \
        -ex 'target remote localhost:1234' \
        -ex 'set architecture i386' \
        -ex 'layout src' \
        -ex 'layout reg' \
        -ex 'break *kmain' \
        -ex 'continue'
The other files remained as they were. These changes should also allow you to turn on optimizations with -Os (optimize for size). Use -O3 if you want to optimize for speed.


Last edited by MichaelPetch on Mon Dec 18, 2017 8:42 am, edited 1 time in total.

Top
 Profile  
 
 Post subject: Re: Real Mode 32
PostPosted: Mon Dec 18, 2017 8:28 am 
Offline
Member
Member

Joined: Mon Mar 25, 2013 7:01 pm
Posts: 5099
xenos1 wrote:
I, too, was pretty weirded out about this, but I did some testing in bochs (which marks the mode as "Real Mode 32"), in qemu (although I believe KVM crashes), and, most surprisingly, it works on real hardware! (Although it had some crashes at times)

Funny enough, the unreal mode wiki page has had a description of this trick for a while.

DOS has forced CPU manufacturers to include support for 16-bit unreal mode, but I'm not aware of any software that does the same thing for 32-bit unreal mode. You may stumble across a CPU that doesn't support it. (According to the FASM developer, someone already has.)


Top
 Profile  
 
 Post subject: Re: Real Mode 32
PostPosted: Mon Dec 18, 2017 6:41 pm 
Offline

Joined: Thu Dec 14, 2017 5:08 pm
Posts: 7
MichaelPetch wrote:
Your interrupt routines don't properly save and restore the volatile registers. When your interrupt handlers finally return it is possible for registers to change and become values that could make the code interrupted fail to work properly.


You're 100% right, my bad. I completely forgot about saving the scratch registers on interrupts, thanks.

MichaelPetch wrote:
GCC 7 added a new function attribute ( __attribute__(interrupt) ).


I didn't know about that, it sounds interesting, I'll look into it.
Thanks for the feedback!

Octocontrabass wrote:
Funny enough, the unreal mode wiki page has had a description of this trick for a while.


Yeah, I found that too, but I think that's referring to giving CS a limit larger than 0xffff, not about enabling the D bit in the selector and switching back. (aka 32 bit (un)real mode). Correct me if I'm wrong.

Brendan wrote:
I'd be tempted to call it "32-bit unreal mode" so that later on there's no confusion when you try "64-bit unreal mode".


I tried 64-bit (un)real mode already to no avail. lol
Well, I can see why you'd call it "32-bit unreal mode", but that leaves me wondering: if I still enable the D bit making the mode effectively a 32 bit mode, but I leave the segment limits at 0xffff (as in "normal" real mode), would that make it Real Mode 32?

Just a naming thing I guess!

Cheers.


Top
 Profile  
 
 Post subject: Re: Real Mode 32
PostPosted: Tue Dec 19, 2017 6:23 am 
Offline
Member
Member
User avatar

Joined: Sun Feb 20, 2011 2:01 pm
Posts: 110
xenos1 wrote:
MichaelPetch wrote:
Your interrupt routines don't properly save and restore the volatile registers. When your interrupt handlers finally return it is possible for registers to change and become values that could make the code interrupted fail to work properly.


You're 100% right, my bad. I completely forgot about saving the scratch registers on interrupts, thanks.

MichaelPetch wrote:
GCC 7 added a new function attribute ( __attribute__(interrupt) ).


I didn't know about that, it sounds interesting, I'll look into it.
Thanks for the feedback!

Octocontrabass wrote:
Funny enough, the unreal mode wiki page has had a description of this trick for a while.


Yeah, I found that too, but I think that's referring to giving CS a limit larger than 0xffff, not about enabling the D bit in the selector and switching back. (aka 32 bit (un)real mode). Correct me if I'm wrong.

Brendan wrote:
I'd be tempted to call it "32-bit unreal mode" so that later on there's no confusion when you try "64-bit unreal mode".


I tried 64-bit (un)real mode already to no avail. lol
Well, I can see why you'd call it "32-bit unreal mode", but that leaves me wondering: if I still enable the D bit making the mode effectively a 32 bit mode, but I leave the segment limits at 0xffff (as in "normal" real mode), would that make it Real Mode 32?

Just a naming thing I guess!

Cheers.

OK, that makes sense. Boy, who knew how many versions of unreal mode there are! Also, I'd be watching the D bit on the stack selector. That can open another can of fun.
64 bit unreal mode is unatainable, I'm afraid. LMA disables when paging is disabled, and the 64 bit segmentation method, as mentioned, prevents caching of limits. I'm not sure about FS/GS though, I might run some tests on that.

_________________
Whoever said you can't do OS development on Windows?
https://github.com/ChaiSoft/ChaiOS


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

All times are UTC - 6 hours


Who is online

Users browsing this forum: Yahoo [Bot] and 65 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