<file_sep>#include <interrupt/idt.h>
#include <lib/stdtypes.h>
#include <lib/x86.h>
#include <lib/string.h>
#include <drivers/screen/textmode.h>

extern void idt_flush(uint32_t);

static void idt_set_gate(uint8_t, uint32_t, uint16_t, uint8_t);

idt_entry_t idt_entries[256];
idt_ptr_t idt_ptr;
interrupt_handler_t interrupt_handlers[256];

void idt_init(void)
{
	// Zero all interrupt handlers
	memset(&interrupt_handlers, 0, sizeof(interrupt_handler_t) * 256);

	// Just like the GDT, the IDT has a "limit" field that is set to the last valid byte in the IDT,
	// after adding in the start position (i.e. size-1).
	idt_ptr.limit = sizeof(idt_entry_t) * 256 - 1;
	idt_ptr.base  = (uint32_t) &idt_entries;

	// Zero the IDT
	memset(&idt_entries, 0, sizeof(idt_entry_t) * 255);

	// Remap IRQs
	outportb(0x20, 0x11);
	outportb(0xA0, 0x11);
	outportb(0x21, 0x20);
	outportb(0xA1, 0x28);
	outportb(0x21, 0x04);
	outportb(0xA1, 0x02);
	outportb(0x21, 0x01);
	outportb(0xA1, 0x01);
	outportb(0x21, 0x0);
	outportb(0xA1, 0x0);

	// Set each gate in the IDT that we care about - that is:
	// 0-32:  Used by the CPU to report conditions, both normal and error.
	// 255:   Will be used later as a way to execute system calls.
	idt_set_gate(0, (uint32_t)isr0 , 0x08, 0x8E);
	idt_set_gate(1, (uint32_t)isr1 , 0x08, 0x8E);
	idt_set_gate(2, (uint32_t)isr2 , 0x08, 0x8E);
	idt_set_gate(3, (uint32_t)isr3 , 0x08, 0x8E);
	idt_set_gate(4, (uint32_t)isr4 , 0x08, 0x8E);
	idt_set_gate(5, (uint32_t)isr5 , 0x08, 0x8E);
	idt_set_gate(6, (uint32_t)isr6 , 0x08, 0x8E);
	idt_set_gate(7, (uint32_t)isr7 , 0x08, 0x8E);
	idt_set_gate(8, (uint32_t)isr8 , 0x08, 0x8E);
	idt_set_gate(9, (uint32_t)isr9 , 0x08, 0x8E);
	idt_set_gate(10, (uint32_t)isr10, 0x08, 0x8E);
	idt_set_gate(11, (uint32_t)isr11, 0x08, 0x8E);
	idt_set_gate(12, (uint32_t)isr12, 0x08, 0x8E);
	idt_set_gate(13, (uint32_t)isr13, 0x08, 0x8E);
	idt_set_gate(14, (uint32_t)isr14, 0x08, 0x8E);
	idt_set_gate(15, (uint32_t)isr15, 0x08, 0x8E);
	idt_set_gate(16, (uint32_t)isr16, 0x08, 0x8E);
	idt_set_gate(17, (uint32_t)isr17, 0x08, 0x8E);
	idt_set_gate(18, (uint32_t)isr18, 0x08, 0x8E);
	idt_set_gate(19, (uint32_t)isr19, 0x08, 0x8E);
	idt_set_gate(20, (uint32_t)isr20, 0x08, 0x8E);
	idt_set_gate(21, (uint32_t)isr21, 0x08, 0x8E);
	idt_set_gate(22, (uint32_t)isr22, 0x08, 0x8E);
	idt_set_gate(23, (uint32_t)isr23, 0x08, 0x8E);
	idt_set_gate(24, (uint32_t)isr24, 0x08, 0x8E);
	idt_set_gate(25, (uint32_t)isr25, 0x08, 0x8E);
	idt_set_gate(26, (uint32_t)isr26, 0x08, 0x8E);
	idt_set_gate(27, (uint32_t)isr27, 0x08, 0x8E);
	idt_set_gate(28, (uint32_t)isr28, 0x08, 0x8E);
	idt_set_gate(29, (uint32_t)isr29, 0x08, 0x8E);
	idt_set_gate(30, (uint32_t)isr30, 0x08, 0x8E);
	idt_set_gate(31, (uint32_t)isr31, 0x08, 0x8E);
	idt_set_gate(32, (uint32_t)irq0, 0x08, 0x8E);
	idt_set_gate(33, (uint32_t)irq1, 0x08, 0x8E);
	idt_set_gate(34, (uint32_t)irq2, 0x08, 0x8E);
	idt_set_gate(35, (uint32_t)irq3, 0x08, 0x8E);
	idt_set_gate(36, (uint32_t)irq4, 0x08, 0x8E);
	idt_set_gate(37, (uint32_t)irq5, 0x08, 0x8E);
	idt_set_gate(38, (uint32_t)irq6, 0x08, 0x8E);
	idt_set_gate(39, (uint32_t)irq7, 0x08, 0x8E);
	idt_set_gate(40, (uint32_t)irq8, 0x08, 0x8E);
	idt_set_gate(41, (uint32_t)irq9, 0x08, 0x8E);
	idt_set_gate(42, (uint32_t)irq10, 0x08, 0x8E);
	idt_set_gate(43, (uint32_t)irq11, 0x08, 0x8E);
	idt_set_gate(44, (uint32_t)irq12, 0x08, 0x8E);
	idt_set_gate(45, (uint32_t)irq13, 0x08, 0x8E);
	idt_set_gate(46, (uint32_t)irq14, 0x08, 0x8E);
	idt_set_gate(47, (uint32_t)irq15, 0x08, 0x8E);
	idt_set_gate(255, (uint32_t)isr255, 0x08, 0x8E);

	idt_flush((uint32_t)&idt_ptr);
}

static void idt_set_gate(uint8_t num, uint32_t base, uint16_t sel, uint8_t flags)
{
	idt_entries[num].base_lo = base & 0xFFFF;
	idt_entries[num].base_hi = (base >> 16) & 0xFFFF;

	idt_entries[num].sel     = sel;
	idt_entries[num].always0 = 0;
	// We must uncomment the OR below when we get to using user-mode
	// It sets the interrupt gate's privilege level to 3
	idt_entries[num].flags   = flags /* | 0x60 */;
}
<file_sep>#include <cpu/fpu.h>
#include <lib/stdtypes.h>
#include <drivers/screen/textmode.h>

void fpu_init(void) // TODO: Check FPU is present
{
	size_t cr4;
	__asm __volatile__("mov %%cr4, %0" : "=r"(cr4));
	cr4 |= 0x200;
	__asm __volatile__("mov %0, %%cr4" :: "r"(cr4));

	fpu_set_cw(0x37F);
}

void fpu_set_cw(const uint16_t cw)
{
	__asm __volatile__("fldcw %0" :: "m"(cw));
}
<file_sep>#ifndef LIB_STRING_H
#define LIB_STRING_H

#include <lib/stdtypes.h>
#include <lib/stddef.h>

void *memcpy(void *dest, const void *src, size_t count);
void *memset(void *dest, int8_t value, size_t count);
void *memsetw(void *dest, uint16_t value, size_t count);
int32_t memcmp(const void *s1, const void *s2, size_t n);
int8_t *itoa(int32_t value, int8_t *result, int32_t base);
int32_t strcmp(const int8_t *str1, const int8_t *str2);
int32_t strncmp(const int8_t *str1, const int8_t *str2, int32_t count);
int8_t *strcpy(int8_t *dest, const int8_t *src);
int8_t *strncpy(int8_t *dest, const int8_t *src, int32_t count);
int8_t *strcat(int8_t *dest, const int8_t *src);
int32_t strlen(const int8_t *src);
int32_t isspace(int8_t c);
int32_t isupper(int8_t c);
int32_t islower(int8_t c);
int32_t isdigit(int8_t c);
int32_t isalpha(int8_t c);
int8_t toupper(int8_t c);
int8_t tolower(int8_t c);

#endif
<file_sep>#ifndef DRIVERS_SERIAL_H
#define DRIVERS_SERIAL_H

#include <lib/stdtypes.h>
#include <interrupt/isr.h>

#define SERIAL_IRQ 4

#define SERIAL_PORT_A 0x3F8
#define SERIAL_PORT_B 0x2F8
#define SERIAL_PORT_C 0x3E8
#define SERIAL_PORT_D 0x2E8

void serial_handler_a(registers_t *regs);
void serial_handler_b(registers_t *regs);
void serial_enable(int32_t device);
void serial_init(void);
void serial_write(int32_t device, const int8_t *out);

#endif
<file_sep>#ifndef DRIVERS_PCI_PCI_H
#define DRIVERS_PCI_PCI_H

void pci_scan(void);

#endif
<file_sep># SimpleOS #
## Simple, yet ingenious. ##

**SimpleOS** is a hobby x86 kernel and operating system loosely based on POSIX, written in C with ASM where needed.

**SimpleOS** aims to keep things simple, small and efficient.
<file_sep>#ifndef DRIVERS_PCI_REGISTRY_H
#define DRIVERS_PCI_REGISTRY_H

#include <lib/stdtypes.h>

const int8_t *pci_device_name(uint32_t vendorId, uint32_t deviceId);
const int8_t *pci_class_name(uint32_t classCode, uint32_t subclass, uint32_t progIntf);

// PCI Vendors
#define VENDOR_INTEL                    0x8086

// PCI Classes
#define PCI_CLASS_LEGACY                0x00
#define PCI_CLASS_STORAGE               0x01
#define PCI_CLASS_NETWORK               0x02
#define PCI_CLASS_DISPLAY               0x03
#define PCI_CLASS_MULTIMEDIA            0x04
#define PCI_CLASS_MEMORY                0x05
#define PCI_CLASS_BRIDGE_DEVICE         0x06
#define PCI_CLASS_COMMUNICATION         0x07
#define PCI_CLASS_PERIHPERALS           0x08
#define PCI_CLASS_INPUT_DEVICES         0x09
#define PCI_CLASS_DOCKING_STATION       0x0a
#define PCI_CLASS_PROCESSOR             0x0b
#define PCI_CLASS_SERIAL_BUS            0x0c
#define PCI_CLASS_WIRELESS              0x0d
#define PCI_CLASS_INTELLIGENT_IO        0x0e
#define PCI_CLASS_SATELLITE             0x0f
#define PCI_CLASS_CRYPT                 0x10
#define PCI_CLASS_SIGNAL_PROCESSING     0x11
#define PCI_CLASS_UNDEFINED             0xff

// Undefined Class
#define PCI_UNCLASSIFIED                0x0000
#define PCI_VGA_COMPATIBLE              0x0001

// Mass Storage Controller
#define PCI_STORAGE_SCSI                0x0100
#define PCI_STORAGE_IDE                 0x0101
#define PCI_STORAGE_FLOPPY              0x0102
#define PCI_STORAGE_IPI                 0x0103
#define PCI_STORAGE_RAID                0x0104
#define PCI_STORAGE_ATA                 0x0105
#define PCI_STORAGE_SATA                0x0106
#define PCI_STORAGE_OTHER               0x0180

// Network Controller
#define PCI_NETWORK_ETHERNET            0x0200
#define PCI_NETWORK_TOKEN_RING          0x0201
#define PCI_NETWORK_FDDI                0x0202
#define PCI_NETWORK_ATM                 0x0203
#define PCI_NETWORK_ISDN                0x0204
#define PCI_NETWORK_WORLDFIP            0x0205
#define PCI_NETWORK_PICGMG              0x0206
#define PCI_NETWORK_OTHER               0x0280

// Display Controller
#define PCI_DISPLAY_VGA                 0x0300
#define PCI_DISPLAY_XGA                 0x0301
#define PCI_DISPLAY_3D                  0x0302
#define PCI_DISPLAY_OTHER               0x0380

// Multimedia Controller
#define PCI_MULTIMEDIA_VIDEO            0x0400
#define PCI_MULTIMEDIA_AUDIO            0x0401
#define PCI_MULTIMEDIA_PHONE            0x0402
#define PCI_MULTIMEDIA_AUDIO_DEVICE     0x0403
#define PCI_MULTIMEDIA_OTHER            0x0480

// Memory Controller
#define PCI_MEMORY_RAM                  0x0500
#define PCI_MEMORY_FLASH                0x0501
#define PCI_MEMORY_OTHER                0x0580

// Bridge Device
#define PCI_BRIDGE_HOST                 0x0600
#define PCI_BRIDGE_ISA                  0x0601
#define PCI_BRIDGE_EISA                 0x0602
#define PCI_BRIDGE_MCA                  0x0603
#define PCI_BRIDGE_PCI                  0x0604
#define PCI_BRIDGE_PCMCIA               0x0605
#define PCI_BRIDGE_NUBUS                0x0606
#define PCI_BRIDGE_CARDBUS              0x0607
#define PCI_BRIDGE_RACEWAY              0x0608
#define PCI_BRIDGE_OTHER                0x0680

// Simple Communication Controller
#define PCI_COMM_SERIAL                 0x0700
#define PCI_COMM_PARALLEL               0x0701
#define PCI_COMM_MULTIPORT              0x0702
#define PCI_COMM_MODEM                  0x0703
#define PCI_COMM_GPIB                   0x0704
#define PCI_COMM_SMARTCARD              0x0705
#define PCI_COMM_OTHER                  0x0780

// Base System Peripherals
#define PCI_SYSTEM_PIC                  0x0800
#define PCI_SYSTEM_DMA                  0x0801
#define PCI_SYSTEM_TIMER                0x0802
#define PCI_SYSTEM_RTC                  0x0803
#define PCI_SYSTEM_PCI_HOTPLUG          0x0804
#define PCI_SYSTEM_SD                   0x0805
#define PCI_SYSTEM_OTHER                0x0880

// Input Devices
#define PCI_INPUT_KEYBOARD              0x0900
#define PCI_INPUT_PEN                   0x0901
#define PCI_INPUT_MOUSE                 0x0902
#define PCI_INPUT_SCANNER               0x0903
#define PCI_INPUT_GAMEPORT              0x0904
#define PCI_INPUT_OTHER                 0x0980

// Docking Stations
#define PCI_DOCKING_GENERIC             0x0a00
#define PCI_DOCKING_OTHER               0x0a80

// Processors
#define PCI_PROCESSOR_386               0x0b00
#define PCI_PROCESSOR_486               0x0b01
#define PCI_PROCESSOR_PENTIUM           0x0b02
#define PCI_PROCESSOR_ALPHA             0x0b10
#define PCI_PROCESSOR_POWERPC           0x0b20
#define PCI_PROCESSOR_MIPS              0x0b30
#define PCI_PROCESSOR_CO                0x0b40

// Serial Bus Controllers
#define PCI_SERIAL_FIREWIRE             0x0c00
#define PCI_SERIAL_ACCESS               0x0c01
#define PCI_SERIAL_SSA                  0x0c02
#define PCI_SERIAL_USB                  0x0c03
#define PCI_SERIAL_FIBER                0x0c04
#define PCI_SERIAL_SMBUS                0x0c05

#define PCI_SERIAL_USB_UHCI             0x00
#define PCI_SERIAL_USB_OHCI             0x10
#define PCI_SERIAL_USB_EHCI             0x20
#define PCI_SERIAL_USB_XHCI             0x30
#define PCI_SERIAL_USB_OTHER            0x80

// Wireless Controllers
#define PCI_WIRELESS_IRDA               0x0d00
#define PCI_WIRLESSS_IR                 0x0d01
#define PCI_WIRLESSS_RF                 0x0d10
#define PCI_WIRLESSS_BLUETOOTH          0x0d11
#define PCI_WIRLESSS_BROADBAND          0x0d12
#define PCI_WIRLESSS_ETHERNET_A         0x0d20
#define PCI_WIRLESSS_ETHERNET_B         0x0d21
#define PCI_WIRELESS_OTHER              0x0d80

// Intelligent I/O Controllers
#define PCI_INTELLIGENT_I2O             0x0e00

// Satellite Communication Controllers
#define PCI_SATELLITE_TV                0x0f00
#define PCI_SATELLITE_AUDIO             0x0f01
#define PCI_SATELLITE_VOICE             0x0f03
#define PCI_SATELLITE_DATA              0x0f04

// Encryption/Decryption Controllers
#define PCI_CRYPT_NETWORK               0x1000
#define PCI_CRYPT_ENTERTAINMENT         0x1001
#define PCI_CRYPT_OTHER                 0x1080

// Data Acquisition and Signal Processing Controllers
#define PCI_SP_DPIO                     0x1100
#define PCI_SP_OTHER                    0x1180

#endif
<file_sep>#include <drivers/screen/textmode.h>
#include <lib/stdtypes.h>
#include <lib/x86.h>
#include <lib/string.h>
#include <lib/vsprintf.h>

// VGA framebuffer location
uint16_t *screen_memory = (uint16_t *)0xB8000;

// Cursor position
uint8_t cursor_x = 0;
uint8_t cursor_y = 0;

// Cursor attributes
int32_t attrib;

static void put_cursor(void);
static void scroll(void);
static void textmode_put(int8_t c);
static void textmode_write(int8_t *c);

void textmode_init(void)
{
	textmode_set_colors(COLOR_LTGRAY, COLOR_BLACK); // Default colors

	if (((*(volatile uint16_t *)0x410) & 0x30) == 0x30) {
		screen_memory = (uint16_t *)0xB0000; // Monochrome display

		// TODO: Panic
	}

	textmode_clear_screen();
}

void textmode_set_colors(uint8_t forecolor, uint8_t backcolor)
{
	attrib = (backcolor << 4) | (forecolor & 0x0F);
}

void textmode_move_cursor(int32_t x, int32_t y)
{
	cursor_x = x;
	cursor_y = y;

	put_cursor();
}

static void put_cursor(void)
{
	uint16_t position = (cursor_y * SCREEN_WIDTH) + cursor_x;

	outportb(0x3D4, 14);
	outportb(0x3D5, position >> 8);

	outportb(0x3D4, 15);
	outportb(0x3D5, position);
}

void textmode_clear_screen(void)
{
	int32_t i;

	for (i = 0; i < SCREEN_HEIGHT; i++) {
		memsetw(screen_memory + i * SCREEN_WIDTH, 0, SCREEN_WIDTH);
	}

	textmode_move_cursor(0, 0);
}

static void scroll(void)
{
	if (cursor_y >= SCREEN_HEIGHT) {
		uint32_t tmp = (cursor_y - SCREEN_HEIGHT) + 1;

		memcpy(screen_memory, screen_memory + tmp * SCREEN_WIDTH, (SCREEN_HEIGHT - tmp) * SCREEN_WIDTH * 2);
		memsetw(screen_memory + (SCREEN_HEIGHT - tmp) * SCREEN_WIDTH, 0, SCREEN_WIDTH);

		cursor_y = (SCREEN_HEIGHT - 1);

		put_cursor();
	}
}

static void textmode_put(int8_t c)
{
	scroll();

	int8_t *memory = (int8_t *)screen_memory;
	int32_t i = ((cursor_y * SCREEN_WIDTH) + cursor_x) * 2;

	if (c == '\b' && cursor_x) {
		cursor_x--;
	} else if (c == '\t') {
		cursor_x = (cursor_x + 8) & ~(8 - 1);
	} else if (c == '\r') {
		cursor_x = 0;
	} else if (c == '\n') {
		cursor_x = 0;
		cursor_y++;
	} else if (c >= ' ') {
		memory[i] = c;
		i++;
		memory[i] = attrib;
		i++;

		cursor_x++;
	}

	if (cursor_x >= SCREEN_WIDTH) {
		cursor_x = 0;
		cursor_y++;
	}

	put_cursor();
}

static void textmode_write(int8_t *c)
{
	while (*c) {
		textmode_put(*c++);
	}
}

void printf(const int8_t *fmt, ...)
{
	static int8_t buf[1920];

	va_list args;
	int32_t i;

	va_start(args, fmt);
	i = vsprintf(buf, fmt, args);
	va_end(args);

	buf[i] = '\0';

	textmode_write(buf);
}
<file_sep>APP = kernel
OBJDIR = build
AUXFILES = Makefile link.ld floppy.img cd.iso

# Pick output [floppy|iso|both]
OUTPUT = both

# Location to mount floppy.img
FLOPPYDIR = /mnt/floppy

VERSION_MAJOR = 0
VERSION_MINOR = 2
VERSION_BUILD := $(shell cat .build 2>/dev/null || (echo 1 > .build && echo 1))
VERSION_DATE := $(shell date +'%Y-%m-%d')

AS = nasm
#CC = gcc # Stock compiler may work, but not recommended
CC = gcc-4.8.2 # Cross compiler
LD = ld

ASFLAGS = -f elf
CFLAGS = -std=c99 -m32 -nodefaultlibs -nostdlib -nostdinc -fno-builtin -ffreestanding -I src/include \
			-Wall -Wextra -Wshadow -Wpointer-arith -Wcast-align -Wwrite-strings -Wmissing-prototypes -Wmissing-declarations -Wredundant-decls -Wnested-externs -Winline -Wno-long-long -Wstrict-prototypes \
			-Wno-unused-function -Wno-unused-parameter -Wno-unused-variable -Wno-unused-but-set-variable \
			-DVERSION_MAJOR=$(VERSION_MAJOR) -DVERSION_MINOR=$(VERSION_MINOR) -DVERSION_BUILD=$(VERSION_BUILD) -DVERSION_DATE=\"$(VERSION_DATE)\"
# -Wpedantic -Wconversion
LDFLAGS = -m elf_i386 -T link.ld

AFILES := $(shell find src/ -name '*.s' | sed 's/src\///')
CFILES := $(shell find src/ -name '*.c' | sed 's/src\///')
FILES = $(AFILES) $(CFILES)
ADIRS := $(shell find src/ -name '*.s' -exec dirname {} \; | sed 's/src//' | uniq)
CDIRS := $(shell find src/ -name '*.c' -exec dirname {} \; | sed 's/src//' | uniq)
DIRS = $(ADIRS) $(CDIRS)

AOBJS := $(patsubst %.s, $(OBJDIR)/%.o, $(AFILES))
COBJS := $(patsubst %.c, $(OBJDIR)/%.o, $(CFILES))
OBJS = $(AOBJS) $(COBJS)

.PHONY: all clean clean-floppy build-floppy build-iso build-both todo dist backup cloc $(OBJDIR)

all: $(OBJDIR) $(OBJDIR)/$(APP) build-$(OUTPUT)
	@echo Done

$(OBJDIR):
	@$(shell for dir in $(DIRS); do mkdir -p $(OBJDIR)/$$dir; done)

$(OBJDIR)/$(APP): $(OBJS)
	@echo $$(($$(cat .build) + 1)) > .build
	@echo Linking $(APP)
	@$(LD) $(LDFLAGS) -o $(OBJDIR)/$(APP) $(OBJS)

$(OBJDIR)/%.o: src/%.s
	@echo Assembling $<
	@$(AS) $(ASFLAGS) $< -o $@

$(OBJDIR)/%.o: src/%.c
	@echo Compiling $<
	@$(CC) $(CFLAGS) -c $< -o $@

clean:
	@echo Cleaning
	-@-rm -rf $(OBJDIR)/* simpleos.tgz

clean-floppy:
	@echo Cleaning floppy.img
	@losetup /dev/loop0 floppy.img
	@mkdir -p $(FLOPPYDIR)
	@mount /dev/loop0 $(FLOPPYDIR)
	@rm -f $(FLOPPYDIR)/$(APP)
	@sync
	@umount /dev/loop0
	@losetup -d /dev/loop0

build-floppy:
	@echo Updating floppy.img
	@losetup /dev/loop0 floppy.img
	@mkdir -p $(FLOPPYDIR)
	@mount /dev/loop0 $(FLOPPYDIR)
	@cp $(OBJDIR)/$(APP) $(FLOPPYDIR)/$(APP)
	@sync
	@umount /dev/loop0
	@losetup -d /dev/loop0

build-iso:
	@echo Creating cd.iso
	@rm -f cd.iso
	@mkdir -p iso/boot/grub
	@cp /usr/share/grub/x86_64-redhat/stage2_eltorito iso/boot/grub/
	@printf "timeout 0\n\ntitle   SimpleOS\nroot    (cd)\nkernel  /kernel\n" > iso/boot/grub/grub.conf
	@cp $(OBJDIR)/$(APP) iso/$(APP)
	@mkisofs -quiet -R -l -b boot/grub/stage2_eltorito -no-emul-boot -boot-load-size 4 -boot-info-table -V SimpleOS -o cd.iso iso
	@rm -rf iso/

build-both: build-floppy build-iso

todo:
	@for file in $(FILES); do fgrep -H -e TODO -e FIXME src/$$file; done; true

dist: clean all build-both
	@echo Building simpleos.tgz
	@tar czf simpleos.tgz --exclude='*.suo' --exclude='*.user' build/ src/ $(AUXFILES)

backup: dist
	@echo Saving to backup/simpleos-$(shell date +%Y-%m-%d).tgz
	@mkdir -p backup/
	@mv simpleos.tgz backup/simpleos-$(shell date +%Y-%m-%d).tgz

cloc:
	@cloc --quiet src/ $(AUXFILES) | tail -n +3
<file_sep>#ifndef DRIVERS_PCI_DRIVER_H
#define DRIVERS_PCI_DRIVER_H

#include <lib/stdtypes.h>

#define PCI_MAKE_ID(bus, dev, func) ((bus) << 16) | ((dev) << 11) | ((func) << 8)

// I/O Ports
#define PCI_CONFIG_ADDR 0xcf8
#define PCI_CONFIG_DATA 0xcfC

// Header Type
#define PCI_TYPE_MULTIFUNC 0x80
#define PCI_TYPE_GENERIC 0x00
#define PCI_TYPE_PCI_BRIDGE 0x01
#define PCI_TYPE_CARDBUS_BRIDGE 0x02

// PCI Configuration Registers
#define PCI_CONFIG_VENDOR_ID 0x00
#define PCI_CONFIG_DEVICE_ID 0x02
#define PCI_CONFIG_COMMAND 0x04
#define PCI_CONFIG_STATUS 0x06
#define PCI_CONFIG_REVISION_ID 0x08
#define PCI_CONFIG_PROG_INTF 0x09
#define PCI_CONFIG_SUBCLASS 0x0a
#define PCI_CONFIG_CLASS_CODE 0x0b
#define PCI_CONFIG_CACHELINE_SIZE 0x0c
#define PCI_CONFIG_LATENCY 0x0d
#define PCI_CONFIG_HEADER_TYPE 0x0e
#define PCI_CONFIG_BIST 0x0f

// Type 0x00 (Generic) Configuration Registers
#define PCI_CONFIG_BAR0 0x10
#define PCI_CONFIG_BAR1 0x14
#define PCI_CONFIG_BAR2 0x18
#define PCI_CONFIG_BAR3 0x1c
#define PCI_CONFIG_BAR4 0x20
#define PCI_CONFIG_BAR5 0x24
#define PCI_CONFIG_CARDBUS_CIS 0x28
#define PCI_CONFIG_SUBSYSTEM_VENDOR_ID 0x2c
#define PCI_CONFIG_SUBSYSTEM_DEVICE_ID 0x2e
#define PCI_CONFIG_EXPANSION_ROM 0x30
#define PCI_CONFIG_CAPABILITIES 0x34
#define PCI_CONFIG_INTERRUPT_LINE 0x3c
#define PCI_CONFIG_INTERRUPT_PIN 0x3d
#define PCI_CONFIG_MIN_GRANT 0x3e
#define PCI_CONFIG_MAX_LATENCY 0x3f

// PCI BAR
#define PCI_BAR_IO 0x01
#define PCI_BAR_LOWMEM 0x02
#define PCI_BAR_64 0x04
#define PCI_BAR_PREFETCH 0x08

typedef struct {
	union {
		void *address;
		uint16_t port;
	} u;
	uint64_t size;
	uint32_t flags;
} pci_bar_t;

typedef struct {
	uint16_t vendorId;
	uint16_t deviceId;
	uint8_t classCode;
	uint8_t subclass;
	uint8_t progIntf;
} pci_device_info_t;

typedef struct {
	void (*init)(uint32_t id, pci_device_info_t *info);
} pci_driver_t;

uint8_t pci_read8(uint32_t id, uint32_t reg);
uint16_t pci_read16(uint32_t id, uint32_t reg);
uint32_t pci_read32(uint32_t id, uint32_t reg);
void pci_write8(uint32_t id, uint32_t reg, uint8_t data);
void pci_write16(uint32_t id, uint32_t reg, uint16_t data);
void pci_write32(uint32_t id, uint32_t reg, uint32_t data);
void pci_get_bar(pci_bar_t *bar, uint32_t id, uint32_t index);

#endif
<file_sep>#ifndef LIB_VSPRINTF_H
#define LIB_VSPRINTF_H

#include <lib/stdtypes.h>
#include <lib/stdarg.h>

int32_t vsprintf(int8_t *buf, const int8_t *fmt, va_list args);
int32_t sprintf(int8_t *buf, const int8_t *fmt, ...);

#endif
<file_sep>#ifndef LIB_STDBOOL_H
#define LIB_STDBOOL_H

#define bool  _Bool
#define true  1
#define false 0

#endif
<file_sep>#ifndef INTERRUPT_ISR_H
#define INTERRUPT_ISR_H

#include <lib/stdtypes.h>

#define IRQ0 32
#define IRQ1 33
#define IRQ2 34
#define IRQ3 35
#define IRQ4 36
#define IRQ5 37
#define IRQ6 38
#define IRQ7 39
#define IRQ8 40
#define IRQ9 41
#define IRQ10 42
#define IRQ11 43
#define IRQ12 44
#define IRQ13 45
#define IRQ14 46
#define IRQ15 47

typedef struct {
	uint32_t ds;                                     // Data segment selector
	uint32_t edi, esi, ebp, esp, ebx, edx, ecx, eax; // Pushed by pusha
	uint32_t int_no, err_code;                       // Interrupt number and error code (if applicable)
	uint32_t eip, cs, eflags, useresp, ss;           // Pushed by the processor automatically
} registers_t;

typedef void (*interrupt_handler_t)(registers_t *);

void register_interrupt_handler(uint8_t n, interrupt_handler_t h);
void irq_handler(registers_t *regs);
void isr_handler(registers_t *regs);
void irq_ack(int32_t irq);

#endif
<file_sep>#include <lib/x86.h>
#include <lib/stdtypes.h>

uint8_t inportb(uint16_t port)
{
	uint8_t rv;
	__asm __volatile__("in %%dx,%%al" : "=a"(rv) : "d"(port));
	return rv;
}

uint16_t inportw(uint16_t port)
{
	uint16_t rv;
	__asm __volatile__("in %%dx, %%eax" : "=a"(rv) : "d"(port));
	return rv;
}

uint32_t inportl(uint16_t port)
{
	uint32_t rv;
	__asm __volatile__("in %%dx,%%eax" : "=a"(rv) : "d"(port));
	return rv;
}

void outportb(uint16_t port, uint8_t value)
{
	__asm __volatile__("outb %%al,%%dx" : : "a"(value), "d"(port));
}

void outportw(uint16_t port, uint16_t value)
{
	__asm __volatile__("outw %%ax,%%dx" : : "a"(value), "d"(port));
}

void outportl(uint16_t port, uint32_t value)
{
	__asm __volatile__("outl %%eax,%%dx" : : "a"(value), "d"(port));
}
<file_sep>#include <cpu/cpuid.h>
#include <lib/stdtypes.h>
#include <lib/string.h>
#include <drivers/screen/textmode.h>

void cpuid(uint32_t reg, uint32_t *eax, uint32_t *ebx, uint32_t *ecx, uint32_t *edx)
{
	__asm __volatile__("cpuid" : "=a"(*eax), "=b"(*ebx), "=c"(*ecx), "=d"(*edx) : "a"(reg));
}

void cpu_detect(void)
{
	printf("Scanning CPU...\n");

	uint32_t eax, ebx, ecx, edx;
	uint32_t largestStandardFunc;

	// Function 0x00 - Vendor-ID and Largest Standard Function

	int8_t vendor[13];

	cpuid(0, &largestStandardFunc, (uint32_t *)(vendor + 0), (uint32_t *)(vendor + 8), (uint32_t *)(vendor + 4));
	vendor[12] = '\0';

	const int8_t *vendorName = "Unknown";

	if (strcmp(vendor, "AuthenticAMD") == 0 || strcmp(vendor, "AMDisbetter") == 0) {
		vendorName = "AMD";
	} else if (strcmp(vendor, "GenuineIntel") == 0) {
		vendorName = "Intel";
	} else if (strcmp(vendor, "CentaurHauls") == 0) {
		vendorName = "Centaur";
	} else if (strcmp(vendor, "CyrixInstead") == 0) {
		vendorName = "Cyrix";
	} else if (strcmp(vendor, "TransmetaCPU") == 0 || strcmp(vendor, "GenuineTMx86") == 0) {
		vendorName = "Transmeta";
	} else if (strcmp(vendor, "Geode by NSC") == 0) {
		vendorName = "National Semiconductor";
	} else if (strcmp(vendor, "NexGenDriven") == 0) {
		vendorName = "NexGen";
	} else if (strcmp(vendor, "RiseRiseRise") == 0) {
		vendorName = "Rise";
	} else if (strcmp(vendor, "SiS SiS SiS ") == 0) {
		vendorName = "SiS";
	} else if (strcmp(vendor, "UMC UMC UMC ") == 0) {
		vendorName = "UMC";
	} else if (strcmp(vendor, "VIA VIA VIA ") == 0) {
		vendorName = "VIA";
	} else if (strcmp(vendor, "Vortex86 SoC") == 0) {
		vendorName = "Vortex";
	} else if (strcmp(vendor, "KVMKVMKVMKVM") == 0) {
		vendorName = "KVM";
	}

	printf("Vendor: %s\n", vendorName);

	// Function 0x01 - Feature Information

	if (largestStandardFunc >= 0x01) {
		cpuid(0x01, &eax, &ebx, &ecx, &edx);

		//struct cpu_signature_s *cpu = (struct cpu_signature_s *)&eax;

		uint32_t stepping = eax & 0x0F;
		uint32_t model = (eax >> 4) & 0x0F;
		uint32_t family = (eax >> 8) & 0x0F;

		if (strcmp(vendor, "GenuineIntel") == 0) {
			uint32_t exmodel = (eax >> 16) & 0x0F;
			uint32_t exfamily = (eax >> 20) & 0xFF;

			if (family == 0x0F) {
				family += exfamily;
				model += (exmodel << 4);
			} else if (family == 0x06) {
				model += (exmodel << 4);
			}
		}

		printf("Family: %X, Model: %X, Stepping: %X\n", family, model, stepping);

		printf("Features:");

		if (edx & EDX_PSE) {
			printf(" PSE");
		}

		if (edx & EDX_PAE) {
			printf(" PAE");
		}

		if (edx & EDX_APIC) {
			printf(" APIC");
		}

		if (edx & EDX_MTRR) {
			printf(" MTRR");
		}

		printf("\nInstructions:");

		if (edx & EDX_HTT) {
			printf(" HTT");
		}

		if (edx & EDX_TSC) {
			printf(" TSC");
		}

		if (edx & EDX_MSR) {
			printf(" MSR");
		}

		if (edx & EDX_SSE) {
			printf(" SSE");
		}

		if (edx & EDX_SSE2) {
			printf(" SSE2");
		}

		if (ecx & ECX_SSE3) {
			printf(" SSE3");
		}

		if (ecx & ECX_SSSE3) {
			printf(" SSSE3");
		}

		if (ecx & ECX_SSE41) {
			printf(" SSE41");
		}

		if (ecx & ECX_SSE42) {
			printf(" SSE42");
		}

		if (ecx & ECX_AVX) {
			printf(" AVX");
		}

		if (ecx & ECX_F16C) {
			printf(" F16C");
		}

		if (ecx & ECX_RDRAND) {
			printf(" RDRAND");
		}

		printf("\n");
	}

	// Extended Function 0x00 - Largest Extended Function

	uint32_t largestExtendedFunc;
	cpuid(0x80000000, &largestExtendedFunc, &ebx, &ecx, &edx);

	// Extended Function 0x01 - Extended Feature Bits

	int32_t bits = 32;

	if (largestExtendedFunc >= 0x80000001) {
		cpuid(0x80000001, &eax, &ebx, &ecx, &edx);

		if (edx & EDX_64_BIT) {
			bits = 64;
		}
	}

	printf("Architecture: %i-bit\n", bits);

	// Extended Function 0x02-0x04 - Processor Name / Brand String

	if (largestExtendedFunc >= 0x80000004) {
		int8_t name[48];
		cpuid(0x80000002, (uint32_t *)(name + 0), (uint32_t *)(name + 4), (uint32_t *)(name + 8), (uint32_t *)(name + 12));
		cpuid(0x80000003, (uint32_t *)(name + 16), (uint32_t *)(name + 20), (uint32_t *)(name + 24), (uint32_t *)(name + 28));
		cpuid(0x80000004, (uint32_t *)(name + 32), (uint32_t *)(name + 36), (uint32_t *)(name + 40), (uint32_t *)(name + 44));

		const int8_t *p = name;

		while (*p == ' ') {
			++p;
		}

		printf("CPU Name: %s\n", p);
	}
}
<file_sep>#ifndef LIB_STDDEF_H
#define LIB_STDDEF_H

#if defined(_MSC_VER) // Visual Studio
#define PACKED( __Declaration__ ) __pragma( pack(push, 1) ) __Declaration__ __pragma( pack(pop) )
#else
#define PACKED( __Declaration__ ) __Declaration__ __attribute__((__packed__)) // GCC
#endif

#define NULL ((void *)0)

typedef unsigned long size_t;

typedef long          intptr_t;
typedef unsigned long uintptr_t;

#endif
<file_sep>#ifndef DRIVERS_PIT_H
#define DRIVERS_PIT_H

#include <lib/stdtypes.h>

#define PIT_FREQUENCY 1193182

void pit_init(void);
void pit_wait(uint32_t ms);

#endif
<file_sep>#ifndef LIB_STDARG_H
#define LIB_STDARG_H

#include <lib/stdtypes.h>

#if defined(_MSC_VER) // Visual Studio
typedef int8_t *va_list;
#define intsizeof(n)    ((sizeof(n) + sizeof(int32_t) - 1) &~(sizeof(int32_t) - 1))
#define va_start(ap, v) (ap = (va_list)&(v) + intsizeof(v))
#define va_arg(ap, t)   (*(t *) ((ap += intsizeof(t)) - intsizeof(t)))
#define va_end(ap)      (ap = (va_list)0)
#else // GCC
typedef __builtin_va_list va_list;
#define va_start(v,l)     __builtin_va_start(v,l)
#define va_arg(v,l)       __builtin_va_arg(v,l)
#define va_end(v)         __builtin_va_end(v)
#define va_copy(d,s)      __builtin_va_copy(d,s)
#endif

#endif
<file_sep>#ifndef LIB_TIME_H
#define LIB_TIME_H

#include <lib/stdtypes.h>

#define LOCAL_TIME_ZONE 0 * 60; // Time zone offset in minutes

typedef uint32_t time_t; // Expiry: 2038

typedef struct datetime {
	int sec;      // [0, 59]
	int min;      // [0, 59]
	int hour;     // [0, 23]
	int day;      // [1, 31]
	int month;    // [1, 12]
	int year;     // [1970, 2038]
	int week_day;  // [0, 6] Sunday = 0
	int year_day;  // [0, 365]
	int tz_offset; // offset in minutes
} datetime_t;

#endif
<file_sep>#ifndef LIB_STDTYPES_H
#define LIB_STDTYPES_H

// 32-bit x86
typedef unsigned long long uint64_t;
typedef          long long int64_t;
typedef unsigned int       uint32_t;
typedef          int       int32_t;
typedef unsigned short     uint16_t;
typedef          short     int16_t;
typedef unsigned char      uint8_t;
typedef          char      int8_t;

#endif
<file_sep>#include <drivers/pit.h>
#include <lib/stdtypes.h>
#include <lib/x86.h>
#include <interrupt/isr.h>
#include <drivers/screen/textmode.h>

volatile uint32_t ticks = 0;

static void pit_callback(registers_t *regs)
{
	ticks++;
}

void pit_init(void)
{
	register_interrupt_handler(IRQ0, &pit_callback);

	int16_t divisor = PIT_FREQUENCY / 1000;

	outportb(0x43, 0x36);
	outportb(0x40, (uint8_t)(divisor & 0xFF));
	outportb(0x40, (uint8_t)((divisor >> 8) & 0xFF));
}

void pit_wait(uint32_t ms)
{
	uint32_t now = ticks;
	++ms;

	while (ticks - now < ms) {
		;
	}
}
<file_sep>#include <interrupt/isr.h>
#include <lib/stdtypes.h>
#include <lib/x86.h>
#include <drivers/screen/textmode.h>

const int8_t *exception_messages[] = {
	"Division By Zero",
	"Debug",
	"Non Maskable Interrupt",
	"Breakpoint",
	"Into Detected Overflow",
	"Out of Bounds",
	"Invalid Opcode",
	"No Coprocessor",
	"Double Fault",
	"Coprocessor Segment Overrun",
	"Bad TSS",
	"Segment Not Present",
	"Stack Fault",
	"General Protection Fault",
	"Page Fault",
	"Unknown Interrupt",
	"Coprocessor Fault",
	"Alignment Check",
	"Machine Check",
	"Reserved",
	"Reserved",
	"Reserved",
	"Reserved",
	"Reserved",
	"Reserved",
	"Reserved",
	"Reserved",
	"Reserved",
	"Reserved",
	"Reserved",
	"Reserved",
	"Reserved"
};

interrupt_handler_t interrupt_handlers[256];

void register_interrupt_handler(uint8_t n, interrupt_handler_t h)
{
	interrupt_handlers[n] = h;
}

void isr_handler(registers_t *regs)
{
	if (interrupt_handlers[regs->int_no]) {
		interrupt_handlers[regs->int_no](regs);
	} else {
		printf("Unhandled interrupt: %i (%s Exception)\n", regs->int_no, exception_messages[regs->int_no]);
		// TODO: Panic
	}
}

void irq_handler(registers_t *regs)
{
	// Send an EOI (end of interrupt) signal to the PICs
	// If this interrupt involved the slave
	if (regs->int_no >= 40) {
		// Send reset signal to slave.
		outportb(0xA0, 0x20);
	}

	// Send reset signal to master. (As well as slave, if necessary)
	outportb(0x20, 0x20);

	if (interrupt_handlers[regs->int_no] != 0) {
		interrupt_handlers[regs->int_no](regs);
	}
}

void irq_ack(int32_t irq)
{
	if (irq >= 12) {
		outportb(0xA0, 0x20);
	}

	outportb(0x20, 0x20);
}
<file_sep>#!/bin/bash

echo Creating floppy.img

dd if=/dev/zero of=floppy.img bs=1k count=1440 > /dev/null 2>&1
losetup /dev/loop0 floppy.img
mke2fs /dev/loop0 > /dev/null 2>&1

echo "(fd0) /dev/loop0" > floppy.map

mount /dev/loop0 /mnt/floppy
mkdir -p /mnt/floppy/boot/grub
cp /usr/share/grub/x86_64-redhat/stage1 /mnt/floppy/boot/grub/stage1
cp /usr/share/grub/x86_64-redhat/stage2 /mnt/floppy/boot/grub/stage2

grub --batch --device-map=floppy.map /dev/loop0 <<EOT > /dev/null 2>&1
root (fd0)
setup (fd0)
quit
EOT

rm -f floppy.map

if [ -f grub.conf ]; then
   cp grub.conf /mnt/floppy/boot/grub/grub.conf
else
	cat << EOF > /mnt/floppy/boot/grub/grub.conf
timeout 0

title   SimpleOS
root    (fd0)
kernel  /kernel
EOF
fi

umount /dev/loop0
losetup -d /dev/loop0

echo Done
<file_sep>#include <lib/rand.h>
#include <lib/stdtypes.h>

static uint32_t next = 1;

int32_t rand(void)
{
	next = next * 1103515245 + 12345;
	return (uint32_t)(next / 65536) % 32768;
}

void srand(uint32_t seed)
{
	next = seed;
}
<file_sep>#include <drivers/rtc.h>
#include <lib/stdtypes.h>
#include <lib/x86.h>
#include <lib/time.h>
#include <drivers/pit.h>
#include <drivers/screen/textmode.h>

static uint8_t rtc_read(uint8_t addr)
{
	outportb(IO_RTC_INDEX, addr);
	return inportb(IO_RTC_TARGET);
}

static void rtc_write(uint8_t addr, uint8_t val)
{
	outportb(IO_RTC_INDEX, addr);
	outportb(IO_RTC_TARGET, val);
}

static uint8_t bcd_to_bin(uint8_t val)
{
	return (val & 0xf) + (val >> 4) * 10;
}

static uint8_t bin_to_bcd(uint8_t val)
{
	return ((val / 10) << 4) + (val % 10);
}

void rtc_get(datetime_t *dt)
{
	// Wait if update is in progress
	if (rtc_read(RTC_A) & RTC_A_UIP) {
		pit_wait(3);
	}

	// Read Registers
	uint8_t sec = rtc_read(RTC_SEC);
	uint8_t min = rtc_read(RTC_MIN);
	uint8_t hour = rtc_read(RTC_HOUR);
	uint8_t weekDay = rtc_read(RTC_WEEK_DAY);
	uint8_t day = rtc_read(RTC_DAY);
	uint8_t month = rtc_read(RTC_MONTH);
	uint16_t year = rtc_read(RTC_YEAR);

	// Get Data configuration
	uint8_t regb = rtc_read(RTC_B);

	// BCD conversion
	if (~regb & RTC_B_DM) {
		sec = bcd_to_bin(sec);
		min = bcd_to_bin(min);
		hour = bcd_to_bin(hour);
		day = bcd_to_bin(day);
		month = bcd_to_bin(month);
		year = bcd_to_bin(year);
	}

	// Century support
	year += 2000;

	// Week day conversion: Sunday as the first day of the week (0-6)
	weekDay--;

	// Write results
	dt->sec = sec;
	dt->min = min;
	dt->hour = hour;
	dt->day = day;
	dt->month = month;
	dt->year = year;
	dt->week_day = weekDay;
	dt->tz_offset = LOCAL_TIME_ZONE;
}

void rtc_set(const datetime_t *dt)
{
	uint8_t sec = dt->sec;
	uint8_t min = dt->min;
	uint8_t hour = dt->hour;
	uint8_t day = dt->day;
	uint8_t month = dt->month;
	uint8_t year = dt->year - 2000;
	uint8_t week_day = dt->week_day + 1;

	// Validate data
	if (sec >= 60 || min >= 60 || hour >= 24 || day > 31 || month > 12 || year >= 100 || week_day > 7) {
		printf("rtc_set: bad data\n");
		return;
	}

	// Get data configuration
	uint8_t regb = rtc_read(RTC_B);

	// BCD conversion
	if (~regb & RTC_B_DM) {
		sec = bin_to_bcd(sec);
		min = bin_to_bcd(min);
		hour = bin_to_bcd(hour);
		day = bin_to_bcd(day);
		month = bin_to_bcd(month);
		year = bin_to_bcd(year);
	}

	// Wait if update is in progress
	if (rtc_read(RTC_A) & RTC_A_UIP) {
		pit_wait(3);
	}

	// Write registers
	rtc_write(RTC_SEC, sec);
	rtc_write(RTC_MIN, min);
	rtc_write(RTC_HOUR, hour);
	rtc_write(RTC_WEEK_DAY, week_day);
	rtc_write(RTC_DAY, day);
	rtc_write(RTC_MONTH, month);
	rtc_write(RTC_YEAR, year);
}<file_sep>#include <drivers/serial.h>
#include <interrupt/isr.h>
#include <lib/stdtypes.h>
#include <lib/x86.h>
#include <lib/string.h>
#include <drivers/screen/textmode.h>

static int32_t serial_rcvd(int32_t device);
static int8_t serial_recv(int32_t device);
static int8_t serial_recv_async(int32_t device);
static int32_t serial_send_empty(int32_t device);
static void serial_send(int32_t device, int8_t out);

void serial_handler_a(registers_t *regs)
{
	int8_t serial = serial_recv(SERIAL_PORT_A);
	irq_ack(SERIAL_IRQ);

	if (serial == 13) {
		serial = '\n';
	}

	printf("%c", serial);
	serial_send(SERIAL_PORT_B, serial);
}

void serial_handler_b(registers_t *regs)
{
	int8_t serial = serial_recv(SERIAL_PORT_B);
	irq_ack(SERIAL_IRQ - 1);
	serial_send(SERIAL_PORT_A, serial);
}

void serial_enable(int32_t device)
{
	outportb(device + 1, 0x00);
	outportb(device + 3, 0x80); /* Enable divisor mode */
	outportb(device + 0, 0x03); /* Div Low:  03 Set the port to 38400 bps */
	outportb(device + 1, 0x00); /* Div High: 00 */
	outportb(device + 3, 0x03);
	outportb(device + 2, 0xC7);
	outportb(device + 4, 0x0B);
}

void serial_init(void)
{
	serial_enable(SERIAL_PORT_A);
	serial_enable(SERIAL_PORT_B);

	register_interrupt_handler(SERIAL_IRQ, serial_handler_a); /* Install the serial input handler */
	register_interrupt_handler(SERIAL_IRQ - 1, serial_handler_b); /* Install the serial input handler */
	outportb(SERIAL_PORT_A + 1, 0x01);      /* Enable interrupts on receive */
	outportb(SERIAL_PORT_B + 1, 0x01);      /* Enable interrupts on receive */
}

static int32_t serial_rcvd(int32_t device)
{
	return inportb(device + 5) & 1;
}

static int8_t serial_recv(int32_t device)
{
	while (serial_rcvd(device) == 0);

	return inportb(device);
}

static int8_t serial_recv_async(int32_t device)
{
	return inportb(device);
}

static int32_t serial_send_empty(int32_t device)
{
	return inportb(device + 5) & 0x20;
}

static void serial_send(int32_t device, int8_t out)
{
	while (serial_send_empty(device) == 0);

	outportb(device, out);
}

void serial_write(int32_t device, const int8_t *out)
{
	for (int32_t i = 0; i < strlen(out); ++i) {
		serial_send(device, out[i]);
	}
}
<file_sep>#ifndef CPU_FPU_H
#define CPU_FPU_H

#include <lib/stdtypes.h>

void fpu_init(void);
void fpu_set_cw(const uint16_t cw);

#endif
<file_sep>#ifndef INTERRUPT_IDT_H
#define INTERRUPT_IDT_H

#include <lib/stdtypes.h>
#include <lib/stddef.h>
#include <interrupt/isr.h>

typedef PACKED(struct {
	uint16_t base_lo;        // The lower 16 bits of the address to jump to
	uint16_t sel;            // Kernel segment selector
	uint8_t  always0;        // This must always be zero
	uint8_t  flags;          // More flags. See documentation
	uint16_t base_hi;        // The upper 16 bits of the address to jump to
}) idt_entry_t;

typedef PACKED(struct {
	uint16_t limit;
	uint32_t base;           // The address of the first element in our idt_entry_t array
}) idt_ptr_t;

void idt_init(void);

extern void isr0(void);
extern void isr1(void);
extern void isr2(void);
extern void isr3(void);
extern void isr4(void);
extern void isr5(void);
extern void isr6(void);
extern void isr7(void);
extern void isr8(void);
extern void isr9(void);
extern void isr10(void);
extern void isr11(void);
extern void isr12(void);
extern void isr13(void);
extern void isr14(void);
extern void isr15(void);
extern void isr16(void);
extern void isr17(void);
extern void isr18(void);
extern void isr19(void);
extern void isr20(void);
extern void isr21(void);
extern void isr22(void);
extern void isr23(void);
extern void isr24(void);
extern void isr25(void);
extern void isr26(void);
extern void isr27(void);
extern void isr28(void);
extern void isr29(void);
extern void isr30(void);
extern void isr31(void);
extern void isr255(void);
extern void irq0(void);
extern void irq1(void);
extern void irq2(void);
extern void irq3(void);
extern void irq4(void);
extern void irq5(void);
extern void irq6(void);
extern void irq7(void);
extern void irq8(void);
extern void irq9(void);
extern void irq10(void);
extern void irq11(void);
extern void irq12(void);
extern void irq13(void);
extern void irq14(void);
extern void irq15(void);

#endif
<file_sep>#ifndef LIB_RAND_H
#define LIB_RAND_H

#include <lib/stdtypes.h>

int32_t rand(void);
void srand(uint32_t seed);

#endif
<file_sep>#ifndef INTERRUPT_GDT_H
#define INTERRUPT_GDT_H

#include <lib/stdtypes.h>
#include <lib/stddef.h>

void gdt_init(void);

typedef PACKED(struct {
	uint16_t limit_low;     // The lower 16 bits of the limit
	uint16_t base_low;      // The lower 16 bits of the base
	uint8_t base_middle;    // The next 8 bits of the base
	uint8_t access;         // Access flags, determines what ring this segment can be used in
	uint8_t granularity;
	uint8_t base_high;      // The last 8 bits of the base
}) gdt_entry_t;

typedef PACKED(struct {
	uint16_t limit;       // The Global Descriptor Table limit
	uint32_t base;        // The address of the first gdt_entry_t struct
}) gdt_ptr_t;

#endif
<file_sep>#ifndef DRIVERS_RTC_H
#define DRIVERS_RTC_H

#include <lib/stdtypes.h>
#include <lib/time.h>

// I/O Ports
#define IO_RTC_INDEX 0x70
#define IO_RTC_TARGET 0x71

// Indexed Registers
#define RTC_SEC 0x00
#define RTC_SEC_ALARM 0x01
#define RTC_MIN 0x02
#define RTC_MIN_ALARM 0x03
#define RTC_HOUR 0x04
#define RTC_HOUR_ALARM 0x05
#define RTC_WEEK_DAY 0x06
#define RTC_DAY 0x07
#define RTC_MONTH 0x08
#define RTC_YEAR 0x09
#define RTC_A 0x0a
#define RTC_B 0x0b
#define RTC_C 0x0c
#define RTC_D 0x0d

// General Configuration Registers
#define RTC_A_UIP (1 << 7) // Update In Progress
#define RTC_B_HOURFORM (1 << 1) // Hour Format (0 = 12hr, 1 = 24hr)
#define RTC_B_DM (1 << 2) // Data Mode (0 = BCD, 1 = Binary)

void rtc_get(datetime_t *dt);
void rtc_set(const datetime_t *dt);

#endif
<file_sep>#ifndef DRIVERS_SCREEN_TEXTMODE_H
#define DRIVERS_SCREEN_TEXTMODE_H

#include <lib/stdtypes.h>
#include <lib/stddef.h>

#define SCREEN_WIDTH 80
#define SCREEN_HEIGHT 25

#define COLOR_BLACK 0
#define COLOR_BLUE 1
#define COLOR_GREEN 2
#define COLOR_CYAN 3
#define COLOR_RED 4
#define COLOR_MAGENTA 5
#define COLOR_BROWN 6
#define COLOR_LTGRAY 7
#define COLOR_GRAY 8
#define COLOR_LTBLUE 9
#define COLOR_LTGREEN 10
#define COLOR_LTCYAN 11
#define COLOR_LTRED 12
#define COLOR_LTMAGENTA 13
#define COLOR_YELLOW 14
#define COLOR_WHITE 15

void textmode_init(void);
void textmode_set_colors(uint8_t forecolor, uint8_t backcolor);
void textmode_move_cursor(int32_t x, int32_t y);
void textmode_clear_screen(void);
void printf(const int8_t *fmt, ...);

#endif
<file_sep>#include <lib/string.h>
#include <lib/stdtypes.h>

void *memcpy(void *dest, const void *src, size_t count)
{
	const int8_t *sp = (const int8_t *)src;
	int8_t *dp = (int8_t *)dest;

	for (; count != 0; count--) {
		*dp++ = *sp++;
	}

	return dest;
}

void *memset(void *dest, int8_t value, size_t count)
{
	int8_t *temp = (int8_t *)dest;

	for (; count != 0; count--) {
		*temp++ = value;
	}

	return dest;
}

void *memsetw(void *dest, uint16_t value, size_t count)
{
	uint16_t *temp = (uint16_t *)dest;

	for (; count != 0; count--) {
		*temp++ = value;
	}

	return dest;
}

int32_t memcmp(const void *s1, const void *s2, size_t n)
{
	if (n) {
		register const uint8_t *p1 = s1, *p2 = s2;

		do {
			if (*p1++ != *p2++) {
				return (*--p1 - *--p2);
			}
		} while (--n);
	}

	return 0;
}

int8_t *itoa(int32_t value, int8_t *result, int32_t base)
{
	if (base < 2 || base > 36) {
		*result = '\0';

		return result;
	}

	int8_t *ptr = result;
	int8_t *ptr1 = result;
	int8_t tmp_char;
	int32_t tmp_value;

	do {
		tmp_value = value;
		value /= base;
		*ptr++ = "zyxwvutsrqp<KEY>"[35 + (tmp_value - value * base)];
	} while (value);

	if (tmp_value < 0) {
		*ptr++ = '-';
	}

	*ptr-- = '\0';

	while (ptr1 < ptr) {
		tmp_char = *ptr;
		*ptr-- = *ptr1;
		*ptr1++ = tmp_char;
	}

	return result;
}

int32_t strcmp(const int8_t *str1, const int8_t *str2)
{
	int32_t i = 0;
	int32_t failed = 0;

	while (str1[i] != '\0' && str2[i] != '\0') {
		if (str1[i] != str2[i]) {
			failed = 1;
			break;
		}

		i++;
	}

	if ((str1[i] == '\0' && str2[i] != '\0') || (str1[i] != '\0' && str2[i] == '\0')) {
		failed = 1;
	}

	return failed;
}

int32_t strncmp(const int8_t *str1, const int8_t *str2, int32_t count)
{
	int32_t i = 0;
	int32_t failed = 0;

	while (str1[i] != '\0' && str2[i] != '\0') {
		if (str1[i] != str2[i]) {
			failed = 1;
			break;
		}

		i++;
		count--;
	}

	if (count && ((str1[i] == '\0' && str2[i] != '\0') || (str1[i] != '\0' && str2[i] == '\0'))) {
		failed = 1;
	}

	return failed;
}


int8_t *strcpy(int8_t *dest, const int8_t *src)
{
	while (*src) {
		*dest++ = *src++;
	}

	*dest = '\0';

	return dest;
}

int8_t *strncpy(int8_t *dest, const int8_t *src, int32_t count)
{
	while (*src && count) {
		*dest++ = *src++;
		count--;
	}

	*dest = '\0';

	return dest;
}

int8_t *strcat(int8_t *dest, const int8_t *src)
{
	strcpy(dest + strlen(dest), src);
	return dest;
}

int32_t strlen(const int8_t *src)
{
	int32_t i = 0;

	while (*src++) {
		i++;
	}

	return i;
}

int32_t isspace(int8_t c)
{
	return (c == ' ' || c == '\n' || c == '\r' || c == '\t');
}

int32_t isupper(int8_t c)
{
	return (c >= 'A' && c <= 'Z');
}

int32_t islower(int8_t c)
{
	return (c >= 'a' && c <= 'z');
}

int32_t isdigit(int8_t c)
{
	return (c >= '0' && c <= '9');
}

int32_t isalpha(int8_t c)
{
	return isupper(c) || islower(c) || isdigit(c);
}

int8_t toupper(int8_t c)
{
	if (islower(c)) {
		return 'A' + (c - 'a');
	} else {
		return c;
	}
}

int8_t tolower(int8_t c)
{
	if (isupper(c)) {
		return 'a' + (c - 'A');
	} else {
		return c;
	}
}
<file_sep>#ifndef MAIN_H
#define MAIN_H

#include <lib/stdtypes.h>
#include <lib/multiboot.h>

int32_t kernel_main(multiboot_t *mboot_ptr);

#endif
<file_sep>#ifndef LIB_IO_H
#define LIB_IO_H

#include <lib/stdtypes.h>

uint8_t inportb(uint16_t port);
uint16_t inportw(uint16_t port);
uint32_t inportl(uint16_t port);
void outportb(uint16_t port, uint8_t value);
void outportw(uint16_t port, uint16_t value);
void outportl(uint16_t port, uint32_t value);

#endif
<file_sep>#include <drivers/pci/pci.h>
#include <drivers/pci/driver.h>
#include <drivers/pci/registry.h>
#include <lib/stdtypes.h>
#include <lib/string.h>
#include <drivers/screen/textmode.h>

static void pci_check(uint32_t bus, uint32_t dev, uint32_t func)
{
	uint32_t id = PCI_MAKE_ID(bus, dev, func);

	pci_device_info_t info;
	info.vendorId = pci_read16(id, PCI_CONFIG_VENDOR_ID);

	if (info.vendorId == 0xFFFF) {
		return;
	}

	info.deviceId = pci_read16(id, PCI_CONFIG_DEVICE_ID);
	info.progIntf = pci_read8(id, PCI_CONFIG_PROG_INTF);
	info.subclass = pci_read8(id, PCI_CONFIG_SUBCLASS);
	info.classCode = pci_read8(id, PCI_CONFIG_CLASS_CODE);

	uint32_t result = pci_read32(id, PCI_CONFIG_VENDOR_ID);
	uint16_t dev_id = result >> 0x10;
	uint16_t ven_id = result & 0xFFFF;

	printf("%02x:%02x.%d %04x:%04x %s\n", bus, dev, func, info.vendorId, info.deviceId, pci_class_name(info.classCode, info.subclass, info.progIntf));
}

void pci_scan(void)
{
	printf("Scanning PCI bus...\n");

	for (uint32_t bus = 0; bus < 256; ++bus) {
		for (uint32_t dev = 0; dev < 32; ++dev) {
			uint32_t baseId = PCI_MAKE_ID(bus, dev, 0);
			uint8_t headerType = pci_read8(baseId, PCI_CONFIG_HEADER_TYPE);
			uint32_t funcCount = headerType & PCI_TYPE_MULTIFUNC ? 8 : 1;

			for (uint32_t func = 0; func < funcCount; ++func) {
				pci_check(bus, dev, func);
			}
		}
	}
}<file_sep>#include <main.h>
#include <lib/stdtypes.h>
#include <lib/multiboot.h>
#include <lib/vsprintf.h>
#include <cpu/cpuid.h>
#include <cpu/fpu.h>
#include <interrupt/gdt.h>
#include <interrupt/idt.h>
#include <drivers/pit.h>
#include <drivers/rtc.h>
#include <drivers/serial.h>
#include <drivers/pci/pci.h>
#include <drivers/screen/textmode.h>

int32_t kernel_main(multiboot_t *mboot_ptr)
{
	textmode_init();

	printf("                   _____ _                 _       ____   _____ \n                  / ____(_)               | |     / __ \\ / ____|\n                 | (___  _ _ __ ___  _ __ | | ___| |  | | (___  \n                  \\___ \\| | '_ ` _ \\| '_ \\| |/ _ \\ |  | |\\___ \\ \n                  ____) | | | | | | | |_) | |  __/ |__| |____) |\n                 |_____/|_|_| |_| |_| .__/|_|\\___|\\____/|_____/ \n                                    | |                         \n                                    |_|                         \n");
	textmode_set_colors(COLOR_RED, COLOR_BLACK);
	textmode_move_cursor(19, 6);
	printf("Version %i.%i.%i", VERSION_MAJOR, VERSION_MINOR, VERSION_BUILD);
	textmode_move_cursor(19, 7);
	printf("Built %s", VERSION_DATE);
	textmode_set_colors(COLOR_GREEN, COLOR_BLACK);
	textmode_move_cursor(41, 6);
	printf("Written by <NAME>");
	textmode_set_colors(COLOR_LTGRAY, COLOR_BLACK);
	textmode_move_cursor(0, 9);

	fpu_init();
	gdt_init();
	idt_init();

	__asm __volatile__("sti"); // Start interrupts

	pit_init();
	serial_init();

	// Test serial
	int8_t buffer[50];
	sprintf(buffer, "SimpleOS %i.%i.%i (%s)\n", VERSION_MAJOR, VERSION_MINOR, VERSION_BUILD, VERSION_DATE);
	serial_write(SERIAL_PORT_A, buffer);

	// Test RTC
	datetime_t *dt = 0;
	rtc_get(dt);
	printf("Started at %02i-%02i-%02i %02i:%02i:%02i\n\n", dt->year, dt->month, dt->day, dt->hour, dt->min, dt->sec);

	// Test CPU
	cpu_detect();

	printf("\n");

	// Test PCI
	pci_scan();

	for (;;);

	return 0x12345678;
}
<file_sep>#ifndef CPU_CPUID_H
#define CPU_CPUID_H

#include <lib/stdtypes.h>

// Function 0x01
#define ECX_SSE3 (1 << 0) // Streaming SIMD Extensions 3
#define ECX_PCLMULQDQ (1 << 1) // PCLMULQDQ Instruction
#define ECX_DTES64 (1 << 2) // 64-Bit Debug Store Area
#define ECX_MONITOR (1 << 3) // MONITOR/MWAIT
#define ECX_DS_CPL (1 << 4) // CPL Qualified Debug Store
#define ECX_VMX (1 << 5) // Virtual Machine Extensions
#define ECX_SMX (1 << 6) // Safer Mode Extensions
#define ECX_EST (1 << 7) // Enhanced SpeedStep Technology
#define ECX_TM2 (1 << 8) // Thermal Monitor 2
#define ECX_SSSE3 (1 << 9) // Supplemental Streaming SIMD Extensions 3
#define ECX_CNXT_ID (1 << 10) // L1 Context ID
#define ECX_FMA (1 << 12) // Fused Multiply Add
#define ECX_CX16 (1 << 13) // CMPXCHG16B Instruction
#define ECX_XTPR (1 << 14) // xTPR Update Control
#define ECX_PDCM (1 << 15) // Perf/Debug Capability MSR
#define ECX_PCID (1 << 17) // Process-context Identifiers
#define ECX_DCA (1 << 18) // Direct Cache Access
#define ECX_SSE41 (1 << 19) // Streaming SIMD Extensions 4.1
#define ECX_SSE42 (1 << 20) // Streaming SIMD Extensions 4.2
#define ECX_X2APIC (1 << 21) // Extended xAPIC Support
#define ECX_MOVBE (1 << 22) // MOVBE Instruction
#define ECX_POPCNT (1 << 23) // POPCNT Instruction
#define ECX_TSC (1 << 24) // Local APIC supports TSC Deadline
#define ECX_AESNI (1 << 25) // AESNI Instruction
#define ECX_XSAVE (1 << 26) // XSAVE/XSTOR States
#define ECX_OSXSAVE (1 << 27) // OS Enabled Extended State Management
#define ECX_AVX (1 << 28) // AVX Instructions
#define ECX_F16C (1 << 29) // 16-bit Floating Point Instructions
#define ECX_RDRAND (1 << 30) // RDRAND Instruction

#define EDX_FPU (1 << 0) // Floating-Point Unit On-Chip
#define EDX_VME (1 << 1) // Virtual 8086 Mode Extensions
#define EDX_DE (1 << 2) // Debugging Extensions
#define EDX_PSE (1 << 3) // Page Size Extension
#define EDX_TSC (1 << 4) // Time Stamp Counter
#define EDX_MSR (1 << 5) // Model Specific Registers
#define EDX_PAE (1 << 6) // Physical Address Extension
#define EDX_MCE (1 << 7) // Machine-Check Exception
#define EDX_CX8 (1 << 8) // CMPXCHG8 Instruction
#define EDX_APIC (1 << 9) // APIC On-Chip
#define EDX_SEP (1 << 11) // SYSENTER/SYSEXIT instructions
#define EDX_MTRR (1 << 12) // Memory Type Range Registers
#define EDX_PGE (1 << 13) // Page Global Bit
#define EDX_MCA (1 << 14) // Machine-Check Architecture
#define EDX_CMOV (1 << 15) // Conditional Move Instruction
#define EDX_PAT (1 << 16) // Page Attribute Table
#define EDX_PSE36 (1 << 17) // 36-bit Page Size Extension
#define EDX_PSN (1 << 18) // Processor Serial Number
#define EDX_CLFLUSH (1 << 19) // CLFLUSH Instruction
#define EDX_DS (1 << 21) // Debug Store
#define EDX_ACPI (1 << 22) // Thermal Monitor and Software Clock Facilities
#define EDX_MMX (1 << 23) // MMX Technology
#define EDX_FXSR (1 << 24) // FXSAVE and FXSTOR Instructions
#define EDX_SSE (1 << 25) // Streaming SIMD Extensions
#define EDX_SSE2 (1 << 26) // Streaming SIMD Extensions 2
#define EDX_SS (1 << 27) // Self Snoop
#define EDX_HTT (1 << 28) // Multi-Threading
#define EDX_TM (1 << 29) // Thermal Monitor
#define EDX_PBE (1 << 31) // Pending Break Enable

// Extended Function 0x01
#define EDX_SYSCALL (1 << 11) // SYSCALL/SYSRET
#define EDX_XD (1 << 20) // Execute Disable Bit
#define EDX_1GB_PAGE (1 << 26) // 1 GB Pages
#define EDX_RDTSCP (1 << 27) // RDTSCP and IA32_TSC_AUX
#define EDX_64_BIT (1 << 29) // 64-bit Architecture

void cpu_detect(void);
void cpuid(uint32_t reg, uint32_t *eax, uint32_t *ebx, uint32_t *ecx, uint32_t *edx);

#endif
<file_sep>#include <drivers/pci/driver.h>
#include <lib/stdtypes.h>
#include <lib/x86.h>

uint8_t pci_read8(uint32_t id, uint32_t reg)
{
	uint32_t addr = 0x80000000 | id | (reg & 0xfc);
	outportl(PCI_CONFIG_ADDR, addr);
	return inportb(PCI_CONFIG_DATA + (reg & 0x03));
}

uint16_t pci_read16(uint32_t id, uint32_t reg)
{
	uint32_t addr = 0x80000000 | id | (reg & 0xfc);
	outportl(PCI_CONFIG_ADDR, addr);
	return inportw(PCI_CONFIG_DATA + (reg & 0x02));
}

uint32_t pci_read32(uint32_t id, uint32_t reg)
{
	uint32_t addr = 0x80000000 | id | (reg & 0xfc);
	outportl(PCI_CONFIG_ADDR, addr);
	return inportl(PCI_CONFIG_DATA);
}

void pci_write8(uint32_t id, uint32_t reg, uint8_t data)
{
	uint32_t address = 0x80000000 | id | (reg & 0xfc);
	outportl(PCI_CONFIG_ADDR, address);
	outportb(PCI_CONFIG_DATA + (reg & 0x03), data);
}

void pci_write16(uint32_t id, uint32_t reg, uint16_t data)
{
	uint32_t address = 0x80000000 | id | (reg & 0xfc);
	outportl(PCI_CONFIG_ADDR, address);
	outportw(PCI_CONFIG_DATA + (reg & 0x02), data);
}

void pci_write32(uint32_t id, uint32_t reg, uint32_t data)
{
	uint32_t address = 0x80000000 | id | (reg & 0xfc);
	outportl(PCI_CONFIG_ADDR, address);
	outportl(PCI_CONFIG_DATA, data);
}

static void pci_read_bar(uint32_t id, uint32_t index, uint32_t *address, uint32_t *mask)
{
	uint32_t reg = PCI_CONFIG_BAR0 + index * sizeof(uint32_t);

	// Get address
	*address = pci_read32(id, reg);

	// Find size of the bar
	pci_write32(id, reg, 0xffffffff);
	*mask = pci_read32(id, reg);

	// Restore adddress
	pci_write32(id, reg, *address);
}

void pci_get_bar(pci_bar_t *bar, uint32_t id, uint32_t index)
{
	// Read PCI bar register
	uint32_t addressLow;
	uint32_t maskLow;
	pci_read_bar(id, index, &addressLow, &maskLow);

	if (addressLow & PCI_BAR_64) {
		// 64-bit MMIO
		uint32_t addressHigh;
		uint32_t maskHigh;
		pci_read_bar(id, index + 1, &addressHigh, &maskHigh);

		bar->u.address = (void *)(((uint32_t)addressHigh << 16) | (addressLow & ~0xf));
		bar->size = ~(((uint32_t)maskHigh << 16) | (maskLow & ~0xf)) + 1;
		bar->flags = addressLow & 0xf;
	} else if (addressLow & PCI_BAR_IO) {
		// I/O register
		bar->u.port = (uint16_t)(addressLow & ~0x3);
		bar->size = (uint16_t)(~(maskLow & ~0x3) + 1);
		bar->flags = addressLow & 0x3;
	} else {
		// 32-bit MMIO
		bar->u.address = (void *)(uint32_t)(addressLow & ~0xf);
		bar->size = ~(maskLow & ~0xf) + 1;
		bar->flags = addressLow & 0xf;
	}
}<file_sep>#include <interrupt/gdt.h>
#include <lib/stdtypes.h>

extern void gdt_flush(uint32_t);

static void gdt_set_gate(int32_t, uint32_t, uint32_t, uint8_t, uint8_t);

gdt_entry_t gdt_entries[3];
gdt_ptr_t gdt_ptr;

void gdt_init(void)
{
	// The limit is the last valid byte from the start of the GDT - i.e. the size of the GDT - 1
	gdt_ptr.limit = sizeof(gdt_entry_t) * 3 - 1;
	gdt_ptr.base = (uint32_t) &gdt_entries;

	gdt_set_gate(0, 0, 0, 0, 0);              // Null segment
	gdt_set_gate(1, 0, 0xFFFFF, 0x9A, 0xCF);  // Code segment
	gdt_set_gate(2, 0, 0xFFFFF, 0x92, 0xCF);  // Data segment

	gdt_flush((uint32_t) &gdt_ptr);
}

static void gdt_set_gate(int32_t num, uint32_t base, uint32_t limit, uint8_t access, uint8_t gran)
{
	gdt_entries[num].base_low    = (base & 0xFFFF);
	gdt_entries[num].base_middle = (base >> 16) & 0xFF;
	gdt_entries[num].base_high   = (base >> 24) & 0xFF;

	gdt_entries[num].limit_low   = (limit & 0xFFFF);
	gdt_entries[num].granularity = (limit >> 16) & 0x0F;

	gdt_entries[num].granularity |= gran & 0xF0;
	gdt_entries[num].access      = access;
}
