Skip to content

Commit

Permalink
basic apic done
Browse files Browse the repository at this point in the history
  • Loading branch information
tw4452852 committed Sep 3, 2013
2 parents d111f9b + 95c5cb0 commit e923098
Show file tree
Hide file tree
Showing 16 changed files with 541 additions and 17 deletions.
119 changes: 119 additions & 0 deletions boot/.bochsrc
Original file line number Diff line number Diff line change
Expand Up @@ -129,3 +129,122 @@ boot: disk
# log: /dev/tty
#=======================================================================
log: bochsout.txt
#=======================================================================
# KEYBOARD:
# This defines parameters related to the emulated keyboard
#
# TYPE:
# Type of keyboard return by a "identify keyboard" command to the
# keyboard controller. It must be one of "xt", "at" or "mf".
# Defaults to "mf". It should be ok for almost everybody. A known
# exception is french macs, that do have a "at"-like keyboard.
#
# SERIAL_DELAY:
# Approximate time in microseconds that it takes one character to
# be transferred from the keyboard to controller over the serial path.
#
# PASTE_DELAY:
# Approximate time in microseconds between attempts to paste
# characters to the keyboard controller. This leaves time for the
# guest os to deal with the flow of characters. The ideal setting
# depends on how your operating system processes characters. The
# default of 100000 usec (.1 seconds) was chosen because it works
# consistently in Windows.
# If your OS is losing characters during a paste, increase the paste
# delay until it stops losing characters.
#
# KEYMAP:
# This enables a remap of a physical localized keyboard to a
# virtualized us keyboard, as the PC architecture expects.
#
# Examples:
# keyboard: type=mf, serial_delay=200, paste_delay=100000
# keyboard: keymap=gui/keymaps/x11-pc-de.map
#=======================================================================
keyboard: type=mf, keymap=$BXSHARE/keymaps/x11-pc-us.map
#=======================================================================
# CPU:
# This defines cpu-related parameters inside Bochs:
#
# MODEL:
# Selects CPU configuration to emulate from pre-defined list of all
# supported configurations. When this option is used, the CPUID option
# has no effect anymore.
#
# CPU configurations that can be selected:
# -----------------------------------------------------------------
# pentium_mmx Intel Pentium MMX
# amd_k6_2_chomper AMD-K6(tm) 3D processor (Chomper)
# p2_klamath Intel Pentium II (Klamath)
# p3_katmai Intel Pentium III (Katmai)
# p4_willamette Intel(R) Pentium(R) 4 (Willamette)
# core_duo_t2400_yonah Intel(R) Core(TM) Duo CPU T2400 (Yonah)
# atom_n270 Intel(R) Atom(TM) CPU N270
# athlon64_clawhammer AMD Athlon(tm) 64 Processor 2800+ (Clawhammer)
# athlon64_venice AMD Athlon(tm) 64 Processor 3000+ (Venice)
# turion64_tyler AMD Turion(tm) 64 X2 Mobile TL-60 (Tyler)
# phenom_8650_toliman AMD Phenom X3 8650 (Toliman)
# p4_prescott_celeron_336 Intel(R) Celeron(R) 336 (Prescott)
# core2_penryn_t9600 Intel Mobile Core 2 Duo T9600 (Penryn)
# corei5_lynnfield_750 Intel(R) Core(TM) i5 750 (Lynnfield)
# corei5_arrandale_m520 Intel(R) Core(TM) i5 M 520 (Arrandale)
# corei7_sandy_bridge_2600k Intel(R) Core(TM) i7-2600K (Sandy Bridge)
# corei7_ivy_bridge_3770k Intel(R) Core(TM) i7-3770K CPU (Ivy Bridge)
#
# COUNT:
# Set the number of processors:cores per processor:threads per core
# when Bochs is compiled for SMP emulation.
# Bochs currently supports up to 8 threads running simultaniosly.
# If Bochs is compiled without SMP support, it won't accept values
# different from 1.
#
# QUANTUM:
# Maximum amount of instructions allowed to execute by processor before
# returning control to another cpu. This option exists only in Bochs
# binary compiled with SMP support.
#
# RESET_ON_TRIPLE_FAULT:
# Reset the CPU when triple fault occur (highly recommended) rather than
# PANIC. Remember that if you trying to continue after triple fault the
# simulation will be completely bogus !
#
# CPUID_LIMIT_WINNT:
# Determine whether to limit maximum CPUID function to 2. This mode is
# required to workaround WinNT installation and boot issues.
#
# MSRS:
# Define path to user CPU Model Specific Registers (MSRs) specification.
# See example in msrs.def.
#
# IGNORE_BAD_MSRS:
# Ignore MSR references that Bochs does not understand; print a warning
# message instead of generating #GP exception. This option is enabled
# by default but will not be avaiable if configurable MSRs are enabled.
#
# MWAIT_IS_NOP:
# When this option is enabled MWAIT will not put the CPU into a sleep state.
# This option exists only if Bochs compiled with --enable-monitor-mwait.
#
# IPS:
# Emulated Instructions Per Second. This is the number of IPS that bochs
# is capable of running on your machine. You can recompile Bochs with
# --enable-show-ips option enabled, to find your host's capability.
# Measured IPS value will then be logged into your log file or shown
# in the status bar (if supported by the gui).
#
# IPS is used to calibrate many time-dependent events within the bochs
# simulation. For example, changing IPS affects the frequency of VGA
# updates, the duration of time before a key starts to autorepeat, and
# the measurement of BogoMips and other benchmarks.
#
# Examples:
#
# Bochs Machine/Compiler Mips
# ______________________________________________________________________
# 2.4.6 3.4Ghz Intel Core i7 2600 with Win7x64/g++ 4.5.2 85 to 95 Mips
# 2.3.7 3.2Ghz Intel Core 2 Q9770 with WinXP/g++ 3.4 50 to 55 Mips
# 2.3.7 2.6Ghz Intel Core 2 Duo with WinXP/g++ 3.4 38 to 43 Mips
# 2.2.6 2.6Ghz Intel Core 2 Duo with WinXP/g++ 3.4 21 to 25 Mips
# 2.2.6 2.1Ghz Athlon XP with Linux 2.6/g++ 3.4 12 to 15 Mips
#=======================================================================
cpu: count=2
2 changes: 1 addition & 1 deletion boot/Makefile
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
TARGET=boot.bin
OBJS=boot.o main.o video.o mem.o interrupt.o gdt.o isr.o
OBJS=boot.o main.o video.o mem.o interrupt.o gdt.o isr.o apic.o io.o keyboard.o
LDSCRIPT=boot.ld
LDFLAGS=-T $(LDSCRIPT)
CFLAGS=-m32
Expand Down
229 changes: 229 additions & 0 deletions boot/apic.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,229 @@
#include "common.h"
#include "apic.h"
#include "video.h"
#include "string.h"
#include "io.h"

static u32 lapic_base_addr;
static u32 ioapic_base_addr = 0;

#define lapic_read_reg(offset) _LAPIC_READ_REG(lapic_base_addr, offset)
#define lapic_write_reg(offset, v) _LAPIC_WRITE_REG(lapic_base_addr, offset, v)

static void get_lapic_base_addr(void);
static void show_all_lapic_regs(void);
static void lapic_init(void);
static void ioapic_init(void);
static void disable_8259(void);
static void detect_ioapic(void);
static u32 ioapic_read(u32 index);
static void ioapic_write(u32 index, u32 value);
static void switch_to_apic(void);

void
apic_eoi(u32 irq)
{
lapic_write_reg(_LAPIC_EOI_OFFSET, 0);
}

void
apic_init()
{
__asm__("cli");
lapic_init();
ioapic_init();
__asm__("sti");
}

void
lapic_init()
{
get_lapic_base_addr();
// inhibite the softints
//lapic_write_reg(_LAPIC_TPR_OFFSET, 0x30);
// local interrupt 0 is a external interrupts
lapic_write_reg(_LAPIC_LINT0_OFFSET, 0x8700);
// local interrupt 1 is a nmi
lapic_write_reg(_LAPIC_LINT1_OFFSET, 0x400);

show_all_lapic_regs();
}

static inline void
get_lapic_base_addr()
{
__asm__(
"rdmsr"
:"=a"(lapic_base_addr)
:"c"(0x1b)
);
tw_printf("apic: 0x%x\n", lapic_base_addr);
// clear lowest 12 bit
lapic_base_addr &= 0xfffff000;
}

static inline void
show_all_lapic_regs()
{
tw_printf("show local apic(%d) regs:\n", lapic_read_reg(_LAPIC_ID_OFFSET));
tw_printf(">>> version: 0x%x\n", lapic_read_reg(_LAPIC_VER_OFFSET));
tw_printf(">>> task priority: 0x%x\n", lapic_read_reg(_LAPIC_TPR_OFFSET));
tw_printf(">>> timer interrupt vector: 0x%x\n", lapic_read_reg(_LAPIC_TIMER_OFFSET));
tw_printf(">>> performance counter: 0x%x\n", lapic_read_reg(_LAPIC_PC_OFFSET));
tw_printf(">>> local interrupt 0: 0x%x\n", lapic_read_reg(_LAPIC_LINT0_OFFSET));
tw_printf(">>> local interrupt 1: 0x%x\n", lapic_read_reg(_LAPIC_LINT1_OFFSET));
tw_printf(">>> error interrupt: 0x%x\n", lapic_read_reg(_LAPIC_LERR_OFFSET));
tw_printf(">>> spurious interrupt: 0x%x\n", lapic_read_reg(_LAPIC_SIV_OFFSET));
}

static void
ioapic_init()
{
// disable pic(8259a)
disable_8259();
detect_ioapic();
if (ioapic_base_addr == 0) {
return;
}
// ioapic irq mapping
// ioapic irq : cpu vector
// 0-15: 0x20-0x2f
int irq;
for (irq = 0; irq < 16; irq++) {
if (irq == 2) {
//disable irq2
continue;
}
ioapic_write(0x10 + irq*2, 0x20 + irq);
//tw_printf("irq %d: 0x%x%x\n", irq, ioapic_read(0x10+irq*2+1), ioapic_read(0x10+irq*2));
}

switch_to_apic();
}

static inline void
switch_to_apic()
{
// for recently motherborad, there is no need to do these
outb(0x22, 0x70);
outb(0x23, 0x01);
}

static inline u32
ioapic_read(u32 index)
{
*(u32 *)ioapic_base_addr = index;
return *(u32 *)(ioapic_base_addr + 0x10);
}

static inline void
ioapic_write(u32 index, u32 value)
{
*(u32 *)ioapic_base_addr = index;
*(u32 *)(ioapic_base_addr + 0x10) = value;
}


static inline void
disable_8259()
{
outb(0x21, 0xff);
outb(0xa1, 0xff);
}

static u32
find_rsdp(char *start, char *end)
{
while (start < end) {
if (tw_memcmp(start, _RSDP_STR, strlen(_RSDP_STR)) == 0) {
return (u32)start;
}
start += 16;
}
return 0;
}


static void
detect_ioapic()
{
u32 ebda_base = (*(u16 *)0x40e) << 4;
u32 rsdp_base, rsdt_base;
int i, entries_cnt;

// try to find rsdp within 1Kb of ebda and [0xe0000-0xfffff]
rsdp_base = find_rsdp((char *)ebda_base, (char *)(ebda_base + 0x400));
if (rsdp_base == 0) {
rsdp_base = find_rsdp((char *)0xe0000, (char *)0xfffff);
}
if (rsdp_base == 0) {
tw_printf("can't find rsdp!!\n");
return;
}
typedef struct {
char sig[8];
u8 checksum;
char oemid[6];
u8 revision;
u32 rsdt_addr;
} __attribute__ ((packed)) rsdp_s;
rsdp_s *rsdp = (rsdp_s *)rsdp_base;
tw_printf("rsdp(0x%x): oemid(%s), revision(0x%x), rsdt_addr(0x%x)\n",
(u32)rsdp, rsdp->oemid, rsdp->revision, rsdp->rsdt_addr);

// parse rsdt
rsdt_base = rsdp->rsdt_addr;
typedef struct {
char sig[4];
u32 len;
u8 revision;
u8 checksum;
char oemid[6];
char oem_tbl_id[8];
u32 oem_revision;
u32 creator_id;
u32 creator_revison;
char* entries[];
} __attribute__ ((packed)) rsdt_header_s;
rsdt_header_s *rsdt_header = (rsdt_header_s *)rsdt_base;
tw_printf("rsdt header(0x%x): len(0x%x), revision(0x%x), oemid(%s), oem_tbl_id(%s), oem_revision(0x%x)\n",
(u32)rsdt_header, rsdt_header->len, rsdt_header->revision, rsdt_header->oemid,
rsdt_header->oem_tbl_id, rsdt_header->oem_revision);

// find madt
entries_cnt = (rsdt_header->len - sizeof(*rsdt_header))/sizeof(char*);
for (i = 0; i < entries_cnt; i++) {
if (tw_memcmp(rsdt_header->entries[i], _APIC_STR, strlen(_APIC_STR)) == 0) {
break;
}
}
if (i == entries_cnt) {
tw_printf("can't find madt!!\n");
return;
}

tw_printf("0x%x\n", (u32)(rsdt_header->entries[i]));
// find io-apic
struct ioapic_head {
u8 type;
u8 len;
u8 ioapic_id;
u8 reverse;
u32 ioapic_addr;
u32 globl_sys_int_base;
} __attribute__ ((packed)) *p = (struct ioapic_head *)(rsdt_header->entries[i] + 44);
while ((u32)p < (u32)(rsdt_header->entries[i] + ((rsdt_header_s *)(rsdt_header->entries[i]))->len)) {
if (p->type == 1) {
break;
}
p = (struct ioapic_head *)((char *)p + p->len);
}
if (p->type != 1) {
tw_printf("can't find ioapic entry!!\n");
return;
}
tw_printf("ioapic: id(%d), addr(0x%x), global_sys_interrupt_base(%d)\n",
p->ioapic_id, p->ioapic_addr, p->globl_sys_int_base);

ioapic_base_addr = p->ioapic_addr;
}
39 changes: 39 additions & 0 deletions boot/apic.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
#ifndef APIC_H

#define APIC_H

void apic_init(void);
void apic_eoi(u32 irq);

#define _LAPIC_ID_OFFSET 0x20
#define _LAPIC_VER_OFFSET 0x30
#define _LAPIC_TPR_OFFSET 0x80
#define _LAPIC_APR_OFFSET 0x90
#define _LAPIC_PPR_OFFSET 0xa0
#define _LAPIC_EOI_OFFSET 0xb0
#define _LAPIC_RRD_OFFSET 0xc0
#define _LAPIC_LD_OFFSET 0xd0
#define _LAPIC_DF_OFFSET 0xe0
#define _LAPIC_SIV_OFFSET 0xf0
#define _LAPIC_ISR_OFFSET 0x100
#define _LAPIC_TMR_OFFSET 0x180
#define _LAPIC_IRR_OFFSET 0x200
#define _LAPIC_ERR_OFFSET 0x280
#define _LAPIC_CMCI_OFFSET 0x2f0
#define _LAPIC_ICR_OFFSET 0x300
#define _LAPIC_TIMER_OFFSET 0x320
#define _LAPIC_SENOR_OFFSET 0x330
#define _LAPIC_PC_OFFSET 0x340
#define _LAPIC_LINT0_OFFSET 0x350
#define _LAPIC_LINT1_OFFSET 0x360
#define _LAPIC_LERR_OFFSET 0x370
#define _LAPIC_IC_OFFSET 0x380
#define _LAPIC_CC_OFFSET 0x390
#define _LAPIC_DC_OFFSET 0x3e0

#define _LAPIC_READ_REG(base, offset) (*(u32 *)((base) + (offset)))
#define _LAPIC_WRITE_REG(base, offset, v) (*(u32 *)((base) + (offset)) = (v))

#define _RSDP_STR "RSD PTR "
#define _APIC_STR "APIC"
#endif /* end of include guard: APIC_H */
Loading

0 comments on commit e923098

Please sign in to comment.