title: OSDEV interrupts brokens aften user mode jump
body: <p>I am trying to create own operating system, but aften jumping to user mode, then calling a syscall interrupts broken, and shows me a &quot;f&quot; on red background.
  But if I disable the jump to user mode, all works fine, any reason?</p>
  <p>Here my gdt.c:</p>
  <pre class="lang-c prettyprint-override"><code>#include &lt;x86/gdt.h&gt;
  #include&lt;serial.h&gt;
  gdt_entry_t gdt_entries[6];
  gdt_ptr_t   gdt_ptr;
  tss_entry_t tss_entry;
  void gdt_init()
  {
      gdt_ptr.limit = (sizeof(gdt_entry_t) * 6) - 1;
      gdt_ptr.base  = (uint32_t)&amp;gdt_entries;
  
      gdt_set_gate(0, 0, 0, 0, 0);                // Null segment
      gdt_set_gate(1, 0, 0xFFFFFFFF, 0x9A, 0xCF); // Code segment
      gdt_set_gate(2, 0, 0xFFFFFFFF, 0x92, 0xCF); // Data segment
      gdt_set_gate(3, 0, 0xFFFFFFFF, 0xFA, 0xCF); // User mode code segment
      gdt_set_gate(4, 0, 0xFFFFFFFF, 0xF2, 0xCF); // User mode data segment
      tss_write(5,0x10,0);
      gdt_flush((int)&amp;gdt_ptr);
      tss_flush();
  }
  void gdt_set_gate(s32 num, uint32_t base, uint32_t limit, uint8_t access, uint8_t gran)
  {
      gdt_entries[num].base_low    = (base &amp; 0xFFFF);
      gdt_entries[num].base_middle = (base &gt;&gt; 16) &amp; 0xFF;
      gdt_entries[num].base_high   = (base &gt;&gt; 24) &amp; 0xFF;
  
      gdt_entries[num].limit_low   = (limit &amp; 0xFFFF);
      gdt_entries[num].granularity = (limit &gt;&gt; 16) &amp; 0x0F;
  
      gdt_entries[num].granularity |= gran &amp; 0xF0;
      gdt_entries[num].access      = access;
  }
  void tss_write(s32 num,uint32_t ss0,uint32_t esp0) {
      uint32_t base = (uint32_t)&amp;tss_entry;
      uint32_t limit = sizeof(tss_entry);
      gdt_set_gate(num,base,limit,0xE9,0x00);
      memset(&amp;tss_entry,0,sizeof(tss_entry));
      tss_entry.ss0 = ss0;
      tss_entry.esp0 = esp0;
      tss_entry.cs = 0x0b;
      tss_entry.ss = tss_entry.ds = tss_entry.es = tss_entry.fs = tss_entry.gs = 0x13;
    }
    void tss_set_stack(uint32_t ss,uint32_t esp) {
        tss_entry.ss0 = ss;
        tss_entry.esp0 = esp;
    }
  </code></pre>
  <p>Switch to user code:</p>
  <pre class="lang-asm prettyprint-override"><code>mov eax, esp
  push 0x23 ; data selector
  push eax ; current esp
  pushf ; eflags
  push 0x1B  ; code selector (ring 3 code with bottom 2 bits set for ring 3)
  push test_user_function ; instruction address to return to
  iret
  test_user_function:
     int 0x80
     ret
  </code></pre>
  <p>Interrupts.s:</p>
  <pre class="lang-asm prettyprint-override"><code>cli
  pusha
  mov ax,ds
  push eax
  mov ax, 0x10  ; load the kernel data segment descriptor
  mov ds, ax
  mov es, ax
  mov fs, ax
  mov gs, ax
  push esp
  call syscall_handler
  add esp,4
  pop ebx
  mov ds, bx
  mov es, bx
  mov fs, bx
  mov gs, bx
  popa
  sti
  iret
  </code></pre>
  <p>The QEMU when i starting kernel: <a href="https://i.stack.imgur.com/djUpx.png" rel="nofollow noreferrer">View picture</a></p>