OSDev.org

The Place to Start for Operating System Developers
It is currently Fri Apr 19, 2024 3:09 pm

All times are UTC - 6 hours




Post new topic Reply to topic  [ 6 posts ] 
Author Message
 Post subject: Problem Setting Up GDT
PostPosted: Sat May 06, 2017 11:43 pm 
Offline
Member
Member
User avatar

Joined: Sun Feb 12, 2017 1:50 am
Posts: 26
I'm trying to set up my GDT table, but upon doing so the system crashes and goes into an infinite loop as it infinitely reboots and tries again. I based my implementation on the OSDev wiki tutorial and MINIX's implementation.

I have a header that defines some packed structs in the same way as MINIX, a source file that sets up the data structures, and an assembly function that loads the GDT and sets up the special registers. I'm pretty sure the problem is with the assembly function that actually loads the GDT, but I've included everything just in case.

How do we know that the correct segment selector to call flush_segments from is 0x08, and why are we setting all other segments to 0x10 now?
Code:
        .intel_syntax noprefix

        .global x86_lgdt
        .type x86_lgdt, @function
x86_lgdt:
        lgdt [esp+4]
        jmp 0x08:flush_segments
flush_segments:
        mov ax, 0x10
        mov ds, ax
        mov es, ax
        mov fs, ax
        mov gs, ax
        mov ss, ax
        ret


Code:
#ifndef _GDT_KERNEL_H
#define _GDT_KERNEL_H

#include <stdint.h>

struct GdtEntry {
  uint16_t limit_low;
  uint16_t base_low;
  uint8_t base_middle;
  uint8_t access;      /* |P|Pr|1|X|D|W|A|  1 indicates that this is code/data */
  uint8_t gran;        /* |G|S|0|0|LMIT|  */
  uint8_t base_high;
}__attribute__((packed));

/*
  P   - Present bit
  Pr  - Privilege bits, 0-3
  X   - Executable bit
  D   - Direction bit for data, 0 grows up, 1 grows down
      - Conforming bit for code, 0 can only be executed by priv set in Pr.
  W   - Read/Write. 1 enables reading for code segments and write access for data.
  A   - Access bit used by CPU. Set it to 0.

  G   - Granularity bit. 0 for limit in 1B blocks. 1 if limit in 4KB blocks (pages)
  S   - Size bit. 0 for 16-bit mode, 1 for 32-bit mode
*/

struct GdtR {
  uint16_t limit;
  uint32_t base;
}__attribute__((packed));

void setup_gdt(void);

#endif


Code:
#include <kernel/gdt.h>
#include <kernel/gdt_asm.h>

#include <string.h>
#include <stdio.h>

#define TYPE_CODE 14
#define TYPE_DATA 6
#define PRIV_KERN 0
#define PRIV_USER 3

struct GdtEntry gdt_entries[5];
struct GdtR gdt;

uint8_t createAccess(uint8_t privilege, uint8_t type) {
  /* Entry will always be present. 0x90 is 1001 0000b */
  return (uint8_t) ((0x90) | (privilege << 5) | (type));
}

void setEntry(uint32_t base, uint32_t limit, uint8_t access, struct GdtEntry* entry) {
  entry->base_low = base & 0xFFFF; //lower 16 bits
  entry->base_middle = (base << 8) >> 24;
  entry->base_high = base >> 24;

  entry->limit_low = limit & 0xFFFF;
  entry->gran = (12 << 4) | (uint8_t)(limit << 12 >> 28);
  /* 12 in highest 4 bits sets granularity bit (setting 4KB blocks)
       and Size bit (set 32-bit mode) */

  entry->access = access;
}

void setup_gdt(void) {
  printf("BEGIN GDT SETUP\n");

  memset(gdt_entries, 0, sizeof(gdt_entries));

  gdt.base = (uint32_t) &gdt_entries;
  gdt.limit = sizeof(gdt_entries) - 1;

  printf("Addr: 0x%x\nBase: 0x%x\nLim: 0x%x\n", &gdt, gdt.base, gdt.limit);

  uint8_t kern_code = createAccess(PRIV_KERN, TYPE_CODE);
  uint8_t kern_data = createAccess(PRIV_KERN, TYPE_DATA);
  uint8_t user_code = createAccess(PRIV_USER, TYPE_CODE);
  uint8_t user_data = createAccess(PRIV_USER, TYPE_DATA);

  //setEntry(0, 0, 0, &gdt_entries[0]);//<--this should be zero'd from memset
  setEntry(0, 0x000FFFFF, kern_code, &gdt_entries[1]);
  setEntry(0, 0x000FFFFF, kern_data, &gdt_entries[2]);
  setEntry(0, 0x000FFFFF, user_code, &gdt_entries[3]);
  setEntry(0, 0x000FFFFF, user_data, &gdt_entries[4]);


  printf("---Entry---\n");
  printf("base: 0x%x\n",(uint32_t)(
         (uint32_t)gdt_entries[1].base_high << 24 |
         (uint32_t)gdt_entries[1].base_middle) << 16 |
         (uint32_t)gdt_entries[1].base_low);
  printf("limit: 0x%x\n", (uint32_t)( (uint32_t)gdt_entries[1].gran << 16
                                       | (uint32_t)gdt_entries[1].limit_low) & 0xFFFFF );

  for (int i = 1; i < 5; i++) {
  struct GdtEntry debugp = gdt_entries[i];
  printf("----Entry%d---\n", i);
  printf("access: 0x%x\n", (uint32_t)debugp.access);
  printf("gran: 0x%x\n", (uint32_t)(debugp.gran >> 4));
  }

  // x86_lgdt((uint32_t) &gdt);
}


Code:
BEGIN GDT SETUP
Addr: 0x102000
Base: 0x102020
Lim: 0x27
---Entry---
base: 0x0
limit: 0xfffff
----Entry1---
access: 0x9e
gran: 0xc
----Entry2---
access: 0x96
gran: 0xc
----Entry3---
access: 0xfe
gran: 0xc
----Entry4---
access: 0xf6
gran: 0xc


Top
 Profile  
 
 Post subject: Re: Problem Setting Up GDT
PostPosted: Sat May 06, 2017 11:58 pm 
Offline
Member
Member
User avatar

Joined: Sun Feb 12, 2017 1:50 am
Posts: 26
OSDev forums are you my rubber duck?

Should
Code:
lgdt [esp+4]
be
Code:
mov eax, [esp+4]
lgdt [eax]


Even then there is a weird stutter that makes me think things aren't quite right...


Top
 Profile  
 
 Post subject: Re: Problem Setting Up GDT
PostPosted: Sun May 07, 2017 12:15 am 
Offline
Member
Member
User avatar

Joined: Fri Oct 21, 2011 9:47 pm
Posts: 286
Location: Tustin, CA USA
MuchLearning wrote:
infinitely reboots and tries again


You are getting a General Protection Fault, which is causing a Double Fault, and then a Triple Fault (and reboot).

I just happen to have my Intel Software Developer's Guide -- System Programmer's Guide vol3A open to figure 5-1... And Section 5-10 handles the discussion of what the Confirming bit means. I just happened to be refreshing my memory on this today, and I set my Kernel code to 0x9a and my Kernel data to 0x92.

MuchLearning wrote:
How do we know that the correct segment selector to call flush_segments from is 0x08, and why are we setting all other segments to 0x10 now?


You should know because that is how you are setting them up. Code selector 0x08 (think of it as a byte offset into the GDT table since each entry is 8 bytes) is exactly what you are defining, and the same holds for 0x10 for kernel data.

Now as an aside, I would also recommend that you refresh your esp right after setting ss. The reason for this is that the CPU will prevent an interrupt for 1 additional instruction when you mov to ss to allow for the stack pointer to be set as well. (And, I just realized I did this backwards today... :oops: ) For me, I found it better to handle the GDT at compile time and set it all properly as soon as grub handed control to my loader -- literally the first thing done.

_________________
Adam

The name is fitting: Century Hobby OS -- At this rate, it's gonna take me that long!
Read about my mistakes and missteps with this iteration: Journal

"Sometimes things just don't make sense until you figure them out." -- Phil Stahlheber


Top
 Profile  
 
 Post subject: Re: Problem Setting Up GDT
PostPosted: Sun May 07, 2017 3:56 am 
Offline
Member
Member
User avatar

Joined: Wed Aug 08, 2012 6:39 am
Posts: 42
Location: New York, NY
Any particular reason you are not using inline assembly to load the GDTR ?
GCC will calculate the correct stack offset automatically for you, whereas your assembly code doesn't even seem to follow the correct calling convention (frame pointer?).

Also, while it is clear that GDT offset 0x0 will be full zero (i.e. the NULL segment), but for clarity maybe it is better to include the code that sets it to zero, instead of relying on memset.

_________________
Cheers,

Lev


Top
 Profile  
 
 Post subject: Re: Problem Setting Up GDT
PostPosted: Fri May 12, 2017 3:07 am 
Offline
Member
Member
User avatar

Joined: Sun Feb 12, 2017 1:50 am
Posts: 26
lev wrote:
Any particular reason you are not using inline assembly to load the GDTR ?


Does incompetence count as a reason? I'm looking at chaning it to inline assembly now.


Top
 Profile  
 
 Post subject: Re: Problem Setting Up GDT
PostPosted: Fri May 12, 2017 3:37 am 
Offline
Member
Member
User avatar

Joined: Sat Mar 31, 2012 3:07 am
Posts: 4594
Location: Chichester, UK
MuchLearning wrote:
Does incompetence count as a reason?

It would certainly be a good reason for trying to live up to your username.

I'm not sure that it is the best reason for posting here.


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

All times are UTC - 6 hours


Who is online

Users browsing this forum: Bing [Bot], DotBot [Bot], Google [Bot], JustVic and 156 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