Merge branch 'master' of git.lfbs.rwth-aachen.de:metalsvm into doxygen

Conflicts:
	.gitignore
	arch/x86/include/asm/apic.h
	arch/x86/include/asm/page.h
	arch/x86/include/asm/processor.h
	arch/x86/kernel/idt.c
This commit is contained in:
Stefan Lankes 2011-04-14 08:40:52 +02:00
commit b5908af744
25 changed files with 427 additions and 228 deletions

View file

@ -49,7 +49,7 @@ extern "C" {
/// LVT LINT0 Register
#define APIC_LINT0 0x0350
/// LVT LINT1 Register
#define APIC_LINT1 0x0360
#define APIC_LINT1 0x0360
/// LVT Error Register
#define APIC_LVT_ER 0x0370
/// Initial Count Register

View file

@ -53,7 +53,9 @@ inline static void irq_disable(void) {
inline static uint32_t irq_nested_disable(void) {
uint32_t flags;
asm volatile("pushf; cli; popl %0": "=r"(flags) : : "memory");
return flags;
if (flags & (1 << 9))
return 1;
return 0;
}
/** @brief Enable IRQs */
@ -69,7 +71,8 @@ inline static void irq_enable(void) {
* @param flags Flags to set. Could be the old ones you got from irq_nested_disable.
*/
inline static void irq_nested_enable(uint32_t flags) {
asm volatile("pushl %0; popf" : : "r"(flags) : "memory");
if (flags)
irq_enable();
}
#ifdef __cplusplus

View file

@ -60,6 +60,8 @@
#define PG_DIRTY (1 << _PAGE_BIT_DIRTY)
/// Big page: 4MB (or 2MB)
#define PG_PSE (1 << _PAGE_BIT_PSE)
/// Page is part of the MPB (SCC specific entry)
#define PG_MPE PG_PSE
/// Global TLB entry (Pentium Pro and later)
#define PG_GLOBAL (1 << _PAGE_BIT_GLOBAL)
/// This virtual address range is reserved as marked

View file

@ -40,21 +40,14 @@ extern "C" {
#endif
#ifdef CONFIG_ROCKCREEK
/*#define SCC_PMEM_REGIONS 2
typedef struct {
uint32_t low;
uint32_t high;
} mem_region_t;
uint32_t addr; // address of the initrd
uint32_t size; // size of the initrd
int32_t argc; // number of RCCE arguments
char** argv; // RCCE arguments
} bootinfo_t;
typedef struct {
uint32_t pid;
uint32_t tile_frequency; // in MHz
uint32_t router_frequency; // in MHz
mem_region_t private_mem[SCC_PMEM_REGIONS];
} scc_info_t;
extern scc_info_t scc_info;*/
extern bootinfo_t* bootinfo;
int scc_init(void);
#endif
@ -135,6 +128,7 @@ inline static void cpuid(uint32_t code, uint32_t* a, uint32_t* b, uint32_t* c, u
asm volatile ("cpuid" : "=a"(*a), "=b"(*b), "=c"(*c), "=d"(*d) : "0"(code));
}
<<<<<<< HEAD
/** @brief Flush the pipeline
*
* The cpuid-instruction is used to flush the pipeline.
@ -155,6 +149,8 @@ inline static void flush_pipeline(void) {
* @param msr The parameter which rdmsr assumes in ECX
* @return The value rdmsr put into EDX:EAX
*/
=======
>>>>>>> a9ce93d119c2709a766c19b9cfa32a0b594b1100
inline static uint64_t rdmsr(uint32_t msr) {
uint32_t low, high;
@ -204,9 +200,22 @@ static inline void write_cr3(uint32_t val) {
asm volatile("mov %0, %%cr3" : : "r"(val));
}
<<<<<<< HEAD
/** @brief Flush a specific page entry in TLB
* @param addr The (virtual) address of the page to flush
*/
=======
static inline uint32_t read_cr4(void) {
uint32_t val;
asm volatile("mov %%cr4, %0" : "=r"(val));
return val;
}
static inline void write_cr4(uint32_t val) {
asm volatile("mov %0, %%cr4" : : "r"(val));
}
>>>>>>> a9ce93d119c2709a766c19b9cfa32a0b594b1100
static inline void tlb_flush_one_page(uint32_t addr)
{
asm volatile("invlpg (%0)" : : "r"(addr) : "memory");
@ -241,18 +250,18 @@ static inline uint32_t read_eflags(void)
uint32_t read_eip(void);
/// A one-instruction-do-nothing
#define NOP1 asm volatile ("nop")
#define NOP1 asm volatile ("nop")
/// Do nothing for 2 instructions
#define NOP2 asm volatile ("nop;nop")
#define NOP2 asm volatile ("nop;nop")
/// Do nothing for 4 instructions
#define NOP4 asm volatile ("nop;nop;nop;nop")
#define NOP4 asm volatile ("nop;nop;nop;nop")
/// Do nothing for 8 instructions
#define NOP8 asm volatile ("nop;nop;nop;nop;nop;nop;nop;nop")
#define NOP8 asm volatile ("nop;nop;nop;nop;nop;nop;nop;nop")
#define HALT asm volatile ("hlt");
/** @brief Init several subsystems
*
* This function calls the initialization procedures for:
* - SCC [if configured]
* - GDT
* - APIC
* - PCI [if configured]
@ -261,9 +270,6 @@ uint32_t read_eip(void);
*/
inline static int system_init(void)
{
#ifdef CONFIG_ROCKCREEK
scc_init();
#endif
gdt_install();
apic_init();
#ifdef CONFIG_PCI

View file

@ -109,6 +109,22 @@ uint32_t apic_cpu_id(void)
return 0;
}
static inline uint32_t apic_version(void)
{
if (lapic)
return lapic_read(APIC_VERSION) & 0xFF;
return 0;
}
static inline uint32_t apic_lvt_entries(void)
{
if (lapic)
return (lapic_read(APIC_VERSION) >> 16) & 0xFF;
return 0;
}
int has_apic(void)
{
return (lapic != 0);
@ -238,6 +254,25 @@ int smp_init(void)
}
#endif
static int lapic_reset(void)
{
uint32_t max_lvt = apic_lvt_entries();
lapic_write(APIC_SVR, 0x17F); // enable the apic and connect to the idt entry 127
lapic_write(APIC_TPR, 0x00); // allow all interrupts
lapic_write(APIC_LVT_T, 0x10000); // disable timer interrupt
if (max_lvt >= 4)
lapic_write(APIC_LVT_TSR, 0x10000); // disable thermal sensor interrupt
if (max_lvt >= 5)
lapic_write(APIC_LVT_PMC, 0x10000); // disable performance counter interrupt
lapic_write(APIC_LINT0, 0x7C); // connect LINT0 to idt entry 124
lapic_write(APIC_LINT1, 0x7D); // connect LINT1 to idt entry 125
lapic_write(APIC_LVT_ER, 0x7E); // connect error to idt entry 126
lapic_write(APIC_ID, 0x00); // reset boot processor id
return 0;
}
/*
* detects the timer frequency of the APIC and restart
* the APIC timer with the correct period
@ -246,10 +281,13 @@ int apic_calibration(void)
{
uint8_t i;
uint32_t flags;
#ifndef CONFIG_ROCKCREEK
uint64_t ticks, old;
uint32_t diff;
#else
uint64_t start, end, ticks;
uint32_t diff;
#endif
if (!has_apic())
return -ENXIO;
@ -257,29 +295,47 @@ int apic_calibration(void)
lapic = map_region(0 /*lapic*/, lapic, 1, MAP_KERNEL_SPACE|MAP_NO_CACHE);
if (BUILTIN_EXPECT(!lapic, 0))
return -ENXIO;
kprintf("Mapped LAPIC at 0x%x\n", lapic);
if (ioapic) {
size_t old = 0;
if (ioapic)
ioapic = (ioapic_t*) map_region(0 /*(size_t)ioapic*/, (size_t) ioapic, 1, MAP_KERNEL_SPACE|MAP_NO_CACHE);
kprintf("Mapped IOAPIC at 0x%x\n", ioapic);
// map all processor entries
for(i=0; i<MAX_CORES; i++) {
if (apic_processors[i] && (old != (((size_t)apic_processors[i]) & 0xFFFFF000)))
old = map_region(((size_t) apic_processors[i]) & 0xFFFFF000, ((size_t) apic_processors[i]) & 0xFFFFF000, 1, MAP_KERNEL_SPACE|MAP_NO_CACHE);
}
}
#ifndef CONFIG_ROCKCREEK
old = get_clock_tick();
/* wait for the next time slice */
while((ticks = get_clock_tick()) - old == 0)
;
HALT;
flags = irq_nested_disable();
lapic_write(APIC_DCR, 0xB); // set it to 1 clock increments
lapic_write(APIC_LVT_T, 0x2007B); // connects the timer to 123 and enables it
lapic_write(APIC_ICR, 0xFFFFFFFF);
lapic_write(APIC_ICR, 0xFFFFFFFFUL);
irq_nested_enable(flags);
/* wait 3 time slices to determine a ICR */
while(get_clock_tick() - ticks < 3)
;
HALT;
diff = 0xFFFFFFFF - lapic_read(APIC_CCR);
diff = 0xFFFFFFFFUL - lapic_read(APIC_CCR);
diff = diff / 3;
flags = irq_nested_disable();
lapic_reset();
lapic_write(APIC_DCR, 0xB); // set it to 1 clock increments
lapic_write(APIC_LVT_T, 0x2007B); // connects the timer to 123 and enables it
lapic_write(APIC_ICR, diff / 3);
lapic_write(APIC_ICR, diff);
irq_nested_enable(flags);
// Now, MetalSVM is able to use the APIC => Therefore, we disable the PIC
outportb(0xA1, 0xFF);
@ -290,39 +346,33 @@ int apic_calibration(void)
* and possess no PIC timer. Therfore, we use the rdtsc to
* to calibrate the APIC timer.
*/
uint64_t start, end, ticks;
uint32_t diff;
if (!has_apic())
return -ENXIO;
lapic = map_region(0 /*lapic*/, lapic, 1, MAP_KERNEL_SPACE|MAP_NO_CACHE);
if (BUILTIN_EXPECT(!lapic, 0))
return -ENXIO;
if (ioapic)
ioapic = (ioapic_t*) map_region(0 /*(size_t)ioapic*/, (size_t)ioapic, 1, MAP_KERNEL_SPACE|MAP_NO_CACHE);
flags = irq_nested_disable();
lapic_write(APIC_DCR, 0xB); // set it to 1 clock increments
lapic_write(APIC_LVT_T, 0x2007B); // connects the timer to 123 and enables it
lapic_write(APIC_ICR, 0xFFFFFFFF);
lapic_write(APIC_ICR, 0xFFFFFFFFUL);
/* wait 3 time slices to determine a ICR */
rmb();
start = rdtsc();
do {
flush_pipeline();
rmb();
end = rdtsc();
ticks = end > start ? end - start : start - end;
} while(ticks*TIMER_FREQ < 3*RC_REFCLOCKMHZ*1000000);
} while(ticks*TIMER_FREQ < 3*RC_REFCLOCKMHZ*1000000UL);
diff = 0xFFFFFFFF - lapic_read(APIC_CCR);
diff = 0xFFFFFFFFUL - lapic_read(APIC_CCR);
diff = diff / 3;
lapic_reset();
lapic_write(APIC_DCR, 0xB); // set it to 1 clock increments
lapic_write(APIC_LVT_T, 0x2007B); // connects the timer to 123 and enables it
lapic_write(APIC_ICR, diff / 3);
lapic_write(APIC_ICR, diff);
irq_nested_enable(flags);
#endif
kprintf("APIC calibration determines an ICR of 0x%x\n", diff / 3);
kprintf("APIC calibration determines an ICR of 0x%x\n", diff);
flags = irq_nested_disable();
#if MAX_CORES > 1
@ -471,16 +521,20 @@ check_lapic:
if (!lapic)
goto out;
i = *((uint32_t*) (lapic+APIC_VERSION));
kprintf("Found APIC at 0x%x\n", lapic);
kprintf("Maximum LVT Entry: 0x%x\n", (i >> 16) & 0xFF);
kprintf("APIC Version: 0x%x\n", i & 0xFF);
kprintf("Maximum LVT Entry: 0x%x\n", apic_lvt_entries());
kprintf("APIC Version: 0x%x\n", apic_version());
if (!((i & 0xFF) >> 4)) {
if (!((apic_version() >> 4))) {
kprintf("Currently, MetalSVM didn't supports extern APICs!\n");
goto out;
}
if (apic_lvt_entries() < 3) {
kprintf("LVT is too small\n");
goto out;
}
return 0;
out:
@ -497,24 +551,28 @@ no_mp:
goto check_lapic;
}
static void apic_err_handler(struct state *s)
{
kprintf("Got APIC error 0x%x\n", lapic_read(APIC_ESR));
}
int apic_init(void)
{
int ret;
uint8_t i;
ret = apic_probe();
if (!ret)
return ret;
lapic_write(APIC_TPR, 0x00); // allow all interrupts
lapic_write(APIC_LVT_T, 0x10000); // disable timer interrupt
lapic_write(APIC_LVT_PMC, 0x10000);// disable performance counter interrupt
lapic_write(APIC_LINT0, 0x7C); // connect LINT0 to idt entry 124
lapic_write(APIC_LINT1, 0x7D); // connect LINT1 to idt entry 125
lapic_write(APIC_LVT_ER, 0x7E); // connect error to idt entry 126
lapic_write(APIC_SVR, 0x17F); // enable the apic and connect to the idt entry 127
// set APIC error handler
irq_install_handler(126, apic_err_handler);
if (0) { //ioapic) {
ret = lapic_reset();
if (!ret)
return ret;
if (ioapic) {
// enable timer interrupt
ioapic_inton(0, apic_processors[boot_processor]->id);
// now lets turn everything else off

View file

@ -103,14 +103,7 @@ gdt_flush:
flush2:
ret
; Loads the IDT defined in '_idtp' into the processor.
; This is declared in C as 'extern void idt_load();'
global idt_load
extern idtp
idt_load:
lidt [idtp]
ret
; determines the current instruction pointer (after the jmp)
global read_eip
read_eip:
pop eax ; Get the return address

View file

@ -69,6 +69,8 @@ int arch_fork(task_t* task)
memcpy(kstacks[id], kstacks[curr_task->id], KERNEL_STACK_SIZE);
task_state_segments[id].cr3 = (uint32_t) (virt_to_phys((size_t)task->pgd));
task_state_segments[id].eflags = read_eflags();
// the parent task will enable the IF flag
task_state_segments[id].eflags |= (1 << 9);
task_state_segments[id].esp0 = (uint32_t) kstacks[id] + KERNEL_STACK_SIZE - sizeof(size_t);
asm volatile("mov %%esp, %0" : "=r"(task_state_segments[id].esp));
@ -76,18 +78,18 @@ int arch_fork(task_t* task)
task_state_segments[id].esp += (uint32_t) kstacks[id];
asm volatile ("pusha");
asm volatile ("pop %%eax" : "=a"(task_state_segments[id].edi));
asm volatile ("pop %%eax" : "=a"(task_state_segments[id].esi));
asm volatile ("pop %%eax" : "=a"(task_state_segments[id].ebp));
asm volatile ("pop %0" : "=r"(task_state_segments[id].edi));
asm volatile ("pop %0" : "=r"(task_state_segments[id].esi));
asm volatile ("pop %0" : "=r"(task_state_segments[id].ebp));
#ifdef WITH_FRAME_POINTER
task_state_segments[id].ebp -= (uint32_t) kstacks[curr_task->id];
task_state_segments[id].ebp += (uint32_t) kstacks[id];
#endif
asm volatile ("add $4, %%esp" ::: "%esp");
asm volatile ("pop %%eax" : "=a"(task_state_segments[id].ebx));
asm volatile ("pop %%eax" : "=a"(task_state_segments[id].edx));
asm volatile ("pop %%eax" : "=a"(task_state_segments[id].ecx));
asm volatile ("pop %%eax" : "=a"(task_state_segments[id].eax));
asm volatile ("pop %0" : "=r"(task_state_segments[id].ebx));
asm volatile ("pop %0" : "=r"(task_state_segments[id].edx));
asm volatile ("pop %0" : "=r"(task_state_segments[id].ecx));
asm volatile ("pop %0" : "=r"(task_state_segments[id].eax));
// This will be the entry point for the new task.
task_state_segments[id].eip = read_eip();

View file

@ -72,14 +72,7 @@ typedef struct {
* "Unhandled Interrupt" exception
*/
static idt_entry_t idt[256] = {[0 ... 255] = {0, 0, 0, 0, 0}};
idt_ptr_t idtp;
/** @brief Loads the IDT
*
* The true definition lives in 'start.asm'
*/
extern void idt_load(void);
static idt_ptr_t idtp;
/*
* Use this function to set an entry in the IDT. Alot simpler
* than twiddling with the GDT ;)
@ -113,5 +106,5 @@ void idt_install(void)
IDT_FLAG_PRESENT|IDT_FLAG_RING3|IDT_FLAG_32BIT|IDT_FLAG_TRAPGATE);
/* Points the processor's internal register to the new IDT */
idt_load();
asm volatile("lidt %0" : : "m" (idtp));
}

View file

@ -23,16 +23,10 @@
#include <metalsvm/processor.h>
#ifdef CONFIG_ROCKCREEK
#include <asm/RCCE_lib.h>
#else
/* disable optimization for the following functions */
uint32_t detect_cpu_frequency(void) __attribute__((optimize(0)));
#endif
static uint32_t cpu_freq = 0;
/* disable optimization for the following functions */
void udelay(uint32_t usecs) __attribute__((optimize(0)));
uint32_t detect_cpu_frequency(void)
{
#ifdef CONFIG_ROCKCREEK
@ -53,12 +47,14 @@ uint32_t detect_cpu_frequency(void)
/* wait for the next time slice */
while((ticks = get_clock_tick()) - old == 0)
;
HALT;
rmb();
start = rdtsc();
/* wait a second to determine the frequency */
while(get_clock_tick() - ticks < TIMER_FREQ)
;
HALT;
rmb();
end = rdtsc();
diff = end > start ? end - start : start - end;
@ -82,6 +78,7 @@ void udelay(uint32_t usecs)
uint64_t deadline = get_cpu_frequency() * usecs;
do {
rmb();
end = rdtsc();
diff = end > start ? end - start : start - end;
} while(diff < deadline);

View file

@ -30,6 +30,10 @@
#include <metalsvm/errno.h>
#include <asm/irq.h>
#include <asm/multiboot.h>
#ifdef CONFIG_ROCKCREEK
#include <asm/RCCE_lib.h>
#include <asm/SCC_API.h>
#endif
/*
* Virtual Memory Layout of the standard configuration
@ -83,6 +87,12 @@ inline static size_t copy_page_table(task_t* task, uint32_t pgd_index, page_tabl
for(i=0; i<1024; i++) {
if (pgt->entries[i] & 0xFFFFF000) {
if (!(pgt->entries[i] & PG_USER)) {
// Kernel page => copy only page entries
new_pgt->entries[i] = pgt->entries[i];
continue;
}
phyaddr = get_page();
if (!phyaddr)
continue;
@ -136,9 +146,10 @@ int create_pgd(task_t* task, int copy)
spinlock_lock(&kslock);
for(i=0; i<KERNEL_SPACE/(1024*PAGE_SIZE); i++) {
for(i=0; i<1024; i++) {
pgd->entries[i] = boot_pgd.entries[i];
if (pgd->entries[i])
// only kernel entries will be copied
if (pgd->entries[i] && !(pgd->entries[i] & PG_USER))
pgt->entries[i] = pgt_container->entries[i];
}
@ -161,6 +172,8 @@ int create_pgd(task_t* task, int copy)
for (i=KERNEL_SPACE/(1024*PAGE_SIZE); i<1024; i++) {
if (!(curr_task->pgd->entries[i]))
continue;
if (!(curr_task->pgd->entries[i] & PG_USER))
continue;
phyaddr = copy_page_table(task, i, (page_table_t*) ((KERNEL_SPACE - 1024*PAGE_SIZE + i*PAGE_SIZE) & 0xFFFFF000), &counter);
if (phyaddr) {
@ -190,8 +203,8 @@ int drop_pgd(void)
spinlock_lock(&task->pgd_lock);
for(i=KERNEL_SPACE/(1024*PAGE_SIZE); i<1024; i++) {
if (pgd->entries[i] & 0xFFFFF000) {
for(i=0; i<1024; i++) {
if (pgd->entries[i] & PG_USER) {
put_page(pgd->entries[i] & 0xFFFFF000);
pgd->entries[i] = 0;
}
@ -324,7 +337,7 @@ size_t map_region(size_t viraddr, size_t phyaddr, uint32_t npages, uint32_t flag
index = (viraddr >> 12) & 0x3FF;
if (BUILTIN_EXPECT(pgt->entries[index], 0)) {
spinlock_unlock(pgd_lock);
kprintf("0x%x is already maped\n");
kprintf("0x%x is already maped\n", viraddr);
return 0;
}
@ -335,6 +348,10 @@ size_t map_region(size_t viraddr, size_t phyaddr, uint32_t npages, uint32_t flag
if (flags & MAP_NO_CACHE)
pgt->entries[index] |= PG_PCD;
#ifdef CONFIG_ROCKCREEK
if (flags & MAP_MPE)
pgt->entries[index] |= PG_MPE;
#endif
if (flags & MAP_USER_SPACE)
atomic_int32_inc(&task->user_usage);
@ -638,8 +655,9 @@ int arch_paging_init(void)
* of course, mb_info has to map into the kernel space
*/
if (mb_info)
map_region((size_t) mb_info, (size_t) mb_info, 1, MAP_KERNEL_SPACE);
map_region((size_t) mb_info & 0xFFFFF000, (size_t) mb_info & 0xFFFFF000, 1, MAP_KERNEL_SPACE);
#if 0
/*
* Map reserved memory regions into the kernel space
*/
@ -657,6 +675,7 @@ int arch_paging_init(void)
mmap++;
}
}
#endif
/*
* Modules like the init ram disk are already loaded.
@ -675,6 +694,25 @@ int arch_paging_init(void)
}
#endif
#ifdef CONFIG_ROCKCREEK
// map SCC's bootinfo
map_region(SCC_BOOTINFO, SCC_BOOTINFO, 1, MAP_KERNEL_SPACE);
// map the initial ramdisk
npages = bootinfo->size / PAGE_SIZE;
if (bootinfo->size % PAGE_SIZE)
npages++;
map_region(bootinfo->addr, bootinfo->addr, npages, MAP_KERNEL_SPACE);
// map SCC's configuration registers
viraddr = map_region(CRB_X0_Y0, CRB_X0_Y0, (CRB_OWN-CRB_X0_Y0+16*1024*1024)/PAGE_SIZE, MAP_KERNEL_SPACE|MAP_NO_CACHE);
kprintf("Map configuration registers at 0x%x\n", viraddr);
// map SCC's message passing buffers
viraddr = map_region(MPB_X0_Y0, MPB_X0_Y0, (MPB_OWN-MPB_X0_Y0+16*1024*1024)/PAGE_SIZE, MAP_KERNEL_SPACE|MAP_MPE);
kprintf("Map message passing buffers at 0x%x\n", viraddr);
#endif
/* enable paging */
write_cr3((uint32_t) &boot_pgd);
i = read_cr0();

View file

@ -51,7 +51,7 @@
// GLOBAL VARIABLES USED BY THE LIBRARY
//......................................................................................
int RCCE_NP; // number of participating cores
int RC_REFCLOCKMHZ=533; // baseline CPU frequency (MHz)
int RC_REFCLOCKMHZ; // baseline CPU frequency (MHz)
int RC_MY_COREID; // physical ID of calling core
int RC_COREID[RCCE_MAXNP]; // array of physical core IDs for all participating
// cores, sorted by rank
@ -232,7 +232,7 @@ int RCCE_init(
unsigned int RCCE_SHM_BUFFER_offset ,result, rd_slot_nbr, wr_slot_nbr;
#endif
void *nothing = NULL;
#ifdef SCC
// Copperridge specific initialization...
InitAPI(0); //fflush(0)

View file

@ -10,12 +10,7 @@
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* This file is part of MetalSVM.
*/
* WITHOUT WARRANTIES OR COND */
#include <metalsvm/stdio.h>
#include <metalsvm/errno.h>
@ -27,22 +22,20 @@
#ifdef CONFIG_ROCKCREEK
#define CCR_INTR_ACTIVE 0x02
bootinfo_t* bootinfo = (bootinfo_t*) SCC_BOOTINFO;
//scc_info_t scc_info;
static char* rcce_argv[] = {"MetalSVM", "1", "533", "0"};
static int rcce_argc = 4;
/* PSE bit for Pentium+ equals MPE (message buffer enable) flag in RCK! So, use it to create _PAGE_MPB symbol... */
#define _CR4_MPE 0x00000800
/*
* This is a modified MPB program, which is part of the RCCE distribution (src/mpb.c).
* This is the modified MPB program, which is part of the RCCE distribution (src/mpb.c).
*
* This function clears the local MPB and resets the test&set register.
*/
static int scc_reset(void)
static int scc_clear(void)
{
int tmp, x, y, z, offset;
// Initialize API
InitAPI(0);
// Find out who I am...
tmp=ReadConfigReg(CRB_OWN+MYTILEID);
x=(tmp>>3) & 0x0f; // bits 06:03
@ -69,74 +62,33 @@ static int scc_reset(void)
int scc_init(void)
{
// uint32_t x, y, z;
// uint32_t tmp;
int num_ranks;
int my_rank;
return 0;
int i, my_rank;
kprintf("Initialize Rock Creek!\n");
if (RCCE_init(&rcce_argc, &rcce_argv) != RCCE_SUCCESS)
kprintf("address of the initrd: 0x%x\n", bootinfo->addr);
kprintf("size of the initrd: %d\n", bootinfo->size);
kprintf("rcce argc = %d\n", bootinfo->argc);
for(i=0; i<bootinfo->argc; i++)
kprintf("rcce argv[%d] = %s\n", i, bootinfo->argv[i]);
if (RCCE_init(&bootinfo->argc, &bootinfo->argv) != RCCE_SUCCESS)
return -ENODEV;
my_rank = RCCE_ue();
num_ranks = RCCE_num_ues();
kprintf("Got rank %d of %d ranks\n", my_rank, num_ranks);
/* Enable Messagepassing in CR4 */
uint32_t cr4 = read_cr4();
cr4 = cr4 | _CR4_MPE;
write_cr4(cr4);
i = ReadConfigReg(CRB_OWN+GLCFG0);
kprintf("glcfg0 0x%x\n", i);
/* synchronize before starting MetalSVM: */
RCCE_barrier(&RCCE_COMM_WORLD);
/*tmp = *((uint32_t*) (CRB_OWN+MYTILEID));
x=(tmp>>3) & 0x0f; // bits 06:03
y=(tmp>>7) & 0x0f; // bits 10:07
z=(tmp ) & 0x07; // bits 02:00
scc_info.pid = PID(x, y, z);
kprintf("SCC Processor Id: %u (%u,%u,%u)\n", scc_info.pid, x, y, z);
*/
/* default values for 16 GB system */
/*scc_info.private_mem[0].low = 0x00;
scc_info.private_mem[0].high = 0x13FFFFFF;
scc_info.private_mem[1].low = 0xFF000000;
scc_info.private_mem[1].high = 0xFFFFFFFF;
*/
// tmp = *((uint32_t*) (CRB_OWN+GCBCFG));
// tmp = (tmp & 0x3FFFFFF) >> 7;
//kprintf("Own GCBCFG is 0x%x\n", tmp);
/* if (tmp == 0x70E1) {
scc_info.tile_frequency = 800;
scc_info.router_frequency = 1600;
} else {
scc_info.tile_frequency = 533;
scc_info.router_frequency = 800;
}
*/
/* kprintf("The default tile frequency is %u MHz\nThe default router frequency is %u MHz\n",
scc_info.tile_frequency, scc_info.router_frequency);
if (z == 0)
tmp = *((uint32_t*) (CRB_OWN+GLCFG0));
else if (z == 1)
tmp = *((uint32_t*) (CRB_OWN+GLCFG1));
else
tmp = 0;
*/
/* set INTR to enable maskable interrupts */
/* tmp = tmp | CCR_INTR_ACTIVE;
if (z == 0)
*((uint32_t*) (CRB_OWN+GLCFG0)) = tmp;
else if (z == 1)
*((uint32_t*) (CRB_OWN+GLCFG1)) = tmp;
*/
/* reload core configuration */
/* tmp = 0;
if (z == 0)
tmp = *((uint32_t*) (CRB_OWN+GLCFG0));
else if (z == 1)
tmp = *((uint32_t*) (CRB_OWN+GLCFG1));
kprintf("Core Configuration %u: 0x%x\n", z, tmp);
*/
//RCCE_barrier(&RCCE_COMM_WORLD);
kputs("Now, the SCC is initialized!\n");

View file

@ -23,6 +23,7 @@
#include <metalsvm/fs.h>
#include <metalsvm/errno.h>
#include <asm/multiboot.h>
#include <asm/processor.h>
static vfs_node_t initrd_root;
@ -213,8 +214,10 @@ int initrd_init(void)
{
dir_block_t* dir_block;
vfs_node_t* tmp;
#ifdef CONFIG_MULTIBOOT
#if defined(CONFIG_ROCKCREEK) || defined(CONFIG_MULTIBOOT)
uint32_t i, j, k, l;
#endif
#ifdef CONFIG_MULTIBOOT
uint32_t mods_count = 0;
multiboot_module_t* mmodule = NULL;
@ -256,6 +259,10 @@ int initrd_init(void)
#ifdef CONFIG_MULTIBOOT
for(i=0; i<mods_count; i++) {
initrd_header_t* header = (initrd_header_t*) mmodule[i].mod_start;
#elif defined(CONFIG_ROCKCREEK)
for(i=0; i<1; i++) {
initrd_header_t* header = (initrd_header_t*) bootinfo->addr;
#endif
initrd_file_desc_t* file_desc;
vfs_node_t* new_node;
@ -328,6 +335,7 @@ int initrd_init(void)
next_file:
file_desc++;
}
#if defined(CONFIG_ROCKCREEK) || defined(CONFIG_MULTIBOOT)
}
#endif

View file

@ -66,6 +66,7 @@ extern "C" {
#define PRIVATE_MEM1_END 0x13FFFFFF
#define PRIVATE_MEM2_START 0xFF000000
#define PRIVATE_MEM2_END 0xFFFFFFFF
#define SCC_BOOTINFO 0x80000
#define BUILTIN_EXPECT(exp, b) __builtin_expect((exp), (b))
//#define BUILTIN_EXPECT(exp, b) (exp)

View file

@ -45,7 +45,9 @@ extern "C" {
#define MAP_HEAP (1 << 5)
#define MAP_CODE (1 << 6)
#define MAP_READONLY (1 << 7)
#ifdef CONFIG_ROCKCREEK
#define MAP_MPE (1 << 8)
#endif
void NORETURN abort(void);
/** @brief Kernel's memory allocator function.
@ -83,6 +85,7 @@ void kfree(void*, size_t);
* @return Long value of the parsed numerical string
*/
long strtol(const char* str, char** endptr, int base);
unsigned long strtoul(const char* nptr, char** endptr, int base);
/** @brief ASCII to integer
*

View file

@ -89,6 +89,9 @@ int main(void)
#endif
multitasking_init();
mmu_init();
#ifdef CONFIG_ROCKCREEK
scc_init();
#endif
initrd_init();
irq_enable();
@ -111,7 +114,7 @@ int main(void)
reschedule();
while(1) {
NOP8;
HALT;
}
return 0;

View file

@ -126,7 +126,7 @@ static void NORETURN do_exit(int arg) {
kputs("Kernel panic: scheduler found no valid task\n");
while(1) {
NOP8;
HALT;
}
}

View file

@ -1,4 +1,4 @@
C_source := string.c stdio.c printf.c sprintf.c ucmpdi2.c lshrdi3.c qdivrem.c udivdi3.c divdi3.c moddi3.c umoddi3.c strtol.c
C_source := string.c stdio.c printf.c sprintf.c ucmpdi2.c lshrdi3.c qdivrem.c udivdi3.c divdi3.c moddi3.c umoddi3.c strtol.c strtoul.c
MODULE := libkern
include $(TOPDIR)/Makefile.inc

112
libkern/strtoul.c Normal file
View file

@ -0,0 +1,112 @@
/*-
* Copyright (c) 1990, 1993
* The Regents of the University of California. All rights reserved.
*
* This code is derived from software contributed to Berkeley by
* Chris Torek.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 4. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* From: @(#)strtoul.c 8.1 (Berkeley) 6/4/93
*/
/*
* The code has been taken from FreeBSD (sys/libkern/strtoul.c) and is therefore
* BSD-licensed. Unnecessary functions have been removed and all typedefs required
* have been added.
*/
/* MetalSVM prelude */
#include <metalsvm/stddef.h>
#include <metalsvm/ctype.h>
#include <asm/limits.h>
/*
* Convert a string to an unsigned long integer.
*
* Ignores `locale' stuff. Assumes that the upper and lower case
* alphabets and digits are each contiguous.
*/
unsigned long
strtoul(nptr, endptr, base)
const char *nptr;
char **endptr;
int base;
{
const char *s = nptr;
unsigned long acc;
unsigned char c;
unsigned long cutoff;
int neg = 0, any, cutlim;
/*
* See strtol for comments as to the logic used.
*/
do {
c = *s++;
} while (isspace(c));
if (c == '-') {
neg = 1;
c = *s++;
} else if (c == '+')
c = *s++;
if ((base == 0 || base == 16) &&
c == '0' && (*s == 'x' || *s == 'X')) {
c = s[1];
s += 2;
base = 16;
}
if (base == 0)
base = c == '0' ? 8 : 10;
cutoff = (unsigned long)ULONG_MAX / (unsigned long)base;
cutlim = (unsigned long)ULONG_MAX % (unsigned long)base;
for (acc = 0, any = 0;; c = *s++) {
if (!isascii(c))
break;
if (isdigit(c))
c -= '0';
else if (isalpha(c))
c -= isupper(c) ? 'A' - 10 : 'a' - 10;
else
break;
if (c >= base)
break;
if (any < 0 || acc > cutoff || (acc == cutoff && c > cutlim))
any = -1;
else {
any = 1;
acc *= base;
acc += c;
}
}
if (any < 0) {
acc = ULONG_MAX;
} else if (neg)
acc = -acc;
if (endptr != 0)
*((const char **)endptr) = any ? s - 1 : nptr;
return (acc);
}

View file

@ -126,6 +126,13 @@ int mmu_init(void)
if (mb_info && (mb_info->flags & MULTIBOOT_INFO_MODS)) {
multiboot_module_t* mmodule = (multiboot_module_t*) mb_info->mods_addr;
/*
* Mark the mb_info as used.
*/
page_set_mark((size_t)mb_info / PAGE_SIZE);
atomic_int32_inc(&total_allocated_pages);
atomic_int32_dec(&total_available_pages);
for(i=0; i<mb_info->mods_count; i++, mmodule++) {
for(addr=mmodule->mod_start; addr<mmodule->mod_end; addr+=PAGE_SIZE) {
page_set_mark(addr / PAGE_SIZE);
@ -150,6 +157,23 @@ int mmu_init(void)
atomic_int32_inc(&total_pages);
atomic_int32_inc(&total_available_pages);
}
/*
* Mark the bootinfo as used.
*/
page_set_mark((size_t)bootinfo / PAGE_SIZE);
atomic_int32_inc(&total_allocated_pages);
atomic_int32_dec(&total_available_pages);
/*
* The init ram disk are already loaded.
* Therefore, we set these pages as used.
*/
for(addr=bootinfo->addr; addr < bootinfo->addr+bootinfo->size; addr+=PAGE_SIZE) {
page_set_mark(addr / PAGE_SIZE);
atomic_int32_inc(&total_allocated_pages);
atomic_int32_dec(&total_available_pages);
}
#else
#error Currently, MetalSVM supports only the Multiboot specification or the RockCreek processor!
#endif

View file

@ -34,7 +34,7 @@ int main(int argc, char** argv)
printf("Create child process...\n");
pid = fork();
pid = 42; //fork();
if (pid == 0) { // child
char* newargs[] = {"/bin/hello", "one", "two", "three", NULL};
char* newenv[] = {"USER=root", "PATH=/bin:/sbin:/usr/bin", "PWD=/", "TEMP=/tmp", NULL};

View file

@ -17,7 +17,7 @@ default: all
all: make_initrd initrd.img
initrd.img: $(EXECFILES)
initrd.img: $(EXECFILES) make_initrd
./make_initrd /bin $(foreach FILE, $(EXECFILES), $(FILE) $(shell basename $(FILE)))
make_initrd: make_initrd.o
@ -35,7 +35,13 @@ scc_setup.bin: scc_setup.asm
reset_vector.bin: reset_vector.o
ld --oformat binary -Ttext 0 -melf_i386 -o $@ $<
SCC: scc_setup.bin reset_vector.bin
scc_bootinfo.asm: bootinfo.sh
./bootinfo.sh 0x00400000 initrd.img 1 533 0 > scc_bootinfo.asm
scc_bootinfo.bin: scc_bootinfo.asm
$(NASM) $(NASMFLAGS) -o $@ $<
SCC: scc_bootinfo.bin scc_setup.bin reset_vector.bin initrd.img
cp ../metalsvm.elf .
$(CROSS_OBJCOPY) -j .mboot -j .text -j .data -j .rodata -j .bss -O binary metalsvm.elf metalsvm.bin
chmod a-x *.bin
@ -44,7 +50,7 @@ SCC: scc_setup.bin reset_vector.bin
sccMerge -noimage -m 8 -n 12 -force ./metalsvm.mt
clean:
$(RM) -rf *.o *~ make_initrd *.bin *.obj *.hex *.elf obj
$(RM) -rf *.o *~ make_initrd initrd.img *.bin *.obj *.hex *.elf obj
depend:
$(CC) -MM $(CFLAGS) *.c > Makefile.dep

39
tools/bootinfo.sh Executable file
View file

@ -0,0 +1,39 @@
#!/bin/sh
#
IMAGESIZE=$(stat -c%s "$2")
NCORES=$3
ORG=0x80000
echo "[BITS 16]"
echo "SECTION .data"
echo "ORG $ORG"
echo "addr DD $1 ; start addresss of the initrd"
echo "size DD $IMAGESIZE ; size of the initrd"
shift
shift
shift
ARGC=`expr $# + 2`
echo "argc DD $ARGC"
echo "argv DD Largv"
echo "Largv EQU \$"
echo -n " DD name, ncores"
for i in $*
do
echo -n ", L$i"
done
echo ""
echo "name EQU \$"
echo " DB \"MetalSVM\", 0"
echo "ncores EQU \$"
echo " DB \"$NCORES\", 0"
for i in $*
do
echo "L$i EQU \$"
echo " DB \"$i\", 0"
done
echo "gap:"
echo "TIMES 4096-(\$-\$\$) DB 0"

View file

@ -1,3 +1,4 @@
0x00080000 scc_bootinfo.bin
0x00090200 scc_setup.bin
0x00100000 metalsvm.bin
0x00400000 initrd.img

View file

@ -28,53 +28,11 @@ _start:
msg db "?ello from MetalSVM bootloader!!",0
enable_A20:
call a20wait
mov al,0xAD
out 0x64,al
call a20wait
mov al,0xD0
out 0x64,al
call a20wait2
in al,0x60
push eax
call a20wait
mov al,0xD1
out 0x64,al
call a20wait
pop eax
or al,2
out 0x60,al
call a20wait
mov al,0xAE
out 0x64,al
call a20wait
ret
a20wait:
in al,0x64
test al,2
jnz a20wait
ret
a20wait2:
in al,0x64
test al,1
jz a20wait2
ret
_realstart:
; IRQs are already disabled by reset_vector
; cli
lgdt [gdtr]
; call enable_A20
; switch to protected mode by setting PE bit
mov eax, cr0