TSS problem

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.
Locked
MSathieu
Posts: 4
Joined: Sun Jan 28, 2018 9:29 am

TSS problem

Post by MSathieu »

I'm trying to switch to ring 3 and implement a TSS, but after i switched interrupts stop working. Even if I use cli to get a general protection fault, nothing happens. What's wrong with my code? The full source code is on https://github.com/MSathieu/Cernel, but I copied here the most important files.

tss.h:

Code: Select all

#include <stdint.h>

struct tss_table {
   uint32_t prev_tss;
   uint32_t esp0;
   uint32_t ss0;
   uint32_t esp1;
   uint32_t ss1;
   uint32_t esp2;
   uint32_t ss2;
   uint32_t cr3;
   uint32_t eip;
   uint32_t eflags;
   uint32_t eax;
   uint32_t ecx;
   uint32_t edx;
   uint32_t ebx;
   uint32_t esp;
   uint32_t ebp;
   uint32_t esi;
   uint32_t edi;
   uint32_t es;         
   uint32_t cs;        
   uint32_t ss;        
   uint32_t ds;        
   uint32_t fs;       
   uint32_t gs;         
   uint32_t ldt;      
   uint16_t trap;
   uint16_t iomap_base;
} __attribute__ ((packed));
struct tss_table tss;
gdt.c:

Code: Select all

#include <tss.h>
extern void load_gdt(uint32_t);
extern void load_tss(void);

struct gdt_table {
  uint16_t limit;
  uint32_t base;
} __attribute__((packed));
struct gdt_entry {
  uint16_t limit_low;
  uint16_t base_low;
  uint8_t base_middle;
  uint8_t access;
  uint8_t granularity;
  uint8_t base_high;
} __attribute__((packed));
struct gdt_table gdt;
struct gdt_entry gdt_entry[6];

void add_gdt_segment(int i, uint32_t base, uint32_t limit, uint32_t access, uint32_t granularity) {
  gdt_entry[i].base_low = (base & 0xffff);
  gdt_entry[i].base_middle = (base >> 16) & 0xff;
  gdt_entry[i].base_high = (base >> 24) & 0xff;
  gdt_entry[i].limit_low = (limit & 0xffff);
  gdt_entry[i].granularity = (limit >> 16) & 0x0f;
  gdt_entry[i].granularity |= granularity & 0xf0;
  gdt_entry[i].access = access;
}
void setup_tss(void) {
  uint32_t base = (uint32_t) &tss;
  uint32_t limit = sizeof(tss);
  add_gdt_segment(5, base, limit, 0xE9, 0x00);
  tss.ss0 = 0x10;
  tss.esp0 = 0x0;
}
void setup_gdt(void) {
  gdt.limit = sizeof(gdt_entry) * 6 - 1;
  gdt.base = (uint32_t) &gdt_entry;
  add_gdt_segment(0, 0, 0, 0, 0);
  add_gdt_segment(1, 0, 0xFFFFFFFF, 0x9A, 0xCF);
  add_gdt_segment(2, 0, 0xFFFFFFFF, 0x92, 0xCF);
  add_gdt_segment(3, 0, 0xFFFFFFFF, 0xFA, 0xCF);
  add_gdt_segment(4, 0, 0xFFFFFFFF, 0xF2, 0xCF);
  setup_tss();
  load_gdt((uint32_t) &gdt);
  load_tss();
}
load_gdt.asm:

Code: Select all

global load_gdt
global load_tss
load_gdt:
  mov eax, [esp+4]
  lgdt [eax]
  mov ax, 0x10
  mov ds, ax
  mov es, ax
  mov fs, ax
  mov gs, ax
  mov ss, ax
  jmp 0x08:flush_gdt
flush_gdt:
  ret
load_tss:
  mov ax, 0x2B
  ltr ax
  ret
usermode.asm:

Code: Select all

global jump_to_usermode
jump_to_usermode:
  mov ax, 0x23
  mov ds, ax
  mov es, ax
  mov fs, ax
  mov gs, ax
  mov eax, esp
  push 0x23
  push eax
  pushf
  push 0x1B
  push start_usermode
  iret
start_usermode:
  jmp $
idt.c:

Code: Select all

#include <ioports.h>
extern void load_idt();
extern void int0();
extern void int1();
extern void int2();
extern void int3();
extern void int4();
extern void int5();
extern void int6();
extern void int7();
extern void int8();
extern void int9();
extern void int10();
extern void int11();
extern void int12();
extern void int13();
extern void int14();
extern void int15();
extern void int16();
extern void int17();
extern void int18();
extern void int19();
extern void int20();
extern void int21();
extern void int22();
extern void int23();
extern void int24();
extern void int25();
extern void int26();
extern void int27();
extern void int28();
extern void int29();
extern void int30();
extern void int31();
extern void int32();
extern void int33();
extern void int34();
extern void int35();
extern void int36();
extern void int37();
extern void int38();
extern void int39();
extern void int40();
extern void int41();
extern void int42();
extern void int43();
extern void int44();
extern void int45();
extern void int46();
extern void int47();

struct idt_table {
  uint16_t limit;
  uint32_t base;
} __attribute__ ((packed));
struct idt_entry {
  uint16_t base_low;
  uint16_t select;
  uint8_t type;
  uint8_t flags;
  uint16_t base_high;
} __attribute__((packed));
struct idt_entry idt_entry[256];
struct idt_table idt;

void add_idt_segment(int i, uint32_t base) {
  idt_entry[i].base_low = (base & 0xFFFF);
  idt_entry[i].base_high = (base >> 16) & 0xFFFF;
  idt_entry[i].select = 0x08;
  idt_entry[i].type = 0;
  idt_entry[i].flags = 0x8E;
}
void setup_idt(void) {
  outb(0x20, 0x11);
  outb(0xA0, 0x11);
  outb(0x21, 0x20);
  outb(0xA1, 0x28);
  outb(0x21, 0x04);
  outb(0xA1, 0x02);
  outb(0x21, 0x01);
  outb(0xA1, 0x01);
  outb(0x21, 0x0);
  outb(0xA1, 0x0);
  idt.limit = (sizeof (struct idt_entry) * 256) - 1;
  idt.base = (int) idt_entry;
  add_idt_segment(0, (uint32_t) int0);
  add_idt_segment(1, (uint32_t) int1);
  add_idt_segment(2, (uint32_t) int2);
  add_idt_segment(3, (uint32_t) int3);
  add_idt_segment(4, (uint32_t) int4);
  add_idt_segment(5, (uint32_t) int5);
  add_idt_segment(6, (uint32_t) int6);
  add_idt_segment(7, (uint32_t) int7);
  add_idt_segment(8, (uint32_t) int8);
  add_idt_segment(9, (uint32_t) int9);
  add_idt_segment(10, (uint32_t) int10);
  add_idt_segment(11, (uint32_t) int11);
  add_idt_segment(12, (uint32_t) int12);
  add_idt_segment(13, (uint32_t) int13);
  add_idt_segment(14, (uint32_t) int14);
  add_idt_segment(15, (uint32_t) int15);
  add_idt_segment(16, (uint32_t) int16);
  add_idt_segment(17, (uint32_t) int17);
  add_idt_segment(18, (uint32_t) int18);
  add_idt_segment(19, (uint32_t) int19);
  add_idt_segment(20, (uint32_t) int20);
  add_idt_segment(21, (uint32_t) int21);
  add_idt_segment(22, (uint32_t) int22);
  add_idt_segment(23, (uint32_t) int23);
  add_idt_segment(24, (uint32_t) int24);
  add_idt_segment(25, (uint32_t) int25);
  add_idt_segment(26, (uint32_t) int26);
  add_idt_segment(27, (uint32_t) int27);
  add_idt_segment(28, (uint32_t) int28);
  add_idt_segment(29, (uint32_t) int29);
  add_idt_segment(30, (uint32_t) int30);
  add_idt_segment(31, (uint32_t) int31);
  add_idt_segment(32, (uint32_t) int32);
  add_idt_segment(33, (uint32_t) int33);
  add_idt_segment(34, (uint32_t) int34);
  add_idt_segment(35, (uint32_t) int35);
  add_idt_segment(36, (uint32_t) int36);
  add_idt_segment(37, (uint32_t) int37);
  add_idt_segment(38, (uint32_t) int38);
  add_idt_segment(39, (uint32_t) int39);
  add_idt_segment(40, (uint32_t) int40);
  add_idt_segment(41, (uint32_t) int41);
  add_idt_segment(42, (uint32_t) int42);
  add_idt_segment(43, (uint32_t) int43);
  add_idt_segment(44, (uint32_t) int44);
  add_idt_segment(45, (uint32_t) int45);
  add_idt_segment(46, (uint32_t) int46);
  add_idt_segment(47, (uint32_t) int47);
  load_idt();
}
User avatar
AJ
Member
Member
Posts: 2646
Joined: Sun Oct 22, 2006 7:01 am
Location: Devon, UK
Contact:

Re: TSS problem

Post by AJ »

Hi,

In your registers structure, what do you load in to eflags as an initial value? Is IF set?

CLI and STI are protected instructions, so depending on IOPL, #GPF may be the correct response.

Cheers,
Adam
MSathieu
Posts: 4
Joined: Sun Jan 28, 2018 9:29 am

Re: TSS problem

Post by MSathieu »

I loaded nothing in it. I don't think its necessary because i've never disabled interrupts before switching. I followed mainly https://wiki.osdev.org/Getting_to_Ring_3 and JamesM tutorial.
User avatar
AJ
Member
Member
Posts: 2646
Joined: Sun Oct 22, 2006 7:01 am
Location: Devon, UK
Contact:

Re: TSS problem

Post by AJ »

Ok - so what is in eflags when you execute PUSHF?
MSathieu
Posts: 4
Joined: Sun Jan 28, 2018 9:29 am

Re: TSS problem

Post by MSathieu »

I didn't change EFLAGS, so I guess the defaults.
User avatar
AJ
Member
Member
Posts: 2646
Joined: Sun Oct 22, 2006 7:01 am
Location: Devon, UK
Contact:

Re: TSS problem

Post by AJ »

If you run in Bochs, what is in EFLAGS just prior to pushing the flags?
MSathieu
Posts: 4
Joined: Sun Jan 28, 2018 9:29 am

Re: TSS problem

Post by MSathieu »

Im using QEMU
User avatar
AJ
Member
Member
Posts: 2646
Joined: Sun Oct 22, 2006 7:01 am
Location: Devon, UK
Contact:

Re: TSS problem

Post by AJ »

Hi,

There has to be some debugging effort on your part here. Either use Bochs or perform a Qemu registers dump just before the pushf instruction. If you are unsure how to do this, you need to learn your toolchain, ensure that you understand the code (not just C&P) and then look at the problem again.

Cheers,
Adam
Locked