Author Topic: gcc asm inline port in/out in x86 protected mode  (Read 6364 times)

0 Members and 2 Guests are viewing this topic.

Offline DiTBhoTopic starter

  • Super Contributor
  • ***
  • Posts: 5090
  • Country: gb
gcc asm inline port in/out in x86 protected mode
« on: May 06, 2023, 09:03:40 pm »
Code: [Select]
static void port_out
(
    uint16_t port,
    uint8_t value
)
{
    asm volatile ("outb %0, %1" : : "a" (value), "Nd" (port));
}

static uint8_t port_in
(
    uint16_t port
)
{
    uint8_t ans;

    asm volatile ("inb %1, %0" : "=a" (ans) : "Nd" (port));
    return ans;
}

is this stuff correct when the x86-CPU is in protected mode?  :o :o :o
(32bit)
The opposite of courage is not cowardice, it is conformity. Even a dead fish can go with the flow
 

Offline magic

  • Super Contributor
  • ***
  • Posts: 8058
  • Country: pl
Re: gcc asm inline port in/out in x86 protected mode
« Reply #1 on: May 07, 2023, 05:17:53 am »
Seems about right if you didn't swap the operands or something, not sure how the silly AT&T syntax works for these instructions.

Of course they are still valid instructions in protected mode. Pretty sure it should work in long mode too.
 
The following users thanked this post: DiTBho

Offline Nominal Animal

  • Super Contributor
  • ***
  • Posts: 8349
  • Country: fi
    • My home page and email address
Re: gcc asm inline port in/out in x86 protected mode
« Reply #2 on: May 07, 2023, 08:51:09 am »
There are two details to consider:
  • Protected mode privilege level

    Direct access to I/O ports requires IOPL 0, as determined by bits 12 and 13 in extended flags (EFLAGS).
     
  • Syntax

    In AT&T syntax (GCC or clang on x86 or x86-64 -m32), you want to use
       
        static inline void outb(const int port, const unsigned char value)
        {
            asm volatile ( "outb %%al, %%dx"
                         :
                         : "a" (value), "d" (port) );
        }
       
        static inline unsigned int inb(const int port)
        {
            unsigned char value;
            asm volatile ( "xor %%eax, %%eax\n\t"
                           "inb %%dx, %%al"
                         : "=a" (value)
                         : "d" (port) );
            return value;
        }
       
    noting that only the low 16 bits of port are used, and low 8 bits of value.  All 24 high bits of the value returned by inb() will always be zero.  (This eliminates certain cases where the high bits of eax register leak through the return value, even when the return type were unsigned char.)

    You can omit the inline if you wish, I only use it to remind us humans that these are an accessor/helper function (which I typically put in a header file), and not "normal" local functions.
 
The following users thanked this post: DiTBho

Offline DiTBhoTopic starter

  • Super Contributor
  • ***
  • Posts: 5090
  • Country: gb
Re: gcc asm inline port in/out in x86 protected mode
« Reply #3 on: May 07, 2023, 10:08:13 am »
thanks, guys

I don't like x86(1) at all, but I am writing a special monitor for my Soekris net5501.
So it's something that boots in real-mode (pure assembly code) and then switches into protected-mode (pure assembly code but jumping into crt0, and then to C main).

Code: [Select]
MBR boot, CPU in 16-bit Mode
CHS loading sec2-10 ... done
console=/serial0,115200-8-n-1
Switching to 32-bit Mode ... done
Installing ISRs ... done
Enabling external interrupts ... done
Initializing dynamic memory ... done
suppa shell
 > help
hallo - if you see the reply, it means it's starting to work
halt  - halt the CPU
 >

the above two in/out x86-port functions are needed to write the serial driver (drivers/serial.c)


(1) actually it's an AMD Geode LX @ 500Mhz
compatible with x86-i586  :-//
The opposite of courage is not cowardice, it is conformity. Even a dead fish can go with the flow
 

Offline Nominal Animal

  • Super Contributor
  • ***
  • Posts: 8349
  • Country: fi
    • My home page and email address
Re: gcc asm inline port in/out in x86 protected mode
« Reply #4 on: May 07, 2023, 11:00:43 am »
AFAIK you can use grub2 or syslinux/extlinux to boot Soekris net5501.

For grub2, the LHS and CHS geometry must match, because the BIOS uses CHS for small drives and LHS for larger ones.  And you may need to set some option to make sure grub does not wait forever if there is no serial (terminal) connected.

In case you're not aware, this and this and this may be useful.
 
The following users thanked this post: DiTBho

Offline magic

  • Super Contributor
  • ***
  • Posts: 8058
  • Country: pl
Re: gcc asm inline port in/out in x86 protected mode
« Reply #5 on: May 07, 2023, 11:08:11 am »
There are apparently some mechanism for permitting I/O port access by unprivileged tasks so it's not that simple. Wouldn't be surprised if they were used by Windows 98 to run DOS programs or the various VXD drivers.

But in ring 0 you don't care.

https://www.felixcloutier.com/x86/out
« Last Edit: May 07, 2023, 11:10:37 am by magic »
 
The following users thanked this post: DiTBho

Offline Nominal Animal

  • Super Contributor
  • ***
  • Posts: 8349
  • Country: fi
    • My home page and email address
Re: gcc asm inline port in/out in x86 protected mode
« Reply #6 on: May 07, 2023, 11:59:32 am »
There are apparently some mechanism for permitting I/O port access by unprivileged tasks
On other rings, the task state segment can contain a pointer to a bitmap where nonzero bits allow the current task access to said port.  This is not a kernel facility, it is provided by the x86 protected mode itself.

This is used in for example Linux via the ioperm() kernel interface; the permission/bitmap is retained over an exec.  The ioperm() call itself requires either root privileges or the CAP_SYS_RAWIO capability.
 
The following users thanked this post: DiTBho

Offline DiTBhoTopic starter

  • Super Contributor
  • ***
  • Posts: 5090
  • Country: gb
Re: gcc asm inline port in/out in x86 protected mode
« Reply #7 on: May 07, 2023, 12:23:23 pm »
grub2 to boot Soekris net5501.

.... on the last dumpster dive my friends found qty=6 Soekris net5501, most completely smashed as if hit by a giant heavy hammer (wtf?!? why?.?.?), some rusted and with popped caps, plus oxidation from being exposed to rain for months, but the last unit was promising: it powered up, and despite the serial port looked drunk as it outputted strings with missing or weird chars, I found it was only a pin with a floating ground connection.

The mobo was cleaned, easily repaired and finally re-installed into its still rusty metal case waiting to be repainted, but it's back to working condition  :-+


Yub, grub is an option, and it can be configured to reassign the console to Com1 but
- I don't like it
- I also need a monitor, not only a bootloader
- so I want something like U-boot
- I don't want to deal with PC_part
- I don't want to deal with EFI_part
- I need to initialize special PCI-fpga stuff (the net5501 offers a PCI 3.3V slot)
- I want to tftpboot

For grub2, the LHS and CHS geometry must match, because the BIOS uses CHS for small drives and LHS for larger ones.

I think I will use the BIOS disk calls (CHS) only to load the second stage, then I will implement a PCI driver to access the PATA controller in order to directly access the disk in LBA mode.

And in LBA, it will load the kernel in ram, and jump into kernel_start.

I already have a working skeleton
- MBR: working
- disk CHS: working
- second stage: partially working
- monitor (ram-dump, edit, fill): partially completed
- micro shell: partially completed
- serial console: working
- dynamic ram: working

The max size of the final code must be < 800Kbyte  :o :o :o
The opposite of courage is not cowardice, it is conformity. Even a dead fish can go with the flow
 

Offline Nominal Animal

  • Super Contributor
  • ***
  • Posts: 8349
  • Country: fi
    • My home page and email address
Re: gcc asm inline port in/out in x86 protected mode
« Reply #8 on: May 07, 2023, 01:41:07 pm »
I think I will use the BIOS disk calls (CHS) only to load the second stage, then I will implement a PCI driver to access the PATA controller in order to directly access the disk in LBA mode.
I recommend having /boot be a separate partition at the beginning of the disk.  Then, as long as your CHS geometry matches the LBA mode, it'll just work.

Soekris net5501 was apparently widely used with old Ubuntu and Gentoo versions, so you'll find quite a lot of information there.  Furthermore, if you set up an image with an old distro that supported net5501 out of the box, you can boot it and compare /proc and /sys pseudofiles to see if your custom kernels (kernel configs) have all the necessary/useful options selected.
 


Share me

Digg  Facebook  SlashDot  Delicious  Technorati  Twitter  Google  Yahoo
Smf