//-------------------------------------------------------------------
//	showgdt.cpp
//
//	This application uses an "unprivileged" Pentium instruction 
//	to obtain the base-address and segment-limit for the Global
//	Descriptor Table, located within the Linux kernel's address
//	space, and also installs a device-driver module ('dram.o'),
//	allowing it to read from our machine's memory as if it were
//	a file (named '/dev/dram'), so that the GDT descriptors can
//	be read and displayed as quadwords in hexadecimal notation.  
//	Note that 'root' privileges are normally needed, to install 
//	kernel modules or to create device-nodes, like this:
//	
//		root#  /bin/mknod /dev/dram c 253 0
//		root#  /sbin/insmod dram.o
//
//	NOTE: Written and tested using Linux kernel version 2.4.21.
//
//	programmer: ALLAN CRUSE
//	written on: 16 MAR 2003
//	revised on: 01 MAR 2004 -- use /dev/dram in lieu of /dev/ram
//-------------------------------------------------------------------

#include <stdio.h>	// for printf(), perror() 
#include <fcntl.h>	// for open() 
#include <stdlib.h>	// for exit() 
#include <unistd.h>	// for read(), close() 

#define TASK_SIZE	0xC0000000
#define virt_to_phys(vaddr) ( vaddr - TASK_SIZE )

char devname[] = "/dev/dram";		// name of the 'device' file
unsigned short gdtr[3];			// to hold 48-bit GDTR value
unsigned long long *gdt;		// pointer to 64-bit entries

int main( int argc, char **argv )
{
	// install device-driver module in the kernel
	system( "/sbin/insmod dram.o" );
	
	// open device file for reading physical memory 
	int	fd = open( devname, O_RDONLY );
	if ( fd < 0 ) { perror( devname ); exit(1);}

	// get virtual address of the processor's GDT 
	asm(" sgdt gdtr " );
	long	gdtbase = *(unsigned long*)(gdtr+1);
	long	gdtsize = 1 + gdtr[0];

	// allocate a memory-buffer for the GDT
	gdt = (unsigned long long *)malloc( gdtsize );
	if ( !gdt ) { perror( "malloc" ); exit(1); }
	
	// read the table of interrupt descriptors
	lseek( fd, virt_to_phys(gdtbase), SEEK_SET );
	int	n_entries = gdtsize/8;
	for (int i = 0; i < n_entries; i++)
		{
		int	nbytes = read( fd, gdt+i, 8 );
		if ( nbytes < 8 ) { perror( "read" ); exit(1); }
		}
		
	// display the descriptors in hexadecimal format
	printf( "\n\nTABLE OF GLOBAL DESCRIPTORS %25s", " " );	
	printf( "(GDTR=%04X%04X-%04X)\n", gdtr[2], gdtr[1], gdtr[0] );
	for (int i = 0; i < n_entries; i++)
		{
		if ( ( i % 4 ) == 0 ) printf( "\n%04X: ", i*8 );
		printf( "%016llX ", gdt[ i ] );
		}
	printf( "\n\n" );	

	// release the memory-buffer and close the device file
	free( gdt );
	close( fd );
}